ETH Price: $3,460.13 (+0.14%)
Gas: 11 Gwei

Contract

0x2e5C0BD35995ea7e8903C55ba66f28270310498f
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60c06040161801032022-12-14 2:58:35582 days ago1670986715IN
 Create: PNounsPrivider
0 ETH0.0470061311.59320737

Advanced mode:
Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PNounsPrivider

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 16 : PNounsProvider.sol
// SPDX-License-Identifier: MIT

/**
 *
 * Created by Satoshi Nakajima (@snakajima)
 */

pragma solidity ^0.8.6;

import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
import 'assetprovider.sol/IAssetProvider.sol';
import 'randomizer.sol/Randomizer.sol';
import '@openzeppelin/contracts/interfaces/IERC165.sol';
import '../packages/graphics/Path.sol';
import '../packages/graphics/SVG.sol';
import '../packages/graphics/Text.sol';
import '../packages/graphics/IFontProvider.sol';

contract PNounsPrivider is IAssetProviderEx, Ownable, IERC165 {
  using Strings for uint256;
  using Randomizer for Randomizer.Seed;
  using Vector for Vector.Struct;
  using Path for uint[];
  using SVG for SVG.Element;
  using TX for string;
  using Trigonometry for uint;

  IFontProvider public immutable font;
  IAssetProvider public immutable nounsProvider;

  constructor(IFontProvider _font, IAssetProvider _nounsProvider) {
    font = _font;
    nounsProvider = _nounsProvider;
  }

  function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
    return
      interfaceId == type(IAssetProvider).interfaceId ||
      interfaceId == type(IAssetProviderEx).interfaceId ||
      interfaceId == type(IERC165).interfaceId;
  }

  function getOwner() external view override returns (address) {
    return owner();
  }

  function getProviderInfo() external view override returns (ProviderInfo memory) {
    return ProviderInfo('pnouns', 'pNouns', this);
  }

  function totalSupply() external pure override returns (uint256) {
    return 0;
  }

  function processPayout(uint256 _assetId) external payable override {
    address payable payableTo = payable(owner());
    payableTo.transfer(msg.value);
    emit Payout('pnouns', _assetId, payableTo, msg.value);
  }

  function generateTraits(uint256 _assetId) external pure override returns (string memory traits) {
    // nothing to return
  }

  // Hack to deal with too many stack variables
  struct Stackframe {
    uint trait; // 0:small, 1:middle, 2:large
    uint degree;
    uint distance;
    uint radius;
    uint rotate;
    int x;
    int y;
  }

  function circles(uint _assetId, string[] memory idNouns) internal pure returns (SVG.Element memory) {
    string[4] memory colors = ['red', 'green', 'yellow', 'blue'];
    uint count = 10;
    SVG.Element[] memory elements = new SVG.Element[](count);
    Randomizer.Seed memory seed = Randomizer.Seed(_assetId, 0);

    for (uint i = 0; i < count; i++) {
      Stackframe memory stack;
      stack.trait = (i + 1) / 4; // 3:4:3
      if (stack.trait == 0) {
        (seed, stack.distance) = seed.random(100);
        stack.distance += 380;
        (seed, stack.radius) = seed.random(40);
        stack.radius += 40;
        (seed, stack.rotate) = seed.random(360);
      } else if (stack.trait == 1) {
        (seed, stack.distance) = seed.random(100);
        stack.distance += 200;
        (seed, stack.radius) = seed.random(70);
        stack.radius += 70;
        (seed, stack.rotate) = seed.random(240);
        stack.rotate += 240;
      } else {
        (seed, stack.distance) = seed.random(180);
        (seed, stack.radius) = seed.random(70);
        stack.radius += 180;
        (seed, stack.rotate) = seed.random(120);
        stack.rotate += 300;
      }
      (seed, stack.degree) = seed.random(0x4000);
      stack.x = 512 + (stack.degree.cos() * int(stack.distance)) / Vector.ONE;
      stack.y = 512 + (stack.degree.sin() * int(stack.distance)) / Vector.ONE;
      elements[i] = SVG.group(
        [
          SVG.use(idNouns[i % idNouns.length]).transform(
            TX
              .translate(stack.x - int(stack.radius), stack.y - int(stack.radius))
              .scale1000((1000 * stack.radius) / 512)
              .rotate(string(abi.encodePacked(stack.rotate.toString(), ',512,512')))
          ),
          SVG.circle(stack.x, stack.y, int(stack.radius + stack.radius / 10)).fill(colors[i % 4]).opacity('0.333')
        ]
      );
    }
    return SVG.group(elements);
  }

  struct StackFrame2 {
    uint width;
    SVG.Element pnouns;
    string[] idNouns;
    SVG.Element[] svgNouns;
    string svg;
    string seriesText;
    SVG.Element series;
  }

  function generateSVGPart(uint256 _assetId) public view override returns (string memory svgPart, string memory tag) {
    StackFrame2 memory stack;
    tag = string(abi.encodePacked('circles', _assetId.toString()));
    stack.width = SVG.textWidth(font, 'pNouns');
    stack.pnouns = SVG.text(font, 'pNouns').fill('#224455').transform(TX.scale1000((1000 * 1024) / stack.width));

    if (_assetId < 10) {
      stack.seriesText = string(abi.encodePacked('000', _assetId.toString(), '/2000'));
    } else if (_assetId < 100) {
      stack.seriesText = string(abi.encodePacked('00', _assetId.toString(), '/2000'));
    } else if (_assetId < 1000) {
      stack.seriesText = string(abi.encodePacked('0', _assetId.toString(), '/2000'));
    } else {
      stack.seriesText = string(abi.encodePacked(_assetId.toString(), '/2000'));
    }
    stack.width = SVG.textWidth(font, stack.seriesText);
    stack.series = SVG.text(font, stack.seriesText).fill('#224455').transform(
      TX.translate(1024 - int(stack.width / 10), 1024 - 102).scale('0.1')
    );

    stack.idNouns = new string[](3);
    stack.svgNouns = new SVG.Element[](3);
    for (uint i = 0; i < stack.idNouns.length; i++) {
      (stack.svg, stack.idNouns[i]) = nounsProvider.generateSVGPart(i + _assetId);
      stack.svgNouns[i] = SVG.element(bytes(stack.svg));
    }

    svgPart = string(
      SVG
        .list(
          [
            SVG.list(stack.svgNouns),
            SVG
              .group(
                [
                  circles(_assetId, stack.idNouns).transform('translate(102,204) scale(0.8)'),
                  stack.pnouns,
                  stack.series
                ]
              )
              .id(tag)
          ]
        )
        .svg()
    );
  }

  function generateSVGDocument(uint256 _assetId) external view override returns (string memory document) {
    string memory svgPart;
    string memory tag;
    (svgPart, tag) = generateSVGPart(_assetId);
    document = SVG.document('0 0 1024 1024', bytes(svgPart), SVG.use(tag).svg());
  }
}

File 2 of 16 : Text.sol
// SPDX-License-Identifier: MIT

/*
 * This is a part of fully-on-chain.sol, a npm package that allows developers
 * to create fully on-chain generative art.
 *
 * Created by Satoshi Nakajima (@snakajima)
 */

pragma solidity ^0.8.6;

library Text {
  function extractLine(
    string memory _text,
    uint _index,
    uint _ch
  ) internal pure returns (string memory line, uint index) {
    uint length = bytes(_text).length;
    assembly {
      line := mload(0x40)
      let wbuf := add(line, 0x20)
      let rbuf := add(add(_text, 0x20), _index)
      let word := 0
      let shift := 0
      let i
      for {
        i := _index
      } lt(i, length) {
        i := add(i, 1)
      } {
        if eq(shift, 0) {
          word := mload(rbuf)
          mstore(wbuf, word)
          rbuf := add(rbuf, 0x20)
          wbuf := add(wbuf, 0x20)
          shift := 256
        }
        shift := sub(shift, 8)
        if eq(and(shr(shift, word), 0xff), _ch) {
          length := i
        }
      }

      index := i
      length := sub(i, _index)
      mstore(line, length) //sub(i, _index))
      mstore(0x40, add(add(line, 0x20), length))
    }
  }

  function split(string memory _str, uint _ch) internal pure returns (string[] memory strs) {
    uint length = bytes(_str).length;
    uint count;
    for (uint i = 0; i < length; i += 1) {
      (, i) = extractLine(_str, i, _ch);
      count += 1;
    }
    strs = new string[](count);
    count = 0;
    for (uint i = 0; i < length; i += 1) {
      (strs[count], i) = extractLine(_str, i, _ch);
      count += 1;
    }
  }
}

File 3 of 16 : SVG.sol
// SPDX-License-Identifier: MIT

/*
 * This is a part of fully-on-chain.sol, a npm package that allows developers
 * to create fully on-chain generative art.
 *
 * Created by Satoshi Nakajima (@snakajima)
 */

pragma solidity ^0.8.6;

import 'bytes-array.sol/BytesArray.sol';
import '@openzeppelin/contracts/utils/Strings.sol';
import './IFontProvider.sol';
import './Path.sol';
import './Transform.sol';

library SVG {
  using Strings for uint;
  using BytesArray for bytes[];

  struct Attribute {
    string key;
    string value;
  }

  struct Element {
    bytes head;
    bytes tail;
    Attribute[] attrs;
  }

  function path(bytes memory _path) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<path d="', _path);
    elem.tail = bytes('"/>\n');
  }

  function char(IFontProvider _font, string memory _char) internal view returns (Element memory elem) {
    elem = SVG.path(Path.decode(_font.pathOf(_char)));
  }

  function textWidth(IFontProvider _font, string memory _str) internal view returns (uint x) {
    bytes memory data = bytes(_str);
    bytes memory ch = new bytes(1);
    for (uint i = 0; i < data.length; i++) {
      ch[0] = data[i];
      x += _font.widthOf(string(ch));
    }
  }

  function text(IFontProvider _font, string[2] memory _strs, uint _width) internal view returns (Element memory elem) {
    string[] memory strs = new string[](2);
    strs[0] = _strs[0];
    strs[1] = _strs[1];
    elem = text(_font, strs, _width);
  }

  function text(IFontProvider _font, string[3] memory _strs, uint _width) internal view returns (Element memory elem) {
    string[] memory strs = new string[](3);
    strs[0] = _strs[0];
    strs[1] = _strs[1];
    strs[2] = _strs[2];
    elem = text(_font, strs, _width);
  }

  function text(IFontProvider _font, string[4] memory _strs, uint _width) internal view returns (Element memory elem) {
    string[] memory strs = new string[](4);
    for (uint i = 0; i < _strs.length; i++) {
      strs[i] = _strs[i];
    }
    elem = text(_font, strs, _width);
  }

  function text(IFontProvider _font, string[5] memory _strs, uint _width) internal view returns (Element memory elem) {
    string[] memory strs = new string[](5);
    for (uint i = 0; i < _strs.length; i++) {
      strs[i] = _strs[i];
    }
    elem = text(_font, strs, _width);
  }

  function text(IFontProvider _font, string[6] memory _strs, uint _width) internal view returns (Element memory elem) {
    string[] memory strs = new string[](6);
    for (uint i = 0; i < _strs.length; i++) {
      strs[i] = _strs[i];
    }
    elem = text(_font, strs, _width);
  }

  function text(IFontProvider _font, string[7] memory _strs, uint _width) internal view returns (Element memory elem) {
    string[] memory strs = new string[](7);
    for (uint i = 0; i < _strs.length; i++) {
      strs[i] = _strs[i];
    }
    elem = text(_font, strs, _width);
  }

  function text(IFontProvider _font, string[] memory _strs, uint _width) internal view returns (Element memory elem) {
    uint height = _font.height();
    uint maxWidth = _width;
    Element[] memory elems = new Element[](_strs.length);
    for (uint i = 0; i < _strs.length; i++) {
      uint width = textWidth(_font, _strs[i]);
      if (width > maxWidth) {
        maxWidth = width;
      }
      elems[i] = transform(text(_font, _strs[i]), TX.translate(0, int(height * i)));
    }
    // extra group is necessary to let it transform
    elem = group(svg(transform(group(elems), TX.scale1000((1000 * _width) / maxWidth))));
  }

  function text(IFontProvider _font, string memory _str) internal view returns (Element memory elem) {
    bytes memory data = bytes(_str);
    bytes memory ch = new bytes(1);
    Element[] memory elems = new Element[](data.length);
    uint x;
    for (uint i = 0; i < data.length; i++) {
      ch[0] = data[i];
      elems[i] = SVG.path(Path.decode(_font.pathOf(string(ch))));
      if (x > 0) {
        elems[i] = transform(elems[i], string(abi.encodePacked('translate(', x.toString(), ' 0)')));
      }
      x += _font.widthOf(string(ch));
    }
    elem = group(elems);
  }

  function circle(int _cx, int _cy, int _radius) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked(
      '<circle cx="',
      uint(_cx).toString(),
      '" cy="',
      uint(_cy).toString(),
      '" r="',
      uint(_radius).toString()
    );
    elem.tail = '"/>\n';
  }

  function ellipse(int _cx, int _cy, int _rx, int _ry) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked(
      '<ellipse cx="',
      uint(_cx).toString(),
      '" cy="',
      uint(_cy).toString(),
      '" rx="',
      uint(_rx).toString(),
      '" ry="',
      uint(_ry).toString()
    );
    elem.tail = '"/>\n';
  }

  function rect(int _x, int _y, uint _width, uint _height) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked(
      '<rect x="',
      uint(_x).toString(),
      '" y="',
      uint(_y).toString(),
      '" width="',
      _width.toString(),
      '" height="',
      _height.toString()
    );
    elem.tail = '"/>\n';
  }

  function rect() internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<rect width="100%" height="100%');
    elem.tail = '"/>\n';
  }

  function stop(uint ratio) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<stop offset="', ratio.toString(), '%');
    elem.tail = '"/>\n';
  }

  function use(string memory _id) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<use href="#', _id);
    elem.tail = '"/>\n';
  }

  // HACK: Solidity does not support literal expression of dynamic array yet
  function packed(Element[8] memory _elements) internal pure returns (bytes memory output) {
    bytes[] memory svgs = new bytes[](8);
    svgs[0] = svg(_elements[0]);
    svgs[1] = svg(_elements[1]);
    svgs[2] = svg(_elements[2]);
    svgs[3] = svg(_elements[3]);
    svgs[4] = svg(_elements[4]);
    svgs[5] = svg(_elements[5]);
    svgs[6] = svg(_elements[6]);
    svgs[7] = svg(_elements[7]);
    output = svgs.packed();
  }

  // HACK: Solidity does not support literal expression of dynamic array yet
  function packed(Element[4] memory _elements) internal pure returns (bytes memory output) {
    bytes[] memory svgs = new bytes[](4);
    svgs[0] = svg(_elements[0]);
    svgs[1] = svg(_elements[1]);
    svgs[2] = svg(_elements[2]);
    svgs[3] = svg(_elements[3]);
    output = svgs.packed();
  }

  // HACK: Solidity does not support literal expression of dynamic array yet
  function packed(Element[3] memory _elements) internal pure returns (bytes memory output) {
    bytes[] memory svgs = new bytes[](3);
    svgs[0] = svg(_elements[0]);
    svgs[1] = svg(_elements[1]);
    svgs[2] = svg(_elements[2]);
    output = svgs.packed();
  }

  // HACK: Solidity does not support literal expression of dynamic array yet
  function packed(Element[2] memory _elements) internal pure returns (bytes memory output) {
    bytes[] memory svgs = new bytes[](2);
    svgs[0] = svg(_elements[0]);
    svgs[1] = svg(_elements[1]);
    output = svgs.packed();
  }

  function packed(Element[] memory _elements) internal pure returns (bytes memory output) {
    bytes[] memory svgs = new bytes[](_elements.length);
    for (uint i = 0; i < _elements.length; i++) {
      svgs[i] = svg(_elements[i]);
    }
    output = svgs.packed();
  }

  function pattern(
    string memory _id,
    string memory _viewbox,
    string memory _width,
    string memory _height,
    bytes memory _elements
  ) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked(
      '<pattern id="',
      _id,
      '" viewBox="',
      _viewbox,
      '" width="',
      _width,
      '" height="',
      _height
    );
    elem.tail = abi.encodePacked('">', _elements, '</pattern>\n');
  }

  function pattern(
    string memory _id,
    string memory _viewbox,
    string memory _width,
    string memory _height,
    Element memory _element
  ) internal pure returns (Element memory elem) {
    elem = pattern(_id, _viewbox, _width, _height, svg(_element));
  }

  function filter(string memory _id, bytes memory _elements) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<filter id="', _id);
    elem.tail = abi.encodePacked('">', _elements, '</filter>\n');
  }

  function filter(string memory _id, Element memory _element) internal pure returns (Element memory elem) {
    elem = filter(_id, svg(_element));
  }

  function feGaussianBlur(string memory _src, string memory _stdDeviation) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<feGaussianBlur in="', _src, '" stdDeviation="', _stdDeviation);
    elem.tail = '" />';
  }

  /*
      '  <feOffset result="offOut" in="SourceAlpha" dx="24" dy="32" />\n'
      '  <feGaussianBlur result="blurOut" in="offOut" stdDeviation="16" />\n'
      '  <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />\n'
  */
  function feOffset(
    string memory _src,
    string memory _dx,
    string memory _dy
  ) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<feOffset in="', _src, '" dx="', _dx, '" dy="', _dy);
    elem.tail = '" />';
  }

  function feBlend(
    string memory _src,
    string memory _src2,
    string memory _mode
  ) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<feBlend in="', _src, '" in2="', _src2, '" mode="', _mode);
    elem.tail = '" />';
  }

  function linearGradient(string memory _id, bytes memory _elements) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<linearGradient id="', _id);
    elem.tail = abi.encodePacked('">', _elements, '</linearGradient>\n');
  }

  function linearGradient(string memory _id, Element memory _element) internal pure returns (Element memory elem) {
    elem = linearGradient(_id, svg(_element));
  }

  function radialGradient(string memory _id, bytes memory _elements) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<radialGradient id="', _id);
    elem.tail = abi.encodePacked('">', _elements, '</radialGradient>\n');
  }

  function radialGradient(string memory _id, Element memory _element) internal pure returns (Element memory elem) {
    elem = radialGradient(_id, svg(_element));
  }

  function group(bytes memory _elements) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<g x_x="x'); // HACK: dummy header for trailing '"'
    elem.tail = abi.encodePacked('">', _elements, '</g>\n');
  }

  function group(Element memory _element) internal pure returns (Element memory elem) {
    elem = group(svg(_element));
  }

  function group(Element[] memory _elements) internal pure returns (Element memory elem) {
    elem = group(packed(_elements));
  }

  // HACK: Solidity does not support literal expression of dynamic array yet
  function group(Element[2] memory _elements) internal pure returns (Element memory elem) {
    elem = group(packed(_elements));
  }

  // HACK: Solidity does not support literal expression of dynamic array yet
  function group(Element[3] memory _elements) internal pure returns (Element memory elem) {
    elem = group(packed(_elements));
  }

  // HACK: Solidity does not support literal expression of dynamic array yet
  function group(Element[4] memory _elements) internal pure returns (Element memory elem) {
    elem = group(packed(_elements));
  }

  function group(Element[8] memory _elements) internal pure returns (Element memory elem) {
    elem = group(packed(_elements));
  }

  function element(bytes memory _body) internal pure returns (Element memory elem) {
    elem.tail = _body;
  }

  function list(Element[] memory _elements) internal pure returns (Element memory elem) {
    elem.tail = packed(_elements);
  }

  // HACK: Solidity does not support literal expression of dynamic array yet
  function list(Element[2] memory _elements) internal pure returns (Element memory elem) {
    elem.tail = packed(_elements);
  }

  // HACK: Solidity does not support literal expression of dynamic array yet
  function list(Element[3] memory _elements) internal pure returns (Element memory elem) {
    elem.tail = packed(_elements);
  }

  // HACK: Solidity does not support literal expression of dynamic array yet
  function list(Element[4] memory _elements) internal pure returns (Element memory elem) {
    elem.tail = packed(_elements);
  }

  // HACK: Solidity does not support literal expression of dynamic array yet
  function list(Element[8] memory _elements) internal pure returns (Element memory elem) {
    elem.tail = packed(_elements);
  }

  function mask(string memory _id, bytes memory _elements) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<mask id="', _id, ''); // HACK: dummy header for trailing '"'
    elem.tail = abi.encodePacked(
      '">'
      '<rect x="0" y="0" width="100%" height="100%" fill="black"/>'
      '<g fill="white">',
      _elements,
      '</g>'
      '</mask>\n'
    );
  }

  function mask(string memory _id, Element memory _element) internal pure returns (Element memory elem) {
    elem = mask(_id, svg(_element));
  }

  function stencil(bytes memory _elements) internal pure returns (Element memory elem) {
    elem.head = abi.encodePacked('<mask x_x="x'); // HACK: dummy header for trailing '"'
    elem.tail = abi.encodePacked(
      '">'
      '<rect x="0" y="0" width="100%" height="100%" fill="white"/>'
      '<g fill="black">',
      _elements,
      '</g>'
      '</mask>\n'
    );
  }

  function stencil(Element memory _element) internal pure returns (Element memory elem) {
    elem = stencil(svg(_element));
  }

  function _append(Element memory _element, Attribute memory _attr) internal pure returns (Element memory elem) {
    elem.head = _element.head;
    elem.tail = _element.tail;
    elem.attrs = new Attribute[](_element.attrs.length + 1);
    for (uint i = 0; i < _element.attrs.length; i++) {
      elem.attrs[i] = _element.attrs[i];
    }
    elem.attrs[_element.attrs.length] = _attr;
  }

  function _append2(
    Element memory _element,
    Attribute memory _attr,
    Attribute memory _attr2
  ) internal pure returns (Element memory elem) {
    elem.head = _element.head;
    elem.tail = _element.tail;
    elem.attrs = new Attribute[](_element.attrs.length + 2);
    for (uint i = 0; i < _element.attrs.length; i++) {
      elem.attrs[i] = _element.attrs[i];
    }
    elem.attrs[_element.attrs.length] = _attr;
    elem.attrs[_element.attrs.length + 1] = _attr2;
  }

  function id(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('id', _value));
  }

  function fill(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('fill', _value));
  }

  function opacity(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('opacity', _value));
  }

  function stopColor(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('stop-color', _value));
  }

  function x1(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('x1', _value));
  }

  function x2(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('x2', _value));
  }

  function y1(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('y1', _value));
  }

  function y2(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('y2', _value));
  }

  function cx(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('cy', _value));
  }

  function cy(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('cy', _value));
  }

  function r(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('r', _value));
  }

  function fx(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('fx', _value));
  }

  function fy(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('fy', _value));
  }

  function result(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('result', _value));
  }

  function fillRef(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('fill', string(abi.encodePacked('url(#', _value, ')'))));
  }

  function filter(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('filter', string(abi.encodePacked('url(#', _value, ')'))));
  }

  function style(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('style', _value));
  }

  function transform(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('transform', _value));
  }

  function mask(Element memory _element, string memory _value) internal pure returns (Element memory elem) {
    elem = _append(_element, Attribute('mask', string(abi.encodePacked('url(#', _value, ')'))));
  }

  function stroke(
    Element memory _element,
    string memory _color,
    uint _width
  ) internal pure returns (Element memory elem) {
    elem = _append2(_element, Attribute('stroke', _color), Attribute('stroke-width', _width.toString()));
  }

  function svg(Element memory _element) internal pure returns (bytes memory output) {
    if (_element.head.length > 0) {
      output = _element.head;
      for (uint i = 0; i < _element.attrs.length; i++) {
        Attribute memory attr = _element.attrs[i];
        output = abi.encodePacked(output, '" ', attr.key, '="', attr.value);
      }
    } else {
      require(_element.attrs.length == 0, 'Attributes on list');
    }
    output = abi.encodePacked(output, _element.tail);
  }

  function document(
    string memory _viewBox,
    bytes memory _defs,
    bytes memory _body
  ) internal pure returns (string memory) {
    bytes memory output = abi.encodePacked(
      '<?xml version="1.0" encoding="UTF-8"?>'
      '<svg viewBox="',
      _viewBox,
      '"'
      ' xmlns="http://www.w3.org/2000/svg">\n'
    );
    if (_defs.length > 0) {
      output = abi.encodePacked(output, '<defs>\n', _defs, '</defs>\n');
    }
    output = abi.encodePacked(output, _body, '</svg>\n');
    return string(output);
  }
}

File 4 of 16 : Path.sol
// SPDX-License-Identifier: MIT

/*
 * This is a part of fully-on-chain.sol, a npm package that allows developers
 * to create fully on-chain generative art.
 *
 * Created by Satoshi Nakajima (@snakajima)
 */

pragma solidity ^0.8.6;

import './Vector.sol';

library Path {
  function roundedCorner(Vector.Struct memory _vector) internal pure returns (uint) {
    return uint(_vector.x / 0x8000) + (uint(_vector.y / 0x8000) << 32) + (566 << 64);
  }

  function sharpCorner(Vector.Struct memory _vector) internal pure returns (uint) {
    return uint(_vector.x / 0x8000) + (uint(_vector.y / 0x8000) << 32) + (0x1 << 80);
  }

  function closedPath(uint[] memory points) internal pure returns (bytes memory newPath) {
    uint length = points.length;
    assembly {
      function toString(_wbuf, _value) -> wbuf {
        let len := 2
        let cmd := 0
        if gt(_value, 9) {
          if gt(_value, 99) {
            if gt(_value, 999) {
              cmd := or(shl(8, cmd), add(48, div(_value, 1000)))
              len := add(1, len)
              _value := mod(_value, 1000)
            }
            cmd := or(shl(8, cmd), add(48, div(_value, 100)))
            len := add(1, len)
            _value := mod(_value, 100)
          }
          cmd := or(shl(8, cmd), add(48, div(_value, 10)))
          len := add(1, len)
          _value := mod(_value, 10)
        }
        cmd := or(or(shl(16, cmd), shl(8, add(48, _value))), 32)

        mstore(_wbuf, shl(sub(256, mul(len, 8)), cmd))
        wbuf := add(_wbuf, len)
      }

      // dynamic allocation
      newPath := mload(0x40)
      let wbuf := add(newPath, 0x20)
      let rbuf := add(points, 0x20)

      let wordP := mload(add(rbuf, mul(sub(length, 1), 0x20)))
      let word := mload(rbuf)
      for {
        let i := 0
      } lt(i, length) {
        i := add(i, 1)
      } {
        let x := and(word, 0xffffffff)
        let y := and(shr(32, word), 0xffffffff)
        let r := and(shr(64, word), 0xffff)
        let sx := div(add(x, and(wordP, 0xffffffff)), 2)
        let sy := div(add(y, and(shr(32, wordP), 0xffffffff)), 2)
        if eq(i, 0) {
          mstore(wbuf, shl(248, 0x4D)) // M
          wbuf := add(wbuf, 1)
          wbuf := toString(wbuf, sx)
          wbuf := toString(wbuf, sy)
        }

        let wordN := mload(add(rbuf, mul(mod(add(i, 1), length), 0x20)))
        {
          let ex := div(add(x, and(wordN, 0xffffffff)), 2)
          let ey := div(add(y, and(shr(32, wordN), 0xffffffff)), 2)

          switch and(shr(80, word), 0x01)
          case 0 {
            mstore(wbuf, shl(248, 0x43)) // C
            wbuf := add(wbuf, 1)
            x := mul(x, r)
            y := mul(y, r)
            r := sub(1024, r)
            wbuf := toString(wbuf, div(add(x, mul(sx, r)), 1024))
            wbuf := toString(wbuf, div(add(y, mul(sy, r)), 1024))
            wbuf := toString(wbuf, div(add(x, mul(ex, r)), 1024))
            wbuf := toString(wbuf, div(add(y, mul(ey, r)), 1024))
          }
          default {
            mstore(wbuf, shl(248, 0x4C)) // L
            wbuf := add(wbuf, 1)
            wbuf := toString(wbuf, x)
            wbuf := toString(wbuf, y)
          }
          wbuf := toString(wbuf, ex)
          wbuf := toString(wbuf, ey)
        }
        wordP := word
        word := wordN
      }

      mstore(newPath, sub(sub(wbuf, newPath), 0x20))
      mstore(0x40, wbuf)
    }
  }

  function decode(bytes memory body) internal pure returns (bytes memory) {
    bytes memory ret;
    assembly {
      let bodyMemory := add(body, 0x20)
      let length := div(mul(mload(body), 2), 3)
      ret := mload(0x40)
      let retMemory := add(ret, 0x20)
      let data
      for {
        let i := 0
      } lt(i, length) {
        i := add(i, 1)
      } {
        if eq(mod(i, 16), 0) {
          data := mload(bodyMemory) // reading 8 extra bytes
          bodyMemory := add(bodyMemory, 24)
        }
        let low
        let high
        switch mod(i, 2)
        case 0 {
          low := shr(248, data)
          high := and(shr(240, data), 0x0f)
        }
        default {
          low := and(shr(232, data), 0xff)
          high := and(shr(244, data), 0x0f)
          data := shl(24, data)
        }

        switch high
        case 0 {
          if or(and(gt(low, 64), lt(low, 91)), and(gt(low, 96), lt(low, 123))) {
            mstore(retMemory, shl(248, low))
            retMemory := add(retMemory, 1)
          }
        }
        default {
          let cmd := 0
          let lenCmd := 2 // last digit and space
          // SVG value: undo (value + 1024) + 0x100
          let value := sub(add(shl(8, high), low), 0x0100)
          switch lt(value, 1024)
          case 0 {
            value := sub(value, 1024)
          }
          default {
            cmd := 45 // "-"
            lenCmd := 3
            value := sub(1024, value)
          }
          if gt(value, 9) {
            if gt(value, 99) {
              if gt(value, 999) {
                cmd := or(shl(8, cmd), 49) // always "1"
                lenCmd := add(1, lenCmd)
                value := mod(value, 1000)
              }
              cmd := or(shl(8, cmd), add(48, div(value, 100)))
              lenCmd := add(1, lenCmd)
              value := mod(value, 100)
            }
            cmd := or(shl(8, cmd), add(48, div(value, 10)))
            lenCmd := add(1, lenCmd)
            value := mod(value, 10)
          }
          // last digit and space
          cmd := or(or(shl(16, cmd), shl(8, add(48, value))), 32)

          mstore(retMemory, shl(sub(256, mul(lenCmd, 8)), cmd))
          retMemory := add(retMemory, lenCmd)
        }
      }
      mstore(ret, sub(sub(retMemory, ret), 0x20))
      mstore(0x40, retMemory)
    }
    return ret;
  }
}

File 5 of 16 : IFontProvider.sol
// SPDX-License-Identifier: MIT

/*
 * This is a part of fully-on-chain.sol, a npm package that allows developers
 * to create fully on-chain generative art.
 *
 * Created by Satoshi Nakajima (@snakajima)
 */

pragma solidity ^0.8.6;

interface IFontProvider {
  function height() external view returns (uint);

  function baseline() external view returns (uint);

  function widthOf(string memory _char) external view returns (uint);

  function pathOf(string memory _char) external view returns (bytes memory);

  /**
   * This function processes the royalty payment from the decentralized autonomous marketplace.
   */
  function processPayout() external payable;

  event Payout(string providerKey, address payable to, uint256 amount);
}

File 6 of 16 : IAssetProvider.sol
// SPDX-License-Identifier: MIT

/**
 * This is a part of an effort to create a decentralized autonomous marketplace for digital assets,
 * which allows artists and developers to sell their arts and generative arts.
 *
 * Please see "https://fullyonchain.xyz/" for details. 
 *
 * Created by Satoshi Nakajima (@snakajima)
 */
pragma solidity ^0.8.6;

/**
 * IAssetProvider is the interface each asset provider implements.
 * We assume there are three types of asset providers.
 * 1. Static asset provider, which has a collection of assets (either in the storage or the code) and returns them.
 * 2. Generative provider, which dynamically (but deterministically from the seed) generates assets.
 * 3. Data visualizer, which generates assets based on various data on the blockchain.
 *
 * Note: Asset providers MUST implements IERC165 (supportsInterface method) as well. 
 */
interface IAssetProvider {
  struct ProviderInfo {
    string key;  // short and unique identifier of this provider (e.g., "asset")
    string name; // human readable display name (e.g., "Asset Store")
    IAssetProvider provider;
  }
  function getProviderInfo() external view returns(ProviderInfo memory);

  /**
   * This function returns SVGPart and the tag. The SVGPart consists of one or more SVG elements.
   * The tag specifies the identifier of the SVG element to be displayed (using <use> tag).
   * The tag is the combination of the provider key and assetId (e.e., "asset123")
   */
  function generateSVGPart(uint256 _assetId) external view returns(string memory svgPart, string memory tag);

  /**
   * This is an optional function, which returns various traits of the image for ERC721 token.
   * Format: {"trait_type":"TRAIL_TYPE","value":"VALUE"},{...}
   */
  function generateTraits(uint256 _assetId) external view returns (string memory);
  
  /**
   * This function returns the number of assets available from this provider. 
   * If the total supply is 100, assetIds of available assets are 0,1,...99.
   * The generative providers may returns 0, which indicates the provider dynamically but
   * deterministically generates assets using the given assetId as the random seed.
   */
  function totalSupply() external view returns(uint256);

  /**
   * Returns the onwer. The registration update is possible only if both contracts have the same owner. 
   */
  function getOwner() external view returns (address);

  /**
   * This function processes the royalty payment from the decentralized autonomous marketplace. 
   */
  function processPayout(uint256 _assetId) external payable;

  event Payout(string providerKey, uint256 assetId, address payable to, uint256 amount);
}

interface IAssetProviderEx is IAssetProvider {
  function generateSVGDocument(uint256 _assetId) external view returns(string memory document);
}

File 7 of 16 : Randomizer.sol
// SPDX-License-Identifier: MIT

/*
 * Pseudo Random genearation library.
 *
 * Created by Satoshi Nakajima (@snakajima)
 */

pragma solidity ^0.8.6;

library Randomizer {
  struct Seed {
    uint256 seed;
    uint256 value;
  }

  /**
   * Returns a seudo random number between 0 and _limit-1.
   * It also returns an updated seed.
   */
  function random(Seed memory _seed, uint256 _limit) internal pure returns (Seed memory seed, uint256 value) {
    seed = _seed;
    if (seed.value < _limit * 256) {
      seed.seed = uint256(keccak256(abi.encodePacked(seed.seed)));
      seed.value = seed.seed;
    }
    value = seed.value % _limit;
    seed.value /= _limit;
  }

  /**
   * Returns a randomized value based on the original value and ration (in percentage).
   * It also returns an updated seed. 
   */
  function randomize(Seed memory _seed, uint256 _value, uint256 _ratio) internal pure returns (Seed memory seed, uint256 value) {
    uint256 limit = _value * _ratio / 100;
    uint256 delta;
    (seed, delta) = random(_seed, limit * 2);
    value = _value - limit + delta;
  }
}

File 8 of 16 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 9 of 16 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/IERC165.sol";

File 10 of 16 : Transform.sol
// SPDX-License-Identifier: MIT

/*
 * This is a part of fully-on-chain.sol, a npm package that allows developers
 * to create fully on-chain generative art.
 *
 * Created by Satoshi Nakajima (@snakajima)
 */

pragma solidity ^0.8.6;

import '@openzeppelin/contracts/utils/Strings.sol';
import 'bytes-array.sol/BytesArray.sol';

library TX {
  using Strings for uint;
  using BytesArray for bytes[];

  function toString(int _value) internal pure returns (string memory) {
    if (_value > 0) {
      return uint(_value).toString();
    }
    return string(abi.encodePacked('-', uint(-_value).toString()));
  }

  function translate(int x, int y) internal pure returns (string memory) {
    return string(abi.encodePacked('translate(', toString(x), ' ', toString(y), ')'));
  }

  function rotate(string memory _base, string memory _value) internal pure returns (string memory) {
    return string(abi.encodePacked(_base, ' rotate(', _value, ')'));
  }

  function scale(string memory _base, string memory _scale) internal pure returns (string memory) {
    return string(abi.encodePacked(_base, ' scale(', _scale, ')'));
  }

  function scale1000(uint _value) internal pure returns (string memory) {
    return string(abi.encodePacked('scale(', fixed1000(_value), ')'));
  }

  function scale1000(string memory _base, uint _value) internal pure returns (string memory) {
    return string(abi.encodePacked(_base, ' scale(', fixed1000(_value), ')'));
  }

  function fixed1000(uint _value) internal pure returns (string memory) {
    bytes[] memory array = new bytes[](3);
    if (_value > 1000) {
      array[0] = bytes((_value / 1000).toString());
    } else {
      array[0] = '0';
    }
    if (_value < 10) {
      array[1] = '.00';
    } else if (_value < 100) {
      array[1] = '.0';
    } else {
      array[1] = '.';
    }
    array[2] = bytes(_value.toString());
    return string(array.packed());
  }
}

File 11 of 16 : BytesArray.sol
// SPDX-License-Identifier: MIT

/*
 * Created by Satoshi Nakajima (@snakajima)
 */

pragma solidity ^0.8.6;

library BytesArray {
  /**
   * Equivalent to abi.encodedPacked(parts[0], parts[1], ..., parts[N-1]), where
   * N is the length of bytes.
   *
   * The complexty of this algorithm is O(M), where M is the number of total bytes.
   * Calling abi.encodePacked() in a loop reallocates memory N times, therefore,
   * the complexity will become O(M * N). 
   */
  function packed(bytes[] memory parts) internal pure returns (bytes memory ret) {
    uint count = parts.length;
    assembly {
      ret := mload(0x40)
      let retMemory := add(ret, 0x20)
      let bufParts := add(parts, 0x20)
      for {let i := 0} lt(i, count) {i := add(i, 1)} {
        let src := mload(bufParts) // read the address
        let dest := retMemory
        let length := mload(src)
        // copy 0x20 bytes each (and let it overrun)
        for {let j := 0} lt(j, length) {j := add(j, 0x20)} {
          src := add(src, 0x20) // dual purpose
          mstore(dest, mload(src))
          dest := add(dest, 0x20)
        }
        retMemory := add(retMemory, length)
        bufParts := add(bufParts, 0x20)
      }
      mstore(ret, sub(sub(retMemory, ret), 0x20))
      mstore(0x40, retMemory)
    }
  }

}

File 12 of 16 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

File 13 of 16 : Vector.sol
// SPDX-License-Identifier: MIT

/*
 * This is a part of fully-on-chain.sol, a npm package that allows developers
 * to create fully on-chain generative art.
 *
 * Created by Satoshi Nakajima (@snakajima)
 */

pragma solidity ^0.8.6;

import 'trigonometry.sol/Trigonometry.sol';

library Vector {
  using Trigonometry for uint;
  int constant PI = 0x2000;
  int constant PI2 = 0x4000;
  int constant ONE = 0x8000;

  struct Struct {
    int x; // fixed point * ONE
    int y; // fixed point * ONE
  }

  function vector(int _x, int _y) internal pure returns (Struct memory newVector) {
    newVector.x = _x * ONE;
    newVector.y = _y * ONE;
  }

  function vectorWithAngle(int _angle, int _radius) internal pure returns (Struct memory newVector) {
    uint angle = uint(_angle + (PI2 << 64));
    newVector.x = _radius * angle.cos();
    newVector.y = _radius * angle.sin();
  }

  function div(Struct memory _vector, int _value) internal pure returns (Struct memory newVector) {
    newVector.x = _vector.x / _value;
    newVector.y = _vector.y / _value;
  }

  function mul(Struct memory _vector, int _value) internal pure returns (Struct memory newVector) {
    newVector.x = _vector.x * _value;
    newVector.y = _vector.y * _value;
  }

  function add(Struct memory _vector, Struct memory _vector2) internal pure returns (Struct memory newVector) {
    newVector.x = _vector.x + _vector2.x;
    newVector.y = _vector.y + _vector2.y;
  }

  function rotate(Struct memory _vector, int _angle) internal pure returns (Struct memory newVector) {
    uint angle = uint(_angle + (PI2 << 64));
    int cos = angle.cos();
    int sin = angle.sin();
    newVector.x = (cos * _vector.x - sin * _vector.y) / ONE;
    newVector.y = (sin * _vector.x + cos * _vector.y) / ONE;
  }
}

File 14 of 16 : Trigonometry.sol
/**
 * Basic trigonometry functions
 *
 * Solidity library offering the functionality of basic trigonometry functions
 * with both input and output being integer approximated.
 *
 * This code was originally written by Lefteris Karapetsas
 * https://github.com/Sikorkaio/sikorka/blob/master/contracts/trigonometry.sol
 *
 * I made several changes to make it easy for me to manage and use. 
 *
 * @author Lefteris Karapetsas 
 * @author Satoshi Nakajima (snakajima)
 * @license BSD3
 */

// SPDX-License-Identifier: BSD3
pragma solidity ^0.8.6;

library Trigonometry {

    // constant sine lookup table generated by gen_tables.py
    // We have no other choice but this since constant arrays don't yet exist
    uint8 constant entry_bytes = 2;
    bytes constant sin_table = "\x00\x00\x0c\x8c\x18\xf9\x25\x28\x30\xfb\x3c\x56\x47\x1c\x51\x33\x5a\x82\x62\xf1\x6a\x6d\x70\xe2\x76\x41\x7a\x7c\x7d\x89\x7f\x61\x7f\xff";

    function sin_table_lookup(uint index) pure internal returns (uint16) {
        bytes memory table = sin_table;
        uint offset = (index + 1) * entry_bytes;
        uint16 trigint_value;
        assembly {
            trigint_value := mload(add(table, offset))
        }

        return trigint_value;
    }

    /**
     * Return the sine of an integer approximated angle as a signed 16-bit
     * integer.
     *
     * @param _angle A 14-bit angle. This divides the circle into 16384 (0x4000)
     *               angle units, instead of the standard 360 degrees.
     * @return The sine result as a number in the range -32767 to 32767.
     */
    function sin(uint _angle) internal pure returns (int) {
        uint angle = _angle % 0x4000;
        if (angle < 0x2000) {
            return sinQuarter(angle < 0x1000 ? angle : 0x2000 - angle);
        }
        return -sinQuarter(angle < 0x3000 ? angle - 0x2000 : 0x4000 - angle);
    }

    function sinQuarter(uint _angle) internal pure returns (int) {
        if (_angle == 0x1000) {
            return 0x7fff;
        }
        uint index = _angle / 0x100; // high 4-bit
        uint interp = _angle & 0xFF; // low 8-bit
        uint x1 = sin_table_lookup(index);
        uint x2 = sin_table_lookup(index + 1);
        return int(x1 + ((x2 - x1) * interp) / 0x100);
    }

    /**
     * Return the cos of an integer approximated angle.
     * It functions just like the sin() method but uses the trigonometric
     * identity sin(x + pi/2) = cos(x) to quickly calculate the cos.
     */
    function cos(uint _angle) internal pure returns (int) {
        return sin(_angle + 0x1000);
    }
}

File 15 of 16 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 16 of 16 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IFontProvider","name":"_font","type":"address"},{"internalType":"contract IAssetProvider","name":"_nounsProvider","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"providerKey","type":"string"},{"indexed":false,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":false,"internalType":"address payable","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Payout","type":"event"},{"inputs":[],"name":"font","outputs":[{"internalType":"contract IFontProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"}],"name":"generateSVGDocument","outputs":[{"internalType":"string","name":"document","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"}],"name":"generateSVGPart","outputs":[{"internalType":"string","name":"svgPart","type":"string"},{"internalType":"string","name":"tag","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"}],"name":"generateTraits","outputs":[{"internalType":"string","name":"traits","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProviderInfo","outputs":[{"components":[{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"contract IAssetProvider","name":"provider","type":"address"}],"internalType":"struct IAssetProvider.ProviderInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nounsProvider","outputs":[{"internalType":"contract IAssetProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"}],"name":"processPayout","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c06040523480156200001157600080fd5b5060405162004b1338038062004b13833981810160405281019062000037919062000256565b620000576200004b620000c760201b60201c565b620000cf60201b60201c565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff168152505050506200029d565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620001c58262000198565b9050919050565b6000620001d982620001b8565b9050919050565b620001eb81620001cc565b8114620001f757600080fd5b50565b6000815190506200020b81620001e0565b92915050565b60006200021e82620001b8565b9050919050565b620002308162000211565b81146200023c57600080fd5b50565b600081519050620002508162000225565b92915050565b6000806040838503121562000270576200026f62000193565b5b60006200028085828601620001fa565b925050602062000293858286016200023f565b9150509250929050565b60805160a05161482d620002e6600039600081816104e50152610afd01526000818161067b015281816106d7015281816107960152818161090701526109ea015261482d6000f3fe6080604052600436106100c25760003560e01c8063893d20e81161007f5780638da5cb5b116100595780638da5cb5b1461025d5780639d37bc7c14610288578063e3f24f02146102b3578063f2fde38b146102f1576100c2565b8063893d20e8146101eb57806389ee68bf146102165780638c40188e14610232576100c2565b806301ffc9a7146100c757806318160ddd146101045780635d6e0dd51461012f578063715018a61461016c57806379b92f271461018357806380bcafbb146101c0575b600080fd5b3480156100d357600080fd5b506100ee60048036038101906100e99190612d96565b61031a565b6040516100fb9190612dde565b60405180910390f35b34801561011057600080fd5b50610119610454565b6040516101269190612e12565b60405180910390f35b34801561013b57600080fd5b5061015660048036038101906101519190612e59565b610459565b6040516101639190612f16565b60405180910390f35b34801561017857600080fd5b506101816104c8565b005b34801561018f57600080fd5b506101aa60048036038101906101a59190612e59565b6104dc565b6040516101b79190612f16565b60405180910390f35b3480156101cc57600080fd5b506101d56104e3565b6040516101e29190612fb7565b60405180910390f35b3480156101f757600080fd5b50610200610507565b60405161020d9190612ff3565b60405180910390f35b610230600480360381019061022b9190612e59565b610516565b005b34801561023e57600080fd5b506102476105a8565b60405161025491906130be565b60405180910390f35b34801561026957600080fd5b50610272610650565b60405161027f9190612ff3565b60405180910390f35b34801561029457600080fd5b5061029d610679565b6040516102aa9190613101565b60405180910390f35b3480156102bf57600080fd5b506102da60048036038101906102d59190612e59565b61069d565b6040516102e892919061311c565b60405180910390f35b3480156102fd57600080fd5b506103186004803603810190610313919061317f565b610cdb565b005b60007f0ece3d21000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806103e557507f5d6e0dd5000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061044d57507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b600090565b60608060606104678461069d565b80925081935050506104bf6040518060400160405280600d81526020017f3020302031303234203130323400000000000000000000000000000000000000815250836104ba6104b585610d5e565b610dd1565b610ed9565b92505050919050565b6104d0610f5d565b6104da6000610fdb565b565b6060919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610511610650565b905090565b6000610520610650565b90508073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610568573d6000803e3d6000fd5b507fbb0eeee27936db25b1a46a81ab6d97326392a3e961efa7273d5d756d7a2e1cad82823460405161059c93929190613219565b60405180910390a15050565b6105b0612c18565b60405180606001604052806040518060400160405280600681526020017f706e6f756e73000000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600681526020017f704e6f756e73000000000000000000000000000000000000000000000000000081525081526020013073ffffffffffffffffffffffffffffffffffffffff16815250905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b6060806106a8612c4f565b6106b18461109f565b6040516020016106c191906132eb565b60405160208183030381529060405291506107317f00000000000000000000000000000000000000000000000000000000000000006040518060400160405280600681526020017f704e6f756e7300000000000000000000000000000000000000000000000000008152506111ff565b81600001818152505061080c6107588260000151620fa000610753919061336b565b611367565b6107fe6040518060400160405280600781526020017f23323234343535000000000000000000000000000000000000000000000000008152506107f07f00000000000000000000000000000000000000000000000000000000000000006040518060400160405280600681526020017f704e6f756e730000000000000000000000000000000000000000000000000000815250611398565b61169290919063ffffffff16565b6116f590919063ffffffff16565b8160200181905250600a841015610852576108268461109f565b6040516020016108369190613434565b6040516020818303038152906040528160a00181905250610902565b6064841015610890576108648461109f565b60405160200161087491906134ad565b6040516020818303038152906040528160a00181905250610901565b6103e88410156108cf576108a38461109f565b6040516020016108b39190613526565b6040516020818303038152906040528160a00181905250610900565b6108d88461109f565b6040516020016108e89190613553565b6040516020818303038152906040528160a001819052505b5b5b6109307f00000000000000000000000000000000000000000000000000000000000000008260a001516111ff565b816000018181525050610a2f6109ac6040518060400160405280600381526020017f302e31000000000000000000000000000000000000000000000000000000000081525061099e600a8560000151610989919061336b565b610400610996919061357f565b61039a611758565b61179490919063ffffffff16565b610a216040518060400160405280600781526020017f2332323434353500000000000000000000000000000000000000000000000000815250610a137f00000000000000000000000000000000000000000000000000000000000000008660a00151611398565b61169290919063ffffffff16565b6116f590919063ffffffff16565b8160c00181905250600367ffffffffffffffff811115610a5257610a516135c2565b5b604051908082528060200260200182016040528015610a8557816020015b6060815260200190600190039081610a705790505b508160400181905250600367ffffffffffffffff811115610aa957610aa86135c2565b5b604051908082528060200260200182016040528015610ae257816020015b610acf612c98565b815260200190600190039081610ac75790505b50816060018190525060005b816040015151811015610c11577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e3f24f028683610b4391906135f1565b6040518263ffffffff1660e01b8152600401610b5f9190612e12565b600060405180830381865afa158015610b7c573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610ba5919061371c565b8360800184604001518481518110610bc057610bbf613794565b5b602002602001018290528290525050610bdc82608001516117c0565b82606001518281518110610bf357610bf2613794565b5b60200260200101819052508080610c09906137c3565b915050610aee565b50610cd3610cce6040518060400160405280610c3085606001516117d6565b8152602001610cc686610cb86040518060600160405280610c9c6040518060400160405280601d81526020017f7472616e736c617465283130322c32303429207363616c6528302e3829000000815250610c8e8f8d604001516117f4565b6116f590919063ffffffff16565b8152602001896020015181526020018960c00151815250611e36565b611e5690919063ffffffff16565b815250611eb9565b610dd1565b925050915091565b610ce3610f5d565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610d52576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d499061387d565b60405180910390fd5b610d5b81610fdb565b50565b610d66612c98565b81604051602001610d7791906138e9565b60405160208183030381529060405281600001819052506040518060400160405280600481526020017f222f3e0a000000000000000000000000000000000000000000000000000000008152508160200181905250919050565b606060008260000151511115610e63578160000151905060005b826040015151811015610e5d57600083604001518281518110610e1157610e10613794565b5b602002602001015190508281600001518260200151604051602001610e38939291906139ea565b6040516020818303038152906040529250508080610e55906137c3565b915050610deb565b50610eac565b600082604001515114610eab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ea290613a7d565b60405180910390fd5b5b808260200151604051602001610ec3929190613a9d565b6040516020818303038152906040529050919050565b6060600084604051602001610eee9190613ba5565b6040516020818303038152906040529050600084511115610f2e578084604051602001610f1c929190613c6a565b60405160208183030381529060405290505b8083604051602001610f41929190613cf0565b6040516020818303038152906040529050809150509392505050565b610f65611ed7565b73ffffffffffffffffffffffffffffffffffffffff16610f83610650565b73ffffffffffffffffffffffffffffffffffffffff1614610fd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fd090613d6b565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6060600082036110e6576040518060400160405280600181526020017f300000000000000000000000000000000000000000000000000000000000000081525090506111fa565b600082905060005b60008214611118578080611101906137c3565b915050600a82611111919061336b565b91506110ee565b60008167ffffffffffffffff811115611134576111336135c2565b5b6040519080825280601f01601f1916602001820160405280156111665781602001600182028036833780820191505090505b5090505b600085146111f35760018261117f9190613d8b565b9150600a8561118e9190613dbf565b603061119a91906135f1565b60f81b8183815181106111b0576111af613794565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a856111ec919061336b565b945061116a565b8093505050505b919050565b6000808290506000600167ffffffffffffffff811115611222576112216135c2565b5b6040519080825280601f01601f1916602001820160405280156112545781602001600182028036833780820191505090505b50905060005b825181101561135e5782818151811061127657611275613794565b5b602001015160f81c60f81b8260008151811061129557611294613794565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508573ffffffffffffffffffffffffffffffffffffffff16637f2406a7836040518263ffffffff1660e01b81526004016112fd9190612f16565b602060405180830381865afa15801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190613e05565b8461134991906135f1565b93508080611356906137c3565b91505061125a565b50505092915050565b606061137282611edf565b6040516020016113829190613eca565b6040516020818303038152906040529050919050565b6113a0612c98565b60008290506000600167ffffffffffffffff8111156113c2576113c16135c2565b5b6040519080825280601f01601f1916602001820160405280156113f45781602001600182028036833780820191505090505b5090506000825167ffffffffffffffff811115611414576114136135c2565b5b60405190808252806020026020018201604052801561144d57816020015b61143a612c98565b8152602001906001900390816114325790505b509050600080600090505b845181101561167c5784818151811061147457611473613794565b5b602001015160f81c60f81b8460008151811061149357611492613794565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061155161154c8973ffffffffffffffffffffffffffffffffffffffff1663a4b3eff4876040518263ffffffff1660e01b81526004016115019190612f16565b600060405180830381865afa15801561151e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906115479190613f98565b612124565b6122bd565b83828151811061156457611563613794565b5b602002602001018190525060008211156115e2576115c383828151811061158e5761158d613794565b5b602002602001015161159f8461109f565b6040516020016115af9190614079565b6040516020818303038152906040526116f5565b8382815181106115d6576115d5613794565b5b60200260200101819052505b8773ffffffffffffffffffffffffffffffffffffffff16637f2406a7856040518263ffffffff1660e01b815260040161161b9190612f16565b602060405180830381865afa158015611638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165c9190613e05565b8261166791906135f1565b91508080611674906137c3565b915050611458565b5061168682612330565b94505050505092915050565b61169a612c98565b6116ed8360405180604001604052806040518060400160405280600481526020017f66696c6c00000000000000000000000000000000000000000000000000000000815250815260200185815250612350565b905092915050565b6116fd612c98565b6117508360405180604001604052806040518060400160405280600981526020017f7472616e73666f726d0000000000000000000000000000000000000000000000815250815260200185815250612350565b905092915050565b606061176383612472565b61176c83612472565b60405160200161177d9291906140f2565b604051602081830303815290604052905092915050565b606082826040516020016117a9929190614183565b604051602081830303815290604052905092915050565b6117c8612c98565b818160200181905250919050565b6117de612c98565b6117e7826124c6565b8160200181905250919050565b6117fc612c98565b600060405180608001604052806040518060400160405280600381526020017f726564000000000000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600581526020017f677265656e00000000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600681526020017f79656c6c6f77000000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600481526020017f626c75650000000000000000000000000000000000000000000000000000000081525081525090506000600a905060008167ffffffffffffffff811115611917576119166135c2565b5b60405190808252806020026020018201604052801561195057816020015b61193d612c98565b8152602001906001900390816119355790505b509050600060405180604001604052808881526020016000815250905060005b83811015611e2057611980612cb9565b600460018361198f91906135f1565b611999919061336b565b8160000181815250506000816000015103611a4c576119c260648461258d90919063ffffffff16565b8260400181815250819450505061017c816040018181516119e391906135f1565b915081815250506119fe60288461258d90919063ffffffff16565b82606001818152508194505050602881606001818151611a1e91906135f1565b91508181525050611a3a6101688461258d90919063ffffffff16565b82608001818152508194505050611ba8565b6001816000015103611b0e57611a6c60648461258d90919063ffffffff16565b8260400181815250819450505060c881604001818151611a8c91906135f1565b91508181525050611aa760468461258d90919063ffffffff16565b82606001818152508194505050604681606001818151611ac791906135f1565b91508181525050611ae260f08461258d90919063ffffffff16565b8260800181815250819450505060f081608001818151611b0291906135f1565b91508181525050611ba7565b611b2260b48461258d90919063ffffffff16565b82604001818152508194505050611b4360468461258d90919063ffffffff16565b8260600181815250819450505060b481606001818151611b6391906135f1565b91508181525050611b7e60788461258d90919063ffffffff16565b8260800181815250819450505061012c81608001818151611b9f91906135f1565b915081815250505b5b611bbd6140008461258d90919063ffffffff16565b826020018181525081945050506180008160400151611bdf836020015161262b565b611be991906141bd565b611bf39190614235565b610200611c00919061429f565b8160a00181815250506180008160400151611c1e836020015161264a565b611c2891906141bd565b611c329190614235565b610200611c3f919061429f565b8160c0018181525050611dee6040518060400160405280611d33611cf6611c69866080015161109f565b604051602001611c79919061432f565b604051602081830303815290604052611ce861020088606001516103e8611ca09190614351565b611caa919061336b565b611cda89606001518a60a00151611cc1919061357f565b8a606001518b60c00151611cd5919061357f565b611758565b6126da90919063ffffffff16565b61270e90919063ffffffff16565b611d258d8e5189611d079190613dbf565b81518110611d1857611d17613794565b5b6020026020010151610d5e565b6116f590919063ffffffff16565b8152602001611de66040518060400160405280600581526020017f302e333333000000000000000000000000000000000000000000000000000000815250611dd88b600489611d829190613dbf565b60048110611d9357611d92613794565b5b6020020151611dca8860a001518960c00151600a8b60600151611db6919061336b565b8b60600151611dc591906135f1565b61273a565b61169290919063ffffffff16565b6127cb90919063ffffffff16565b81525061282e565b848381518110611e0157611e00613794565b5b6020026020010181905250508080611e18906137c3565b915050611970565b50611e2a82612330565b94505050505092915050565b611e3e612c98565b611e4f611e4a8361284e565b612974565b9050919050565b611e5e612c98565b611eb18360405180604001604052806040518060400160405280600281526020017f6964000000000000000000000000000000000000000000000000000000000000815250815260200185815250612350565b905092915050565b611ec1612c98565b611eca826129cf565b8160200181905250919050565b600033905090565b60606000600367ffffffffffffffff811115611efe57611efd6135c2565b5b604051908082528060200260200182016040528015611f3157816020015b6060815260200190600190039081611f1c5790505b5090506103e8831115611f7857611f546103e884611f4f919061336b565b61109f565b81600081518110611f6857611f67613794565b5b6020026020010181905250611fce565b6040518060400160405280600181526020017f300000000000000000000000000000000000000000000000000000000000000081525081600081518110611fc257611fc1613794565b5b60200260200101819052505b600a831015612031576040518060400160405280600381526020017f2e303000000000000000000000000000000000000000000000000000000000008152508160018151811061202157612020613794565b5b60200260200101819052506120eb565b6064831015612094576040518060400160405280600281526020017f2e300000000000000000000000000000000000000000000000000000000000008152508160018151811061208457612083613794565b5b60200260200101819052506120ea565b6040518060400160405280600181526020017f2e00000000000000000000000000000000000000000000000000000000000000815250816001815181106120de576120dd613794565b5b60200260200101819052505b5b6120f48361109f565b8160028151811061210857612107613794565b5b602002602001018190525061211c81612ab5565b915050919050565b6060806020830160036002855102046040519250602083016000805b838110156122a3576000601082060361215e57845191506018850194505b600080600283066000811461218a5760ff8560e81c169250600f8560f41c1691508460181b945061219a565b8460f81c9250600f8560f01c1691505b50806000811461226f5760006002610100858560081b01036104008110600081146121d357602d935060039250816104000391506121db565b610400820391505b50600981111561224557606381111561222a576103e781111561220f5760318360081b1792508160010191506103e8810690505b606481046030018360081b1792508160010191506064810690505b600a81046030018360081b179250816001019150600a810690505b60208160300160081b8460101b171792508260088302610100031b89528189019850505050612295565b607b83106060841116605b841060408511161715612294578260f81b86526001860195505b5b505050600181019050612140565b506020858303038552816040525050505080915050919050565b6122c5612c98565b816040516020016122d691906143df565b60405160208183030381529060405281600001819052506040518060400160405280600481526020017f222f3e0a000000000000000000000000000000000000000000000000000000008152508160200181905250919050565b612338612c98565b612349612344836124c6565b612974565b9050919050565b612358612c98565b8260000151816000018190525082602001518160200181905250600183604001515161238491906135f1565b67ffffffffffffffff81111561239d5761239c6135c2565b5b6040519080825280602002602001820160405280156123d657816020015b6123c3612cf6565b8152602001906001900390816123bb5790505b50816040018190525060005b836040015151811015612443578360400151818151811061240657612405613794565b5b60200260200101518260400151828151811061242557612424613794565b5b6020026020010181905250808061243b906137c3565b9150506123e2565b508181604001518460400151518151811061246157612460613794565b5b602002602001018190525092915050565b6060600082131561248d576124868261109f565b90506124c1565b61249f8261249a90614401565b61109f565b6040516020016124af9190614495565b60405160208183030381529060405290505b919050565b60606000825167ffffffffffffffff8111156124e5576124e46135c2565b5b60405190808252806020026020018201604052801561251857816020015b60608152602001906001900390816125035790505b50905060005b835181101561257b5761254a84828151811061253d5761253c613794565b5b6020026020010151610dd1565b82828151811061255d5761255c613794565b5b60200260200101819052508080612573906137c3565b91505061251e565b5061258581612ab5565b915050919050565b612595612d10565b6000839150610100836125a89190614351565b826020015110156125f95781600001516040516020016125c891906144d8565b6040516020818303038152906040528051906020012060001c82600001818152505081600001518260200181815250505b8282602001516126099190613dbf565b9050828260200181815161261d919061336b565b915081815250509250929050565b60006126436110008361263e91906135f1565b61264a565b9050919050565b6000806140008361265b9190613dbf565b90506120008110156126955761268d611000821061268657816120006126819190613d8b565b612688565b815b612b2f565b9150506126d5565b6126c861300082106126b457816140006126af9190613d8b565b6126c3565b612000826126c29190613d8b565b5b612b2f565b6126d190614401565b9150505b919050565b6060826126e683611edf565b6040516020016126f7929190614183565b604051602081830303815290604052905092915050565b6060828260405160200161272392919061453f565b604051602081830303815290604052905092915050565b612742612c98565b61274b8461109f565b6127548461109f565b61275d8461109f565b60405160200161276f9392919061465d565b60405160208183030381529060405281600001819052506040518060400160405280600481526020017f222f3e0a0000000000000000000000000000000000000000000000000000000081525081602001819052509392505050565b6127d3612c98565b6128268360405180604001604052806040518060400160405280600781526020017f6f70616369747900000000000000000000000000000000000000000000000000815250815260200185815250612350565b905092915050565b612836612c98565b612847612842836129cf565b612974565b9050919050565b60606000600367ffffffffffffffff81111561286d5761286c6135c2565b5b6040519080825280602002602001820160405280156128a057816020015b606081526020019060019003908161288b5790505b5090506128c4836000600381106128ba576128b9613794565b5b6020020151610dd1565b816000815181106128d8576128d7613794565b5b6020026020010181905250612904836001600381106128fa576128f9613794565b5b6020020151610dd1565b8160018151811061291857612917613794565b5b60200260200101819052506129448360026003811061293a57612939613794565b5b6020020151610dd1565b8160028151811061295857612957613794565b5b602002602001018190525061296c81612ab5565b915050919050565b61297c612c98565b60405160200161298b906146fb565b6040516020818303038152906040528160000181905250816040516020016129b391906147a8565b6040516020818303038152906040528160200181905250919050565b60606000600267ffffffffffffffff8111156129ee576129ed6135c2565b5b604051908082528060200260200182016040528015612a2157816020015b6060815260200190600190039081612a0c5790505b509050612a4583600060028110612a3b57612a3a613794565b5b6020020151610dd1565b81600081518110612a5957612a58613794565b5b6020026020010181905250612a8583600160028110612a7b57612a7a613794565b5b6020020151610dd1565b81600181518110612a9957612a98613794565b5b6020026020010181905250612aad81612ab5565b915050919050565b60606000825190506040519150602082016020840160005b83811015612b1a57815183815160005b81811015612b005760208401935083518352602083019250602081019050612add565b508086019550602085019450505050600181019050612acd565b50602084830303845281604052505050919050565b60006110008203612b4457617fff9050612bc2565b600061010083612b54919061336b565b9050600060ff841690506000612b6983612bc7565b61ffff1690506000612b86600185612b8191906135f1565b612bc7565b61ffff169050610100838383612b9c9190613d8b565b612ba69190614351565b612bb0919061336b565b82612bbb91906135f1565b9450505050505b919050565b6000806040518060600160405280602281526020016147d66022913990506000600260ff16600185612bf991906135f1565b612c039190614351565b90506000818301519050809350505050919050565b60405180606001604052806060815260200160608152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b6040518060e0016040528060008152602001612c69612c98565b815260200160608152602001606081526020016060815260200160608152602001612c92612c98565b81525090565b60405180606001604052806060815260200160608152602001606081525090565b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806040016040528060608152602001606081525090565b604051806040016040528060008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612d7381612d3e565b8114612d7e57600080fd5b50565b600081359050612d9081612d6a565b92915050565b600060208284031215612dac57612dab612d34565b5b6000612dba84828501612d81565b91505092915050565b60008115159050919050565b612dd881612dc3565b82525050565b6000602082019050612df36000830184612dcf565b92915050565b6000819050919050565b612e0c81612df9565b82525050565b6000602082019050612e276000830184612e03565b92915050565b612e3681612df9565b8114612e4157600080fd5b50565b600081359050612e5381612e2d565b92915050565b600060208284031215612e6f57612e6e612d34565b5b6000612e7d84828501612e44565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612ec0578082015181840152602081019050612ea5565b60008484015250505050565b6000601f19601f8301169050919050565b6000612ee882612e86565b612ef28185612e91565b9350612f02818560208601612ea2565b612f0b81612ecc565b840191505092915050565b60006020820190508181036000830152612f308184612edd565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000612f7d612f78612f7384612f38565b612f58565b612f38565b9050919050565b6000612f8f82612f62565b9050919050565b6000612fa182612f84565b9050919050565b612fb181612f96565b82525050565b6000602082019050612fcc6000830184612fa8565b92915050565b6000612fdd82612f38565b9050919050565b612fed81612fd2565b82525050565b60006020820190506130086000830184612fe4565b92915050565b600082825260208201905092915050565b600061302a82612e86565b613034818561300e565b9350613044818560208601612ea2565b61304d81612ecc565b840191505092915050565b61306181612f96565b82525050565b60006060830160008301518482036000860152613084828261301f565b9150506020830151848203602086015261309e828261301f565b91505060408301516130b36040860182613058565b508091505092915050565b600060208201905081810360008301526130d88184613067565b905092915050565b60006130eb82612f84565b9050919050565b6130fb816130e0565b82525050565b600060208201905061311660008301846130f2565b92915050565b600060408201905081810360008301526131368185612edd565b9050818103602083015261314a8184612edd565b90509392505050565b61315c81612fd2565b811461316757600080fd5b50565b60008135905061317981613153565b92915050565b60006020828403121561319557613194612d34565b5b60006131a38482850161316a565b91505092915050565b7f706e6f756e730000000000000000000000000000000000000000000000000000600082015250565b60006131e2600683612e91565b91506131ed826131ac565b602082019050919050565b600061320382612f38565b9050919050565b613213816131f8565b82525050565b60006080820190508181036000830152613232816131d5565b90506132416020830186612e03565b61324e604083018561320a565b61325b6060830184612e03565b949350505050565b600081905092915050565b7f636972636c657300000000000000000000000000000000000000000000000000600082015250565b60006132a4600783613263565b91506132af8261326e565b600782019050919050565b60006132c582612e86565b6132cf8185613263565b93506132df818560208601612ea2565b80840191505092915050565b60006132f682613297565b915061330282846132ba565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061337682612df9565b915061338183612df9565b9250826133915761339061330d565b5b828204905092915050565b7f3030300000000000000000000000000000000000000000000000000000000000600082015250565b60006133d2600383613263565b91506133dd8261339c565b600382019050919050565b7f2f32303030000000000000000000000000000000000000000000000000000000600082015250565b600061341e600583613263565b9150613429826133e8565b600582019050919050565b600061343f826133c5565b915061344b82846132ba565b915061345682613411565b915081905092915050565b7f3030000000000000000000000000000000000000000000000000000000000000600082015250565b6000613497600283613263565b91506134a282613461565b600282019050919050565b60006134b88261348a565b91506134c482846132ba565b91506134cf82613411565b915081905092915050565b7f3000000000000000000000000000000000000000000000000000000000000000600082015250565b6000613510600183613263565b915061351b826134da565b600182019050919050565b600061353182613503565b915061353d82846132ba565b915061354882613411565b915081905092915050565b600061355f82846132ba565b915061356a82613411565b915081905092915050565b6000819050919050565b600061358a82613575565b915061359583613575565b92508282039050818112600084121682821360008512151617156135bc576135bb61333c565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006135fc82612df9565b915061360783612df9565b925082820190508082111561361f5761361e61333c565b5b92915050565b600080fd5b600080fd5b61363882612ecc565b810181811067ffffffffffffffff82111715613657576136566135c2565b5b80604052505050565b600061366a612d2a565b9050613676828261362f565b919050565b600067ffffffffffffffff821115613696576136956135c2565b5b61369f82612ecc565b9050602081019050919050565b60006136bf6136ba8461367b565b613660565b9050828152602081018484840111156136db576136da61362a565b5b6136e6848285612ea2565b509392505050565b600082601f83011261370357613702613625565b5b81516137138482602086016136ac565b91505092915050565b6000806040838503121561373357613732612d34565b5b600083015167ffffffffffffffff81111561375157613750612d39565b5b61375d858286016136ee565b925050602083015167ffffffffffffffff81111561377e5761377d612d39565b5b61378a858286016136ee565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006137ce82612df9565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613800576137ff61333c565b5b600182019050919050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000613867602683612e91565b91506138728261380b565b604082019050919050565b600060208201905081810360008301526138968161385a565b9050919050565b7f3c75736520687265663d22230000000000000000000000000000000000000000600082015250565b60006138d3600c83613263565b91506138de8261389d565b600c82019050919050565b60006138f4826138c6565b915061390082846132ba565b915081905092915050565b600081519050919050565b600081905092915050565b600061392c8261390b565b6139368185613916565b9350613946818560208601612ea2565b80840191505092915050565b7f2220000000000000000000000000000000000000000000000000000000000000600082015250565b6000613988600283613263565b915061399382613952565b600282019050919050565b7f3d22000000000000000000000000000000000000000000000000000000000000600082015250565b60006139d4600283613263565b91506139df8261399e565b600282019050919050565b60006139f68286613921565b9150613a018261397b565b9150613a0d82856132ba565b9150613a18826139c7565b9150613a2482846132ba565b9150819050949350505050565b7f41747472696275746573206f6e206c6973740000000000000000000000000000600082015250565b6000613a67601283612e91565b9150613a7282613a31565b602082019050919050565b60006020820190508181036000830152613a9681613a5a565b9050919050565b6000613aa98285613921565b9150613ab58284613921565b91508190509392505050565b7f3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d22555460008201527f462d38223f3e3c7376672076696577426f783d22000000000000000000000000602082015250565b6000613b1d603483613263565b9150613b2882613ac1565b603482019050919050565b7f2220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f60008201527f737667223e0a0000000000000000000000000000000000000000000000000000602082015250565b6000613b8f602683613263565b9150613b9a82613b33565b602682019050919050565b6000613bb082613b10565b9150613bbc82846132ba565b9150613bc782613b82565b915081905092915050565b7f3c646566733e0a00000000000000000000000000000000000000000000000000600082015250565b6000613c08600783613263565b9150613c1382613bd2565b600782019050919050565b7f3c2f646566733e0a000000000000000000000000000000000000000000000000600082015250565b6000613c54600883613263565b9150613c5f82613c1e565b600882019050919050565b6000613c768285613921565b9150613c8182613bfb565b9150613c8d8284613921565b9150613c9882613c47565b91508190509392505050565b7f3c2f7376673e0a00000000000000000000000000000000000000000000000000600082015250565b6000613cda600783613263565b9150613ce582613ca4565b600782019050919050565b6000613cfc8285613921565b9150613d088284613921565b9150613d1382613ccd565b91508190509392505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000613d55602083612e91565b9150613d6082613d1f565b602082019050919050565b60006020820190508181036000830152613d8481613d48565b9050919050565b6000613d9682612df9565b9150613da183612df9565b9250828203905081811115613db957613db861333c565b5b92915050565b6000613dca82612df9565b9150613dd583612df9565b925082613de557613de461330d565b5b828206905092915050565b600081519050613dff81612e2d565b92915050565b600060208284031215613e1b57613e1a612d34565b5b6000613e2984828501613df0565b91505092915050565b7f7363616c65280000000000000000000000000000000000000000000000000000600082015250565b6000613e68600683613263565b9150613e7382613e32565b600682019050919050565b7f2900000000000000000000000000000000000000000000000000000000000000600082015250565b6000613eb4600183613263565b9150613ebf82613e7e565b600182019050919050565b6000613ed582613e5b565b9150613ee182846132ba565b9150613eec82613ea7565b915081905092915050565b600067ffffffffffffffff821115613f1257613f116135c2565b5b613f1b82612ecc565b9050602081019050919050565b6000613f3b613f3684613ef7565b613660565b905082815260208101848484011115613f5757613f5661362a565b5b613f62848285612ea2565b509392505050565b600082601f830112613f7f57613f7e613625565b5b8151613f8f848260208601613f28565b91505092915050565b600060208284031215613fae57613fad612d34565b5b600082015167ffffffffffffffff811115613fcc57613fcb612d39565b5b613fd884828501613f6a565b91505092915050565b7f7472616e736c6174652800000000000000000000000000000000000000000000600082015250565b6000614017600a83613263565b915061402282613fe1565b600a82019050919050565b7f2030290000000000000000000000000000000000000000000000000000000000600082015250565b6000614063600383613263565b915061406e8261402d565b600382019050919050565b60006140848261400a565b915061409082846132ba565b915061409b82614056565b915081905092915050565b7f2000000000000000000000000000000000000000000000000000000000000000600082015250565b60006140dc600183613263565b91506140e7826140a6565b600182019050919050565b60006140fd8261400a565b915061410982856132ba565b9150614114826140cf565b915061412082846132ba565b915061412b82613ea7565b91508190509392505050565b7f207363616c652800000000000000000000000000000000000000000000000000600082015250565b600061416d600783613263565b915061417882614137565b600782019050919050565b600061418f82856132ba565b915061419a82614160565b91506141a682846132ba565b91506141b182613ea7565b91508190509392505050565b60006141c882613575565b91506141d383613575565b92508282026141e181613575565b91507f800000000000000000000000000000000000000000000000000000000000000084146000841216156142195761421861333c565b5b828205841483151761422e5761422d61333c565b5b5092915050565b600061424082613575565b915061424b83613575565b92508261425b5761425a61330d565b5b600160000383147f8000000000000000000000000000000000000000000000000000000000000000831416156142945761429361333c565b5b828205905092915050565b60006142aa82613575565b91506142b583613575565b9250828201905082811215600083121683821260008412151617156142dd576142dc61333c565b5b92915050565b7f2c3531322c353132000000000000000000000000000000000000000000000000600082015250565b6000614319600883613263565b9150614324826142e3565b600882019050919050565b600061433b82846132ba565b91506143468261430c565b915081905092915050565b600061435c82612df9565b915061436783612df9565b925082820261437581612df9565b9150828204841483151761438c5761438b61333c565b5b5092915050565b7f3c7061746820643d220000000000000000000000000000000000000000000000600082015250565b60006143c9600983613263565b91506143d482614393565b600982019050919050565b60006143ea826143bc565b91506143f68284613921565b915081905092915050565b600061440c82613575565b91507f8000000000000000000000000000000000000000000000000000000000000000820361443e5761443d61333c565b5b816000039050919050565b7f2d00000000000000000000000000000000000000000000000000000000000000600082015250565b600061447f600183613263565b915061448a82614449565b600182019050919050565b60006144a082614472565b91506144ac82846132ba565b915081905092915050565b6000819050919050565b6144d26144cd82612df9565b6144b7565b82525050565b60006144e482846144c1565b60208201915081905092915050565b7f20726f7461746528000000000000000000000000000000000000000000000000600082015250565b6000614529600883613263565b9150614534826144f3565b600882019050919050565b600061454b82856132ba565b91506145568261451c565b915061456282846132ba565b915061456d82613ea7565b91508190509392505050565b7f3c636972636c652063783d220000000000000000000000000000000000000000600082015250565b60006145af600c83613263565b91506145ba82614579565b600c82019050919050565b7f222063793d220000000000000000000000000000000000000000000000000000600082015250565b60006145fb600683613263565b9150614606826145c5565b600682019050919050565b7f2220723d22000000000000000000000000000000000000000000000000000000600082015250565b6000614647600583613263565b915061465282614611565b600582019050919050565b6000614668826145a2565b915061467482866132ba565b915061467f826145ee565b915061468b82856132ba565b91506146968261463a565b91506146a282846132ba565b9150819050949350505050565b7f3c6720785f783d22780000000000000000000000000000000000000000000000600082015250565b60006146e5600983613263565b91506146f0826146af565b600982019050919050565b6000614706826146d8565b9150819050919050565b7f223e000000000000000000000000000000000000000000000000000000000000600082015250565b6000614746600283613263565b915061475182614710565b600282019050919050565b7f3c2f673e0a000000000000000000000000000000000000000000000000000000600082015250565b6000614792600583613263565b915061479d8261475c565b600582019050919050565b60006147b382614739565b91506147bf8284613921565b91506147ca82614785565b91508190509291505056fe00000c8c18f9252830fb3c56471c51335a8262f16a6d70e276417a7c7d897f617fffa26469706673582212202b3121552882053fad5b22a033340dc49f62ecc6e3e5641256282d0690f9f23764736f6c63430008110033000000000000000000000000980aac123617e2b2ea407081ceb72d5854baa3d10000000000000000000000009385ba0ac58a29720ff1a746f1ce60c6c7fffa93

Deployed Bytecode

0x6080604052600436106100c25760003560e01c8063893d20e81161007f5780638da5cb5b116100595780638da5cb5b1461025d5780639d37bc7c14610288578063e3f24f02146102b3578063f2fde38b146102f1576100c2565b8063893d20e8146101eb57806389ee68bf146102165780638c40188e14610232576100c2565b806301ffc9a7146100c757806318160ddd146101045780635d6e0dd51461012f578063715018a61461016c57806379b92f271461018357806380bcafbb146101c0575b600080fd5b3480156100d357600080fd5b506100ee60048036038101906100e99190612d96565b61031a565b6040516100fb9190612dde565b60405180910390f35b34801561011057600080fd5b50610119610454565b6040516101269190612e12565b60405180910390f35b34801561013b57600080fd5b5061015660048036038101906101519190612e59565b610459565b6040516101639190612f16565b60405180910390f35b34801561017857600080fd5b506101816104c8565b005b34801561018f57600080fd5b506101aa60048036038101906101a59190612e59565b6104dc565b6040516101b79190612f16565b60405180910390f35b3480156101cc57600080fd5b506101d56104e3565b6040516101e29190612fb7565b60405180910390f35b3480156101f757600080fd5b50610200610507565b60405161020d9190612ff3565b60405180910390f35b610230600480360381019061022b9190612e59565b610516565b005b34801561023e57600080fd5b506102476105a8565b60405161025491906130be565b60405180910390f35b34801561026957600080fd5b50610272610650565b60405161027f9190612ff3565b60405180910390f35b34801561029457600080fd5b5061029d610679565b6040516102aa9190613101565b60405180910390f35b3480156102bf57600080fd5b506102da60048036038101906102d59190612e59565b61069d565b6040516102e892919061311c565b60405180910390f35b3480156102fd57600080fd5b506103186004803603810190610313919061317f565b610cdb565b005b60007f0ece3d21000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806103e557507f5d6e0dd5000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061044d57507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b600090565b60608060606104678461069d565b80925081935050506104bf6040518060400160405280600d81526020017f3020302031303234203130323400000000000000000000000000000000000000815250836104ba6104b585610d5e565b610dd1565b610ed9565b92505050919050565b6104d0610f5d565b6104da6000610fdb565b565b6060919050565b7f0000000000000000000000009385ba0ac58a29720ff1a746f1ce60c6c7fffa9381565b6000610511610650565b905090565b6000610520610650565b90508073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015610568573d6000803e3d6000fd5b507fbb0eeee27936db25b1a46a81ab6d97326392a3e961efa7273d5d756d7a2e1cad82823460405161059c93929190613219565b60405180910390a15050565b6105b0612c18565b60405180606001604052806040518060400160405280600681526020017f706e6f756e73000000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600681526020017f704e6f756e73000000000000000000000000000000000000000000000000000081525081526020013073ffffffffffffffffffffffffffffffffffffffff16815250905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b7f000000000000000000000000980aac123617e2b2ea407081ceb72d5854baa3d181565b6060806106a8612c4f565b6106b18461109f565b6040516020016106c191906132eb565b60405160208183030381529060405291506107317f000000000000000000000000980aac123617e2b2ea407081ceb72d5854baa3d16040518060400160405280600681526020017f704e6f756e7300000000000000000000000000000000000000000000000000008152506111ff565b81600001818152505061080c6107588260000151620fa000610753919061336b565b611367565b6107fe6040518060400160405280600781526020017f23323234343535000000000000000000000000000000000000000000000000008152506107f07f000000000000000000000000980aac123617e2b2ea407081ceb72d5854baa3d16040518060400160405280600681526020017f704e6f756e730000000000000000000000000000000000000000000000000000815250611398565b61169290919063ffffffff16565b6116f590919063ffffffff16565b8160200181905250600a841015610852576108268461109f565b6040516020016108369190613434565b6040516020818303038152906040528160a00181905250610902565b6064841015610890576108648461109f565b60405160200161087491906134ad565b6040516020818303038152906040528160a00181905250610901565b6103e88410156108cf576108a38461109f565b6040516020016108b39190613526565b6040516020818303038152906040528160a00181905250610900565b6108d88461109f565b6040516020016108e89190613553565b6040516020818303038152906040528160a001819052505b5b5b6109307f000000000000000000000000980aac123617e2b2ea407081ceb72d5854baa3d18260a001516111ff565b816000018181525050610a2f6109ac6040518060400160405280600381526020017f302e31000000000000000000000000000000000000000000000000000000000081525061099e600a8560000151610989919061336b565b610400610996919061357f565b61039a611758565b61179490919063ffffffff16565b610a216040518060400160405280600781526020017f2332323434353500000000000000000000000000000000000000000000000000815250610a137f000000000000000000000000980aac123617e2b2ea407081ceb72d5854baa3d18660a00151611398565b61169290919063ffffffff16565b6116f590919063ffffffff16565b8160c00181905250600367ffffffffffffffff811115610a5257610a516135c2565b5b604051908082528060200260200182016040528015610a8557816020015b6060815260200190600190039081610a705790505b508160400181905250600367ffffffffffffffff811115610aa957610aa86135c2565b5b604051908082528060200260200182016040528015610ae257816020015b610acf612c98565b815260200190600190039081610ac75790505b50816060018190525060005b816040015151811015610c11577f0000000000000000000000009385ba0ac58a29720ff1a746f1ce60c6c7fffa9373ffffffffffffffffffffffffffffffffffffffff1663e3f24f028683610b4391906135f1565b6040518263ffffffff1660e01b8152600401610b5f9190612e12565b600060405180830381865afa158015610b7c573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610ba5919061371c565b8360800184604001518481518110610bc057610bbf613794565b5b602002602001018290528290525050610bdc82608001516117c0565b82606001518281518110610bf357610bf2613794565b5b60200260200101819052508080610c09906137c3565b915050610aee565b50610cd3610cce6040518060400160405280610c3085606001516117d6565b8152602001610cc686610cb86040518060600160405280610c9c6040518060400160405280601d81526020017f7472616e736c617465283130322c32303429207363616c6528302e3829000000815250610c8e8f8d604001516117f4565b6116f590919063ffffffff16565b8152602001896020015181526020018960c00151815250611e36565b611e5690919063ffffffff16565b815250611eb9565b610dd1565b925050915091565b610ce3610f5d565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610d52576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d499061387d565b60405180910390fd5b610d5b81610fdb565b50565b610d66612c98565b81604051602001610d7791906138e9565b60405160208183030381529060405281600001819052506040518060400160405280600481526020017f222f3e0a000000000000000000000000000000000000000000000000000000008152508160200181905250919050565b606060008260000151511115610e63578160000151905060005b826040015151811015610e5d57600083604001518281518110610e1157610e10613794565b5b602002602001015190508281600001518260200151604051602001610e38939291906139ea565b6040516020818303038152906040529250508080610e55906137c3565b915050610deb565b50610eac565b600082604001515114610eab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ea290613a7d565b60405180910390fd5b5b808260200151604051602001610ec3929190613a9d565b6040516020818303038152906040529050919050565b6060600084604051602001610eee9190613ba5565b6040516020818303038152906040529050600084511115610f2e578084604051602001610f1c929190613c6a565b60405160208183030381529060405290505b8083604051602001610f41929190613cf0565b6040516020818303038152906040529050809150509392505050565b610f65611ed7565b73ffffffffffffffffffffffffffffffffffffffff16610f83610650565b73ffffffffffffffffffffffffffffffffffffffff1614610fd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fd090613d6b565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6060600082036110e6576040518060400160405280600181526020017f300000000000000000000000000000000000000000000000000000000000000081525090506111fa565b600082905060005b60008214611118578080611101906137c3565b915050600a82611111919061336b565b91506110ee565b60008167ffffffffffffffff811115611134576111336135c2565b5b6040519080825280601f01601f1916602001820160405280156111665781602001600182028036833780820191505090505b5090505b600085146111f35760018261117f9190613d8b565b9150600a8561118e9190613dbf565b603061119a91906135f1565b60f81b8183815181106111b0576111af613794565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a856111ec919061336b565b945061116a565b8093505050505b919050565b6000808290506000600167ffffffffffffffff811115611222576112216135c2565b5b6040519080825280601f01601f1916602001820160405280156112545781602001600182028036833780820191505090505b50905060005b825181101561135e5782818151811061127657611275613794565b5b602001015160f81c60f81b8260008151811061129557611294613794565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508573ffffffffffffffffffffffffffffffffffffffff16637f2406a7836040518263ffffffff1660e01b81526004016112fd9190612f16565b602060405180830381865afa15801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190613e05565b8461134991906135f1565b93508080611356906137c3565b91505061125a565b50505092915050565b606061137282611edf565b6040516020016113829190613eca565b6040516020818303038152906040529050919050565b6113a0612c98565b60008290506000600167ffffffffffffffff8111156113c2576113c16135c2565b5b6040519080825280601f01601f1916602001820160405280156113f45781602001600182028036833780820191505090505b5090506000825167ffffffffffffffff811115611414576114136135c2565b5b60405190808252806020026020018201604052801561144d57816020015b61143a612c98565b8152602001906001900390816114325790505b509050600080600090505b845181101561167c5784818151811061147457611473613794565b5b602001015160f81c60f81b8460008151811061149357611492613794565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061155161154c8973ffffffffffffffffffffffffffffffffffffffff1663a4b3eff4876040518263ffffffff1660e01b81526004016115019190612f16565b600060405180830381865afa15801561151e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906115479190613f98565b612124565b6122bd565b83828151811061156457611563613794565b5b602002602001018190525060008211156115e2576115c383828151811061158e5761158d613794565b5b602002602001015161159f8461109f565b6040516020016115af9190614079565b6040516020818303038152906040526116f5565b8382815181106115d6576115d5613794565b5b60200260200101819052505b8773ffffffffffffffffffffffffffffffffffffffff16637f2406a7856040518263ffffffff1660e01b815260040161161b9190612f16565b602060405180830381865afa158015611638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165c9190613e05565b8261166791906135f1565b91508080611674906137c3565b915050611458565b5061168682612330565b94505050505092915050565b61169a612c98565b6116ed8360405180604001604052806040518060400160405280600481526020017f66696c6c00000000000000000000000000000000000000000000000000000000815250815260200185815250612350565b905092915050565b6116fd612c98565b6117508360405180604001604052806040518060400160405280600981526020017f7472616e73666f726d0000000000000000000000000000000000000000000000815250815260200185815250612350565b905092915050565b606061176383612472565b61176c83612472565b60405160200161177d9291906140f2565b604051602081830303815290604052905092915050565b606082826040516020016117a9929190614183565b604051602081830303815290604052905092915050565b6117c8612c98565b818160200181905250919050565b6117de612c98565b6117e7826124c6565b8160200181905250919050565b6117fc612c98565b600060405180608001604052806040518060400160405280600381526020017f726564000000000000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600581526020017f677265656e00000000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600681526020017f79656c6c6f77000000000000000000000000000000000000000000000000000081525081526020016040518060400160405280600481526020017f626c75650000000000000000000000000000000000000000000000000000000081525081525090506000600a905060008167ffffffffffffffff811115611917576119166135c2565b5b60405190808252806020026020018201604052801561195057816020015b61193d612c98565b8152602001906001900390816119355790505b509050600060405180604001604052808881526020016000815250905060005b83811015611e2057611980612cb9565b600460018361198f91906135f1565b611999919061336b565b8160000181815250506000816000015103611a4c576119c260648461258d90919063ffffffff16565b8260400181815250819450505061017c816040018181516119e391906135f1565b915081815250506119fe60288461258d90919063ffffffff16565b82606001818152508194505050602881606001818151611a1e91906135f1565b91508181525050611a3a6101688461258d90919063ffffffff16565b82608001818152508194505050611ba8565b6001816000015103611b0e57611a6c60648461258d90919063ffffffff16565b8260400181815250819450505060c881604001818151611a8c91906135f1565b91508181525050611aa760468461258d90919063ffffffff16565b82606001818152508194505050604681606001818151611ac791906135f1565b91508181525050611ae260f08461258d90919063ffffffff16565b8260800181815250819450505060f081608001818151611b0291906135f1565b91508181525050611ba7565b611b2260b48461258d90919063ffffffff16565b82604001818152508194505050611b4360468461258d90919063ffffffff16565b8260600181815250819450505060b481606001818151611b6391906135f1565b91508181525050611b7e60788461258d90919063ffffffff16565b8260800181815250819450505061012c81608001818151611b9f91906135f1565b915081815250505b5b611bbd6140008461258d90919063ffffffff16565b826020018181525081945050506180008160400151611bdf836020015161262b565b611be991906141bd565b611bf39190614235565b610200611c00919061429f565b8160a00181815250506180008160400151611c1e836020015161264a565b611c2891906141bd565b611c329190614235565b610200611c3f919061429f565b8160c0018181525050611dee6040518060400160405280611d33611cf6611c69866080015161109f565b604051602001611c79919061432f565b604051602081830303815290604052611ce861020088606001516103e8611ca09190614351565b611caa919061336b565b611cda89606001518a60a00151611cc1919061357f565b8a606001518b60c00151611cd5919061357f565b611758565b6126da90919063ffffffff16565b61270e90919063ffffffff16565b611d258d8e5189611d079190613dbf565b81518110611d1857611d17613794565b5b6020026020010151610d5e565b6116f590919063ffffffff16565b8152602001611de66040518060400160405280600581526020017f302e333333000000000000000000000000000000000000000000000000000000815250611dd88b600489611d829190613dbf565b60048110611d9357611d92613794565b5b6020020151611dca8860a001518960c00151600a8b60600151611db6919061336b565b8b60600151611dc591906135f1565b61273a565b61169290919063ffffffff16565b6127cb90919063ffffffff16565b81525061282e565b848381518110611e0157611e00613794565b5b6020026020010181905250508080611e18906137c3565b915050611970565b50611e2a82612330565b94505050505092915050565b611e3e612c98565b611e4f611e4a8361284e565b612974565b9050919050565b611e5e612c98565b611eb18360405180604001604052806040518060400160405280600281526020017f6964000000000000000000000000000000000000000000000000000000000000815250815260200185815250612350565b905092915050565b611ec1612c98565b611eca826129cf565b8160200181905250919050565b600033905090565b60606000600367ffffffffffffffff811115611efe57611efd6135c2565b5b604051908082528060200260200182016040528015611f3157816020015b6060815260200190600190039081611f1c5790505b5090506103e8831115611f7857611f546103e884611f4f919061336b565b61109f565b81600081518110611f6857611f67613794565b5b6020026020010181905250611fce565b6040518060400160405280600181526020017f300000000000000000000000000000000000000000000000000000000000000081525081600081518110611fc257611fc1613794565b5b60200260200101819052505b600a831015612031576040518060400160405280600381526020017f2e303000000000000000000000000000000000000000000000000000000000008152508160018151811061202157612020613794565b5b60200260200101819052506120eb565b6064831015612094576040518060400160405280600281526020017f2e300000000000000000000000000000000000000000000000000000000000008152508160018151811061208457612083613794565b5b60200260200101819052506120ea565b6040518060400160405280600181526020017f2e00000000000000000000000000000000000000000000000000000000000000815250816001815181106120de576120dd613794565b5b60200260200101819052505b5b6120f48361109f565b8160028151811061210857612107613794565b5b602002602001018190525061211c81612ab5565b915050919050565b6060806020830160036002855102046040519250602083016000805b838110156122a3576000601082060361215e57845191506018850194505b600080600283066000811461218a5760ff8560e81c169250600f8560f41c1691508460181b945061219a565b8460f81c9250600f8560f01c1691505b50806000811461226f5760006002610100858560081b01036104008110600081146121d357602d935060039250816104000391506121db565b610400820391505b50600981111561224557606381111561222a576103e781111561220f5760318360081b1792508160010191506103e8810690505b606481046030018360081b1792508160010191506064810690505b600a81046030018360081b179250816001019150600a810690505b60208160300160081b8460101b171792508260088302610100031b89528189019850505050612295565b607b83106060841116605b841060408511161715612294578260f81b86526001860195505b5b505050600181019050612140565b506020858303038552816040525050505080915050919050565b6122c5612c98565b816040516020016122d691906143df565b60405160208183030381529060405281600001819052506040518060400160405280600481526020017f222f3e0a000000000000000000000000000000000000000000000000000000008152508160200181905250919050565b612338612c98565b612349612344836124c6565b612974565b9050919050565b612358612c98565b8260000151816000018190525082602001518160200181905250600183604001515161238491906135f1565b67ffffffffffffffff81111561239d5761239c6135c2565b5b6040519080825280602002602001820160405280156123d657816020015b6123c3612cf6565b8152602001906001900390816123bb5790505b50816040018190525060005b836040015151811015612443578360400151818151811061240657612405613794565b5b60200260200101518260400151828151811061242557612424613794565b5b6020026020010181905250808061243b906137c3565b9150506123e2565b508181604001518460400151518151811061246157612460613794565b5b602002602001018190525092915050565b6060600082131561248d576124868261109f565b90506124c1565b61249f8261249a90614401565b61109f565b6040516020016124af9190614495565b60405160208183030381529060405290505b919050565b60606000825167ffffffffffffffff8111156124e5576124e46135c2565b5b60405190808252806020026020018201604052801561251857816020015b60608152602001906001900390816125035790505b50905060005b835181101561257b5761254a84828151811061253d5761253c613794565b5b6020026020010151610dd1565b82828151811061255d5761255c613794565b5b60200260200101819052508080612573906137c3565b91505061251e565b5061258581612ab5565b915050919050565b612595612d10565b6000839150610100836125a89190614351565b826020015110156125f95781600001516040516020016125c891906144d8565b6040516020818303038152906040528051906020012060001c82600001818152505081600001518260200181815250505b8282602001516126099190613dbf565b9050828260200181815161261d919061336b565b915081815250509250929050565b60006126436110008361263e91906135f1565b61264a565b9050919050565b6000806140008361265b9190613dbf565b90506120008110156126955761268d611000821061268657816120006126819190613d8b565b612688565b815b612b2f565b9150506126d5565b6126c861300082106126b457816140006126af9190613d8b565b6126c3565b612000826126c29190613d8b565b5b612b2f565b6126d190614401565b9150505b919050565b6060826126e683611edf565b6040516020016126f7929190614183565b604051602081830303815290604052905092915050565b6060828260405160200161272392919061453f565b604051602081830303815290604052905092915050565b612742612c98565b61274b8461109f565b6127548461109f565b61275d8461109f565b60405160200161276f9392919061465d565b60405160208183030381529060405281600001819052506040518060400160405280600481526020017f222f3e0a0000000000000000000000000000000000000000000000000000000081525081602001819052509392505050565b6127d3612c98565b6128268360405180604001604052806040518060400160405280600781526020017f6f70616369747900000000000000000000000000000000000000000000000000815250815260200185815250612350565b905092915050565b612836612c98565b612847612842836129cf565b612974565b9050919050565b60606000600367ffffffffffffffff81111561286d5761286c6135c2565b5b6040519080825280602002602001820160405280156128a057816020015b606081526020019060019003908161288b5790505b5090506128c4836000600381106128ba576128b9613794565b5b6020020151610dd1565b816000815181106128d8576128d7613794565b5b6020026020010181905250612904836001600381106128fa576128f9613794565b5b6020020151610dd1565b8160018151811061291857612917613794565b5b60200260200101819052506129448360026003811061293a57612939613794565b5b6020020151610dd1565b8160028151811061295857612957613794565b5b602002602001018190525061296c81612ab5565b915050919050565b61297c612c98565b60405160200161298b906146fb565b6040516020818303038152906040528160000181905250816040516020016129b391906147a8565b6040516020818303038152906040528160200181905250919050565b60606000600267ffffffffffffffff8111156129ee576129ed6135c2565b5b604051908082528060200260200182016040528015612a2157816020015b6060815260200190600190039081612a0c5790505b509050612a4583600060028110612a3b57612a3a613794565b5b6020020151610dd1565b81600081518110612a5957612a58613794565b5b6020026020010181905250612a8583600160028110612a7b57612a7a613794565b5b6020020151610dd1565b81600181518110612a9957612a98613794565b5b6020026020010181905250612aad81612ab5565b915050919050565b60606000825190506040519150602082016020840160005b83811015612b1a57815183815160005b81811015612b005760208401935083518352602083019250602081019050612add565b508086019550602085019450505050600181019050612acd565b50602084830303845281604052505050919050565b60006110008203612b4457617fff9050612bc2565b600061010083612b54919061336b565b9050600060ff841690506000612b6983612bc7565b61ffff1690506000612b86600185612b8191906135f1565b612bc7565b61ffff169050610100838383612b9c9190613d8b565b612ba69190614351565b612bb0919061336b565b82612bbb91906135f1565b9450505050505b919050565b6000806040518060600160405280602281526020016147d66022913990506000600260ff16600185612bf991906135f1565b612c039190614351565b90506000818301519050809350505050919050565b60405180606001604052806060815260200160608152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b6040518060e0016040528060008152602001612c69612c98565b815260200160608152602001606081526020016060815260200160608152602001612c92612c98565b81525090565b60405180606001604052806060815260200160608152602001606081525090565b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806040016040528060608152602001606081525090565b604051806040016040528060008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612d7381612d3e565b8114612d7e57600080fd5b50565b600081359050612d9081612d6a565b92915050565b600060208284031215612dac57612dab612d34565b5b6000612dba84828501612d81565b91505092915050565b60008115159050919050565b612dd881612dc3565b82525050565b6000602082019050612df36000830184612dcf565b92915050565b6000819050919050565b612e0c81612df9565b82525050565b6000602082019050612e276000830184612e03565b92915050565b612e3681612df9565b8114612e4157600080fd5b50565b600081359050612e5381612e2d565b92915050565b600060208284031215612e6f57612e6e612d34565b5b6000612e7d84828501612e44565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612ec0578082015181840152602081019050612ea5565b60008484015250505050565b6000601f19601f8301169050919050565b6000612ee882612e86565b612ef28185612e91565b9350612f02818560208601612ea2565b612f0b81612ecc565b840191505092915050565b60006020820190508181036000830152612f308184612edd565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000612f7d612f78612f7384612f38565b612f58565b612f38565b9050919050565b6000612f8f82612f62565b9050919050565b6000612fa182612f84565b9050919050565b612fb181612f96565b82525050565b6000602082019050612fcc6000830184612fa8565b92915050565b6000612fdd82612f38565b9050919050565b612fed81612fd2565b82525050565b60006020820190506130086000830184612fe4565b92915050565b600082825260208201905092915050565b600061302a82612e86565b613034818561300e565b9350613044818560208601612ea2565b61304d81612ecc565b840191505092915050565b61306181612f96565b82525050565b60006060830160008301518482036000860152613084828261301f565b9150506020830151848203602086015261309e828261301f565b91505060408301516130b36040860182613058565b508091505092915050565b600060208201905081810360008301526130d88184613067565b905092915050565b60006130eb82612f84565b9050919050565b6130fb816130e0565b82525050565b600060208201905061311660008301846130f2565b92915050565b600060408201905081810360008301526131368185612edd565b9050818103602083015261314a8184612edd565b90509392505050565b61315c81612fd2565b811461316757600080fd5b50565b60008135905061317981613153565b92915050565b60006020828403121561319557613194612d34565b5b60006131a38482850161316a565b91505092915050565b7f706e6f756e730000000000000000000000000000000000000000000000000000600082015250565b60006131e2600683612e91565b91506131ed826131ac565b602082019050919050565b600061320382612f38565b9050919050565b613213816131f8565b82525050565b60006080820190508181036000830152613232816131d5565b90506132416020830186612e03565b61324e604083018561320a565b61325b6060830184612e03565b949350505050565b600081905092915050565b7f636972636c657300000000000000000000000000000000000000000000000000600082015250565b60006132a4600783613263565b91506132af8261326e565b600782019050919050565b60006132c582612e86565b6132cf8185613263565b93506132df818560208601612ea2565b80840191505092915050565b60006132f682613297565b915061330282846132ba565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061337682612df9565b915061338183612df9565b9250826133915761339061330d565b5b828204905092915050565b7f3030300000000000000000000000000000000000000000000000000000000000600082015250565b60006133d2600383613263565b91506133dd8261339c565b600382019050919050565b7f2f32303030000000000000000000000000000000000000000000000000000000600082015250565b600061341e600583613263565b9150613429826133e8565b600582019050919050565b600061343f826133c5565b915061344b82846132ba565b915061345682613411565b915081905092915050565b7f3030000000000000000000000000000000000000000000000000000000000000600082015250565b6000613497600283613263565b91506134a282613461565b600282019050919050565b60006134b88261348a565b91506134c482846132ba565b91506134cf82613411565b915081905092915050565b7f3000000000000000000000000000000000000000000000000000000000000000600082015250565b6000613510600183613263565b915061351b826134da565b600182019050919050565b600061353182613503565b915061353d82846132ba565b915061354882613411565b915081905092915050565b600061355f82846132ba565b915061356a82613411565b915081905092915050565b6000819050919050565b600061358a82613575565b915061359583613575565b92508282039050818112600084121682821360008512151617156135bc576135bb61333c565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006135fc82612df9565b915061360783612df9565b925082820190508082111561361f5761361e61333c565b5b92915050565b600080fd5b600080fd5b61363882612ecc565b810181811067ffffffffffffffff82111715613657576136566135c2565b5b80604052505050565b600061366a612d2a565b9050613676828261362f565b919050565b600067ffffffffffffffff821115613696576136956135c2565b5b61369f82612ecc565b9050602081019050919050565b60006136bf6136ba8461367b565b613660565b9050828152602081018484840111156136db576136da61362a565b5b6136e6848285612ea2565b509392505050565b600082601f83011261370357613702613625565b5b81516137138482602086016136ac565b91505092915050565b6000806040838503121561373357613732612d34565b5b600083015167ffffffffffffffff81111561375157613750612d39565b5b61375d858286016136ee565b925050602083015167ffffffffffffffff81111561377e5761377d612d39565b5b61378a858286016136ee565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006137ce82612df9565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613800576137ff61333c565b5b600182019050919050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000613867602683612e91565b91506138728261380b565b604082019050919050565b600060208201905081810360008301526138968161385a565b9050919050565b7f3c75736520687265663d22230000000000000000000000000000000000000000600082015250565b60006138d3600c83613263565b91506138de8261389d565b600c82019050919050565b60006138f4826138c6565b915061390082846132ba565b915081905092915050565b600081519050919050565b600081905092915050565b600061392c8261390b565b6139368185613916565b9350613946818560208601612ea2565b80840191505092915050565b7f2220000000000000000000000000000000000000000000000000000000000000600082015250565b6000613988600283613263565b915061399382613952565b600282019050919050565b7f3d22000000000000000000000000000000000000000000000000000000000000600082015250565b60006139d4600283613263565b91506139df8261399e565b600282019050919050565b60006139f68286613921565b9150613a018261397b565b9150613a0d82856132ba565b9150613a18826139c7565b9150613a2482846132ba565b9150819050949350505050565b7f41747472696275746573206f6e206c6973740000000000000000000000000000600082015250565b6000613a67601283612e91565b9150613a7282613a31565b602082019050919050565b60006020820190508181036000830152613a9681613a5a565b9050919050565b6000613aa98285613921565b9150613ab58284613921565b91508190509392505050565b7f3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d22555460008201527f462d38223f3e3c7376672076696577426f783d22000000000000000000000000602082015250565b6000613b1d603483613263565b9150613b2882613ac1565b603482019050919050565b7f2220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f60008201527f737667223e0a0000000000000000000000000000000000000000000000000000602082015250565b6000613b8f602683613263565b9150613b9a82613b33565b602682019050919050565b6000613bb082613b10565b9150613bbc82846132ba565b9150613bc782613b82565b915081905092915050565b7f3c646566733e0a00000000000000000000000000000000000000000000000000600082015250565b6000613c08600783613263565b9150613c1382613bd2565b600782019050919050565b7f3c2f646566733e0a000000000000000000000000000000000000000000000000600082015250565b6000613c54600883613263565b9150613c5f82613c1e565b600882019050919050565b6000613c768285613921565b9150613c8182613bfb565b9150613c8d8284613921565b9150613c9882613c47565b91508190509392505050565b7f3c2f7376673e0a00000000000000000000000000000000000000000000000000600082015250565b6000613cda600783613263565b9150613ce582613ca4565b600782019050919050565b6000613cfc8285613921565b9150613d088284613921565b9150613d1382613ccd565b91508190509392505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000613d55602083612e91565b9150613d6082613d1f565b602082019050919050565b60006020820190508181036000830152613d8481613d48565b9050919050565b6000613d9682612df9565b9150613da183612df9565b9250828203905081811115613db957613db861333c565b5b92915050565b6000613dca82612df9565b9150613dd583612df9565b925082613de557613de461330d565b5b828206905092915050565b600081519050613dff81612e2d565b92915050565b600060208284031215613e1b57613e1a612d34565b5b6000613e2984828501613df0565b91505092915050565b7f7363616c65280000000000000000000000000000000000000000000000000000600082015250565b6000613e68600683613263565b9150613e7382613e32565b600682019050919050565b7f2900000000000000000000000000000000000000000000000000000000000000600082015250565b6000613eb4600183613263565b9150613ebf82613e7e565b600182019050919050565b6000613ed582613e5b565b9150613ee182846132ba565b9150613eec82613ea7565b915081905092915050565b600067ffffffffffffffff821115613f1257613f116135c2565b5b613f1b82612ecc565b9050602081019050919050565b6000613f3b613f3684613ef7565b613660565b905082815260208101848484011115613f5757613f5661362a565b5b613f62848285612ea2565b509392505050565b600082601f830112613f7f57613f7e613625565b5b8151613f8f848260208601613f28565b91505092915050565b600060208284031215613fae57613fad612d34565b5b600082015167ffffffffffffffff811115613fcc57613fcb612d39565b5b613fd884828501613f6a565b91505092915050565b7f7472616e736c6174652800000000000000000000000000000000000000000000600082015250565b6000614017600a83613263565b915061402282613fe1565b600a82019050919050565b7f2030290000000000000000000000000000000000000000000000000000000000600082015250565b6000614063600383613263565b915061406e8261402d565b600382019050919050565b60006140848261400a565b915061409082846132ba565b915061409b82614056565b915081905092915050565b7f2000000000000000000000000000000000000000000000000000000000000000600082015250565b60006140dc600183613263565b91506140e7826140a6565b600182019050919050565b60006140fd8261400a565b915061410982856132ba565b9150614114826140cf565b915061412082846132ba565b915061412b82613ea7565b91508190509392505050565b7f207363616c652800000000000000000000000000000000000000000000000000600082015250565b600061416d600783613263565b915061417882614137565b600782019050919050565b600061418f82856132ba565b915061419a82614160565b91506141a682846132ba565b91506141b182613ea7565b91508190509392505050565b60006141c882613575565b91506141d383613575565b92508282026141e181613575565b91507f800000000000000000000000000000000000000000000000000000000000000084146000841216156142195761421861333c565b5b828205841483151761422e5761422d61333c565b5b5092915050565b600061424082613575565b915061424b83613575565b92508261425b5761425a61330d565b5b600160000383147f8000000000000000000000000000000000000000000000000000000000000000831416156142945761429361333c565b5b828205905092915050565b60006142aa82613575565b91506142b583613575565b9250828201905082811215600083121683821260008412151617156142dd576142dc61333c565b5b92915050565b7f2c3531322c353132000000000000000000000000000000000000000000000000600082015250565b6000614319600883613263565b9150614324826142e3565b600882019050919050565b600061433b82846132ba565b91506143468261430c565b915081905092915050565b600061435c82612df9565b915061436783612df9565b925082820261437581612df9565b9150828204841483151761438c5761438b61333c565b5b5092915050565b7f3c7061746820643d220000000000000000000000000000000000000000000000600082015250565b60006143c9600983613263565b91506143d482614393565b600982019050919050565b60006143ea826143bc565b91506143f68284613921565b915081905092915050565b600061440c82613575565b91507f8000000000000000000000000000000000000000000000000000000000000000820361443e5761443d61333c565b5b816000039050919050565b7f2d00000000000000000000000000000000000000000000000000000000000000600082015250565b600061447f600183613263565b915061448a82614449565b600182019050919050565b60006144a082614472565b91506144ac82846132ba565b915081905092915050565b6000819050919050565b6144d26144cd82612df9565b6144b7565b82525050565b60006144e482846144c1565b60208201915081905092915050565b7f20726f7461746528000000000000000000000000000000000000000000000000600082015250565b6000614529600883613263565b9150614534826144f3565b600882019050919050565b600061454b82856132ba565b91506145568261451c565b915061456282846132ba565b915061456d82613ea7565b91508190509392505050565b7f3c636972636c652063783d220000000000000000000000000000000000000000600082015250565b60006145af600c83613263565b91506145ba82614579565b600c82019050919050565b7f222063793d220000000000000000000000000000000000000000000000000000600082015250565b60006145fb600683613263565b9150614606826145c5565b600682019050919050565b7f2220723d22000000000000000000000000000000000000000000000000000000600082015250565b6000614647600583613263565b915061465282614611565b600582019050919050565b6000614668826145a2565b915061467482866132ba565b915061467f826145ee565b915061468b82856132ba565b91506146968261463a565b91506146a282846132ba565b9150819050949350505050565b7f3c6720785f783d22780000000000000000000000000000000000000000000000600082015250565b60006146e5600983613263565b91506146f0826146af565b600982019050919050565b6000614706826146d8565b9150819050919050565b7f223e000000000000000000000000000000000000000000000000000000000000600082015250565b6000614746600283613263565b915061475182614710565b600282019050919050565b7f3c2f673e0a000000000000000000000000000000000000000000000000000000600082015250565b6000614792600583613263565b915061479d8261475c565b600582019050919050565b60006147b382614739565b91506147bf8284613921565b91506147ca82614785565b91508190509291505056fe00000c8c18f9252830fb3c56471c51335a8262f16a6d70e276417a7c7d897f617fffa26469706673582212202b3121552882053fad5b22a033340dc49f62ecc6e3e5641256282d0690f9f23764736f6c63430008110033

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

000000000000000000000000980aac123617e2b2ea407081ceb72d5854baa3d10000000000000000000000009385ba0ac58a29720ff1a746f1ce60c6c7fffa93

-----Decoded View---------------
Arg [0] : _font (address): 0x980aAc123617e2B2ea407081Ceb72d5854BAa3D1
Arg [1] : _nounsProvider (address): 0x9385bA0ac58A29720Ff1a746f1CE60C6c7FfFA93

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000980aac123617e2b2ea407081ceb72d5854baa3d1
Arg [1] : 0000000000000000000000009385ba0ac58a29720ff1a746f1ce60c6c7fffa93


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.