Feature Tip: Add private address tag to any address under My Name Tag !
ERC-1155
Overview
Max Total Supply
29
Holders
19
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
LW00x0
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol"; import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "./LW77x7.sol"; import './LTNT.sol'; import 'base64-sol/base64.sol'; import './lib/Rando.sol'; import './LTNTFont.sol'; /** ___ ___ ___ __ __ __ | /\ | |__ |\ | | | | / \ |__) |__/ /__` |___ /~~\ | |___ | \| | .|/\| \__/ | \ | \ .__/ "00x0", latent.works, 2022 */ contract LW00x0 is ERC1155, ERC1155Supply, ERC1155Holder, Ownable, ReentrancyGuard, LTNTIssuer { // Orientation enum for artworks enum Orientation{LANDSCAPE, PORTRAIT} // Comp info struct Comp { uint id; address creator; string seed; string image; Orientation orientation; uint editions; uint available; } event CompCreated(uint indexed comp_id, address indexed creator); string public constant NAME = unicode"Latent Works · 00x0"; string public constant DESCRIPTION = "latent.works"; uint public constant PRICE = 0.07 ether; LTNT public immutable _ltnt; LW77x7 public immutable _77x7; LW77x7_LTNTIssuer public immutable _77x7_ltnt_issuer; LW00x0_Meta public immutable _00x0_meta; uint private _comp_ids; mapping(uint => uint[]) private _comp_works; mapping(uint => address) private _comp_creators; constructor(address seven7x7_, address seven7x7_ltnt_issuer_, address ltnt_) ERC1155("") { _77x7 = LW77x7(seven7x7_); _77x7_ltnt_issuer = LW77x7_LTNTIssuer(seven7x7_ltnt_issuer_); _ltnt = LTNT(ltnt_); LW00x0_Meta meta_ = new LW00x0_Meta(address(this), seven7x7_); _00x0_meta = LW00x0_Meta(address(meta_)); } /// @dev require function to check if an address is the 77x7 contract function _req77x7Token(address address_) private view { require(address_ == address(_77x7), 'ONLY_77X7_ACCEPTED'); } /// @dev return issuer information for LTNT passports function issuerInfo(uint, LTNT.Param memory param_) public view override returns(LTNT.IssuerInfo memory){ return LTNT.IssuerInfo( '00x0', getImage(param_._uint, true, true) ); } /// @dev override for supportsInterface function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, ERC1155Receiver) returns (bool) { return super.supportsInterface(interfaceId); } /// @dev recieves a batch of 77x7 works and creates a 00x from them as well as issues a LTNT for each work function onERC1155BatchReceived(address, address from_, uint[] memory ids_, uint[] memory, bytes memory) public override returns(bytes4){ _req77x7Token(_msgSender()); require(ids_.length > 1 && ids_.length <= 7, 'ID_COUNT_OUT_OF_RANGE'); uint comp_id_ = _create(from_, ids_); uint id_; for(uint i = 0; i < ids_.length; i++){ id_ = _77x7_ltnt_issuer.issueTo(from_, LTNT.Param(ids_[i], from_, '', true), true); _ltnt.stamp(id_, LTNT.Param(comp_id_, from_, '', false)); } return super.onERC1155BatchReceived.selector; } /// @dev recieves a single 77x7 work and issues a LTNT for it function onERC1155Received(address, address from_, uint256 id_, uint256, bytes memory) public override returns(bytes4){ _req77x7Token(_msgSender()); _77x7_ltnt_issuer.issueTo(from_, LTNT.Param(id_, from_, '', false), true); return super.onERC1155Received.selector; } /// @dev internal function to create a comp for a given set of 77x7 works function _create(address for_, uint[] memory works_) private returns(uint) { require((works_.length > 1 && works_.length <= 7), "MIN_2_MAX_7_WORKS"); _comp_ids++; _comp_works[_comp_ids] = works_; _comp_creators[_comp_ids] = for_; emit CompCreated(_comp_ids, for_); _mintFor(for_, _comp_ids); return _comp_ids; } /// @dev internal mint function function _mintFor(address for_, uint comp_id_) private { _mint(for_, comp_id_, 1, ""); } /// @dev mint yeah function mint(uint comp_id_) public payable nonReentrant { require(msg.sender != _comp_creators[comp_id_], 'COMP_CREATOR'); require(msg.value == PRICE, "INVALID_VALUE"); require(getAvailable(comp_id_) > 0, "UNAVAILABLE"); require(_comp_creators[comp_id_] != msg.sender, "NO_CREATOR_MINT"); address owner_ = owner(); uint each_ = msg.value / 2; (bool creator_sent_,) = _comp_creators[comp_id_].call{value: each_}(""); (bool owner_sent_,) = owner_.call{value: each_}(""); require((creator_sent_ && owner_sent_), "INTERNAL_ETHER_TX_FAILED"); _mintFor(msg.sender, comp_id_); _ltnt.issueTo(msg.sender, LTNT.Param(comp_id_, msg.sender, '', false), true); } /// @dev get the number of total editions for a given comp function getEditions(uint comp_id_) public view returns(uint) { return _comp_works[comp_id_].length; } /// @dev get the creator adress of a given comp id function getCreator(uint comp_id_) public view returns(address){ return _comp_creators[comp_id_]; } /// @dev get the total available editions left for comp function getAvailable(uint comp_id_) public view returns(uint){ return _comp_works[comp_id_].length - totalSupply(comp_id_); } /// @dev get the 77x7 work IDs used to create a given comp function getWorks(uint comp_id_) public view returns(uint[] memory){ return _comp_works[comp_id_]; } /// @dev get the image of a given comp function getImage(uint comp_id_, bool mark_, bool encode_) public view returns(string memory output_){ require(totalSupply(comp_id_) > 0, 'DOES_NOT_EXIST'); return _00x0_meta.getImage(comp_id_, mark_, encode_); } function getComps(uint limit_, uint page_, bool ascending_) public view returns(LW00x0.Comp[] memory){ uint count_ = _comp_ids; if(limit_ < 1 && page_ < 1){ limit_ = count_; page_ = 1; } LW00x0.Comp[] memory comps_ = new LW00x0.Comp[](limit_); uint i; if(ascending_){ // ASCENDING uint id = page_ == 1 ? 1 : ((page_-1)*limit_)+1; while(id <= count_ && i < limit_){ comps_[i] = getComp(id); ++i; ++id; } } else { /// DESCENDING uint id = page_ == 1 ? count_ : count_ - (limit_*(page_-1)); while(id > 0 && i < limit_){ comps_[i] = getComp(id); ++i; --id; } } return comps_; } /// @dev get the comp struct for a given comp ID function getComp(uint comp_id_) public view returns(LW00x0.Comp memory){ return LW00x0.Comp( comp_id_, getCreator(comp_id_), _00x0_meta.getSeed(comp_id_, ''), getImage(comp_id_, true, true), _00x0_meta.getOrientation(comp_id_), getEditions(comp_id_), getAvailable(comp_id_) ); } /// @dev get total number of comps created function getCompCount() public view returns(uint){ return _comp_ids; } /// @dev return the metadata uri for a given url function uri(uint comp_id_) public view override returns(string memory){ return _00x0_meta.getJSON(comp_id_); } // Required overrides function _beforeTokenTransfer(address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual override(ERC1155, ERC1155Supply){ super._beforeTokenTransfer(operator, from, to, ids, amounts, data); } function _mint(address account, uint256 id, uint256 amount, bytes memory data) internal override (ERC1155) { super._mint(account, id, amount, data); } function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal override (ERC1155) { super._mintBatch(to, ids, amounts, data); } function _burn(address account, uint256 id, uint256 amount) internal override (ERC1155) { super._burn(account, id, amount); } function _burnBatch(address to, uint256[] memory ids, uint256[] memory amounts) internal override (ERC1155) { super._burnBatch(to, ids, amounts); } } contract LW00x0_Meta { LW00x0 private _00x0; LW77x7 private _77x7; string private _easing = 'keyTimes="0; 0.33; 0.66; 1" keySplines="0.5 0 0.5 1; 0.5 0 0.5 1; 0.5 0 0.5 1; 0.5 0 0.5 1;"'; string private _noise = 'data:@file/png;base64,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'; // Compinfo for passing to the comp creator struct CompInfo { string id; string id_string; bool mark; string seed; string seed0; string seed1; string seed2; string seed3; uint[] works; bytes defs; bytes ani_elements; bytes elements; uint left; uint right; LW00x0.Orientation orientation; string width_string; string height_string; string[2] pos; uint start; uint last_left; uint last_right; bytes begin_t; bytes translate; bytes scale; } constructor(address zero0x0_, address seven7x7_){ _00x0 = LW00x0(zero0x0_); _77x7 = LW77x7(seven7x7_); } /** SEEDS */ function _generateSeed(address salt_, uint[] memory works_, string memory append_) private pure returns(string memory){ uint salt_uint_ = (uint256(uint160(salt_)))/10000000000000000000000000000000000000; return string(abi.encodePacked(Strings.toString(salt_uint_+(works_[0]+works_[1])*(works_[0]+works_[1])*(77*works_.length)), append_)); } function getSeed(uint comp_id_, string memory append_) public view returns(string memory){ uint[] memory works_ = _00x0.getWorks(comp_id_); address salt_ = _00x0.getCreator(comp_id_); return _generateSeed(salt_, works_, append_); } /** ORIENTATION */ function _generateOrientation(string memory seed_) private pure returns(LW00x0.Orientation){ return Rando.number(seed_, 0, 99) > 50 ? LW00x0.Orientation.LANDSCAPE : LW00x0.Orientation.PORTRAIT; } function getOrientation(uint comp_id_) public view returns(LW00x0.Orientation){ string memory seed_ = _generateSeed(_00x0.getCreator(comp_id_), _00x0.getWorks(comp_id_), ''); return _generateOrientation(seed_); } /** COMPS */ function _generateComp(address salt_, uint[] memory works_) private pure returns(CompInfo memory) { return CompInfo( '', '', false, _generateSeed(salt_, works_, ''), '', '', '', _generateSeed(salt_, works_, 'rand'), works_, '', '', '', 0, 0, _generateOrientation(_generateSeed(salt_, works_, '')), '', '', ['', ''], 0, 0, 0, '', '', '' ); } function getImage(uint comp_id_, bool mark_, bool encode_) public view returns(string memory) { CompInfo memory comp_ = _generateComp(_00x0.getCreator(comp_id_), _00x0.getWorks(comp_id_)); comp_.id = Strings.toString(comp_id_); comp_.mark = mark_; return _generateImage(comp_, encode_); } function previewImage(address salt_, uint[] memory works_) public view returns(string memory){ require((works_.length > 1 && works_.length <= 7), "MIN_2_MAX_7_WORKS"); for(uint i = 0; i < works_.length; i++){ require(_77x7.exists(works_[i]), 'WORK_DOES_NOT_EXIST'); } CompInfo memory comp_ = _generateComp(salt_, works_); comp_.id = 'PRE'; comp_.mark = true; return _generateImage(comp_, true); } function _generateImage(CompInfo memory comp_, bool encode_) private view returns(string memory){ comp_.start = (700/comp_.works.length); comp_.last_left = Rando.number(comp_.seed1, comp_.start-100, comp_.start); comp_.last_right = Rando.number(comp_.seed2, comp_.start-100, comp_.start); comp_.pos[0] = Strings.toString(Rando.number(comp_.seed, 100, comp_.orientation == LW00x0.Orientation.LANDSCAPE ? 800 : 500)); comp_.pos[1] = Strings.toString(Rando.number(comp_.seed1, 100, comp_.orientation == LW00x0.Orientation.LANDSCAPE ? 500 : 800)); comp_.width_string = comp_.orientation == LW00x0.Orientation.LANDSCAPE ? '1000' : '700'; comp_.height_string = comp_.orientation == LW00x0.Orientation.LANDSCAPE ? '700' : '1000'; for(uint i = 0; i < comp_.works.length; i++) { comp_.seed0 = string(abi.encodePacked(comp_.seed, Strings.toString(i))); comp_.seed1 = string(abi.encodePacked(comp_.seed, abi.encodePacked(comp_.seed0, 'left'))); comp_.seed2 = string(abi.encodePacked(comp_.seed, abi.encodePacked(comp_.seed0, 'right'))); comp_.id_string = Strings.toString(i+1); comp_.left = Rando.number(comp_.seed1, comp_.last_left/10, 1000); comp_.right = Rando.number(comp_.seed2, comp_.last_right/2, 1000); comp_.defs = abi.encodePacked(comp_.defs, '<clipPath id="clip',comp_.id_string,'"><polygon points="0,',Strings.toString(comp_.last_left),' 0,',Strings.toString(comp_.left),' 1000,',Strings.toString(comp_.right),' 1000,',Strings.toString(comp_.last_right),'">', '</polygon></clipPath>'); comp_.elements = abi.encodePacked(comp_.elements, '<rect fill="', _77x7.getColor(comp_.works[i], Rando.number(comp_.seed0, 1, 7)),'" y="0" x="0" height="1000" width="1000" clip-path="url(#clip',comp_.id_string,')">', '</rect>' ); comp_.begin_t = abi.encodePacked(Strings.toString(Rando.number(comp_.seed1, 100, 700)),' ',Strings.toString(Rando.number(comp_.seed2, 100, 700))); comp_.translate = abi.encodePacked(comp_.begin_t, ';', Strings.toString(Rando.number(comp_.seed1, 10, 800)),' ', Strings.toString(Rando.number(comp_.seed2, 10, 800)),';', Strings.toString(Rando.number(comp_.seed2, 100, 1000)),' ', Strings.toString(Rando.number(comp_.seed1, 400, 800)),';',comp_.begin_t); comp_.scale = abi.encodePacked('1; 0.', Strings.toString(Rando.number(comp_.seed1, 1, 9)),'; 0.',Strings.toString(Rando.number(comp_.seed2, 1, 9)),'; 1'); comp_.ani_elements = abi.encodePacked(comp_.ani_elements, '<rect fill="', _77x7.getColor(comp_.works[i], Rando.number(comp_.seed0, 1, 7)),'" y="0" x="0" height="1000" width="1000" clip-path="url(#clip',comp_.id_string,')">', '<animateTransform ',_easing,' attributeName="transform" type="scale" values="',comp_.scale,'" begin="0s" dur="',Strings.toString(Rando.number(comp_.seed2, 50, 100)),'s" repeatCount="indefinite"/>', '</rect>' ); comp_.last_left = comp_.left; comp_.last_right = comp_.right; } comp_.pos[0] = Strings.toString(Rando.number(comp_.seed, 100, comp_.orientation == LW00x0.Orientation.LANDSCAPE ? 800 : 500)); comp_.pos[1] = Strings.toString(Rando.number(comp_.seed1, 100, comp_.orientation == LW00x0.Orientation.LANDSCAPE ? 500 : 800)); bytes memory output_ = abi.encodePacked( '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ',comp_.width_string, ' ', comp_.height_string, '" preserveAspectRatio="xMinYMin meet">', '<defs>', '<pattern id="noise" x="0" y="0" width="51" height="51" patternUnits="userSpaceOnUse"><image opacity="0.2" width="51" height="51" href="',_noise,'"/></pattern>', '<g id="main" transform="translate(-5 -5) scale(1.2)" opacity="0.8">', comp_.elements, '</g>', '<g id="main-ani" transform="translate(-5 -5) scale(1.2)" opacity="0.8">', comp_.ani_elements, '</g>', '<filter id="blur" x="0" y="0"><feGaussianBlur in="SourceGraphic" stdDeviation="100"/></filter>', '<rect id="bg" height="',comp_.height_string,'" width="',comp_.width_string,'" x="0" y="0"/><clipPath id="clip"><use href="#bg"/></clipPath>', comp_.defs, '</defs>' ); output_ = abi.encodePacked( output_, '<g clip-path="url(#clip)">', '<use href="#bg" fill="white"/>', '<use href="#bg" fill="',_77x7.getColor(comp_.works[0], 1),'" opacity="0.25"/>', '<use href="#main" filter="url(#blur)" transform="rotate(90, 500, 500)"/>', '<use href="#main-ani" filter="url(#blur)" transform="scale(0.',Strings.toString(Rando.number(comp_.seed0, 5, 9)),') rotate(90, 500, 500)"/>', '<use href="#main-ani" filter="url(#blur)" transform="scale(0.',Strings.toString(Rando.number(comp_.seed0, 3, 6)),') translate(',comp_.pos[0],', ',comp_.pos[1],')"/>', comp_.mark ? _getMark(comp_) : bytes(''), '<use href="#bg" fill="url(#noise)"/>', '</g>', '</svg>' ); if(encode_) return string(abi.encodePacked('data:image/svg+xml;base64,', Base64.encode(output_))); return string(output_); } function _getMark(CompInfo memory comp_) private pure returns(bytes memory){ bytes memory leading_zeroes_; if(bytes(comp_.id).length == 1) leading_zeroes_ = '00'; else if(bytes(comp_.id).length == 2) leading_zeroes_ = '0'; string memory lift_text_ = Strings.toString((comp_.orientation == LW00x0.Orientation.LANDSCAPE ? 700 : 1000)-10); return abi.encodePacked('<style>.txt{font: normal 12px monospace;fill: white; letter-spacing:0.1em;}</style><rect width="115" height="30" x="-2" y="',Strings.toString((comp_.orientation == LW00x0.Orientation.LANDSCAPE ? 700 : 1000)-28),'" fill="#000" class="box"></rect><text x="12" y="',lift_text_,'" class="txt">#', leading_zeroes_, comp_.id,unicode' · ', '00x0</text><text x="123" y="',lift_text_,'" class="txt">',comp_.seed0,'</text>'); } function getJSON(uint comp_id_) public view returns(string memory){ LW00x0.Comp memory comp_ = _00x0.getComp(comp_id_); bytes memory meta_ = abi.encodePacked( '{', '"name": "00x0 comp #',Strings.toString(comp_id_),'", ', '"description": "latent.works", ', '"image": "',comp_.image,'", ' '"attributes": [', '{"trait_type": "orientation", "value":"',comp_.orientation == LW00x0.Orientation.LANDSCAPE ? 'Landscape' : 'Portrait','"},', '{"trait_type": "base", "value":',Strings.toString(_00x0.getWorks(comp_id_).length),'}', ']', '}'); return string(abi.encodePacked('data:application/json;base64,', Base64.encode(meta_))); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/ERC1155.sol) pragma solidity ^0.8.0; import "./IERC1155.sol"; import "./IERC1155Receiver.sol"; import "./extensions/IERC1155MetadataURI.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of the basic standard multi-token. * See https://eips.ethereum.org/EIPS/eip-1155 * Originally based on code by Enjin: https://github.com/enjin/erc-1155 * * _Available since v3.1._ */ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { using Address for address; // Mapping from token ID to account balances mapping(uint256 => mapping(address => uint256)) private _balances; // Mapping from account to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json string private _uri; /** * @dev See {_setURI}. */ constructor(string memory uri_) { _setURI(uri_); } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC1155).interfaceId || interfaceId == type(IERC1155MetadataURI).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC1155MetadataURI-uri}. * * This implementation returns the same URI for *all* token types. It relies * on the token type ID substitution mechanism * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. * * Clients calling this function must replace the `\{id\}` substring with the * actual token type ID. */ function uri(uint256) public view virtual override returns (string memory) { return _uri; } /** * @dev See {IERC1155-balanceOf}. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { require(account != address(0), "ERC1155: balance query for the zero address"); return _balances[id][account]; } /** * @dev See {IERC1155-balanceOfBatch}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] memory accounts, uint256[] memory ids) public view virtual override returns (uint256[] memory) { require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); uint256[] memory batchBalances = new uint256[](accounts.length); for (uint256 i = 0; i < accounts.length; ++i) { batchBalances[i] = balanceOf(accounts[i], ids[i]); } return batchBalances; } /** * @dev See {IERC1155-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC1155-isApprovedForAll}. */ function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { return _operatorApprovals[account][operator]; } /** * @dev See {IERC1155-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes memory data ) public virtual override { require( from == _msgSender() || isApprovedForAll(from, _msgSender()), "ERC1155: caller is not owner nor approved" ); _safeTransferFrom(from, to, id, amount, data); } /** * @dev See {IERC1155-safeBatchTransferFrom}. */ function safeBatchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) public virtual override { require( from == _msgSender() || isApprovedForAll(from, _msgSender()), "ERC1155: transfer caller is not owner nor approved" ); _safeBatchTransferFrom(from, to, ids, amounts, data); } /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function _safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { require(to != address(0), "ERC1155: transfer to the zero address"); address operator = _msgSender(); uint256[] memory ids = _asSingletonArray(id); uint256[] memory amounts = _asSingletonArray(amount); _beforeTokenTransfer(operator, from, to, ids, amounts, data); uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); unchecked { _balances[id][from] = fromBalance - amount; } _balances[id][to] += amount; emit TransferSingle(operator, from, to, id, amount); _afterTokenTransfer(operator, from, to, ids, amounts, data); _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); } /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function _safeBatchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); require(to != address(0), "ERC1155: transfer to the zero address"); address operator = _msgSender(); _beforeTokenTransfer(operator, from, to, ids, amounts, data); for (uint256 i = 0; i < ids.length; ++i) { uint256 id = ids[i]; uint256 amount = amounts[i]; uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); unchecked { _balances[id][from] = fromBalance - amount; } _balances[id][to] += amount; } emit TransferBatch(operator, from, to, ids, amounts); _afterTokenTransfer(operator, from, to, ids, amounts, data); _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); } /** * @dev Sets a new URI for all token types, by relying on the token type ID * substitution mechanism * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. * * By this mechanism, any occurrence of the `\{id\}` substring in either the * URI or any of the amounts in the JSON file at said URI will be replaced by * clients with the token type ID. * * For example, the `https://token-cdn-domain/\{id\}.json` URI would be * interpreted by clients as * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` * for token type ID 0x4cce0. * * See {uri}. * * Because these URIs cannot be meaningfully represented by the {URI} event, * this function emits no events. */ function _setURI(string memory newuri) internal virtual { _uri = newuri; } /** * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function _mint( address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { require(to != address(0), "ERC1155: mint to the zero address"); address operator = _msgSender(); uint256[] memory ids = _asSingletonArray(id); uint256[] memory amounts = _asSingletonArray(amount); _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); _balances[id][to] += amount; emit TransferSingle(operator, address(0), to, id, amount); _afterTokenTransfer(operator, address(0), to, ids, amounts, data); _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); } /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function _mintBatch( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { require(to != address(0), "ERC1155: mint to the zero address"); require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); address operator = _msgSender(); _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); for (uint256 i = 0; i < ids.length; i++) { _balances[ids[i]][to] += amounts[i]; } emit TransferBatch(operator, address(0), to, ids, amounts); _afterTokenTransfer(operator, address(0), to, ids, amounts, data); _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); } /** * @dev Destroys `amount` tokens of token type `id` from `from` * * Requirements: * * - `from` cannot be the zero address. * - `from` must have at least `amount` tokens of token type `id`. */ function _burn( address from, uint256 id, uint256 amount ) internal virtual { require(from != address(0), "ERC1155: burn from the zero address"); address operator = _msgSender(); uint256[] memory ids = _asSingletonArray(id); uint256[] memory amounts = _asSingletonArray(amount); _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); unchecked { _balances[id][from] = fromBalance - amount; } emit TransferSingle(operator, from, address(0), id, amount); _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); } /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. * * Requirements: * * - `ids` and `amounts` must have the same length. */ function _burnBatch( address from, uint256[] memory ids, uint256[] memory amounts ) internal virtual { require(from != address(0), "ERC1155: burn from the zero address"); require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); address operator = _msgSender(); _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); for (uint256 i = 0; i < ids.length; i++) { uint256 id = ids[i]; uint256 amount = amounts[i]; uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); unchecked { _balances[id][from] = fromBalance - amount; } } emit TransferBatch(operator, from, address(0), ids, amounts); _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits a {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC1155: setting approval status for self"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Hook that is called before any token transfer. This includes minting * and burning, as well as batched variants. * * The same hook is called on both single and batched variants. For single * transfers, the length of the `id` and `amount` arrays will be 1. * * Calling conditions (for each `id` and `amount` pair): * * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens * of token type `id` will be transferred to `to`. * - When `from` is zero, `amount` tokens of token type `id` will be minted * for `to`. * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` * will be burned. * - `from` and `to` are never both zero. * - `ids` and `amounts` have the same, non-zero length. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /** * @dev Hook that is called after any token transfer. This includes minting * and burning, as well as batched variants. * * The same hook is called on both single and batched variants. For single * transfers, the length of the `id` and `amount` arrays will be 1. * * Calling conditions (for each `id` and `amount` pair): * * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens * of token type `id` will be transferred to `to`. * - When `from` is zero, `amount` tokens of token type `id` will be minted * for `to`. * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` * will be burned. * - `from` and `to` are never both zero. * - `ids` and `amounts` have the same, non-zero length. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} function _doSafeTransferAcceptanceCheck( address operator, address from, address to, uint256 id, uint256 amount, bytes memory data ) private { if (to.isContract()) { try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { if (response != IERC1155Receiver.onERC1155Received.selector) { revert("ERC1155: ERC1155Receiver rejected tokens"); } } catch Error(string memory reason) { revert(reason); } catch { revert("ERC1155: transfer to non ERC1155Receiver implementer"); } } } function _doSafeBatchTransferAcceptanceCheck( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) private { if (to.isContract()) { try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( bytes4 response ) { if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { revert("ERC1155: ERC1155Receiver rejected tokens"); } } catch Error(string memory reason) { revert(reason); } catch { revert("ERC1155: transfer to non ERC1155Receiver implementer"); } } } function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { uint256[] memory array = new uint256[](1); array[0] = element; return array; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/extensions/ERC1155Supply.sol) pragma solidity ^0.8.0; import "../ERC1155.sol"; /** * @dev Extension of ERC1155 that adds tracking of total supply per id. * * Useful for scenarios where Fungible and Non-fungible tokens have to be * clearly identified. Note: While a totalSupply of 1 might mean the * corresponding is an NFT, there is no guarantees that no other token with the * same id are not going to be minted. */ abstract contract ERC1155Supply is ERC1155 { mapping(uint256 => uint256) private _totalSupply; /** * @dev Total amount of tokens in with a given id. */ function totalSupply(uint256 id) public view virtual returns (uint256) { return _totalSupply[id]; } /** * @dev Indicates whether any token exist with a given id, or not. */ function exists(uint256 id) public view virtual returns (bool) { return ERC1155Supply.totalSupply(id) > 0; } /** * @dev See {ERC1155-_beforeTokenTransfer}. */ function _beforeTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual override { super._beforeTokenTransfer(operator, from, to, ids, amounts, data); if (from == address(0)) { for (uint256 i = 0; i < ids.length; ++i) { _totalSupply[ids[i]] += amounts[i]; } } if (to == address(0)) { for (uint256 i = 0; i < ids.length; ++i) { uint256 id = ids[i]; uint256 amount = amounts[i]; uint256 supply = _totalSupply[id]; require(supply >= amount, "ERC1155: burn amount exceeds totalSupply"); unchecked { _totalSupply[id] = supply - amount; } } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol) pragma solidity ^0.8.0; import "./ERC1155Receiver.sol"; /** * Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens. * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. * * @dev _Available since v3.1._ */ contract ERC1155Holder is ERC1155Receiver { function onERC1155Received( address, address, uint256, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (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 Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { 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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library Counters { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
//SPDX-License-Identifier: Unlicense pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import './LTNT.sol'; import 'base64-sol/base64.sol'; import './lib/Rando.sol'; /** ___ ___ ___ __ __ __ | /\ | |__ |\ | | | | / \ |__) |__/ /__` |___ /~~\ | |___ | \| | .|/\| \__/ | \ | \ .__/ "77x7", troels_a, 2021 */ contract LW77x7 is ERC1155, ERC1155Supply, Ownable { using Counters for Counters.Counter; // Constants string public constant NAME = "Latent Works \xc2\xb7 77x7"; string public constant DESCRIPTION = "latent.works"; uint public constant MAX_WORKS = 77; uint public constant MAX_EDITIONS = 7; // Works Counters.Counter private _id_tracker; uint private _released = 0; uint private _editions = 0; uint private _minted = 0; uint private _curr_edition = 0; uint private _price = 0.07 ether; mapping(uint => string) private _seeds; mapping(uint => mapping(uint => address)) private _minters; mapping(uint => mapping(uint => uint)) private _timestamps; struct Work { uint token_id; string name; string description; string image; string[7] iterations; string[7] colors; } // Canvas mapping(uint256 => string[]) private _palettes; constructor() ERC1155("") { _palettes[1] = ["#82968c","#6a706e","#ffd447","#ff5714","#170312","#0cf574","#f9b4ed"]; _palettes[2] = ["#f59ca9","#775253","#01fdf6","#cff27e","#294d4a","#0cf574","#0e103d"]; _palettes[3] = ['rgba(90, 232, 89, 0.706)', 'rgba(255, 98, 98, 0.706)', 'rgba(79, 42, 109, 0.706)', 'rgba(0, 255, 208, 0.769)', 'pink', '#888', 'black']; } // State function getAvailable() public view returns (uint){ return (_released - _minted); } function getMinted() public view returns (uint){ return _minted; } function getEditions() public view returns(uint){ return _editions; } function getCurrentEdition() public view returns(uint){ return _curr_edition; } // Minting function releaseEdition(address[] memory to) public onlyOwner { require(_editions < MAX_EDITIONS, 'MAX_EDITIONS_RELEASED'); _released = _released+MAX_WORKS; _editions++; for(uint256 i = 0; i < to.length; i++){ _mintTo(to[i]); } } function mint() public payable returns (uint) { require(msg.value >= _price, "VALUE_TOO_LOW"); require((getAvailable() > 0), "NOT_AVAILABLE"); return _mintTo(msg.sender); } function _mintTo(address to) private returns(uint){ _id_tracker.increment(); uint256 token_id = _id_tracker.current(); if(token_id == 1) _curr_edition++; uint edition = getCurrentEdition(); if(edition == 1){ _seeds[token_id] = string(abi.encodePacked(Strings.toString(token_id), block.timestamp, block.difficulty)); } _mint(to, token_id, 1, ""); _minted++; _minters[token_id][edition] = to; _timestamps[token_id][edition] = block.timestamp; if(token_id == MAX_WORKS){ _id_tracker.reset(); } return token_id; } // Media and metadata function _getIterationSeed(uint token_id, uint iteration) private view returns(string memory){ return string(abi.encodePacked(_seeds[token_id], Strings.toString(iteration))); } function _getPaletteIndex(uint token_id) private view returns(uint) { return Rando.number(string(abi.encodePacked(_seeds[token_id], 'P')), 1, 3); } function getPalette(uint token_id) public view returns(string[] memory){ uint index = _getPaletteIndex(token_id); return _palettes[index]; } function getColor(uint token_id, uint iteration) public view returns(string memory){ string[] memory palette = getPalette(token_id); return palette[Rando.number(string(abi.encodePacked(_getIterationSeed(token_id, iteration), 'C')), 1, 7)]; } function getMinter(uint token_id, uint edition) public view returns(address){ return _minters[token_id][edition]; } function getWork(uint token_id) public view returns(Work memory){ string[7] memory iterations; string[7] memory colors; uint supply = totalSupply(token_id); uint i = 0; while(i < supply){ iterations[i] = getSVG(token_id, i+1, true); i++; } i = 0; while(i < supply){ colors[i] = getColor(token_id, i); i++; } return Work( token_id, string(abi.encodePacked("Latent Work #", Strings.toString(token_id))), DESCRIPTION, getSVG(token_id, supply, true), iterations, colors ); } function _getElement(uint token_id, uint iteration, string memory filter) private view returns(string memory){ string memory svgSeed = _getIterationSeed(token_id, iteration); string memory C = getColor(token_id, iteration); uint X = Rando.number(string(abi.encodePacked(svgSeed, 'X')), 10, 90); uint Y = Rando.number(string(abi.encodePacked(svgSeed, 'Y')), 10, 90); uint R = Rando.number(string(abi.encodePacked(svgSeed, 'R')), 5, 70); return string(abi.encodePacked('<circle cx="',Strings.toString(X),'%" cy="',Strings.toString(Y),'%" r="',Strings.toString(R),'%" filter="url(#',filter,')" fill="',C,'"></circle>')); } function _getWatermark(uint token_id, uint iteration) private view returns (string memory) { return string(abi.encodePacked('<style>.txt{font: normal 12px monospace;fill: white;}</style><rect width="90" height="30" x="0" y="747" fill="#000" class="box"></rect><text x="12" y="766" class="txt">#',(token_id < 10 ? string(abi.encodePacked('0', Strings.toString(token_id))) : Strings.toString(token_id)),' \xc2\xb7 ',Strings.toString(iteration),'/',Strings.toString(MAX_EDITIONS),'</text><text x="103" y="766" class="txt">',Strings.toString(_timestamps[token_id][iteration]),'</text>')); } function getSVG(uint256 token_id, uint iteration, bool mark) public view returns (string memory){ require(iteration <= totalSupply(token_id), 'EDITION_NOT_MINTED'); string[4] memory parts; string memory elements = string(abi.encodePacked(_getElement(token_id, 70, "f1"), _getElement(token_id, 700, "f1"))); uint i; while(i < iteration){ elements = string(abi.encodePacked(elements, _getElement(token_id, i, "f0"))); i++; } uint size = 777; string memory view_box_size = Strings.toString(size); string memory blur = Strings.toString(size/(iteration+1)); parts[0] = string(abi.encodePacked('<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMinYMin meet" viewBox="0 0 ',view_box_size,' ',view_box_size,'"><defs><rect id="bg" width="100%" height="100%" fill="#fff" /><clipPath id="clip"><use xlink:href="#bg"/></clipPath><filter id="f0" width="300%" height="300%" x="-100%" y="-100%"><feGaussianBlur in="SourceGraphic" stdDeviation="',blur,'"/></filter><filter id="f1" width="300%" height="300%" x="-100%" y="-100%"><feGaussianBlur in="SourceGraphic" stdDeviation="700"/></filter></defs><rect width="100%" height="100%" fill="#fff" />')); parts[1] = string(abi.encodePacked('<g clip-path="url(#clip)"><use xlink:href="#bg"/>', elements, '</g>')); parts[2] = mark ? _getWatermark(token_id, iteration) : ''; parts[3] = '</svg>'; string memory output = string(abi.encodePacked('data:image/svg+xml;base64,', Base64.encode(bytes(string(abi.encodePacked(parts[0], parts[1], parts[2], parts[3])))))); return output; } function uri(uint256 token_id) virtual public view override returns (string memory) { require(exists(token_id), 'INVALID_ID'); Work memory work = getWork(token_id); string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "', work.name, '", "description": "', work.description, '", "image": "', work.image, '"}')))); return string(abi.encodePacked('data:application/json;base64,', json)); } // Balance function withdrawAll() public payable onlyOwner { require(payable(msg.sender).send(address(this).balance)); } // Required overrides function _beforeTokenTransfer(address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual override(ERC1155, ERC1155Supply){ super._beforeTokenTransfer(operator, from, to, ids, amounts, data); } function _mint(address account, uint256 id, uint256 amount, bytes memory data) internal override (ERC1155) { super._mint(account, id, amount, data); } function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal override (ERC1155) { super._mintBatch(to, ids, amounts, data); } function _burn(address account, uint256 id, uint256 amount) internal override (ERC1155) { super._burn(account, id, amount); } function _burnBatch(address to, uint256[] memory ids, uint256[] memory amounts) internal override (ERC1155) { super._burnBatch(to, ids, amounts); } } contract LW77x7_LTNTIssuer is LTNTIssuer, Ownable { LW77x7 public immutable _77x7; LTNT public immutable _ltnt; address private _caller; mapping(uint => uint) private _iterations; constructor(address seven7x7_, address ltnt_) { _77x7 = LW77x7(seven7x7_); _ltnt = LTNT(ltnt_); } function issuerInfo(uint id_, LTNT.Param memory param_) public override view returns(LTNT.IssuerInfo memory){ return LTNT.IssuerInfo( '77x7', _77x7.getSVG(param_._uint, _iterations[id_], true) ); } function issueTo(address to_, LTNT.Param memory param_, bool stamp_) public returns(uint) { require(msg.sender == _caller, 'ONLY_CALLER'); uint id_ = _ltnt.issueTo(to_, param_, stamp_); _iterations[id_] = 7; return id_; } function setCaller(address caller_) public onlyOwner { _caller = caller_; } function setIteration(uint id_, uint iteration_) public { require(msg.sender == _ltnt.ownerOf(id_), 'NOT_OWNER'); require(iteration_ > 0 && iteration_ < 8, 'ITERATION_OUT_OF_RANGE'); _iterations[id_] = iteration_; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./LTNTFont.sol"; import "base64-sol/base64.sol"; ////////////////////////////////// // // // LTNT // Passport NFTs for Latent Works // // ////////////////////////////////// /// @title LTNT /// @author troels_a contract LTNT is ERC721, Ownable { struct Param { uint _uint; address _address; string _string; bool _bool; } struct IssuerInfo { string name; string image; } struct Issuer { address location; Param param; } event Issued(uint indexed id, address indexed to); event Stamped(uint indexed id, address indexed stamper); LTNT_Meta private _ltnt_meta; address[] private _issuers; ///@dev array of addresses registered as issuers mapping(uint => mapping(address => bool)) private _stamps; ///@dev (ltnt => (issuer => is stamped?)) mapping(uint => mapping(address => Param)) private _params; ///@dev (ltnt => (issuer => stamp parameters)); mapping(uint => Issuer) private _issuer_for_id; ///@dev (ltnt => issuer) - the Issuer for a given LTNT uint private _ids; ///@dev LTNT _id counter /// @dev pass address of onchain fonts to the constructor constructor(address regular_, address italic_) ERC721("Latents", "LTNT"){ LTNT_Meta ltnt_meta_ = new LTNT_Meta(address(this), regular_, italic_); _ltnt_meta = LTNT_Meta(address(ltnt_meta_)); } /// @notice Require a given address to be a registered issuer /// @param caller_ the address to check for issuer privilegies function _reqOnlyIssuer(address caller_) private view { require(isIssuer(caller_), 'ONLY_ISSUER'); } /// @notice Issue a token to the address /// @param to_ the address to issue the LTNT to /// @param param_ a Param struct of parameters associated with the token /// @param stamp_ boolean determining wether the newly issued LTNT should be stamped by the issuer /// @return uint the id of the newly issued LTNT function issueTo(address to_, Param memory param_, bool stamp_) public returns(uint){ _reqOnlyIssuer(msg.sender); _ids++; _safeMint(to_, _ids); _issuer_for_id[_ids] = Issuer(msg.sender, param_); emit Issued(_ids, to_); if(stamp_) _stamp(_ids, msg.sender, param_); return _ids; } /// @dev Lets a registered issuer stamp a given LTNT /// @param id_ the ID of the LTNT to stamp /// @param param_ a Param struct with any associated params function stamp(uint id_, Param memory param_) public { _reqOnlyIssuer(msg.sender); _stamp(id_, msg.sender, param_); } /// @dev internal stamping mechanism /// @param id_ the id of the LTNT to stamp /// @param issuer_ the address of the issuer stamping the LTNT /// @param param_ a Param struct with stamp parameters function _stamp(uint id_, address issuer_, Param memory param_) private { _stamps[id_][issuer_] = true; _params[id_][issuer_] = param_; emit Stamped(_ids, issuer_); } /// @dev checks if a given id_ is stamped by address_ /// @param id_ the ID of the LTNT to check /// @param address_ the address of the stamper /// @return bool indicating wether LTNT is stamped function hasStamp(uint id_, address address_) public view returns(bool){ return _stamps[id_][address_]; } /// @dev get params for a given stamp on a LTNT /// @param id_ the id of the LTNT /// @param address_ the address of the stamper /// @return Param the param to return function getStampParams(uint id_, address address_) public view returns(Param memory){ return _params[id_][address_]; } /// @dev Get the addresses of the issuers that have stamped a given LTNT /// @param id_ the ID of the LTNT to fetch stamps for /// @return addresses an array of issuer addresses that have stamped the LTNT function getStamps(uint id_) public view returns(address[] memory){ // First count the stamps uint count; for(uint i = 0; i < _issuers.length; i++){ if(_stamps[id_][_issuers[i]]) ++count; } // Init a stamps_ array with the right length from count_ address[] memory stamps_ = new address[](count); // Loop over the issuers and save stampers in stamps_ count = 0; for(uint i = 0; i < _issuers.length; i++){ if(_stamps[id_][_issuers[i]]){ stamps_[count] = _issuers[i]; ++count; } } return stamps_; } /// @dev list all issuer addresses /// @return addresses list of all issuers function getIssuers() public view returns(address[] memory){ return _issuers; } /// @dev get the issuer of a LTNT function getIssuerFor(uint id_) public view returns(LTNT.Issuer memory){ return _issuer_for_id[id_]; } /// @dev set the meta contract /// @param address_ the address of the meta contract function setMetaContract(address address_) public onlyOwner { _ltnt_meta = LTNT_Meta(address_); } /// @dev get the meta contract /// @return LTNT_Meta the meta contract currently in use function getMetaContract() public view returns(LTNT_Meta) { return _ltnt_meta; } /// @notice register an issuer address /// @param address_ the address of the issuer to add function addIssuer(address address_) public onlyOwner { _issuers.push(address_); } /// @notice determine if an address is a LW project /// @param address_ the address of the issuer /// @return bool indicating wether the address is an issuer or not function isIssuer(address address_) public view returns(bool){ for(uint i = 0; i < _issuers.length; i++) { if(_issuers[i] == address_) return true; } return false; } /// @notice the ERC721 tokenURI for a given LTNT /// @param id_ the id of the LTNT /// @return json_ base64 encoded data URI containing the JSON metadata function tokenURI(uint id_) public view override returns(string memory json_){ return _ltnt_meta.getJSON(id_, true); } } /// @title A title that should describe the contract/interface /// @author troels_a /// @dev Handles meta for this contract contract LTNT_Meta { LTNT public immutable _ltnt; ///@dev latent fonts XanhMonoRegularLatin public immutable _xanh_regular; XanhMonoItalicLatin public immutable _xanh_italic; constructor(address ltnt_, address regular_, address italic_){ _ltnt = LTNT(ltnt_); _xanh_regular = XanhMonoRegularLatin(regular_); _xanh_italic = XanhMonoItalicLatin(italic_); } /// @notice return image string for id_ /// @param id_ the id of the LTNT to retrieve the image for /// @param encode_ encode output as base64 uri /// @return string the image string function getImage(uint id_, bool encode_) public view returns(string memory){ LTNT.Issuer memory issuer_for_id_ = _ltnt.getIssuerFor(id_); LTNT.IssuerInfo memory issuer_info_ = LTNTIssuer(issuer_for_id_.location).issuerInfo(id_, issuer_for_id_.param); LTNT.IssuerInfo memory stamper_; LTNT.Param memory stamp_param_; address[] memory issuers_ = _ltnt.getIssuers(); bytes memory stamps_svg_; string memory delay_; uint stamp_count_; bool has_stamp_; for(uint i = 0; i < issuers_.length; i++) { delay_ = Strings.toString(i*150); stamp_param_ = _ltnt.getStampParams(id_,issuers_[i]); stamper_ = LTNTIssuer(issuers_[i]).issuerInfo(id_, stamp_param_); has_stamp_ = _ltnt.hasStamp(id_, issuers_[i]); stamps_svg_ = abi.encodePacked(stamps_svg_, '<text class="txt italic" fill-opacity="0" y="',Strings.toString(25*i),'">',stamper_.name,' <animate attributeName="fill-opacity" values="0;',has_stamp_ ? '1' : '0.4','" dur="500ms" repeatCount="1" begin="',delay_,'ms" fill="freeze"/></text>'); if(has_stamp_) ++stamp_count_; } bytes memory image_; image_ = abi.encodePacked( '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 1000" preserveAspectRatio="xMinYMin meet">', '<defs><style>', _xanh_regular.fontFace(), _xanh_italic.fontFace(),' .txt {font-family: "Xanh Mono"; font-size:20px; font-weight: normal; letter-spacing: 0.01em; fill: white;} .italic {font-style: italic;} .large {font-size: 55px;} .small {font-size: 12px;}</style><rect ry="30" rx="30" id="bg" height="1000" width="600" fill="black"/></defs>', '<use href="#bg"/>', '<g transform="translate(65, 980) rotate(-90)">', '<text class="txt large italic">Latent Works</text>', '</g>', '<g transform="translate(537, 21) rotate(90)">', '<text class="txt large italic">LTNT #',Strings.toString(id_),'</text>', '</g>', '<g transform="translate(517, 22) rotate(90)">', '<text class="txt small">Issued by ',issuer_info_.name,unicode' · ', Strings.toString(stamp_count_) , stamp_count_ > 1 ? ' stamps' : ' stamp', '</text>', '</g>' '<g transform="translate(25, 25)">', '<image width="300" href="', issuer_info_.image, '"/>', '</g>', '<g transform="translate(343, 41)">', stamps_svg_, '</g>', '<g transform="translate(509, 980)">', '<text class="txt small">latent.works</text>', '</g>', '</svg>' ); if(encode_) image_ = abi.encodePacked('data:image/svg+xml;base64,', Base64.encode(image_)); return string(image_); } /// @notice return base64 encoded JSON metadata for id_ /// @param id_ the id of the LTNT to retrieve the image for /// @param encode_ encode output as base64 uri /// @return string the image string function getJSON(uint id_, bool encode_) public view returns(string memory) { LTNT.Issuer memory issuer_for_id_ = _ltnt.getIssuerFor(id_); LTNT.IssuerInfo memory issuer_info_ = LTNTIssuer(issuer_for_id_.location).issuerInfo(id_, issuer_for_id_.param); bytes memory json_ = abi.encodePacked( '{', '"name":"LTNT #',Strings.toString(id_),'", ', '"image": "', getImage(id_, true),'", ', '"description": "latent.works",', '"attributes": [', '{"trait_type": "Stamps", "value": ',Strings.toString(_ltnt.getStamps(id_).length),'},', '{"trait_type": "Issuer", "value": "', issuer_info_.name, '"}', ']', '}' ); if(encode_) json_ = abi.encodePacked('data:application/json;base64,', Base64.encode(json_)); return string(json_); } } /// @title LTNTIssuer /// @author troels_a /// @dev LTNTIssuers implement this contract and use issuerInfo to pass info to LTNT main contract abstract contract LTNTIssuer { function issuerInfo(uint id_, LTNT.Param memory param_) external virtual view returns(LTNT.IssuerInfo memory); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0; /// @title Base64 /// @author Brecht Devos - <[email protected]> /// @notice Provides functions for encoding/decoding base64 library Base64 { string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; bytes internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000" hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000" hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000" hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000"; function encode(bytes memory data) internal pure returns (string memory) { if (data.length == 0) return ''; // load the table into memory string memory table = TABLE_ENCODE; // multiply by 4/3 rounded up uint256 encodedLen = 4 * ((data.length + 2) / 3); // add some extra buffer at the end required for the writing string memory result = new string(encodedLen + 32); assembly { // set the actual output length mstore(result, encodedLen) // prepare the lookup table let tablePtr := add(table, 1) // input ptr let dataPtr := data let endPtr := add(dataPtr, mload(data)) // result ptr, jump over length let resultPtr := add(result, 32) // run over the input, 3 bytes at a time for {} lt(dataPtr, endPtr) {} { // read 3 bytes dataPtr := add(dataPtr, 3) let input := mload(dataPtr) // write 4 characters mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and( input, 0x3F)))) resultPtr := add(resultPtr, 1) } // padding with '=' switch mod(mload(data), 3) case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) } case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) } } return result; } function decode(string memory _data) internal pure returns (bytes memory) { bytes memory data = bytes(_data); if (data.length == 0) return new bytes(0); require(data.length % 4 == 0, "invalid base64 decoder input"); // load the table into memory bytes memory table = TABLE_DECODE; // every 4 characters represent 3 bytes uint256 decodedLen = (data.length / 4) * 3; // add some extra buffer at the end required for the writing bytes memory result = new bytes(decodedLen + 32); assembly { // padding with '=' let lastBytes := mload(add(data, mload(data))) if eq(and(lastBytes, 0xFF), 0x3d) { decodedLen := sub(decodedLen, 1) if eq(and(lastBytes, 0xFFFF), 0x3d3d) { decodedLen := sub(decodedLen, 1) } } // set the actual output length mstore(result, decodedLen) // prepare the lookup table let tablePtr := add(table, 1) // input ptr let dataPtr := data let endPtr := add(dataPtr, mload(data)) // result ptr, jump over length let resultPtr := add(result, 32) // run over the input, 4 characters at a time for {} lt(dataPtr, endPtr) {} { // read 4 characters dataPtr := add(dataPtr, 4) let input := mload(dataPtr) // write 3 bytes let output := add( add( shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)), shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))), add( shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)), and(mload(add(tablePtr, and( input , 0xFF))), 0xFF) ) ) mstore(resultPtr, shl(232, output)) resultPtr := add(resultPtr, 3) } } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; library Rando { function number(string memory seed, uint min, uint max) internal pure returns (uint) { if (max <= min) return min; return (uint256(keccak256(abi.encodePacked(seed))) % (max - min)) + min; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; contract XanhMonoRegularLatin { function fontFace() public pure returns(string memory){ return "@font-face { font-family: 'Xanh Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,d09GMgABAAAAACl0AA4AAAAAVSAAACkaAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoEwGx4cgiwGYACEXhEICoGFOOxnC4QKAAE2AiQDiAIEIAWENAeHeBvORTMDwcYBIIPbRhJFqSDlwf8hgRtDsTeofNFh3GDcYFzEDpYkELUNde47dWQor2Tb6E/7dLxmGXWD8M3s+hS51DEaGklM6On347d77vvqVT0kQS1E0wrxN4ZMJSU80cnm003u8PzcetuIjcg1i783Vsk6iN7IUamEpDY2YB1eJVbjYeVhn9dmXSnqHaeeWPDw/2PM+z6atFmCVIkuiSjeSXjzEDndt7azql5XVV4DgHcahe/rdttN8k8DzjBLaiaQRFp9q0FgDbpp+9J34t/O7d+35/D3ryA1A68HTaBTRENYynNonUMBDvJ791+bVdUdea8q3MTiMmJ++tKhkcg4h8uuN1fY9ZiMCTLiAiQBFQD+f5v2tu96/P6X7DXoE/ojJ71mvV1IRRkoulRX7z1Z8+bpSRyPNfaCvAQa28k3LI3We46lAFAFAGPgzxBAbtOFizJVmbbPtklR1lTF36xensKk3Sf4RcSKhCHtfriky+bv/dcd4JLktVUhYzrml8twuu3cvMoQbQkQZP1HIjRod2gvFAxAP1ZDAQQJChZKuPOYFgMPhYgIhYwGhYEJhUUARUINRUsLRc8Bxc0DJUUGlBwFUIoUQylRA6XRJChN2qB06IDSZRqUrbZC2WknlGHDUE45BQUF0ImGBtW5L90PsIIAqBUA1wU23dBDuXOVnS0gKjRs6FQaAsIC6ebVL5nRVJj+bmevtzYD+R9LiGNra3UT+D2ubjug+hRKAFCFdHDeWKzVlpilgXYh4sS5xey8lnxBCIDhXGEwUC4tTbxuGzSU93zKroBG44zWyGdWg1M3pLsh+dSK3vdKeHhnASMnMtNCnx0JhvLmCIqvDqj7g+ymEMBhObszKMMFCNBh99g7wBzAYew3OH8uwDGR7SOYczUR0HRxA+AOAGnLAwDjMO6Kkxo+IkMkqByS676vdZAYkWT05pgwbujLqVzLjXE8QkUYCES4iAFxIZ3IVhaEcZAwMQH0QMgZDAZp7gXxCBmhrU2ffjr+N6paWYD/+nfcd5w7OwB4c1B/H1ad8o7o9vlb526dBCiAVYBDfgXAfXZP002X8LV/ZshP9rrkT3/72QEH7XHdVsdssc8229112x3f+gtKmHCRYhAQkZDRX0KARNhEn3spGTkFDS0dPaMj9jvqdye8BSYubl4pMmXJlqPwJQWBXWXqNDREpFm76tyue8g/4LD7fv2/7gVXXHTVv+CRN2DUdN974LjHgeape9Za5x34w0O7AsMaM5y3yUabDQuBFgQrWCicCHix4sSjoaBKEAXiScQhwHUTn5pSEhUDsclszCwcrOycPDKkSpOugI9fnmSlqpSrUKPSLdXatGg1Rbd6UwnVOuuck0474xQUVE7QB4CVAEgtgFfAUAcAY2cANO8B5RwABDp3/C3ARkmuZVC2squti0jSVCWs0GnPATrIFX+5iPQkHB4TA9U55OTKjcK3SV3z5nNrdM9yalv+UY+efdXJsXmXHKEhCoen+GuTExM7MVl/WAzqT9fBbiYgiB/JX25GJ/E91DSSab/sm4I0UsCgvj31wfGpo+vYF8UMa5IlNSYaSwfbJaZvqAv0kMEjTUBKHEKyxiQFsAOYxUGnxbIDG37A5FLJ/hGkxPFjdSpjrNqA/5L0J0O8S6XWRkx+49jV5HjpY1HNKAwAU/uNte4zpkpVl0tJ6o5WeJ4ZCBEeluXVu1iKMcvwvtrm+BvGDJa/UDyS1S/V9RGljWg7grDhV4hXR7tMakjJSlfFkOt0DCHHOcpQdioSm+IWc6+Tal0eNedQGXXHIORfZ+VtWKcZqpCRQpafz5AuwcEPmuFsNBBAB6frSlJVJrIiK1dHpojpRFfY64uygX0CAUnyicBgOOWTmywg2UYT0gfmdvERTYFmjqhWP5SlKTDrzYWnnmQwvQUnZsfUEunj9Dsms6YeVO3uYa5YUItik3GcJuEtlPkbRYGCGUMWnwtKlGEBEwQtynB+0rP4ZYWLDmOkbFIQ/eeOsAD2Kf8KHI3L64tQLBYHY8N8VYLWZ1GPqwoH4qWEUVvlqp+tHKF36BbxdPV4wuhUzkM896j6ad/gMZJt8C0OGRoRizVRrZx2FJdzYXtHSO/dmxvJCfN2EcIhQUjSR1NgIYHj1ZHM2L4KHOYiPThuGsXgdO8QHmrkzXkdY9GQ4wI8NpOrP+M5Jtkpggb8IIVKQvmFgLQLEgt4LmzIYSYHesA+c1gXPB8TP8p5CcicuOzo5NWPnEKVNORAOf4q+ZZFAF3Umds5R+pFEHKLq43hpspgpnGjGKgy1aCL+XoqRONPOjK8u99WHAVIV4TCFpfs8AJ+1lbYKIs0MNfwUEol1HFdcPSda7LTx4WVOjZXIvRf5MGSENCb56YFFsFwGhF9LRPSHR3l4Ge9UY87sExdAcUZkJGpHH383Kb9bF3SXuDmxH0zaAcumzkhf0LOkw/fQF33MIPXfcgFaUK6Y3N6cRm9JrAVGEIxAjIi7XQo6rVs8DR8D44c/mkJdC45EOuKH5xskJ3AZfJUAR0qateYDwC2GYtwgnyoZQIVJIWrB1DKzjIGsSqFh1tvatPweoh7DgOi5F0rBhiTZINAfYmsCN0s12sQX6NEbwgSITGhEL9HGqDdVVoYj5eJkRbqOb2YRhPdVaMc7rfhinfJKwyAIS5U4f5Uwfdt+CqWPep9n++SVvJ+UV90ylw/re6RJeBveqSf6sNqsagdY+ddqxoBD+ovguXafAaR4DWTFCDjrwno9LhHJv5MjlLvHiwFlxFu2QHCKDLEuU6j1lbl2wR3gqkQQHbuBzwNOXbNz6QioeWMfwg3QYM+os4vVkJegz3NaoL2rbmr/Xf0tWzKgn/irf2M01bdWU9fyQnD++s7J+vJF4H7lnlvJl0jzbJftAjjtLS7EQD3wwaBIexk/Iwnrbpy7UY3UjFMMxSY4f8sc2+DodC1h6txj/uUD5lETI7zBlNpoboaYFoJEpBZqpfJCOzyPpU+PfMXY2d87R0Rq8v9WPz4NIsKb5COSc9T06eN6uPH+YL7tL+MENyCWFfJtd684dX0MY4+gh3vVjO4oKrQ48yeJ4XEMBKSW1zM0RyGQWUzHxpswFkt+e6fFdjYqlUDGZy2yHrpuPKSQAPN2b6Sr9NH8mTzwU6dck5T37fttZ0s1zrKSJa8nzl6FkIn5/MgQEAAjyC7hupUXEoufMbS4U7hw5r0ER0m0a5ywzhJjlCTExFWeV31cbVgylRXzx/79Hm4zMjuMONfP4q3hpMA0rTt4kJagOmEYz98aVXny8MrDx6zuUuFa/lbrhcolzrG+V53+8mSw3viX3vnEUptL/jdsVF4xg9XsphVsAqP7Nj7l4BhiE1ulQf+VrviFausQGfEH72D4GiUawq+rkCO8wvwtEX1B+JN8dXbvz/HF7DjP7oHV5qBsMRTW92PfPZusSq2jmGXsqHFWCfQ/N18b8NzzjWP2Vp/qrPcGQcijvpP0QwZVJJYxeUGX7aReWQ8Ydv5xWUfW/tkCwmxp61tXMzDJdRxNkUXQ5bFso7V29h8wYJJbNp68yIIS1E0HqLp9oxuppswjb9Fudl9Mt1QvQYxdQd1kfP7vznbGbWIcDt9YxGSgvMrK0Y+p0/qHF6brdZl8JXFuBmWCFZlmIapHZQQu7g239jeAwKh7SJwQSUKWLa8E5d+/PhyyDtCSwOaJuFxLh66Oj7vWJt0CGNJhr+EjGsWRHZMgUqUz0ruZ8vGqdod1f+aFtWVSyL8C+wv2ZIf3QGLZQdE3ilFVagEfAsFNWxFGnXzURk8DzFxBpau7x49iHOEZCWbao9ZkalKVAPF1nP+PK6sL2mqdX3dEV4JeKW/IxmqAmR7xXxoQzDewYK9aa/S0qdYeLQUbrlPEV8YRrk2W98jQKLTIlvaE3PIn/mHwZ/4x8Fc0lT6OIOlbCz2yHyTdZ79vZxNlnz3YBvGJsvKLepn84f8OvSDBQ9AcrZ+J6KWdulYd4XSKlHEcL9SHiPlkFS2vCDfPBe3mTtPSjtS5UBVfPxWKwm5gsBGFwxuQEMxcdeGFWqPkNqrlU+CHWZL4isD3/ROMbRuu6npfPDcuY5oYYzb3l9g0J1a3em6VJe838iT7hBxyLNsVxf+6nojmcCzklbkmtFe9uNy85FIqTHnzbIFKDi1frTCeNj2r9wIY0653ryBoiYbjNdFncyVGmFNnYauKXU6Z1U8QHOdvWjT+HdxBFypjmEED+I/C56hEOZMz3dc3ilZ+yq4W6vNs29tpqx5sme1yK+6WFATLQY/QIKZw16pVfGQdHd7yACS17hcRL8P3LZA7cPHwZYD/j0ND+GwZ2CQntHMmUj594jaSW76ciTvqg+HnrhUCG19c/cCQhxUnZrRlsy0qYtTSO9la2Z0i23pSmiErla7+lraMynfSadO0wwufCAUH0n3hPbBJr5WMZ3oqtNUa9KXOGC9X22rM9ERWcdzOEerUAkEVZxaGrkZUXkCMvR3PYytgi8IJqZ6HOqYCAuqR3rG1JqtFV/Z1dM1bl5H81IYTeOBrhwRhXgQH5rb+8c5FAU5QODcyIt6C5DKYHVEe9a+8AUEg2Y3xpIiS5X+KA6Hr7wS790kNhl+UlwGDWrZ/jfHx/7SmjP3k+l0RSZgn2j4etZuWCXhXQmT1AxjljMzkNObvR/2b0rvHbuXFK95Fb6ccIJYVUAl51SwHOFKXIF4Jq0OVkjNaiUeuC6tGL2nocrGnSalLqqflKfWPPDaKaqM7cDYZrYiS83QXFqAsA0FKWgRRy5VIM7mdE/gvjMyppIrbJONiPcdQabSWHR8/4RiGdcs4iGLM0O9Uh1P9LLdz5Agz+InCYRjNS0CECdSAo5Z6U3TMaD4ssxfIc5LKeHKsicAfC0W4vvk1dx9+z8LpDuLH0r/ZKKLu3d1AzYuz7jt9h+pw4UNjsJa/eg63agHuqpTVB+BUKg+9k0AlXKJFjYpySfm0cw9DITRY64cGHKowmfTHtKg5mmt44kJTp5ekloKaNA/6IePA+WBQgXT/qs/dNcWQZapdvLkusKvAjU1ZTU1gbUBi9VmrrZMWALgLS4p3apsovR6vZReZVO6NYlf8daNDSBvVKQMWFDDMFgC+an55oCRUQMLMkiqN0gA63pXAbjyAg5bAxZjI32B2+2xxNZS1hPstWxxskCUbTAYRVkVtv5t5WQgGbJr3jizvd13P0zMVrQDpoDgLy7RIidhvakLafN6EDNfz7yKFSnY5KjZtIcL6Tp3BW25Y/4KyytXQ/ASJ0nWq+ppfVnJlN6k5gyrmmOLtOrkTkR7n1RCAjkvtEJkXQ9vfciehkt73Q/CoWPQAU9BDxfTp0Y7yy6WTQAquHZwLVzx/uDB3ONRAB1or8x3pqjY+EYivu0U99MH2Rn5MVthMQQoFuTM3S6+U2SC+6F/1csz673wDszaVGMqDa2AplhPOPONdaNR0DRoglUDrS64DdoGbfAA1IxOj2SqNdqaCBbh3vn4frhnxWDdP0lx51d9HoxvY63xgUSj+bVnQxcAi+RXqTnrhJtLaD0JYwq8/e9RtGCGewrqTivugPWBikFh2mt+0tL59NwH1+Rei2wSaZHHTZwna/Ca5f+Ci7TISUnDbB5IEBPmUBBKNkRcIWQPq0y8K/8xo9fGRBZZSDZtlRZvYzSCOAhV5zbZNHV6nV+pyZ7LBqvhKo/B6fE4a+60YfFbMuDCVjbFk7cuhAt2T9YXX9C0hGXali8KcBIyHv9CFJrJyCQ+tbL4G1S2VQsu9acw+48QBS0w0a+kfFnrK2byg4lY6QjmX4yNe03hPwSf4oRnpPu0S8zyPB98rNsx5Y+0Qi3XJ3Dm5DkjbSG2fTdVQ2HSF3GkC4RtjCHi06yoQaPTo3RqnR6T0wgicKJBKZOBXYTwVLzYlKdXkvjyA2opP8PuSXbZPfxsmUzgcCUKZZ/8l4utRV6qEA2jYL5A8LuAz0+2u5Ld9lS+X6mSpmUIQCqydJUxFeuNnES7E3c1/2rcnWi4rcZVSxHwGpflK8qj2+DPMJVh07k0Gj+/jWGEn0IjPS+3CNzLMxuX2JfZYX+NPJ9u0Fdx3AS3Q4X7jbU//kN7KiP3jQjOgcqO41z7naw7IAZ6ZycvyPfCi9BTE+Kk9vyz7u2ULW/1whswo4XRzDBB4IYDxG/6s+ALWL2idH6pA26EzvcXUwYgMOOtW7foTTrl1BY9+EMO9uK0Fodccs7Ji6qVViouy0TT19RPjo9tJhFXkEh1972IQv031cZ2CenxZRYCuzg9gdErbFPri/t5L/jUxTsy95ZJJ32+AczEKbYrxb2r+lNpHwWLjp5KoH+xnOGxn8zg2L0SpWjVR5S3DLWprJBOPzWLIPyLg8SplpkpCCVPU2Jivf4zJ1Kx4fqc+pyYjyKg+BKTJUpb+gmLyv7KlrCLtyVR1Auqh+rItRH7yHRMO5GKKJ0O2JXhFyzOyjQkmkd9YXmLCTKty/XYPMyF31Vyx9K+AhE4Y7FLOSPbp55XkWoTe+HnHLYMH7M2Hv8r48tUriejsaTGys+1C7iJ1nd+T8kKlxCcwKlcdqTNmy9YmpNrZo8e2yd90wEv2ZPfTB6mkkTdCL9rI46lfSUU/C8ceIhTF+qT2nwpok6f26S0SaHTisVla+bt+EDKms59k8xNydtQIlg7i8eqYrjdq1sLeTNsqVmwXe9O9XzhTU43aBzp3i88zlQQizNXuDQzczXkGlVOpkyTVTG5MjI4WOu3inK9Aj43K8rvKfnaLVRHCweZfsKZcNdfDIvVDnazrrUT23AUYJKUlqi9+jQBJ16Lp40U7XyQnZ0veYg8vHYYdkPw1+GS+jQDOzrCH4SnQ+Zf009X9xFtLAFMS1EY2Ps/YVZ9QnZCPkxPVhgRq+Ty+CuD8GzxsR6cLago1a7UplbzZDvVEqdSqJQ41e93WbzcVWRScz4ZmFIesnqtkKPyGUEU9K/w4f2nYNrweqhYZlzmh59uzPbQ+hfbFxhRfBbAw8OnVpCXrx4cdBiCki7SBOnrHYvIInNRQbl1kypNDgEk9hLIX1TG2mQ/pNwCQmG1lPtw6dhdNdwDiz/cdlrghT9By/rx2G/PZkGQgOYVcP7TQoTiUxr8kRnxXkz3U5jAjsMsvg2ZZN4uBWz/jcuK67sQ01cjbWckxk47MQJE0XyhJ2Q9uxxLbsO8qlAaGMcpU6TybFK1Sk2qKrGVUo47VWrViJ2rmVZrQ2lNaZa2DhwMGnFHyZdpzYYrZ0n8NO/IjtArtCbDo5gZF7bH8eaHGozlvTBHwCNnf9sZDT7CCb6E1eHdDouP+UsBt4Yq3MWPryW1JWrBiJBanYWIsqqWVYnKPFN8j9kzv33KEqeCkpgbAUIPw6kL7dV5KUact5aey+/NyjJyIn4+thauKQG9+Ixvb6Z145Lvu6W/mUNrcLT7HWcOw7V//pdw7zSVy4H8HubwerNzzGzJI39YHmtfNYy+kWIjq1mwHE47JfE7bwiTSXQVBMzcHCReS6D0zB5NzOXlPr0xgYtT2iQshxm7CHmoigiTXB5R8CWPOYn+fQ7eoWKBLsVrleZud2ADyHdCDHX/SDRHyqQi2Us/30dKhPxWRyL4FCfPqMUaaANyojJaIDzESwwyrNcHJ7KfXrjwNFHwXKZwp+Wn7Kd14i6VEUtxFBO/NF/tNjs566kQF8UMY0OUbr0ZJ7BlpwA+LqW4uCi3HWkXTyJNDkaCM9zaVK04hejiUxlUWqRDaOOAGRzyGLrMUY6pjqCz5I+dbeaO25bnpi//PKl+NAjc2zSeAV/AmiWDznaje/DGcbA5b1wPN8MkQynt5MMWmDjQqYRtOHEnmRaf3gcY0Nv517QnXvgr9AR2Fe+qHadNujAfTa6eXnum5swdSz6sOIXgt1OIdUclec4CP6t67f0smWfOnztn7syDf6KV5TkmYMab/txYP8hU2dmiB3+IwA+XOZuZjAuCRx9xkS6Emtr89LvwqPiomGcx+G8XibhbRKQhWmz4A8pvSWdp+H30efdteZTXJKosoyFxtAWMXxa9R0vLp6W9Jxq4lU3cMq1UV8rlNOuk2pb+Ys/iAfLiJIIltqyBAe+w5vIaa/M1+aZaj8c0MDvAwOtFexIKQ4NsibUI8G9/J44sVsupKb0fPypIjfoBccud3nQjL3vCvaj2KxJxfxxxi1wiLvDpTZosqShLqZFn2/W7ihxrXNAp+YDHZo/NaqdS5FZiOaOCqEXnsFmHr2+5SaL4pnxdvSA+2g3+xemzlcICtcpNw/cTKNdfXdB40jz2tGR3r1LuMfCeXnFiGNuilr4Th6TSLmU4L/0dt64pQZghkpdn5WibSrXgEzhvOBzyR7mPZ8FZw/Pg9hcPF4ExnMGnFOVr2HelpbldycewlUlat51/o2H+iLgXfTUuA0ESBt+/zM2t62rJUrWU6MArHC8FMaWzF1bn0z82thfbzfacNBd3hB5Xhyf2Pmzj/CMz5hYIv2mWYK3QaZcqTbk20SSLTdpc6Jivd6Z6OryOdI0hOd3b4XGngiFZHXtAW2tOmWkRNB1gQ9OurVSyzUKyM64z5EG2K5DW//yigEj5I8Uzn8Z4slitoHsn1CmyKvp79TLwFucscomajHqOv/tzLKnrAE8r9aaxxWK/hNSj4R+s5WE/7+b49cbV8YUu589NjdrGptfLT95msztti3sGgsA4Tvw+PbOYlrn6dbKraYStmd4/wP1c5pd9zuVsfvv3CfTT6v7OI6w8fgb+FIWSBGhgGy7WG09an019b+9uJYXlolOSJ4+I4yLGYuMDJIEtSSKt4TAtN//a/u+8qPpf4olwLIYwOZQWz4zSNCUQdjbMw0f+j7+HEKNwh8H/OMk3InpfDIMedlK12mcUkimQbmXiX3cd7+vwx5vjhVE1+5gzGkAsOlL8pUrzEuyluTRLaZ9cZ9xIpiVrUmkPmqesB//j+OfYfQX4H1FcDg35GwaNH6jEDy+5gBUPRLQ3+mmCiCh7nL0EvMQl2TPzfO46E37WV1Ty9NhzMnL/GBGxImVWajjGUcfhvY62xdiNG6hjCBu5T0nA8H0cA9cJaoq3p/0WRDT/xsSvWxgdWxqDx9fjCWjS3fgdNX1JPG49eg9rIzb0M2z4fxSq//47gldHAG9x3Kc2Cj89JOjEahrHwBcIObTVJ4JC0vkU223urxJlrEIiUcQqxQepP9GF9J+olNs0321wH4ef9TWF3B+j5xpazMnKOq4WG1RUfPGeouq9HWRo79PtXxWcq9mZsSmWIkigviMRIxBGyENw4b4Hr6VF7m4SXhH8v3c0p+9ZQ/ndgNETFBpFx8x+cp3pkrm8KakOfpL5m2TIFTzv1h28zMhg5maS3X9FW6YspRURvvXoVKc3dTdpXxzpizyyNFjX1dcxE7OeSbB/6lXiN3ispaxsx9vXMTH929KX80EQSLaET2FMZQ0sYiwzh0FWs385rYzuXtVCxlJLOGQy23ELZrfHzAbSrfELhtm+F6wauU2S6T87eiTbGxslOxxzfqYNmeYIdlyjBNtNPUPg2+kx0iPYbu3oe4Zod+xzJCu4tdHecwe0qsz7pRxSoZs5EbaVELgJXEJJOytxYjqOdL9ZQ5ZLl7CREFDCS6wTh4rrEnk1pNEIe4lUTga9c9Yet2xGaIYso5HRxmrvaIOrgUPTUei2TdQFlgVUcGD679/6pjY0CrRCiIVAte8v8tfwmSqQ775+KsI6X3xxDC5Y6P4tv+hVgb+P41ke+f0CbwO+EzlpwmnedMkMX/o0PyNX7On6P+0YzOO5Hy0zUhBKRn6FKyh3uS5PV9XwZ4m+JhuoRl0+/04vl2JvKCxyFQeO2mw7ivvgLypCZybv9Pv8fn92BxsuqGjDuL02pVWJstud/In0kwye4pKKCI3fxfXQb97KeT/V502T+lW2rMx0TBmjVJ4b+dGGuBaX9vV9WJueoywzuH0FuSHljNKi6dKkrHzM8M/XY3SGon5REB9wcLp0laKQ0mpQMhSo+Hi0gqFMo7QqCjKStGx7/PiWGAw5A89PspcUVu5j7EvD17Gq0F6SxCeQ0zExW8bt8UDaDHtWXe0lMf9GioiEFMTB8OrkxOJH85Du68RCmU2Ung4V+jQBN+6I8J34scWepSSXv92HbLuK9wlTjYW+2qpEybVwCpfOJWFth1OAGw4Q+pA+dEI30tBNy4T/wopFhhkGC1wDHU20aqQ1HD0XmUsYgGDaiuiRYTZ5wd2Plq+AK/Dul8Ply8H4kfh69zdqkWXIyU0zY0BtHuRCTk9WBQb9NZdixJkd9TO+QGD0YdVOxs5qWD3EGKr69QPGAgZQpxGxZ+NY0kis+Wg3njR+JXZsCeD3w9RvkQHwxdvUp3x2InJX8vcv4B9WOeUs/BcEfN0RSWVMW0hC9+kDkqneWRFYct9XZ+7T2M5yzzXubnfFaUl4TMwvpe9HtLwqZyfoR7Wboq+yC6UZ37DpldGRmLLMur2FYOXfnOAljiXBnJ9/ZD1EtlQpg0QilCml7LCB47nU4wUfLl0KvMO5J9mMswMn+mcPNDb6//n2P4BoLrNLFZS1upcmOUgvSVIxSg9KaFNXZ2HsBoOQQRf+OaO5JxBo7plxfnrHnCKUwEa+OGj71pBCM5xh+PykKWSfj8G4bpljvgGauvgcZ8WQL+E+T3wMMgS+nUa/QdLotrEKBGs6OCkKS1qqxeJyJvGKtKaBXeE0UdQaS/jacM9axWZVJiVxAa1en384X/ntepM31aj0qpJ/1bVNVgNh9eLcJrumTqfX1DXZcpdDMZfB5XABevN/K197gcTttWZbvU5Jpkyrc3yPYwq9QgHX4eRJZBv+y8W2IhEqRqVzslnwgMuROLyWbJvXI8mWq9XOw7h/+F7Bny2fBqr/81/YfK5rNFlP/wOyuXynw5xmAuM4S8BqbqL3er2MJbYaWcYDr2uyjeoa6myHgzqLnWyDhsAAs2D2d44xqY/bwkwLC4QFkLQyLq2xhoX1kvZwSXa+l59w8xwvbFoY79zNBD4/2Ubi7iF5sUhtIxhPdJXYJXU6naQmYHO7AzZJrZC6FVwkU7aeF1AqecVZevMYKfox4AeyDDMd8cRYBTGaFNsQH10TjfkbE10ltpATQhIwGDRXKA2R4iLipHHKyGudH5AShhMilVoS0O+Oro0k0DOKIsuwwytGQssiisxMfGRttCA6h5AToTL8b/xfH7GKsOrC+Ok7p7pGSrp27pdo8DZBMVsknqVQzBKLZkey05hIKpudijDTwO2tw3C48CzugT2sJASBZSXEQwTCISLhPLWe36gIMy8Exm7BA0Go0znswQ2DESeuJM7tO5y2TXzrRCQ34nMJLvqgAuuRx3FaBqnUwTmcODnOwwJqL/cYZP/E5f7EhseKqUMk0hD1120E/DLClf7oyH2ESCz9PU884eyn0VEbq6FQxhcYtM5mYpng+AXxYELEH3EkFE2D/Iaj74hPOMIJUy5YyM9gTR/xNhBjgzcCNFftksS+54APzlzG/g8SY19MPI8dm9gT+2ziWezLiRMnjk+8hPCqEPDaCdCcjwbV5pj6mDJzjDmmnhw3k81kM7meNVY9O83MNrPNbDPbrDArzAqzol5PYLJC0EsBWseLP2LA2IaOZ7/HgJe7W8b/Ntwtr4uNlI7nxhjwAtsxdrYLPAsFoCU3lFzA/wAtMjIMxHjxqGNsa4z/3rY8e2iUtIy/NMo6nvNjvHjeMbYnxrNnAtHN0c3RzdHNqa7YFCfNOPYL0Gde3MmDJ08+WITCWGz0Gn1Gv7HEWGosM5bDCrsmI+dzSRfTXtpH++kSupQuo8uNFZMZZiVmbWgCYM7iHPRTyp7dx6a539yHfPn/QOi/HbwJ6UgIWwD1tPAUsmZrtY70lj/752hxYh57QOj/YyBa32H9W9mRlALHJuxz7BFIv2dTTt9Rgeyv5C//TTPuhq3j+pwqmNx+MspMp/JNlhDtZPxjEHTkJLCD64dx1/kfrpIu/X2MAp7YCWb93GcP/HxbddAt17PZkJXtX4/2uMVDJ96N3/kDLB5+Loznxgv98iXBkHqFLwQAm7vTbspsJt49U3nwX2UEbNSJ/z8AzP4FIjYAfR/X2rb4vRyTa9vznPT7bms/ihS5OU/gAr7MA5iAd/0Jonsy/TaoMndA92T6sYOTL7ylSwnJ0xCge/w2J6DANUF0T5I89Q+An3xN8lJeEn3ynB2n67pS5P5wMctjJIg+yRynsQmAr/IAPE5+nJf0CT2e5HB9Iz/QdnW+8KieYPrER5wwJsZMSPrkMHvv9eoIBogwTGuvP0y3O0f/y3PHuqn00XnN+lkpm3Q5BbAEH0ALLJSTpPo6FvHzITTAXFmH5bvjvHOKkP64ZFdB6NOhWa6EbIKcYsMU+ABaYKGcROrrWETIh9AAc2Udjma8UH24MZh8wOmAVDeP5RhBv4IazBIuJ/MLtYl6WJwRau2QE1mVfBk/RYEfedlO000Bw4egsA/robw1DMDjnM69cUPh+EmeEByNVlxTyRMHvHPjgfjOyXlQc2e67YtWhzDJi02J50wpfVi7ThSX+CTBkCym8+6XZPu3ryzluukLypQyx2n5ikCK5NaXoABK8/MZG88tjzZ9w0aXLwB4fnolOQ21PLIlnCZ9hZPt+gVWJbN+dYX+JzHDz9Y/Rw4lPxcTfZhQoFFFNHddmKCA8O5UwNcoP6A0B+sqASqN0xIJyUB/NhSE63PyKETYmvpHGPO6ymUMw1vtAohA0J0Z7JITgzeQ8OzxEHPWL7wqgjk/voSpIYhiIQ+CoQ6idXxWTehHVUDNXIcYGbrJ9BKQHFMbbIgEvRZYoNbMGPTLPsBKmAIfwEL4Gj78O5vrr+0lGaWJh70cA4zooxJOglkfJ+rSIzmglySADCbBNzCs51bpg6BToAAUugDQpBtAj1IlnQkDcDEagAsQSAcmEZUm/nkYtL8SukEFdVNNBPMhT34ZhXJgQzxgQA0yCAIR8OAj+w5OBwCcgUP0BAxBL9yHjTBFBiDPuOAE2nKldUcDiQEKsJL5QnQKhiZWbDnf7boIMNAA7epgoCo7ANwLvHYRSlygL0KL8uwiDI0jFwWBvrwomEf+RSEQGhm17QBc1NlddooOBjKUO6q1azRkZ5PSHjXZJGWrKet9y2fxSFeoUosGGVrJ20oiVy1kV0RWbjJfVe0ZzDcWkURKQd5LI7NiWeeXXVK1rjGjV3a2CF93n5Su35BEUJZB2loQf35fpix+7dyMQ/rVI5Up5yKymj4PVT8pB6Fk3vch/AbU1iSEzA72tZrkUtXXyn5Q3OzWmXDUnLpbr9G5fJcqUtVaNZOZrpZkk7pjKonOJqe0iESdt0uLGu1tQGbaILR5UABt9/TVuygB9DdtJYBpZwPNaVW2qbbdAA6uGjx/Bwa+Wmec8z0BIRGx837wo5/W1e9+HaWf/aLeb1baYUiSx1TUi+z354KLGlyiZ2Bk8oiZS6PJmq6hZbVBbh6tvB5KNmVOA21SlsQXv6xTt6kRRJeM5fcv3TS5pptplhlWmW0nnyf88uTrV6DQHHPN07Mkv/ioA0p95Wvx8Ev4YoH9n11aBNtqm+122GmX3fbYa5/9xhpnvHgJEiVJliLVBGnSZcgUkSWUbaIcuRzyDDwHL0CsaHQMWwRZA1ptRK9IIeJYhYtQpoKFTUzw+NYwhxNO2mW3PfbaZLMjjgoWBhPzCljosNBYZJGPQ0SUp/4B+yBYmD5QaS17iMFiw+mz2FJLLLNAub9ColSZchUqTVKlWg0rOC13xU1XXXOr2n66vba7NsR1pr21shPXuNrUWt3kz00L7breqJTr5JIqqJImURVVUw3VUl1ej/vtVuxjNjZjW6/Xnih23jBU2Kei8GbjPi4loZQudftP6rg0jX84jLjkv/WKX5ZaLt2xqGIf3MHATzBwCPBrDn7BwcHATwjwawEODn7BjrVFLnfoJVUm5gJappfsLtopRztPBX2bGKcBpUIdE3Ryklz3wlrcX+eor/0fF7twlWe6OlvCo5VENe/Bjuu81FTjbFbllVoAAA==) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }"; } } contract XanhMonoItalicLatin { function fontFace() public pure returns(string memory){ return "@font-face { font-family: 'Xanh Mono'; font-style: italic; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }"; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev _Available since v3.1._ */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol) pragma solidity ^0.8.0; import "../IERC1155.sol"; /** * @dev Interface of the optional ERC1155MetadataExtension interface, as defined * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. * * _Available since v3.1._ */ interface IERC1155MetadataURI is IERC1155 { /** * @dev Returns the URI for token type `id`. * * If the `\{id\}` substring is present in the URI, it must be replaced by * clients with the actual token type ID. */ function uri(uint256 id) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// 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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol) pragma solidity ^0.8.0; import "../IERC1155Receiver.sol"; import "../../../utils/introspection/ERC165.sol"; /** * @dev _Available since v3.1._ */ abstract contract ERC1155Receiver is ERC165, IERC1155Receiver { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol) pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler * now has built in overflow checking. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a % b; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "./extensions/IERC721Metadata.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/Strings.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: owner query for nonexistent token"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not owner nor approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransfer(from, to, tokenId, _data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `_data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory _data ) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _owners[tokenId] != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ERC721.ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory _data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); _balances[to] += 1; _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); // Clear approvals _approve(address(0), tokenId); _balances[owner] -= 1; delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _balances[from] -= 1; _balances[to] += 1; _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId); } /** * @dev Approve `to` to operate on `tokenId` * * Emits a {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits a {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
{ "optimizer": { "enabled": false, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"seven7x7_","type":"address"},{"internalType":"address","name":"seven7x7_ltnt_issuer_","type":"address"},{"internalType":"address","name":"ltnt_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"comp_id","type":"uint256"},{"indexed":true,"internalType":"address","name":"creator","type":"address"}],"name":"CompCreated","type":"event"},{"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":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"DESCRIPTION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_00x0_meta","outputs":[{"internalType":"contract LW00x0_Meta","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_77x7","outputs":[{"internalType":"contract LW77x7","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_77x7_ltnt_issuer","outputs":[{"internalType":"contract LW77x7_LTNTIssuer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_ltnt","outputs":[{"internalType":"contract LTNT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"comp_id_","type":"uint256"}],"name":"getAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"comp_id_","type":"uint256"}],"name":"getComp","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"string","name":"seed","type":"string"},{"internalType":"string","name":"image","type":"string"},{"internalType":"enum LW00x0.Orientation","name":"orientation","type":"uint8"},{"internalType":"uint256","name":"editions","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"internalType":"struct LW00x0.Comp","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCompCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit_","type":"uint256"},{"internalType":"uint256","name":"page_","type":"uint256"},{"internalType":"bool","name":"ascending_","type":"bool"}],"name":"getComps","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"string","name":"seed","type":"string"},{"internalType":"string","name":"image","type":"string"},{"internalType":"enum LW00x0.Orientation","name":"orientation","type":"uint8"},{"internalType":"uint256","name":"editions","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"internalType":"struct LW00x0.Comp[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"comp_id_","type":"uint256"}],"name":"getCreator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"comp_id_","type":"uint256"}],"name":"getEditions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"comp_id_","type":"uint256"},{"internalType":"bool","name":"mark_","type":"bool"},{"internalType":"bool","name":"encode_","type":"bool"}],"name":"getImage","outputs":[{"internalType":"string","name":"output_","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"comp_id_","type":"uint256"}],"name":"getWorks","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"components":[{"internalType":"uint256","name":"_uint","type":"uint256"},{"internalType":"address","name":"_address","type":"address"},{"internalType":"string","name":"_string","type":"string"},{"internalType":"bool","name":"_bool","type":"bool"}],"internalType":"struct LTNT.Param","name":"param_","type":"tuple"}],"name":"issuerInfo","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"image","type":"string"}],"internalType":"struct LTNT.IssuerInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"comp_id_","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint256[]","name":"ids_","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","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":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"comp_id_","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101006040523480156200001257600080fd5b506040516200c32b3803806200c32b833981810160405281019062000038919062000366565b604051806020016040528060008152506200005981620001a760201b60201c565b506200007a6200006e620001c360201b60201c565b620001cb60201b60201c565b60016005819055508273ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff1660601b815250508173ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff1660601b815250508073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1660601b8152505060003084604051620001399062000291565b62000146929190620003cd565b604051809103906000f08015801562000163573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1660e08173ffffffffffffffffffffffffffffffffffffffff1660601b8152505050505050620004ad565b8060029080519060200190620001bf9291906200029f565b5050565b600033905090565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6164f28062005e3983390190565b828054620002ad906200042e565b90600052602060002090601f016020900481019282620002d157600085556200031d565b82601f10620002ec57805160ff19168380011785556200031d565b828001600101855582156200031d579182015b828111156200031c578251825591602001919060010190620002ff565b5b5090506200032c919062000330565b5090565b5b808211156200034b57600081600090555060010162000331565b5090565b600081519050620003608162000493565b92915050565b6000806000606084860312156200037c57600080fd5b60006200038c868287016200034f565b93505060206200039f868287016200034f565b9250506040620003b2868287016200034f565b9150509250925092565b620003c781620003fa565b82525050565b6000604082019050620003e46000830185620003bc565b620003f36020830184620003bc565b9392505050565b600062000407826200040e565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600060028204905060018216806200044757607f821691505b602082108114156200045e576200045d62000464565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6200049e81620003fa565b8114620004aa57600080fd5b50565b60805160601c60a05160601c60c05160601c60e05160601c615907620005326000396000818161095101528181610a2a01528181610f5801528181611ad90152611b9d015260008181610a06015281816117760152611cef01526000818161109b01526125d701526000818161092b0152818161159c01526118b001526159076000f3fe6080604052600436106101e25760003560e01c80638da5cb5b11610102578063bd85b03911610095578063f1ae885611610064578063f1ae885614610794578063f23a6e61146107bf578063f242432a146107fc578063f2fde38b14610825576101e2565b8063bd85b039146106a0578063d48e638a146106dd578063e985e9c51461071a578063ec420c1114610757576101e2565b8063a0712d68116100d1578063a0712d68146105f3578063a22cb4651461060f578063a3f4df7e14610638578063bc197c8114610663576101e2565b80638da5cb5b1461051157806394056d171461053c578063967f2222146105795780639f093552146105b6576101e2565b8063385571251161017a578063535776f211610149578063535776f214610467578063715018a6146104a45780637c9c151d146104bb5780638d859f3e146104e6576101e2565b806338557125146103735780633e6e0859146103b05780634e1273f4146103ed5780634f558e791461042a576101e2565b8063204f0056116101b6578063204f0056146102c957806323e42156146102f45780632eb2c2d61461031f57806338151ec414610348576101e2565b8062fdd58e146101e757806301ffc9a71461022457806309e61a73146102615780630e89341c1461028c575b600080fd5b3480156101f357600080fd5b5061020e60048036038101906102099190613b20565b61084e565b60405161021b9190614b54565b60405180910390f35b34801561023057600080fd5b5061024b60048036038101906102469190613bc8565b610917565b604051610258919061474c565b60405180910390f35b34801561026d57600080fd5b50610276610929565b6040516102839190614782565b60405180910390f35b34801561029857600080fd5b506102b360048036038101906102ae9190613c84565b61094d565b6040516102c091906147ee565b60405180910390f35b3480156102d557600080fd5b506102de610a04565b6040516102eb91906147d3565b60405180910390f35b34801561030057600080fd5b50610309610a28565b604051610316919061479d565b60405180910390f35b34801561032b57600080fd5b5061034660048036038101906103419190613996565b610a4c565b005b34801561035457600080fd5b5061035d610aed565b60405161036a9190614b54565b60405180910390f35b34801561037f57600080fd5b5061039a60048036038101906103959190613d79565b610af7565b6040516103a791906146d1565b60405180910390f35b3480156103bc57600080fd5b506103d760048036038101906103d29190613c84565b610d24565b6040516103e49190614b54565b60405180910390f35b3480156103f957600080fd5b50610414600480360381019061040f9190613b5c565b610d44565b60405161042191906146f3565b60405180910390f35b34801561043657600080fd5b50610451600480360381019061044c9190613c84565b610ef5565b60405161045e919061474c565b60405180910390f35b34801561047357600080fd5b5061048e60048036038101906104899190613cd6565b610f09565b60405161049b91906147ee565b60405180910390f35b3480156104b057600080fd5b506104b9611011565b005b3480156104c757600080fd5b506104d0611099565b6040516104dd91906147b8565b60405180910390f35b3480156104f257600080fd5b506104fb6110bd565b6040516105089190614b54565b60405180910390f35b34801561051d57600080fd5b506105266110c8565b60405161053391906145b6565b60405180910390f35b34801561054857600080fd5b50610563600480360381019061055e9190613c84565b6110f2565b60405161057091906146f3565b60405180910390f35b34801561058557600080fd5b506105a0600480360381019061059b9190613d25565b61115d565b6040516105ad9190614b32565b60405180910390f35b3480156105c257600080fd5b506105dd60048036038101906105d89190613c84565b6111c6565b6040516105ea9190614b54565b60405180910390f35b61060d60048036038101906106089190613c84565b6111f9565b005b34801561061b57600080fd5b5061063660048036038101906106319190613ae4565b6116a2565b005b34801561064457600080fd5b5061064d6116b8565b60405161065a91906147ee565b60405180910390f35b34801561066f57600080fd5b5061068a60048036038101906106859190613996565b6116f1565b6040516106979190614767565b60405180910390f35b3480156106ac57600080fd5b506106c760048036038101906106c29190613c84565b6119ac565b6040516106d49190614b54565b60405180910390f35b3480156106e957600080fd5b5061070460048036038101906106ff9190613c84565b6119c9565b60405161071191906145b6565b60405180910390f35b34801561072657600080fd5b50610741600480360381019061073c919061395a565b611a06565b60405161074e919061474c565b60405180910390f35b34801561076357600080fd5b5061077e60048036038101906107799190613c84565b611a9a565b60405161078b9190614b10565b60405180910390f35b3480156107a057600080fd5b506107a9611ca2565b6040516107b691906147ee565b60405180910390f35b3480156107cb57600080fd5b506107e660048036038101906107e19190613a55565b611cdb565b6040516107f39190614767565b60405180910390f35b34801561080857600080fd5b50610823600480360381019061081e9190613a55565b611df9565b005b34801561083157600080fd5b5061084c60048036038101906108479190613931565b611e9a565b005b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156108bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108b690614850565b60405180910390fd5b60008083815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600061092282611f92565b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60607f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631301f0f5836040518263ffffffff1660e01b81526004016109a89190614b54565b60006040518083038186803b1580156109c057600080fd5b505afa1580156109d4573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906109fd9190613c43565b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b610a5461200c565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480610a9a5750610a9985610a9461200c565b611a06565b5b610ad9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ad090614930565b60405180910390fd5b610ae68585858585612014565b5050505050565b6000600654905090565b606060006006549050600185108015610b105750600184105b15610b1d57809450600193505b60008567ffffffffffffffff811115610b5f577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015610b9857816020015b610b8561349f565b815260200190600190039081610b7d5790505b50905060008415610c6057600060018714610bd657600188600189610bbd9190614eb3565b610bc79190614e59565b610bd19190614dd2565b610bd9565b60015b90505b838111158015610beb57508782105b15610c5a57610bf981611a9a565b838381518110610c32577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001018190525081610c47906150ad565b915080610c53906150ad565b9050610bdc565b50610d17565b600060018714610c9257600187610c779190614eb3565b88610c829190614e59565b84610c8d9190614eb3565b610c94565b835b90505b600081118015610ca657508782105b15610d1557610cb481611a9a565b838381518110610ced577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001018190525081610d02906150ad565b915080610d0e90615052565b9050610c97565b505b8193505050509392505050565b600060076000838152602001908152602001600020805490509050919050565b60608151835114610d8a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d8190614a30565b60405180910390fd5b6000835167ffffffffffffffff811115610dcd577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015610dfb5781602001602082028036833780820191505090505b50905060005b8451811015610eea57610e94858281518110610e46577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151858381518110610e87577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015161084e565b828281518110610ecd577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101818152505080610ee3906150ad565b9050610e01565b508091505092915050565b600080610f01836119ac565b119050919050565b60606000610f16856119ac565b11610f56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4d906149d0565b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663535776f28585856040518463ffffffff1660e01b8152600401610fb393929190614b6f565b60006040518083038186803b158015610fcb57600080fd5b505afa158015610fdf573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906110089190613c43565b90509392505050565b61101961200c565b73ffffffffffffffffffffffffffffffffffffffff166110376110c8565b73ffffffffffffffffffffffffffffffffffffffff161461108d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161108490614970565b60405180910390fd5b6110976000612382565b565b7f000000000000000000000000000000000000000000000000000000000000000081565b66f8b0a10e47000081565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60606007600083815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561115157602002820191906000526020600020905b81548152602001906001019080831161113d575b50505050509050919050565b61116561352a565b60405180604001604052806040518060400160405280600481526020017f303078300000000000000000000000000000000000000000000000000000000081525081526020016111bb8460000151600180610f09565b815250905092915050565b60006111d1826119ac565b60076000848152602001908152602001600020805490506111f29190614eb3565b9050919050565b6002600554141561123f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161123690614ad0565b60405180910390fd5b60026005819055506008600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156112e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e0906148f0565b60405180910390fd5b66f8b0a10e4700003414611332576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161132990614af0565b60405180910390fd5b600061133d826111c6565b1161137d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611374906148d0565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff166008600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561141f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611416906148b0565b60405180910390fd5b60006114296110c8565b9050600060023461143a9190614e28565b905060006008600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1682604051611495906145a1565b60006040518083038185875af1925050503d80600081146114d2576040519150601f19603f3d011682016040523d82523d6000602084013e6114d7565b606091505b5050905060008373ffffffffffffffffffffffffffffffffffffffff1683604051611501906145a1565b60006040518083038185875af1925050503d806000811461153e576040519150601f19603f3d011682016040523d82523d6000602084013e611543565b606091505b505090508180156115515750805b611590576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611587906149f0565b60405180910390fd5b61159a3386612448565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663faa059b33360405180608001604052808981526020013373ffffffffffffffffffffffffffffffffffffffff1681526020016040518060200160405280600081525081526020016000151581525060016040518463ffffffff1660e01b815260040161164093929190614693565b602060405180830381600087803b15801561165a57600080fd5b505af115801561166e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116929190613cad565b5050505050600160058190555050565b6116b46116ad61200c565b8383612468565b5050565b6040518060400160405280601481526020017f4c6174656e7420576f726b7320c2b7203030783000000000000000000000000081525081565b60006117036116fe61200c565b6125d5565b6001845111801561171657506007845111155b611755576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161174c90614a90565b60405180910390fd5b60006117618686612666565b9050600080600090505b8651811015611996577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663faa059b38960405180608001604052808b86815181106117f5577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015181526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020016040518060200160405280600081525081526020016001151581525060016040518463ffffffff1660e01b815260040161185a93929190614693565b602060405180830381600087803b15801561187457600080fd5b505af1158015611888573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ac9190613cad565b91507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a843ee08360405180608001604052808781526020018c73ffffffffffffffffffffffffffffffffffffffff168152602001604051806020016040528060008152508152602001600015158152506040518363ffffffff1660e01b8152600401611951929190614bd4565b600060405180830381600087803b15801561196b57600080fd5b505af115801561197f573d6000803e3d6000fd5b50505050808061198e906150ad565b91505061176b565b5063bc197c8160e01b9250505095945050505050565b600060036000838152602001908152602001600020549050919050565b60006008600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b611aa261349f565b6040518060e00160405280838152602001611abc846119c9565b73ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630fcec87e856040518263ffffffff1660e01b8152600401611b309190614ba6565b60006040518083038186803b158015611b4857600080fd5b505afa158015611b5c573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611b859190613c43565b8152602001611b9684600180610f09565b81526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166371692b7f856040518263ffffffff1660e01b8152600401611bf49190614b54565b60206040518083038186803b158015611c0c57600080fd5b505afa158015611c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c449190613c1a565b6001811115611c7c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8152602001611c8a84610d24565b8152602001611c98846111c6565b8152509050919050565b6040518060400160405280600c81526020017f6c6174656e742e776f726b73000000000000000000000000000000000000000081525081565b6000611ced611ce861200c565b6125d5565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663faa059b38660405180608001604052808881526020018973ffffffffffffffffffffffffffffffffffffffff1681526020016040518060200160405280600081525081526020016000151581525060016040518463ffffffff1660e01b8152600401611d9393929190614693565b602060405180830381600087803b158015611dad57600080fd5b505af1158015611dc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de59190613cad565b5063f23a6e6160e01b905095945050505050565b611e0161200c565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480611e475750611e4685611e4161200c565b611a06565b5b611e86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e7d90614890565b60405180910390fd5b611e9385858585856127ad565b5050505050565b611ea261200c565b73ffffffffffffffffffffffffffffffffffffffff16611ec06110c8565b73ffffffffffffffffffffffffffffffffffffffff1614611f16576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f0d90614970565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611f86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f7d90614870565b60405180910390fd5b611f8f81612382565b50565b60007f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612005575061200482612a49565b5b9050919050565b600033905090565b8151835114612058576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161204f90614a70565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156120c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120bf90614910565b60405180910390fd5b60006120d261200c565b90506120e2818787878787612b2b565b60005b84518110156122df576000858281518110612129577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101519050600085838151811061216e577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101519050600080600084815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561220f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161220690614950565b60405180910390fd5b81810360008085815260200190815260200160002060008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508160008085815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546122c49190614dd2565b92505081905550505050806122d8906150ad565b90506120e5565b508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051612356929190614715565b60405180910390a461236c818787878787612b41565b61237a818787878787612b49565b505050505050565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6124648282600160405180602001604052806000815250612d30565b5050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156124d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124ce90614a10565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516125c8919061474c565b60405180910390a3505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612663576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161265a906149b0565b60405180910390fd5b50565b60006001825111801561267b57506007825111155b6126ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126b190614a50565b60405180910390fd5b600660008154809291906126cd906150ad565b91905055508160076000600654815260200190815260200160002090805190602001906126fb929190613544565b508260086000600654815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff166006547f5e4c8fdadf6d741f750742bca018b78b7d181d8de6dbe8df3206a2f432dad9ea60405160405180910390a36127a283600654612448565b600654905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561281d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161281490614910565b60405180910390fd5b600061282761200c565b9050600061283485612d42565b9050600061284185612d42565b9050612851838989858589612b2b565b600080600088815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050858110156128e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128df90614950565b60405180910390fd5b85810360008089815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508560008089815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461299d9190614dd2565b925050819055508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628a8a604051612a1a929190614c04565b60405180910390a4612a30848a8a86868a612b41565b612a3e848a8a8a8a8a612e08565b505050505050505050565b60007fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612b1457507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80612b245750612b2382612fef565b5b9050919050565b612b39868686868686613059565b505050505050565b505050505050565b612b688473ffffffffffffffffffffffffffffffffffffffff166132c3565b15612d28578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b8152600401612bae9594939291906145d1565b602060405180830381600087803b158015612bc857600080fd5b505af1925050508015612bf957506040513d601f19601f82011682018060405250810190612bf69190613bf1565b60015b612c9f57612c056151b2565b806308c379a01415612c625750612c1a6157bb565b80612c255750612c64565b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c5991906147ee565b60405180910390fd5b505b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c9690614810565b60405180910390fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612d26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d1d90614830565b60405180910390fd5b505b505050505050565b612d3c848484846132e6565b50505050565b60606000600167ffffffffffffffff811115612d87577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015612db55781602001602082028036833780820191505090505b5090508281600081518110612df3577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101818152505080915050919050565b612e278473ffffffffffffffffffffffffffffffffffffffff166132c3565b15612fe7578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b8152600401612e6d959493929190614639565b602060405180830381600087803b158015612e8757600080fd5b505af1925050508015612eb857506040513d601f19601f82011682018060405250810190612eb59190613bf1565b60015b612f5e57612ec46151b2565b806308c379a01415612f215750612ed96157bb565b80612ee45750612f23565b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f1891906147ee565b60405180910390fd5b505b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f5590614810565b60405180910390fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612fe5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612fdc90614830565b60405180910390fd5b505b505050505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b613067868686868686613497565b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614156131655760005b8351811015613163578281815181106130e1577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015160036000868481518110613126577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101518152602001908152602001600020600082825461314b9190614dd2565b925050819055508061315c906150ad565b905061309f565b505b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156132bb5760005b83518110156132b95760008482815181106131e1577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015190506000848381518110613226577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015190506000600360008481526020019081526020016000205490508181101561328b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161328290614990565b60405180910390fd5b8181036003600085815260200190815260200160002081905550505050806132b2906150ad565b905061319d565b505b505050505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415613356576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161334d90614ab0565b60405180910390fd5b600061336061200c565b9050600061336d85612d42565b9050600061337a85612d42565b905061338b83600089858589612b2b565b8460008088815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546133ea9190614dd2565b925050819055508673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628989604051613468929190614c04565b60405180910390a461347f83600089858589612b41565b61348e83600089898989612e08565b50505050505050565b505050505050565b6040518060e0016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081526020016060815260200160006001811115613516577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b815260200160008152602001600081525090565b604051806040016040528060608152602001606081525090565b828054828255906000526020600020908101928215613580579160200282015b8281111561357f578251825591602001919060010190613564565b5b50905061358d9190613591565b5090565b5b808211156135aa576000816000905550600101613592565b5090565b60006135c16135bc84614c52565b614c2d565b905080838252602082019050828560208602820111156135e057600080fd5b60005b8581101561361057816135f68882613740565b8452602084019350602083019250506001810190506135e3565b5050509392505050565b600061362d61362884614c7e565b614c2d565b9050808382526020820190508285602086028201111561364c57600080fd5b60005b8581101561367c57816136628882613907565b84526020840193506020830192505060018101905061364f565b5050509392505050565b600061369961369484614caa565b614c2d565b9050828152602081018484840111156136b157600080fd5b6136bc848285615010565b509392505050565b60006136d76136d284614cdb565b614c2d565b9050828152602081018484840111156136ef57600080fd5b6136fa848285615010565b509392505050565b600061371561371084614cdb565b614c2d565b90508281526020810184848401111561372d57600080fd5b61373884828561501f565b509392505050565b60008135905061374f81615865565b92915050565b600082601f83011261376657600080fd5b81356137768482602086016135ae565b91505092915050565b600082601f83011261379057600080fd5b81356137a084826020860161361a565b91505092915050565b6000813590506137b88161587c565b92915050565b6000813590506137cd81615893565b92915050565b6000815190506137e281615893565b92915050565b600082601f8301126137f957600080fd5b8135613809848260208601613686565b91505092915050565b600081519050613821816158aa565b92915050565b600082601f83011261383857600080fd5b81356138488482602086016136c4565b91505092915050565b600082601f83011261386257600080fd5b8151613872848260208601613702565b91505092915050565b60006080828403121561388d57600080fd5b6138976080614c2d565b905060006138a784828501613907565b60008301525060206138bb84828501613740565b602083015250604082013567ffffffffffffffff8111156138db57600080fd5b6138e784828501613827565b60408301525060606138fb848285016137a9565b60608301525092915050565b600081359050613916816158ba565b92915050565b60008151905061392b816158ba565b92915050565b60006020828403121561394357600080fd5b600061395184828501613740565b91505092915050565b6000806040838503121561396d57600080fd5b600061397b85828601613740565b925050602061398c85828601613740565b9150509250929050565b600080600080600060a086880312156139ae57600080fd5b60006139bc88828901613740565b95505060206139cd88828901613740565b945050604086013567ffffffffffffffff8111156139ea57600080fd5b6139f68882890161377f565b935050606086013567ffffffffffffffff811115613a1357600080fd5b613a1f8882890161377f565b925050608086013567ffffffffffffffff811115613a3c57600080fd5b613a48888289016137e8565b9150509295509295909350565b600080600080600060a08688031215613a6d57600080fd5b6000613a7b88828901613740565b9550506020613a8c88828901613740565b9450506040613a9d88828901613907565b9350506060613aae88828901613907565b925050608086013567ffffffffffffffff811115613acb57600080fd5b613ad7888289016137e8565b9150509295509295909350565b60008060408385031215613af757600080fd5b6000613b0585828601613740565b9250506020613b16858286016137a9565b9150509250929050565b60008060408385031215613b3357600080fd5b6000613b4185828601613740565b9250506020613b5285828601613907565b9150509250929050565b60008060408385031215613b6f57600080fd5b600083013567ffffffffffffffff811115613b8957600080fd5b613b9585828601613755565b925050602083013567ffffffffffffffff811115613bb257600080fd5b613bbe8582860161377f565b9150509250929050565b600060208284031215613bda57600080fd5b6000613be8848285016137be565b91505092915050565b600060208284031215613c0357600080fd5b6000613c11848285016137d3565b91505092915050565b600060208284031215613c2c57600080fd5b6000613c3a84828501613812565b91505092915050565b600060208284031215613c5557600080fd5b600082015167ffffffffffffffff811115613c6f57600080fd5b613c7b84828501613851565b91505092915050565b600060208284031215613c9657600080fd5b6000613ca484828501613907565b91505092915050565b600060208284031215613cbf57600080fd5b6000613ccd8482850161391c565b91505092915050565b600080600060608486031215613ceb57600080fd5b6000613cf986828701613907565b9350506020613d0a868287016137a9565b9250506040613d1b868287016137a9565b9150509250925092565b60008060408385031215613d3857600080fd5b6000613d4685828601613907565b925050602083013567ffffffffffffffff811115613d6357600080fd5b613d6f8582860161387b565b9150509250929050565b600080600060608486031215613d8e57600080fd5b6000613d9c86828701613907565b9350506020613dad86828701613907565b9250506040613dbe868287016137a9565b9150509250925092565b6000613dd48383614396565b905092915050565b6000613de88383614583565b60208301905092915050565b613dfd81614ee7565b82525050565b613e0c81614ee7565b82525050565b6000613e1d82614d2c565b613e278185614d72565b935083602082028501613e3985614d0c565b8060005b85811015613e755784840389528151613e568582613dc8565b9450613e6183614d58565b925060208a01995050600181019050613e3d565b50829750879550505050505092915050565b6000613e9282614d37565b613e9c8185614d83565b9350613ea783614d1c565b8060005b83811015613ed8578151613ebf8882613ddc565b9750613eca83614d65565b925050600181019050613eab565b5085935050505092915050565b613eee81614ef9565b82525050565b613efd81614ef9565b82525050565b613f0c81614f05565b82525050565b6000613f1d82614d42565b613f278185614d94565b9350613f3781856020860161501f565b613f40816151d4565b840191505092915050565b613f5481614f6e565b82525050565b613f6381614f92565b82525050565b613f7281614fb6565b82525050565b613f8181614fda565b82525050565b613f9081614ffe565b82525050565b6000613fa182614d4d565b613fab8185614db0565b9350613fbb81856020860161501f565b613fc4816151d4565b840191505092915050565b6000613fda82614d4d565b613fe48185614dc1565b9350613ff481856020860161501f565b613ffd816151d4565b840191505092915050565b6000614015603483614dc1565b9150614020826151f2565b604082019050919050565b6000614038602883614dc1565b915061404382615241565b604082019050919050565b600061405b602b83614dc1565b915061406682615290565b604082019050919050565b600061407e602683614dc1565b9150614089826152df565b604082019050919050565b60006140a1602983614dc1565b91506140ac8261532e565b604082019050919050565b60006140c4600f83614dc1565b91506140cf8261537d565b602082019050919050565b60006140e7600b83614dc1565b91506140f2826153a6565b602082019050919050565b600061410a600c83614dc1565b9150614115826153cf565b602082019050919050565b600061412d602583614dc1565b9150614138826153f8565b604082019050919050565b6000614150603283614dc1565b915061415b82615447565b604082019050919050565b6000614173602a83614dc1565b915061417e82615496565b604082019050919050565b6000614196602083614dc1565b91506141a1826154e5565b602082019050919050565b60006141b9602883614dc1565b91506141c48261550e565b604082019050919050565b60006141dc601283614dc1565b91506141e78261555d565b602082019050919050565b60006141ff600e83614dc1565b915061420a82615586565b602082019050919050565b6000614222600083614da5565b915061422d826155af565b600082019050919050565b6000614245600083614dc1565b9150614250826155af565b600082019050919050565b6000614268601883614dc1565b9150614273826155b2565b602082019050919050565b600061428b602983614dc1565b9150614296826155db565b604082019050919050565b60006142ae602983614dc1565b91506142b98261562a565b604082019050919050565b60006142d1601183614dc1565b91506142dc82615679565b602082019050919050565b60006142f4602883614dc1565b91506142ff826156a2565b604082019050919050565b6000614317601583614dc1565b9150614322826156f1565b602082019050919050565b600061433a602183614dc1565b91506143458261571a565b604082019050919050565b600061435d601f83614dc1565b915061436882615769565b602082019050919050565b6000614380600d83614dc1565b915061438b82615792565b602082019050919050565b600060e0830160008301516143ae6000860182614583565b5060208301516143c16020860182613df4565b50604083015184820360408601526143d98282613f96565b915050606083015184820360608601526143f38282613f96565b91505060808301516144086080860182613f87565b5060a083015161441b60a0860182614583565b5060c083015161442e60c0860182614583565b508091505092915050565b600060e0830160008301516144516000860182614583565b5060208301516144646020860182613df4565b506040830151848203604086015261447c8282613f96565b915050606083015184820360608601526144968282613f96565b91505060808301516144ab6080860182613f87565b5060a08301516144be60a0860182614583565b5060c08301516144d160c0860182614583565b508091505092915050565b600060408301600083015184820360008601526144f98282613f96565b915050602083015184820360208601526145138282613f96565b9150508091505092915050565b60006080830160008301516145386000860182614583565b50602083015161454b6020860182613df4565b50604083015184820360408601526145638282613f96565b91505060608301516145786060860182613ee5565b508091505092915050565b61458c81614f64565b82525050565b61459b81614f64565b82525050565b60006145ac82614215565b9150819050919050565b60006020820190506145cb6000830184613e03565b92915050565b600060a0820190506145e66000830188613e03565b6145f36020830187613e03565b81810360408301526146058186613e87565b905081810360608301526146198185613e87565b9050818103608083015261462d8184613f12565b90509695505050505050565b600060a08201905061464e6000830188613e03565b61465b6020830187613e03565b6146686040830186614592565b6146756060830185614592565b81810360808301526146878184613f12565b90509695505050505050565b60006060820190506146a86000830186613e03565b81810360208301526146ba8185614520565b90506146c96040830184613ef4565b949350505050565b600060208201905081810360008301526146eb8184613e12565b905092915050565b6000602082019050818103600083015261470d8184613e87565b905092915050565b6000604082019050818103600083015261472f8185613e87565b905081810360208301526147438184613e87565b90509392505050565b60006020820190506147616000830184613ef4565b92915050565b600060208201905061477c6000830184613f03565b92915050565b60006020820190506147976000830184613f4b565b92915050565b60006020820190506147b26000830184613f5a565b92915050565b60006020820190506147cd6000830184613f69565b92915050565b60006020820190506147e86000830184613f78565b92915050565b600060208201905081810360008301526148088184613fcf565b905092915050565b6000602082019050818103600083015261482981614008565b9050919050565b600060208201905081810360008301526148498161402b565b9050919050565b600060208201905081810360008301526148698161404e565b9050919050565b6000602082019050818103600083015261488981614071565b9050919050565b600060208201905081810360008301526148a981614094565b9050919050565b600060208201905081810360008301526148c9816140b7565b9050919050565b600060208201905081810360008301526148e9816140da565b9050919050565b60006020820190508181036000830152614909816140fd565b9050919050565b6000602082019050818103600083015261492981614120565b9050919050565b6000602082019050818103600083015261494981614143565b9050919050565b6000602082019050818103600083015261496981614166565b9050919050565b6000602082019050818103600083015261498981614189565b9050919050565b600060208201905081810360008301526149a9816141ac565b9050919050565b600060208201905081810360008301526149c9816141cf565b9050919050565b600060208201905081810360008301526149e9816141f2565b9050919050565b60006020820190508181036000830152614a098161425b565b9050919050565b60006020820190508181036000830152614a298161427e565b9050919050565b60006020820190508181036000830152614a49816142a1565b9050919050565b60006020820190508181036000830152614a69816142c4565b9050919050565b60006020820190508181036000830152614a89816142e7565b9050919050565b60006020820190508181036000830152614aa98161430a565b9050919050565b60006020820190508181036000830152614ac98161432d565b9050919050565b60006020820190508181036000830152614ae981614350565b9050919050565b60006020820190508181036000830152614b0981614373565b9050919050565b60006020820190508181036000830152614b2a8184614439565b905092915050565b60006020820190508181036000830152614b4c81846144dc565b905092915050565b6000602082019050614b696000830184614592565b92915050565b6000606082019050614b846000830186614592565b614b916020830185613ef4565b614b9e6040830184613ef4565b949350505050565b6000604082019050614bbb6000830184614592565b8181036020830152614bcc81614238565b905092915050565b6000604082019050614be96000830185614592565b8181036020830152614bfb8184614520565b90509392505050565b6000604082019050614c196000830185614592565b614c266020830184614592565b9392505050565b6000614c37614c48565b9050614c43828261507c565b919050565b6000604051905090565b600067ffffffffffffffff821115614c6d57614c6c615183565b5b602082029050602081019050919050565b600067ffffffffffffffff821115614c9957614c98615183565b5b602082029050602081019050919050565b600067ffffffffffffffff821115614cc557614cc4615183565b5b614cce826151d4565b9050602081019050919050565b600067ffffffffffffffff821115614cf657614cf5615183565b5b614cff826151d4565b9050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b6000614ddd82614f64565b9150614de883614f64565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115614e1d57614e1c6150f6565b5b828201905092915050565b6000614e3382614f64565b9150614e3e83614f64565b925082614e4e57614e4d615125565b5b828204905092915050565b6000614e6482614f64565b9150614e6f83614f64565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614ea857614ea76150f6565b5b828202905092915050565b6000614ebe82614f64565b9150614ec983614f64565b925082821015614edc57614edb6150f6565b5b828203905092915050565b6000614ef282614f44565b9050919050565b60008115159050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050614f3f82615851565b919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000614f7982614f80565b9050919050565b6000614f8b82614f44565b9050919050565b6000614f9d82614fa4565b9050919050565b6000614faf82614f44565b9050919050565b6000614fc182614fc8565b9050919050565b6000614fd382614f44565b9050919050565b6000614fe582614fec565b9050919050565b6000614ff782614f44565b9050919050565b600061500982614f31565b9050919050565b82818337600083830152505050565b60005b8381101561503d578082015181840152602081019050615022565b8381111561504c576000848401525b50505050565b600061505d82614f64565b91506000821415615071576150706150f6565b5b600182039050919050565b615085826151d4565b810181811067ffffffffffffffff821117156150a4576150a3615183565b5b80604052505050565b60006150b882614f64565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156150eb576150ea6150f6565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060033d11156151d15760046000803e6151ce6000516151e5565b90505b90565b6000601f19601f8301169050919050565b60008160e01c9050919050565b7f455243313135353a207472616e7366657220746f206e6f6e204552433131353560008201527f526563656976657220696d706c656d656e746572000000000000000000000000602082015250565b7f455243313135353a204552433131353552656365697665722072656a6563746560008201527f6420746f6b656e73000000000000000000000000000000000000000000000000602082015250565b7f455243313135353a2062616c616e636520717565727920666f7220746865207a60008201527f65726f2061646472657373000000000000000000000000000000000000000000602082015250565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b7f455243313135353a2063616c6c6572206973206e6f74206f776e6572206e6f7260008201527f20617070726f7665640000000000000000000000000000000000000000000000602082015250565b7f4e4f5f43524541544f525f4d494e540000000000000000000000000000000000600082015250565b7f554e415641494c41424c45000000000000000000000000000000000000000000600082015250565b7f434f4d505f43524541544f520000000000000000000000000000000000000000600082015250565b7f455243313135353a207472616e7366657220746f20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b7f455243313135353a207472616e736665722063616c6c6572206973206e6f742060008201527f6f776e6572206e6f7220617070726f7665640000000000000000000000000000602082015250565b7f455243313135353a20696e73756666696369656e742062616c616e636520666f60008201527f72207472616e7366657200000000000000000000000000000000000000000000602082015250565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b7f455243313135353a206275726e20616d6f756e74206578636565647320746f7460008201527f616c537570706c79000000000000000000000000000000000000000000000000602082015250565b7f4f4e4c595f373758375f41434345505445440000000000000000000000000000600082015250565b7f444f45535f4e4f545f4558495354000000000000000000000000000000000000600082015250565b50565b7f494e5445524e414c5f45544845525f54585f4641494c45440000000000000000600082015250565b7f455243313135353a2073657474696e6720617070726f76616c2073746174757360008201527f20666f722073656c660000000000000000000000000000000000000000000000602082015250565b7f455243313135353a206163636f756e747320616e6420696473206c656e67746860008201527f206d69736d617463680000000000000000000000000000000000000000000000602082015250565b7f4d494e5f325f4d41585f375f574f524b53000000000000000000000000000000600082015250565b7f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060008201527f6d69736d61746368000000000000000000000000000000000000000000000000602082015250565b7f49445f434f554e545f4f55545f4f465f52414e47450000000000000000000000600082015250565b7f455243313135353a206d696e7420746f20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b7f494e56414c49445f56414c554500000000000000000000000000000000000000600082015250565b600060443d10156157cb5761584e565b6157d3614c48565b60043d036004823e80513d602482011167ffffffffffffffff821117156157fb57505061584e565b808201805167ffffffffffffffff811115615819575050505061584e565b80602083010160043d03850181111561583657505050505061584e565b6158458260200185018661507c565b82955050505050505b90565b6002811061586257615861615154565b5b50565b61586e81614ee7565b811461587957600080fd5b50565b61588581614ef9565b811461589057600080fd5b50565b61589c81614f05565b81146158a757600080fd5b50565b600281106158b757600080fd5b50565b6158c381614f64565b81146158ce57600080fd5b5056fea264697066735822122060466c411f445ed89d0fb9d682479b0fdabbb7dbaba1f8f848763b0df687befe64736f6c6343000804003360806040526040518060800160405280605c815260200162006496605c9139600290805190602001906200003592919062000127565b506040518061110001604052806110de8152602001620053b86110de9139600390805190602001906200006a92919062000127565b503480156200007857600080fd5b50604051620064f2380380620064f283398181016040528101906200009e9190620001ee565b816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050620002e2565b828054620001359062000263565b90600052602060002090601f016020900481019282620001595760008555620001a5565b82601f106200017457805160ff1916838001178555620001a5565b82800160010185558215620001a5579182015b82811115620001a457825182559160200191906001019062000187565b5b509050620001b49190620001b8565b5090565b5b80821115620001d3576000816000905550600101620001b9565b5090565b600081519050620001e881620002c8565b92915050565b600080604083850312156200020257600080fd5b60006200021285828601620001d7565b92505060206200022585828601620001d7565b9150509250929050565b60006200023c8262000243565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600060028204905060018216806200027c57607f821691505b6020821081141562000293576200029262000299565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b620002d3816200022f565b8114620002df57600080fd5b50565b6150c680620002f26000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80630fcec87e1461005c5780631301f0f51461008c57806318c910ff146100bc578063535776f2146100ec57806371692b7f1461011c575b600080fd5b610076600480360381019061007191906129c4565b61014c565b6040516100839190613bdf565b60405180910390f35b6100a660048036038101906100a1919061294c565b6102c4565b6040516100b39190613bdf565b60405180910390f35b6100d660048036038101906100d1919061280c565b610583565b6040516100e39190613bdf565b60405180910390f35b61010660048036038101906101019190612975565b610792565b6040516101139190613bdf565b60405180910390f35b6101366004803603810190610131919061294c565b61092c565b6040516101439190613bc4565b60405180910390f35b606060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166394056d17856040518263ffffffff1660e01b81526004016101aa9190613c41565b60006040518083038186803b1580156101c257600080fd5b505afa1580156101d6573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906101ff9190612860565b905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d48e638a866040518263ffffffff1660e01b815260040161025d9190613c41565b60206040518083038186803b15801561027557600080fd5b505afa158015610289573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ad91906127e3565b90506102ba818386610ab1565b9250505092915050565b606060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ec420c11846040518263ffffffff1660e01b81526004016103229190613c41565b60006040518083038186803b15801561033a57600080fd5b505afa15801561034e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610377919061290b565b9050600061038484610c65565b8260600151600060018111156103c3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b84608001516001811115610400577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14610440576040518060400160405280600881526020017f506f727472616974000000000000000000000000000000000000000000000000815250610477565b6040518060400160405280600981526020017f4c616e64736361706500000000000000000000000000000000000000000000008152505b61052e60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166394056d17896040518263ffffffff1660e01b81526004016104d39190613c41565b60006040518083038186803b1580156104eb57600080fd5b505afa1580156104ff573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906105289190612860565b51610c65565b60405160200161054194939291906139d4565b604051602081830303815290604052905061055b81610e12565b60405160200161056b9190613b3b565b60405160208183030381529060405292505050919050565b60606001825111801561059857506007825111155b6105d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ce90613c21565b60405180910390fd5b60005b825181101561072057600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634f558e7984838151811061065a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101516040518263ffffffff1660e01b815260040161067e9190613c41565b60206040518083038186803b15801561069657600080fd5b505afa1580156106aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ce91906128a1565b61070d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161070490613c01565b60405180910390fd5b808061071890613ffd565b9150506105da565b50600061072d8484610fb1565b90506040518060400160405280600381526020017f505245000000000000000000000000000000000000000000000000000000000081525081600001819052506001816040019015159081151581525050610789816001611209565b91505092915050565b606060006108f560008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d48e638a876040518263ffffffff1660e01b81526004016107f29190613c41565b60206040518083038186803b15801561080a57600080fd5b505afa15801561081e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084291906127e3565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166394056d17886040518263ffffffff1660e01b815260040161089b9190613c41565b60006040518083038186803b1580156108b357600080fd5b505afa1580156108c7573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906108f09190612860565b610fb1565b905061090085610c65565b8160000181905250838160400190151590811515815250506109228184611209565b9150509392505050565b600080610a9e60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d48e638a856040518263ffffffff1660e01b815260040161098b9190613c41565b60206040518083038186803b1580156109a357600080fd5b505afa1580156109b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109db91906127e3565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166394056d17866040518263ffffffff1660e01b8152600401610a349190613c41565b60006040518083038186803b158015610a4c57600080fd5b505afa158015610a60573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610a899190612860565b60405180602001604052806000815250610ab1565b9050610aa9816120b5565b915050919050565b606060006f0785ee10d5da46d900f436a0000000008573ffffffffffffffffffffffffffffffffffffffff16610ae79190613dd8565b9050610c3a8451604d610afa9190613e09565b85600181518110610b34577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015186600081518110610b76577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151610b889190613d82565b86600181518110610bc2577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015187600081518110610c04577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151610c169190613d82565b610c209190613e09565b610c2a9190613e09565b82610c359190613d82565b610c65565b83604051602001610c4c929190613826565b6040516020818303038152906040529150509392505050565b60606000821415610cad576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050610e0d565b600082905060005b60008214610cdf578080610cc890613ffd565b915050600a82610cd89190613dd8565b9150610cb5565b60008167ffffffffffffffff811115610d21577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015610d535781602001600182028036833780820191505090505b5090505b60008514610e0657600182610d6c9190613e97565b9150600a85610d7b9190614046565b6030610d879190613d82565b60f81b818381518110610dc3577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a85610dff9190613dd8565b9450610d57565b8093505050505b919050565b6060600082511415610e3557604051806020016040528060008152509050610fac565b60006040518060600160405280604081526020016150516040913990506000600360028551610e649190613d82565b610e6e9190613dd8565b6004610e7a9190613e09565b90506000602082610e8b9190613d82565b67ffffffffffffffff811115610eca577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015610efc5781602001600182028036833780820191505090505b509050818152600183018586518101602084015b81831015610f6b576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f8116850151825360018201915050610f10565b600389510660018114610f855760028114610f9557610fa0565b613d3d60f01b6002830352610fa0565b603d60f81b60018303525b50505050508093505050505b919050565b610fb9612358565b604051806103000160405280604051806020016040528060008152508152602001604051806020016040528060008152508152602001600015158152602001611012858560405180602001604052806000815250610ab1565b815260200160405180602001604052806000815250815260200160405180602001604052806000815250815260200160405180602001604052806000815250815260200161109685856040518060400160405280600481526020017f72616e6400000000000000000000000000000000000000000000000000000000815250610ab1565b8152602001838152602001604051806020016040528060008152508152602001604051806020016040528060008152508152602001604051806020016040528060008152508152602001600081526020016000815260200161111061110b868660405180602001604052806000815250610ab1565b6120b5565b6001811115611148577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8152602001604051806020016040528060008152508152602001604051806020016040528060008152508152602001604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250815260200160008152602001600081526020016000815260200160405180602001604052806000815250815260200160405180602001604052806000815250815260200160405180602001604052806000815250815250905092915050565b6060826101000151516102bc61121f9190613dd8565b8361024001818152505061124e8360a0015160648561024001516112439190613e97565b8561024001516120dc565b8361026001818152505061127d8360c0015160648561024001516112729190613e97565b8561024001516120dc565b8361028001818152505061132b61132684606001516064600060018111156112ce577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b876101c00151600181111561130c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611319576101f461131d565b6103205b61ffff166120dc565b610c65565b83610220015160006002811061136a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200201819052506114166114118460a001516064600060018111156113b9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b876101c0015160018111156113f7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1461140457610320611408565b6101f45b61ffff166120dc565b610c65565b836102200151600160028110611455577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002018190525060006001811115611497577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b836101c0015160018111156114d5577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611515576040518060400160405280600381526020017f373030000000000000000000000000000000000000000000000000000000000081525061154c565b6040518060400160405280600481526020017f31303030000000000000000000000000000000000000000000000000000000008152505b836101e001819052506000600181111561158f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b836101c0015160018111156115cd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1461160d576040518060400160405280600481526020017f3130303000000000000000000000000000000000000000000000000000000000815250611644565b6040518060400160405280600381526020017f37303000000000000000000000000000000000000000000000000000000000008152505b83610200018190525060005b83610100015151811015611c4457836060015161166c82610c65565b60405160200161167d929190613826565b6040516020818303038152906040528460800181905250836060015184608001516040516020016116ae919061384a565b6040516020818303038152906040526040516020016116ce929190613802565b6040516020818303038152906040528460a00181905250836060015184608001516040516020016116ff919061389b565b60405160208183030381529060405260405160200161171f929190613802565b6040516020818303038152906040528460c0018190525061174b6001826117469190613d82565b610c65565b84602001819052506117758460a00151600a86610260015161176d9190613dd8565b6103e86120dc565b846101800181815250506117a18460c0015160028661028001516117999190613dd8565b6103e86120dc565b846101a001818152505083610120015184602001516117c4866102600151610c65565b6117d2876101800151610c65565b6117e0886101a00151610c65565b6117ee896102800151610c65565b604051602001611803969594939291906134ab565b604051602081830303815290604052846101200181905250836101600151600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663eded5d9e866101000151848151811061189d577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101516118b68860800151600160076120dc565b6040518363ffffffff1660e01b81526004016118d3929190613c85565b60006040518083038186803b1580156118eb57600080fd5b505afa1580156118ff573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061192891906128ca565b856020015160405160200161193f939291906135df565b60405160208183030381529060405284610160018190525061197161196c8560a0015160646102bc6120dc565b610c65565b61198b6119868660c0015160646102bc6120dc565b610c65565b60405160200161199c92919061386c565b604051602081830303815290604052846102a00181905250836102a001516119d46119cf8660a00151600a6103206120dc565b610c65565b6119ee6119e98760c00151600a6103206120dc565b610c65565b611a08611a038860c0015160646103e86120dc565b610c65565b611a23611a1e8960a001516101906103206120dc565b610c65565b886102a00151604051602001611a3e96959493929190613550565b604051602081830303815290604052846102c00181905250611a6f611a6a8560a00151600160096120dc565b610c65565b611a88611a838660c00151600160096120dc565b610c65565b604051602001611a99929190613b7f565b604051602081830303815290604052846102e00181905250836101400151600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663eded5d9e8661010001518481518110611b33577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151611b4c8860800151600160076120dc565b6040518363ffffffff1660e01b8152600401611b69929190613c85565b60006040518083038186803b158015611b8157600080fd5b505afa158015611b95573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611bbe91906128ca565b85602001516002876102e00151611be4611bdf8a60c00151603260646120dc565b610c65565b604051602001611bf99695949392919061363c565b60405160208183030381529060405284610140018190525083610180015184610260018181525050836101a00151846102800181815250508080611c3c90613ffd565b915050611650565b50611ce9611ce48460600151606460006001811115611c8c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b876101c001516001811115611cca577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611cd7576101f4611cdb565b6103205b61ffff166120dc565b610c65565b836102200151600060028110611d28577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020020181905250611dd4611dcf8460a00151606460006001811115611d77577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b876101c001516001811115611db5577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611dc257610320611dc6565b6101f45b61ffff166120dc565b610c65565b836102200151600160028110611e13577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200201819052506000836101e001518461020001516003866101600151876101400151886102000151896101e001518a6101200151604051602001611e609897969594939291906138bd565b604051602081830303815290604052905080600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663eded5d9e866101000151600081518110611eef577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015160016040518363ffffffff1660e01b8152600401611f16929190613c5c565b60006040518083038186803b158015611f2e57600080fd5b505afa158015611f42573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611f6b91906128ca565b611f84611f7f8760800151600560096120dc565b610c65565b611f9d611f988860800151600360066120dc565b610c65565b876102200151600060028110611fdc577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020020151886102200151600160028110612020577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200201518960400151612043576040518060200160405280600081525061204d565b61204c8a612142565b5b60405160200161206397969594939291906136ec565b604051602081830303815290604052905082156120aa5761208381610e12565b6040516020016120939190613b5d565b6040516020818303038152906040529150506120af565b809150505b92915050565b600060326120c683600060636120dc565b116120d25760016120d5565b60005b9050919050565b60008282116120ed5782905061213b565b8283836120fa9190613e97565b8560405160200161210b91906137eb565b6040516020818303038152906040528051906020012060001c61212e9190614046565b6121389190613d82565b90505b9392505050565b60608060018360000151511415612190576040518060400160405280600281526020017f303000000000000000000000000000000000000000000000000000000000000081525090506121d8565b600283600001515114156121d7576040518060400160405280600181526020017f300000000000000000000000000000000000000000000000000000000000000081525090505b5b600061227b600a60006001811115612219577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b866101c001516001811115612257577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14612264576103e8612268565b6102bc5b6122729190613e63565b61ffff16610c65565b905061231e601c600060018111156122bc577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b866101c0015160018111156122fa577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14612307576103e861230b565b6102bc5b6123159190613e63565b61ffff16610c65565b8183866000015184886080015160405160200161234096959493929190613a96565b60405160208183030381529060405292505050919050565b6040518061030001604052806060815260200160608152602001600015158152602001606081526020016060815260200160608152602001606081526020016060815260200160608152602001606081526020016060815260200160608152602001600081526020016000815260200160006001811115612402577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8152602001606081526020016060815260200161241d61244d565b81526020016000815260200160008152602001600081526020016060815260200160608152602001606081525090565b60405180604001604052806002905b606081526020019060019003908161245c5790505090565b600061248761248284613cd3565b613cae565b905080838252602082019050828560208602820111156124a657600080fd5b60005b858110156124d657816124bc88826127b9565b8452602084019350602083019250506001810190506124a9565b5050509392505050565b60006124f36124ee84613cd3565b613cae565b9050808382526020820190508285602086028201111561251257600080fd5b60005b85811015612542578161252888826127ce565b845260208401935060208301925050600181019050612515565b5050509392505050565b600061255f61255a84613cff565b613cae565b90508281526020810184848401111561257757600080fd5b612582848285613f58565b509392505050565b600061259d61259884613cff565b613cae565b9050828152602081018484840111156125b557600080fd5b6125c0848285613f67565b509392505050565b6000813590506125d781614ffb565b92915050565b6000815190506125ec81614ffb565b92915050565b600082601f83011261260357600080fd5b8135612613848260208601612474565b91505092915050565b600082601f83011261262d57600080fd5b815161263d8482602086016124e0565b91505092915050565b60008135905061265581615012565b92915050565b60008151905061266a81615012565b92915050565b60008151905061267f81615029565b92915050565b600082601f83011261269657600080fd5b81356126a684826020860161254c565b91505092915050565b600082601f8301126126c057600080fd5b81516126d084826020860161258a565b91505092915050565b600060e082840312156126eb57600080fd5b6126f560e0613cae565b90506000612705848285016127ce565b6000830152506020612719848285016125dd565b602083015250604082015167ffffffffffffffff81111561273957600080fd5b612745848285016126af565b604083015250606082015167ffffffffffffffff81111561276557600080fd5b612771848285016126af565b606083015250608061278584828501612670565b60808301525060a0612799848285016127ce565b60a08301525060c06127ad848285016127ce565b60c08301525092915050565b6000813590506127c881615039565b92915050565b6000815190506127dd81615039565b92915050565b6000602082840312156127f557600080fd5b6000612803848285016125dd565b91505092915050565b6000806040838503121561281f57600080fd5b600061282d858286016125c8565b925050602083013567ffffffffffffffff81111561284a57600080fd5b612856858286016125f2565b9150509250929050565b60006020828403121561287257600080fd5b600082015167ffffffffffffffff81111561288c57600080fd5b6128988482850161261c565b91505092915050565b6000602082840312156128b357600080fd5b60006128c18482850161265b565b91505092915050565b6000602082840312156128dc57600080fd5b600082015167ffffffffffffffff8111156128f657600080fd5b612902848285016126af565b91505092915050565b60006020828403121561291d57600080fd5b600082015167ffffffffffffffff81111561293757600080fd5b612943848285016126d9565b91505092915050565b60006020828403121561295e57600080fd5b600061296c848285016127b9565b91505092915050565b60008060006060848603121561298a57600080fd5b6000612998868287016127b9565b93505060206129a986828701612646565b92505060406129ba86828701612646565b9150509250925092565b600080604083850312156129d757600080fd5b60006129e5858286016127b9565b925050602083013567ffffffffffffffff811115612a0257600080fd5b612a0e85828601612685565b9150509250929050565b6000612a2382613d45565b612a2d8185613d5b565b9350612a3d818560208601613f67565b80840191505092915050565b612a5281613f34565b82525050565b612a6181613f46565b82525050565b6000612a7282613d50565b612a7c8185613d66565b9350612a8c818560208601613f67565b612a9581614162565b840191505092915050565b6000612aab82613d50565b612ab58185613d77565b9350612ac5818560208601613f67565b80840191505092915050565b60008154612ade81613f9a565b612ae88186613d77565b94506001821660008114612b035760018114612b1457612b47565b60ff19831686528186019350612b47565b612b1d85613d30565b60005b83811015612b3f57815481890152600182019150602081019050612b20565b838801955050505b50505092915050565b6000612b5d601683613d77565b9150612b6882614173565b601682019050919050565b6000612b80601283613d77565b9150612b8b8261419c565b601282019050919050565b6000612ba3604783613d77565b9150612bae826141c5565b604782019050919050565b6000612bc6602483613d77565b9150612bd18261423a565b602482019050919050565b6000612be9601983613d77565b9150612bf482614289565b601982019050919050565b6000612c0c600383613d77565b9150612c17826142b2565b600382019050919050565b6000612c2f603f83613d77565b9150612c3a826142db565b603f82019050919050565b6000612c52601283613d77565b9150612c5d8261432a565b601282019050919050565b6000612c75603583613d77565b9150612c8082614353565b603582019050919050565b6000612c98601283613d77565b9150612ca3826143a2565b601282019050919050565b6000612cbb600483613d77565b9150612cc6826143cb565b600482019050919050565b6000612cde605e83613d77565b9150612ce9826143f4565b605e82019050919050565b6000612d01601d83613d77565b9150612d0c82614469565b601d82019050919050565b6000612d24601683613d77565b9150612d2f82614492565b601682019050919050565b6000612d47604383613d77565b9150612d52826144bb565b604382019050919050565b6000612d6a601483613d77565b9150612d7582614530565b601482019050919050565b6000612d8d600483613d77565b9150612d9882614559565b600482019050919050565b6000612db0601383613d66565b9150612dbb82614582565b602082019050919050565b6000612dd3602783613d77565b9150612dde826145ab565b602782019050919050565b6000612df6600383613d77565b9150612e01826145fa565b600382019050919050565b6000612e19601f83613d77565b9150612e2482614623565b601f82019050919050565b6000612e3c600d83613d77565b9150612e478261464c565b600d82019050919050565b6000612e5f600383613d77565b9150612e6a82614675565b600382019050919050565b6000612e82600e83613d77565b9150612e8d8261469e565b600e82019050919050565b6000612ea5600183613d77565b9150612eb0826146c7565b600182019050919050565b6000612ec8600183613d77565b9150612ed3826146f0565b600182019050919050565b6000612eeb601583613d77565b9150612ef682614719565b601582019050919050565b6000612f0e600f83613d77565b9150612f1982614742565b600f82019050919050565b6000612f31600583613d77565b9150612f3c8261476b565b600582019050919050565b6000612f54601c83613d77565b9150612f5f82614794565b601c82019050919050565b6000612f77600783613d77565b9150612f82826147bd565b600782019050919050565b6000612f9a600483613d77565b9150612fa5826147e6565b600482019050919050565b6000612fbd602683613d77565b9150612fc88261480f565b602682019050919050565b6000612fe0600c83613d77565b9150612feb8261485e565b600c82019050919050565b6000613003608783613d77565b915061300e82614887565b608782019050919050565b6000613026600783613d77565b915061303182614948565b600782019050919050565b6000613049601e83613d77565b915061305482614971565b601e82019050919050565b600061306c604883613d77565b91506130778261499a565b604882019050919050565b600061308f600683613d77565b915061309a82614a0f565b600682019050919050565b60006130b2603083613d77565b91506130bd82614a38565b603082019050919050565b60006130d5601283613d77565b91506130e082614a87565b601282019050919050565b60006130f8600183613d77565b915061310382614ab0565b600182019050919050565b600061311b603d83613d77565b915061312682614ad9565b603d82019050919050565b600061313e600c83613d77565b915061314982614b28565b600c82019050919050565b6000613161601a83613d77565b915061316c82614b51565b601a82019050919050565b6000613184601583613d77565b915061318f82614b7a565b601582019050919050565b60006131a7603183613d77565b91506131b282614ba3565b603182019050919050565b60006131ca600483613d77565b91506131d582614bf2565b600482019050919050565b60006131ed603d83613d77565b91506131f882614c1b565b603d82019050919050565b6000613210600183613d77565b915061321b82614c6a565b600182019050919050565b6000613233601283613d77565b915061323e82614c93565b601282019050919050565b6000613256600183613d77565b915061326182614cbc565b600182019050919050565b6000613279607b83613d77565b915061328482614ce5565b607b82019050919050565b600061329c600283613d77565b91506132a782614d80565b600282019050919050565b60006132bf601d83613d77565b91506132ca82614da9565b601d82019050919050565b60006132e2600783613d77565b91506132ed82614dd2565b600782019050919050565b6000613305600483613d77565b915061331082614dfb565b600482019050919050565b6000613328600683613d77565b915061333382614e24565b600682019050919050565b600061334b600383613d77565b915061335682614e4d565b600382019050919050565b600061336e600283613d77565b915061337982614e76565b600282019050919050565b6000613391600a83613d77565b915061339c82614e9f565b600a82019050919050565b60006133b4601f83613d77565b91506133bf82614ec8565b601f82019050919050565b60006133d7601183613d66565b91506133e282614ef1565b602082019050919050565b60006133fa600683613d77565b915061340582614f1a565b600682019050919050565b600061341d600983613d77565b915061342882614f43565b600982019050919050565b6000613440600383613d77565b915061344b82614f6c565b600382019050919050565b6000613463601a83613d77565b915061346e82614f95565b601a82019050919050565b6000613486600583613d77565b915061349182614fbe565b600582019050919050565b6134a581613f2a565b82525050565b60006134b78289612a18565b91506134c282612c45565b91506134ce8288612aa0565b91506134d982613177565b91506134e58287612aa0565b91506134f082612e52565b91506134fc8286612aa0565b915061350782613082565b91506135138285612aa0565b915061351e82613082565b915061352a8284612aa0565b915061353582613361565b915061354082612ede565b9150819050979650505050505050565b600061355c8289612a18565b915061356782612ebb565b91506135738288612aa0565b915061357e82612e98565b915061358a8287612aa0565b915061359582612ebb565b91506135a18286612aa0565b91506135ac82612e98565b91506135b88285612aa0565b91506135c382612ebb565b91506135cf8284612a18565b9150819050979650505050505050565b60006135eb8286612a18565b91506135f682612fd3565b91506136028285612aa0565b915061360d8261310e565b91506136198284612aa0565b915061362482613433565b915061362f82612f6a565b9150819050949350505050565b60006136488289612a18565b915061365382612fd3565b915061365f8288612aa0565b915061366a8261310e565b91506136768287612aa0565b915061368182613433565b915061368c82613226565b91506136988286612ad1565b91506136a3826130a5565b91506136af8285612a18565b91506136ba826130c8565b91506136c68284612aa0565b91506136d182612cf4565b91506136dc82612f6a565b9150819050979650505050505050565b60006136f8828a612a18565b915061370382613154565b915061370e8261303c565b915061371982612b50565b91506137258289612aa0565b915061373082612b73565b915061373b8261305f565b9150613746826131e0565b91506137528288612aa0565b915061375d82612bdc565b9150613768826131e0565b91506137748287612aa0565b915061377f82613131565b915061378b8286612aa0565b91506137968261328f565b91506137a28285612aa0565b91506137ad82612f8d565b91506137b98284612a18565b91506137c482612bb9565b91506137cf826131bd565b91506137da826133ed565b915081905098975050505050505050565b60006137f78284612aa0565b915081905092915050565b600061380e8285612aa0565b915061381a8284612a18565b91508190509392505050565b60006138328285612aa0565b915061383e8284612aa0565b91508190509392505050565b60006138568284612aa0565b915061386182612d80565b915081905092915050565b60006138788285612aa0565b915061388382612e98565b915061388f8284612aa0565b91508190509392505050565b60006138a78284612aa0565b91506138b282612f24565b915081905092915050565b60006138c882612c68565b91506138d4828b612aa0565b91506138df82612e98565b91506138eb828a612aa0565b91506138f682612fb0565b91506139018261331b565b915061390c82612ff6565b91506139188289612ad1565b915061392382612e2f565b915061392e82612d3a565b915061393a8288612a18565b9150613945826131bd565b915061395082612b96565b915061395c8287612a18565b9150613967826131bd565b915061397282612cd1565b915061397d82612d17565b91506139898286612aa0565b915061399482613410565b91506139a08285612aa0565b91506139ab82612c22565b91506139b78284612a18565b91506139c2826132d5565b91508190509998505050505050505050565b60006139df82613203565b91506139ea82612d5d565b91506139f68287612aa0565b9150613a018261333e565b9150613a0c826133a7565b9150613a1782613384565b9150613a238286612aa0565b9150613a2e82612c8b565b9150613a3982612dc6565b9150613a458285612aa0565b9150613a5082612de9565b9150613a5b82612e0c565b9150613a678284612aa0565b9150613a72826130eb565b9150613a7d82613249565b9150613a88826130eb565b915081905095945050505050565b6000613aa18261326c565b9150613aad8289612aa0565b9150613ab88261319a565b9150613ac48288612aa0565b9150613acf82612f01565b9150613adb8287612a18565b9150613ae78286612aa0565b9150613af282612cae565b9150613afd82612f47565b9150613b098285612aa0565b9150613b1482612e75565b9150613b208284612aa0565b9150613b2b82613019565b9150819050979650505050505050565b6000613b46826132b2565b9150613b528284612aa0565b915081905092915050565b6000613b6882613456565b9150613b748284612aa0565b915081905092915050565b6000613b8a82613479565b9150613b968285612aa0565b9150613ba1826132f8565b9150613bad8284612aa0565b9150613bb882612bff565b91508190509392505050565b6000602082019050613bd96000830184612a49565b92915050565b60006020820190508181036000830152613bf98184612a67565b905092915050565b60006020820190508181036000830152613c1a81612da3565b9050919050565b60006020820190508181036000830152613c3a816133ca565b9050919050565b6000602082019050613c56600083018461349c565b92915050565b6000604082019050613c71600083018561349c565b613c7e6020830184612a58565b9392505050565b6000604082019050613c9a600083018561349c565b613ca7602083018461349c565b9392505050565b6000613cb8613cc9565b9050613cc48282613fcc565b919050565b6000604051905090565b600067ffffffffffffffff821115613cee57613ced614133565b5b602082029050602081019050919050565b600067ffffffffffffffff821115613d1a57613d19614133565b5b613d2382614162565b9050602081019050919050565b60008190508160005260206000209050919050565b600081519050919050565b600081519050919050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b6000613d8d82613f2a565b9150613d9883613f2a565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115613dcd57613dcc614077565b5b828201905092915050565b6000613de382613f2a565b9150613dee83613f2a565b925082613dfe57613dfd6140a6565b5b828204905092915050565b6000613e1482613f2a565b9150613e1f83613f2a565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613e5857613e57614077565b5b828202905092915050565b6000613e6e82613efc565b9150613e7983613efc565b925082821015613e8c57613e8b614077565b5b828203905092915050565b6000613ea282613f2a565b9150613ead83613f2a565b925082821015613ec057613ebf614077565b5b828203905092915050565b6000613ed682613f0a565b9050919050565b60008115159050919050565b6000819050613ef782614fe7565b919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000613f3f82613ee9565b9050919050565b6000613f5182613f2a565b9050919050565b82818337600083830152505050565b60005b83811015613f85578082015181840152602081019050613f6a565b83811115613f94576000848401525b50505050565b60006002820490506001821680613fb257607f821691505b60208210811415613fc657613fc5614104565b5b50919050565b613fd582614162565b810181811067ffffffffffffffff82111715613ff457613ff3614133565b5b80604052505050565b600061400882613f2a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561403b5761403a614077565b5b600182019050919050565b600061405182613f2a565b915061405c83613f2a565b92508261406c5761406b6140a6565b5b828206905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f3c75736520687265663d22236267222066696c6c3d2200000000000000000000600082015250565b7f22206f7061636974793d22302e3235222f3e0000000000000000000000000000600082015250565b7f3c672069643d226d61696e2d616e6922207472616e73666f726d3d227472616e60008201527f736c617465282d35202d3529207363616c6528312e322922206f70616369747960208201527f3d22302e38223e00000000000000000000000000000000000000000000000000604082015250565b7f3c75736520687265663d22236267222066696c6c3d2275726c28236e6f69736560008201527f29222f3e00000000000000000000000000000000000000000000000000000000602082015250565b7f2920726f746174652839302c203530302c2035303029222f3e00000000000000600082015250565b7f3b20310000000000000000000000000000000000000000000000000000000000600082015250565b7f2220783d22302220793d2230222f3e3c636c6970506174682069643d22636c6960008201527f70223e3c75736520687265663d22236267222f3e3c2f636c6970506174683e00602082015250565b7f3c636c6970506174682069643d22636c69700000000000000000000000000000600082015250565b7f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060008201527f30302f737667222076696577426f783d22302030200000000000000000000000602082015250565b7f222c202261747472696275746573223a205b0000000000000000000000000000600082015250565b7f20c2b72000000000000000000000000000000000000000000000000000000000600082015250565b7f3c66696c7465722069643d22626c75722220783d22302220793d2230223e3c6660008201527f65476175737369616e426c757220696e3d22536f75726365477261706869632260208201527f20737464446576696174696f6e3d22313030222f3e3c2f66696c7465723e0000604082015250565b7f732220726570656174436f756e743d22696e646566696e697465222f3e000000600082015250565b7f3c726563742069643d22626722206865696768743d2200000000000000000000600082015250565b7f3c672069643d226d61696e22207472616e73666f726d3d227472616e736c617460008201527f65282d35202d3529207363616c6528312e322922206f7061636974793d22302e60208201527f38223e0000000000000000000000000000000000000000000000000000000000604082015250565b7f226e616d65223a20223030783020636f6d702023000000000000000000000000600082015250565b7f6c65667400000000000000000000000000000000000000000000000000000000600082015250565b7f574f524b5f444f45535f4e4f545f455849535400000000000000000000000000600082015250565b7f7b2274726169745f74797065223a20226f7269656e746174696f6e222c20227660008201527f616c7565223a2200000000000000000000000000000000000000000000000000602082015250565b7f227d2c0000000000000000000000000000000000000000000000000000000000600082015250565b7f7b2274726169745f74797065223a202262617365222c202276616c7565223a00600082015250565b7f222f3e3c2f7061747465726e3e00000000000000000000000000000000000000600082015250565b7f20302c0000000000000000000000000000000000000000000000000000000000600082015250565b7f2220636c6173733d22747874223e000000000000000000000000000000000000600082015250565b7f2000000000000000000000000000000000000000000000000000000000000000600082015250565b7f3b00000000000000000000000000000000000000000000000000000000000000600082015250565b7f3c2f706f6c79676f6e3e3c2f636c6970506174683e0000000000000000000000600082015250565b7f2220636c6173733d22747874223e230000000000000000000000000000000000600082015250565b7f7269676874000000000000000000000000000000000000000000000000000000600082015250565b7f303078303c2f746578743e3c7465787420783d223132332220793d2200000000600082015250565b7f3c2f726563743e00000000000000000000000000000000000000000000000000600082015250565b7f29222f3e00000000000000000000000000000000000000000000000000000000600082015250565b7f22207072657365727665417370656374526174696f3d22784d696e594d696e2060008201527f6d656574223e0000000000000000000000000000000000000000000000000000602082015250565b7f3c726563742066696c6c3d220000000000000000000000000000000000000000600082015250565b7f3c7061747465726e2069643d226e6f6973652220783d22302220793d2230222060008201527f77696474683d22353122206865696768743d22353122207061747465726e556e60208201527f6974733d227573657253706163654f6e557365223e3c696d616765206f70616360408201527f6974793d22302e32222077696474683d22353122206865696768743d2235312260608201527f20687265663d2200000000000000000000000000000000000000000000000000608082015250565b7f3c2f746578743e00000000000000000000000000000000000000000000000000600082015250565b7f3c75736520687265663d22236267222066696c6c3d227768697465222f3e0000600082015250565b7f3c75736520687265663d22236d61696e222066696c7465723d2275726c28236260008201527f6c75722922207472616e73666f726d3d22726f746174652839302c203530302c60208201527f2035303029222f3e000000000000000000000000000000000000000000000000604082015250565b7f20313030302c0000000000000000000000000000000000000000000000000000600082015250565b7f206174747269627574654e616d653d227472616e73666f726d2220747970653d60008201527f227363616c65222076616c7565733d2200000000000000000000000000000000602082015250565b7f2220626567696e3d22307322206475723d220000000000000000000000000000600082015250565b7f7d00000000000000000000000000000000000000000000000000000000000000600082015250565b7f2220793d22302220783d223022206865696768743d223130303022207769647460008201527f683d22313030302220636c69702d706174683d2275726c2823636c6970000000602082015250565b7f29207472616e736c617465280000000000000000000000000000000000000000600082015250565b7f3c6720636c69702d706174683d2275726c2823636c697029223e000000000000600082015250565b7f223e3c706f6c79676f6e20706f696e74733d22302c0000000000000000000000600082015250565b7f222066696c6c3d22233030302220636c6173733d22626f78223e3c2f7265637460008201527f3e3c7465787420783d2231322220793d22000000000000000000000000000000602082015250565b7f3c2f673e00000000000000000000000000000000000000000000000000000000600082015250565b7f3c75736520687265663d22236d61696e2d616e69222066696c7465723d22757260008201527f6c2823626c75722922207472616e73666f726d3d227363616c6528302e000000602082015250565b7f7b00000000000000000000000000000000000000000000000000000000000000600082015250565b7f3c616e696d6174655472616e73666f726d200000000000000000000000000000600082015250565b7f5d00000000000000000000000000000000000000000000000000000000000000600082015250565b7f3c7374796c653e2e7478747b666f6e743a206e6f726d616c2031327078206d6f60008201527f6e6f73706163653b66696c6c3a2077686974653b206c65747465722d7370616360208201527f696e673a302e31656d3b7d3c2f7374796c653e3c726563742077696474683d2260408201527f31313522206865696768743d2233302220783d222d322220793d220000000000606082015250565b7f2c20000000000000000000000000000000000000000000000000000000000000600082015250565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000600082015250565b7f3c2f646566733e00000000000000000000000000000000000000000000000000600082015250565b7f3b20302e00000000000000000000000000000000000000000000000000000000600082015250565b7f3c646566733e0000000000000000000000000000000000000000000000000000600082015250565b7f222c200000000000000000000000000000000000000000000000000000000000600082015250565b7f223e000000000000000000000000000000000000000000000000000000000000600082015250565b7f22696d616765223a202200000000000000000000000000000000000000000000600082015250565b7f226465736372697074696f6e223a20226c6174656e742e776f726b73222c2000600082015250565b7f4d494e5f325f4d41585f375f574f524b53000000000000000000000000000000600082015250565b7f3c2f7376673e0000000000000000000000000000000000000000000000000000600082015250565b7f222077696474683d220000000000000000000000000000000000000000000000600082015250565b7f29223e0000000000000000000000000000000000000000000000000000000000600082015250565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000600082015250565b7f313b20302e000000000000000000000000000000000000000000000000000000600082015250565b60028110614ff857614ff76140d5565b5b50565b61500481613ecb565b811461500f57600080fd5b50565b61501b81613edd565b811461502657600080fd5b50565b6002811061503657600080fd5b50565b61504281613f2a565b811461504d57600080fd5b5056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122081daa0d3f6e8194d858963a005d2fa6f5b77e88ed84c8805c741f4ba7c1dfb4e64736f6c63430008040033646174613a4066696c652f706e673b6261736536342c6956424f5277304b47676f414141414e535568455567414141444d414141417a43415941414141366f5441714141414d57306c455156526f67643161425778565452616556787263673136672f536c654b453642347534537042516e4f4d5731704a41534a4c6837634a64434b513668514c4467467077437853307445437859366474386833646d5a2b37634c736d66335379374a356d4d6e5a6b37636e7975792b31325730494930627433623746382b584c686472764632376476785973584c3052415141445641533658533652506e3135382f5068524d4a773463554a5572313564316f467a37646f3155624a6b53546e75304b46446f6e37392b745133624e67774d5776574c436f7a544a382b58547836394567554b564a4544426f30534d3644385a7972387a7656662f37384b5536644f6956636777594e7375725571534f614e3238755646416e4c4643676745684b53684a7863584847684d6b42357274313635626f31713262474474327241674f4468626e7a7030546a78382f4673655048786331617454515267594642596c657658714a746d336230714878596c4f6b534345534578506c41616a66337256726c3069564b70565975584b6c324c5a74473356616e747578754e7978593065717132324d382f446851316c66765871314e5876326243702f2b664c46476a56716c44486d314b6c5431754c466936336c79356462642b3763736235392b3662686f4e797055796574506d54494547304f2b7872554e48546f55446b664e6d686c795a4b464b724e6d7a614c382f506e7a31744b6c532b5767545a733257642b2f663565444d454739657657736a78382f47682f6a744844685175763639657657397533627463556e4a69624b7a61754c327268786f7978506e5472566d4d387074573362567273495962385670506676337875334e58506d544f4f4579705572522b56657658724a573045715862713031626476583863464d45365a4d6d574d4e703450616637382b6461316139656f48425957707130464e3232666e2b5a41495733617442705a4a5a63374c55797462393236315a4538392b7a5a6f7931363774793573752f7533627647707453784579644f704c626576587362363171356371574736775536573770304b5445725136745772616a557633392f796d4e695973536d545a736b557749795a4d676742515453756e5872694d6e7633372b765352756b5a73326161594a6a384f44426b756b687856546d6274323674527748534a30364e6557544a302b6d2f727031363870356576546f6f59736670784f326e33372b2f506d74487a392b55426b6e3558523778597358743036634f4b47316f58372f2f6e3148664d366e545a746d4d5856557131614e326873316169527856717859515758775875584b6c5933313264623636327137642b397564494c32375175776b304a73624b7842636969584c567657494e304e477a5a59773463504e37366a6a76663139545532334b4e4844774f2f567131615672703036625476657432356330664d6d544f486c466d544a6b336f65697458726b79336475584b46636f6a49794f7066636951495a6f5342667a3438554d7357624b453271466f6d5a77755837357336434d6f335a6b7a5a3871784c6f5763754134467972427834305971726c697851734d624f4843674f487230714267356371533248692f514c42614a53666274323065645a38366345656e5370534f6b62392b2b45532b6776564b6c536f6269387666334a365547794a4d6e6a3647356d5438414c5675324e4651732b496249777949714562647633355a6a4f33546f4942563175336274354a6a382b664d4c58414b506b64387258373638566146434263637235337a476a426d796e434a4643736f686b516f564b6954484a43556c4f5372454e476e5347504d787161315a733062796f4a7059696336624e3039726a34364f746c7775467958556f51734e305a77376432356a51683573583178794173504f53387a344b6e3652496b57304d53716664753361315a6737613961736a742f496c537358315a63745736614e4964454d576e6543566174576b5630326164496b366f5864354f76725331634b2b386f6d46596e58567139654c5435392b6b546a68474a664165376576617652506d777132466348447834556e7a392f7072625470302f4c2f6a6476336d6a386957386776587a35556e6835655a467862462b4563534b777561426c5559595a597a39354c683837646f78796d445a6f6239476968584644626f39356844592f507a2f6a746c713262476d6376744e746e447835307342424868415159495745684644646c54466a5275764468772f69776f554c49696f71536e547533466b554c3137636b45514d563639654661564c6c396261314a4e6a5a6c79775941454a6a70773563326f4377636e364257544e6d705663442b34486b3450353765446b48764159722f667633347437392b3542454a44306748514345767753774d4f4844776b5a4730554f736b414f6339314f5a6941622f6844454a7a59436b6c4174426674475872392b54586d44426733495251434a6f702b2f43356733623537326e66587231355046777632775747684f39536f624e6d786f33626878673872703036633353435a54706b7979337135644f344d6b577256716c617951754854706b734855705571564972776e5435356f3479705671715352564a382b6662547671764f434a535175524377334c4669775148613866506e53344a452f33566f67747a6c62746d7769495347427267334b71476a526f675950414b42592f2f72724c32726a4d5537304878306454566350556f58726e527a644a39654738746d7a5a305846696855642b3143474d725a377943536173536949556942684932795a39757a5a55364e33624951584878386654376e6433595a6f4c56657548416b4b6d454e4d3132693763654f477354444f6f666c5673613175524467494476415266357637764647416d66486777514e4e5567695054615465454141534a7a593256706f324d496532624e6b69327264767233334d783864486c437056536e5470306f5863673075584c6d6e393046317030715452326b614d47454535447054585974383467412b3164753361704e6679357333377138504f794441686e48534b6b395a5836586641674146575445794d4652455249585554644258366e545235654867346c53644d6d4542356d7a5a744c42386648324e657a734858753366764e755a42766d3362746c2f31794d68495936464f766f64546d354e773448546b794247725973574b354163785870557156597a44534568494d49534358574569775131417a695952446f3850587549376e6661574c56757364657657475a766a78495a6e6777594e4e4d6e795878667a343865503178426851547564507564733569416767556b4441774d4e50453676583738324c462f4747547834734445336c396d41644c6f6c6c4e56445244707a35677a6c587444514b70772f6631356a2b4c4a6c793270694e4451306c4b77464f462f6f363953706b37515777734c434e456146315141703551527a353836566f6c335978447462462b7063545a73326c51494968716d36486e596d78614a4669326958374c38376e636a76796d3650753442383739363931426355464b544678747765567a6462746d7a6166476f41454b544a354d637541644c4f6e54766c5041554b464c446934754b4d645571656357492b7033594539584c6d7a4b6e31677847524e323361564c596a424d516668326b4353665832375674744c735443344a776859414568414e7744427734594a4955634d546d6e3962463059782f4835526b6b6968557252695178646570554d5872303647533174456f534b686d6f6251674c685965486b3875644d6d564b617676363953764668586c65364457347a4441306e62356c422b6967716c5772537466625067615776766764557a6e64454a38635278795263444a4f4e387733686a3645693977656c39754f642f446751546b6536754a33564d4c703975336252486f6b414a6a5a57614d443449756f3963444151486b61716d5a2b2f767735315273326243684e6655543856594333796744335174694348477942774158677463436a74515066517548436855586a786f316c4c367746446a7836376479356b784172564b684144565771564346706f766f66694e526b7a35356462674c74634f4b774361356e7a70795a386d66506e736b507766664a6b534f4866426268364b514b474139544344364b734a6c4f4442796577766667652b336676312b614e4c7a4f526f30616b514649562f536e424c2b35484238666e36776b74646442796f4b6a4d386b6c467264326365723252465a554b344554503063776e7571373278664469705054364e476a715232696d4a573558616b364b56514f2f48767856544c645862392b585636766e3538663556436b37446f44786f3866543779415a304356396748776331534142474c467a435442664166464b525458476634532f42693449424552455271354152646a574b47434c4e6c7451475348672f334754744632364e41684b694d43773233386f68556348477a6356484a316b433979623239763668737a5a6f7a4567513349654869795547386756617055736f396a6350794541544f4a63565533576f7342384566775844646e7a687a7233627433567550476a6158795578664a316a5a765542312f382b5a4e61634d39662f3763734e33554843546c5245354f5a65523459584d364f436876312f486a7836302f366357345a733261557172684d6666496b534f69652f6675786c6955515971516b6e6a5451564265507030376165462f683139753339682f2b7557616a44336b3438614e6f79754444616153564d71554b613336396574726e6834656156563639666633313634647673616b535a4d4d45724c7a352b584c6c37554857654163506e785934714b4d6e4b56627759494672634b46437874386972584458694c6d4c4661736d505a6b445951534a557249636c52556c425561476972374f336675544f3039652f5930466f6e465158517a2f586670306b566135586e79354e46774f5753375938634f62564f7165655630434e793266763336667a714737762b444a334e446d726b39377962716165436445674b43322b422f327a31486e4b6a54427a6b3966767a59614c4d765242585264687a4767332b6b6a754e2f463767745134594d7635536d743763334d5139736f4b64506e314a3532624a6c5a414443426f4c55414c783639597043534869465a6d6d47674465583455594134455977347750664c677a7377694d6b4a4d5234447077795a51715634555949547a774f5a52596b38446a68526943656a5462383030502b7a4a38596e66773755744272382b624e795734456742326a58643049416e68703036625678754378564c306442765574464944484b747732363435382b664a7030556b386c2f416a4c617870767246363965725279344239737872676f63624f534378356c69785a516a6b6b485a776e4f37306a2b495a3354436436487a74324c4f453557643534522b58796f3065504b502f382b54506c467935634944633658373538786a684f396a387a6d4c656b3068516552347050544469347951787231363456586274324664753362786474327254353136646c477a397131436a796e6667465778326e5767784f44316a3250674e345a7a432f375365415631336f494b3744774c4d72516963524354744f4e56414e4563704b7a764d32773233392b7657544f6f5a787a35303752333241697863766b73754e3578627568303247664f444167575a303576547030396f692f6d6573413766622b676532345a4f447a757939787741414141424a52553545726b4a6767673d3d6b657954696d65733d22303b20302e33333b20302e36363b203122206b657953706c696e65733d22302e35203020302e3520313b20302e35203020302e3520313b20302e35203020302e3520313b20302e35203020302e3520313b22000000000000000000000000ef7c89f051ac48885b240eb53934b04fcf3339ab00000000000000000000000056965521ca0fd26d1a6733a87848c00bcd56a0ac0000000000000000000000006f2ff40f793776aa559644f52e58d83e21871ec3
Deployed Bytecode
0x6080604052600436106101e25760003560e01c80638da5cb5b11610102578063bd85b03911610095578063f1ae885611610064578063f1ae885614610794578063f23a6e61146107bf578063f242432a146107fc578063f2fde38b14610825576101e2565b8063bd85b039146106a0578063d48e638a146106dd578063e985e9c51461071a578063ec420c1114610757576101e2565b8063a0712d68116100d1578063a0712d68146105f3578063a22cb4651461060f578063a3f4df7e14610638578063bc197c8114610663576101e2565b80638da5cb5b1461051157806394056d171461053c578063967f2222146105795780639f093552146105b6576101e2565b8063385571251161017a578063535776f211610149578063535776f214610467578063715018a6146104a45780637c9c151d146104bb5780638d859f3e146104e6576101e2565b806338557125146103735780633e6e0859146103b05780634e1273f4146103ed5780634f558e791461042a576101e2565b8063204f0056116101b6578063204f0056146102c957806323e42156146102f45780632eb2c2d61461031f57806338151ec414610348576101e2565b8062fdd58e146101e757806301ffc9a71461022457806309e61a73146102615780630e89341c1461028c575b600080fd5b3480156101f357600080fd5b5061020e60048036038101906102099190613b20565b61084e565b60405161021b9190614b54565b60405180910390f35b34801561023057600080fd5b5061024b60048036038101906102469190613bc8565b610917565b604051610258919061474c565b60405180910390f35b34801561026d57600080fd5b50610276610929565b6040516102839190614782565b60405180910390f35b34801561029857600080fd5b506102b360048036038101906102ae9190613c84565b61094d565b6040516102c091906147ee565b60405180910390f35b3480156102d557600080fd5b506102de610a04565b6040516102eb91906147d3565b60405180910390f35b34801561030057600080fd5b50610309610a28565b604051610316919061479d565b60405180910390f35b34801561032b57600080fd5b5061034660048036038101906103419190613996565b610a4c565b005b34801561035457600080fd5b5061035d610aed565b60405161036a9190614b54565b60405180910390f35b34801561037f57600080fd5b5061039a60048036038101906103959190613d79565b610af7565b6040516103a791906146d1565b60405180910390f35b3480156103bc57600080fd5b506103d760048036038101906103d29190613c84565b610d24565b6040516103e49190614b54565b60405180910390f35b3480156103f957600080fd5b50610414600480360381019061040f9190613b5c565b610d44565b60405161042191906146f3565b60405180910390f35b34801561043657600080fd5b50610451600480360381019061044c9190613c84565b610ef5565b60405161045e919061474c565b60405180910390f35b34801561047357600080fd5b5061048e60048036038101906104899190613cd6565b610f09565b60405161049b91906147ee565b60405180910390f35b3480156104b057600080fd5b506104b9611011565b005b3480156104c757600080fd5b506104d0611099565b6040516104dd91906147b8565b60405180910390f35b3480156104f257600080fd5b506104fb6110bd565b6040516105089190614b54565b60405180910390f35b34801561051d57600080fd5b506105266110c8565b60405161053391906145b6565b60405180910390f35b34801561054857600080fd5b50610563600480360381019061055e9190613c84565b6110f2565b60405161057091906146f3565b60405180910390f35b34801561058557600080fd5b506105a0600480360381019061059b9190613d25565b61115d565b6040516105ad9190614b32565b60405180910390f35b3480156105c257600080fd5b506105dd60048036038101906105d89190613c84565b6111c6565b6040516105ea9190614b54565b60405180910390f35b61060d60048036038101906106089190613c84565b6111f9565b005b34801561061b57600080fd5b5061063660048036038101906106319190613ae4565b6116a2565b005b34801561064457600080fd5b5061064d6116b8565b60405161065a91906147ee565b60405180910390f35b34801561066f57600080fd5b5061068a60048036038101906106859190613996565b6116f1565b6040516106979190614767565b60405180910390f35b3480156106ac57600080fd5b506106c760048036038101906106c29190613c84565b6119ac565b6040516106d49190614b54565b60405180910390f35b3480156106e957600080fd5b5061070460048036038101906106ff9190613c84565b6119c9565b60405161071191906145b6565b60405180910390f35b34801561072657600080fd5b50610741600480360381019061073c919061395a565b611a06565b60405161074e919061474c565b60405180910390f35b34801561076357600080fd5b5061077e60048036038101906107799190613c84565b611a9a565b60405161078b9190614b10565b60405180910390f35b3480156107a057600080fd5b506107a9611ca2565b6040516107b691906147ee565b60405180910390f35b3480156107cb57600080fd5b506107e660048036038101906107e19190613a55565b611cdb565b6040516107f39190614767565b60405180910390f35b34801561080857600080fd5b50610823600480360381019061081e9190613a55565b611df9565b005b34801561083157600080fd5b5061084c60048036038101906108479190613931565b611e9a565b005b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156108bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108b690614850565b60405180910390fd5b60008083815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600061092282611f92565b9050919050565b7f0000000000000000000000006f2ff40f793776aa559644f52e58d83e21871ec381565b60607f0000000000000000000000009b743a1928cb9fa61f8a9b0ca686673c28f19f4073ffffffffffffffffffffffffffffffffffffffff16631301f0f5836040518263ffffffff1660e01b81526004016109a89190614b54565b60006040518083038186803b1580156109c057600080fd5b505afa1580156109d4573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906109fd9190613c43565b9050919050565b7f00000000000000000000000056965521ca0fd26d1a6733a87848c00bcd56a0ac81565b7f0000000000000000000000009b743a1928cb9fa61f8a9b0ca686673c28f19f4081565b610a5461200c565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480610a9a5750610a9985610a9461200c565b611a06565b5b610ad9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ad090614930565b60405180910390fd5b610ae68585858585612014565b5050505050565b6000600654905090565b606060006006549050600185108015610b105750600184105b15610b1d57809450600193505b60008567ffffffffffffffff811115610b5f577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015610b9857816020015b610b8561349f565b815260200190600190039081610b7d5790505b50905060008415610c6057600060018714610bd657600188600189610bbd9190614eb3565b610bc79190614e59565b610bd19190614dd2565b610bd9565b60015b90505b838111158015610beb57508782105b15610c5a57610bf981611a9a565b838381518110610c32577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001018190525081610c47906150ad565b915080610c53906150ad565b9050610bdc565b50610d17565b600060018714610c9257600187610c779190614eb3565b88610c829190614e59565b84610c8d9190614eb3565b610c94565b835b90505b600081118015610ca657508782105b15610d1557610cb481611a9a565b838381518110610ced577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001018190525081610d02906150ad565b915080610d0e90615052565b9050610c97565b505b8193505050509392505050565b600060076000838152602001908152602001600020805490509050919050565b60608151835114610d8a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d8190614a30565b60405180910390fd5b6000835167ffffffffffffffff811115610dcd577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015610dfb5781602001602082028036833780820191505090505b50905060005b8451811015610eea57610e94858281518110610e46577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151858381518110610e87577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015161084e565b828281518110610ecd577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101818152505080610ee3906150ad565b9050610e01565b508091505092915050565b600080610f01836119ac565b119050919050565b60606000610f16856119ac565b11610f56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4d906149d0565b60405180910390fd5b7f0000000000000000000000009b743a1928cb9fa61f8a9b0ca686673c28f19f4073ffffffffffffffffffffffffffffffffffffffff1663535776f28585856040518463ffffffff1660e01b8152600401610fb393929190614b6f565b60006040518083038186803b158015610fcb57600080fd5b505afa158015610fdf573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906110089190613c43565b90509392505050565b61101961200c565b73ffffffffffffffffffffffffffffffffffffffff166110376110c8565b73ffffffffffffffffffffffffffffffffffffffff161461108d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161108490614970565b60405180910390fd5b6110976000612382565b565b7f000000000000000000000000ef7c89f051ac48885b240eb53934b04fcf3339ab81565b66f8b0a10e47000081565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60606007600083815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561115157602002820191906000526020600020905b81548152602001906001019080831161113d575b50505050509050919050565b61116561352a565b60405180604001604052806040518060400160405280600481526020017f303078300000000000000000000000000000000000000000000000000000000081525081526020016111bb8460000151600180610f09565b815250905092915050565b60006111d1826119ac565b60076000848152602001908152602001600020805490506111f29190614eb3565b9050919050565b6002600554141561123f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161123690614ad0565b60405180910390fd5b60026005819055506008600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156112e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e0906148f0565b60405180910390fd5b66f8b0a10e4700003414611332576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161132990614af0565b60405180910390fd5b600061133d826111c6565b1161137d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611374906148d0565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff166008600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561141f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611416906148b0565b60405180910390fd5b60006114296110c8565b9050600060023461143a9190614e28565b905060006008600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1682604051611495906145a1565b60006040518083038185875af1925050503d80600081146114d2576040519150601f19603f3d011682016040523d82523d6000602084013e6114d7565b606091505b5050905060008373ffffffffffffffffffffffffffffffffffffffff1683604051611501906145a1565b60006040518083038185875af1925050503d806000811461153e576040519150601f19603f3d011682016040523d82523d6000602084013e611543565b606091505b505090508180156115515750805b611590576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611587906149f0565b60405180910390fd5b61159a3386612448565b7f0000000000000000000000006f2ff40f793776aa559644f52e58d83e21871ec373ffffffffffffffffffffffffffffffffffffffff1663faa059b33360405180608001604052808981526020013373ffffffffffffffffffffffffffffffffffffffff1681526020016040518060200160405280600081525081526020016000151581525060016040518463ffffffff1660e01b815260040161164093929190614693565b602060405180830381600087803b15801561165a57600080fd5b505af115801561166e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116929190613cad565b5050505050600160058190555050565b6116b46116ad61200c565b8383612468565b5050565b6040518060400160405280601481526020017f4c6174656e7420576f726b7320c2b7203030783000000000000000000000000081525081565b60006117036116fe61200c565b6125d5565b6001845111801561171657506007845111155b611755576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161174c90614a90565b60405180910390fd5b60006117618686612666565b9050600080600090505b8651811015611996577f00000000000000000000000056965521ca0fd26d1a6733a87848c00bcd56a0ac73ffffffffffffffffffffffffffffffffffffffff1663faa059b38960405180608001604052808b86815181106117f5577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015181526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020016040518060200160405280600081525081526020016001151581525060016040518463ffffffff1660e01b815260040161185a93929190614693565b602060405180830381600087803b15801561187457600080fd5b505af1158015611888573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ac9190613cad565b91507f0000000000000000000000006f2ff40f793776aa559644f52e58d83e21871ec373ffffffffffffffffffffffffffffffffffffffff16632a843ee08360405180608001604052808781526020018c73ffffffffffffffffffffffffffffffffffffffff168152602001604051806020016040528060008152508152602001600015158152506040518363ffffffff1660e01b8152600401611951929190614bd4565b600060405180830381600087803b15801561196b57600080fd5b505af115801561197f573d6000803e3d6000fd5b50505050808061198e906150ad565b91505061176b565b5063bc197c8160e01b9250505095945050505050565b600060036000838152602001908152602001600020549050919050565b60006008600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b611aa261349f565b6040518060e00160405280838152602001611abc846119c9565b73ffffffffffffffffffffffffffffffffffffffff1681526020017f0000000000000000000000009b743a1928cb9fa61f8a9b0ca686673c28f19f4073ffffffffffffffffffffffffffffffffffffffff16630fcec87e856040518263ffffffff1660e01b8152600401611b309190614ba6565b60006040518083038186803b158015611b4857600080fd5b505afa158015611b5c573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611b859190613c43565b8152602001611b9684600180610f09565b81526020017f0000000000000000000000009b743a1928cb9fa61f8a9b0ca686673c28f19f4073ffffffffffffffffffffffffffffffffffffffff166371692b7f856040518263ffffffff1660e01b8152600401611bf49190614b54565b60206040518083038186803b158015611c0c57600080fd5b505afa158015611c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c449190613c1a565b6001811115611c7c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8152602001611c8a84610d24565b8152602001611c98846111c6565b8152509050919050565b6040518060400160405280600c81526020017f6c6174656e742e776f726b73000000000000000000000000000000000000000081525081565b6000611ced611ce861200c565b6125d5565b7f00000000000000000000000056965521ca0fd26d1a6733a87848c00bcd56a0ac73ffffffffffffffffffffffffffffffffffffffff1663faa059b38660405180608001604052808881526020018973ffffffffffffffffffffffffffffffffffffffff1681526020016040518060200160405280600081525081526020016000151581525060016040518463ffffffff1660e01b8152600401611d9393929190614693565b602060405180830381600087803b158015611dad57600080fd5b505af1158015611dc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de59190613cad565b5063f23a6e6160e01b905095945050505050565b611e0161200c565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480611e475750611e4685611e4161200c565b611a06565b5b611e86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e7d90614890565b60405180910390fd5b611e9385858585856127ad565b5050505050565b611ea261200c565b73ffffffffffffffffffffffffffffffffffffffff16611ec06110c8565b73ffffffffffffffffffffffffffffffffffffffff1614611f16576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f0d90614970565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611f86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f7d90614870565b60405180910390fd5b611f8f81612382565b50565b60007f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612005575061200482612a49565b5b9050919050565b600033905090565b8151835114612058576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161204f90614a70565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156120c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120bf90614910565b60405180910390fd5b60006120d261200c565b90506120e2818787878787612b2b565b60005b84518110156122df576000858281518110612129577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101519050600085838151811061216e577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101519050600080600084815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561220f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161220690614950565b60405180910390fd5b81810360008085815260200190815260200160002060008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508160008085815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546122c49190614dd2565b92505081905550505050806122d8906150ad565b90506120e5565b508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051612356929190614715565b60405180910390a461236c818787878787612b41565b61237a818787878787612b49565b505050505050565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6124648282600160405180602001604052806000815250612d30565b5050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156124d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124ce90614a10565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516125c8919061474c565b60405180910390a3505050565b7f000000000000000000000000ef7c89f051ac48885b240eb53934b04fcf3339ab73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612663576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161265a906149b0565b60405180910390fd5b50565b60006001825111801561267b57506007825111155b6126ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126b190614a50565b60405180910390fd5b600660008154809291906126cd906150ad565b91905055508160076000600654815260200190815260200160002090805190602001906126fb929190613544565b508260086000600654815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff166006547f5e4c8fdadf6d741f750742bca018b78b7d181d8de6dbe8df3206a2f432dad9ea60405160405180910390a36127a283600654612448565b600654905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561281d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161281490614910565b60405180910390fd5b600061282761200c565b9050600061283485612d42565b9050600061284185612d42565b9050612851838989858589612b2b565b600080600088815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050858110156128e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128df90614950565b60405180910390fd5b85810360008089815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508560008089815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461299d9190614dd2565b925050819055508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628a8a604051612a1a929190614c04565b60405180910390a4612a30848a8a86868a612b41565b612a3e848a8a8a8a8a612e08565b505050505050505050565b60007fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612b1457507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80612b245750612b2382612fef565b5b9050919050565b612b39868686868686613059565b505050505050565b505050505050565b612b688473ffffffffffffffffffffffffffffffffffffffff166132c3565b15612d28578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b8152600401612bae9594939291906145d1565b602060405180830381600087803b158015612bc857600080fd5b505af1925050508015612bf957506040513d601f19601f82011682018060405250810190612bf69190613bf1565b60015b612c9f57612c056151b2565b806308c379a01415612c625750612c1a6157bb565b80612c255750612c64565b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c5991906147ee565b60405180910390fd5b505b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c9690614810565b60405180910390fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612d26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d1d90614830565b60405180910390fd5b505b505050505050565b612d3c848484846132e6565b50505050565b60606000600167ffffffffffffffff811115612d87577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015612db55781602001602082028036833780820191505090505b5090508281600081518110612df3577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101818152505080915050919050565b612e278473ffffffffffffffffffffffffffffffffffffffff166132c3565b15612fe7578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b8152600401612e6d959493929190614639565b602060405180830381600087803b158015612e8757600080fd5b505af1925050508015612eb857506040513d601f19601f82011682018060405250810190612eb59190613bf1565b60015b612f5e57612ec46151b2565b806308c379a01415612f215750612ed96157bb565b80612ee45750612f23565b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f1891906147ee565b60405180910390fd5b505b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f5590614810565b60405180910390fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612fe5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612fdc90614830565b60405180910390fd5b505b505050505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b613067868686868686613497565b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614156131655760005b8351811015613163578281815181106130e1577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015160036000868481518110613126577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101518152602001908152602001600020600082825461314b9190614dd2565b925050819055508061315c906150ad565b905061309f565b505b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156132bb5760005b83518110156132b95760008482815181106131e1577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015190506000848381518110613226577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015190506000600360008481526020019081526020016000205490508181101561328b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161328290614990565b60405180910390fd5b8181036003600085815260200190815260200160002081905550505050806132b2906150ad565b905061319d565b505b505050505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415613356576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161334d90614ab0565b60405180910390fd5b600061336061200c565b9050600061336d85612d42565b9050600061337a85612d42565b905061338b83600089858589612b2b565b8460008088815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546133ea9190614dd2565b925050819055508673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628989604051613468929190614c04565b60405180910390a461347f83600089858589612b41565b61348e83600089898989612e08565b50505050505050565b505050505050565b6040518060e0016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081526020016060815260200160006001811115613516577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b815260200160008152602001600081525090565b604051806040016040528060608152602001606081525090565b828054828255906000526020600020908101928215613580579160200282015b8281111561357f578251825591602001919060010190613564565b5b50905061358d9190613591565b5090565b5b808211156135aa576000816000905550600101613592565b5090565b60006135c16135bc84614c52565b614c2d565b905080838252602082019050828560208602820111156135e057600080fd5b60005b8581101561361057816135f68882613740565b8452602084019350602083019250506001810190506135e3565b5050509392505050565b600061362d61362884614c7e565b614c2d565b9050808382526020820190508285602086028201111561364c57600080fd5b60005b8581101561367c57816136628882613907565b84526020840193506020830192505060018101905061364f565b5050509392505050565b600061369961369484614caa565b614c2d565b9050828152602081018484840111156136b157600080fd5b6136bc848285615010565b509392505050565b60006136d76136d284614cdb565b614c2d565b9050828152602081018484840111156136ef57600080fd5b6136fa848285615010565b509392505050565b600061371561371084614cdb565b614c2d565b90508281526020810184848401111561372d57600080fd5b61373884828561501f565b509392505050565b60008135905061374f81615865565b92915050565b600082601f83011261376657600080fd5b81356137768482602086016135ae565b91505092915050565b600082601f83011261379057600080fd5b81356137a084826020860161361a565b91505092915050565b6000813590506137b88161587c565b92915050565b6000813590506137cd81615893565b92915050565b6000815190506137e281615893565b92915050565b600082601f8301126137f957600080fd5b8135613809848260208601613686565b91505092915050565b600081519050613821816158aa565b92915050565b600082601f83011261383857600080fd5b81356138488482602086016136c4565b91505092915050565b600082601f83011261386257600080fd5b8151613872848260208601613702565b91505092915050565b60006080828403121561388d57600080fd5b6138976080614c2d565b905060006138a784828501613907565b60008301525060206138bb84828501613740565b602083015250604082013567ffffffffffffffff8111156138db57600080fd5b6138e784828501613827565b60408301525060606138fb848285016137a9565b60608301525092915050565b600081359050613916816158ba565b92915050565b60008151905061392b816158ba565b92915050565b60006020828403121561394357600080fd5b600061395184828501613740565b91505092915050565b6000806040838503121561396d57600080fd5b600061397b85828601613740565b925050602061398c85828601613740565b9150509250929050565b600080600080600060a086880312156139ae57600080fd5b60006139bc88828901613740565b95505060206139cd88828901613740565b945050604086013567ffffffffffffffff8111156139ea57600080fd5b6139f68882890161377f565b935050606086013567ffffffffffffffff811115613a1357600080fd5b613a1f8882890161377f565b925050608086013567ffffffffffffffff811115613a3c57600080fd5b613a48888289016137e8565b9150509295509295909350565b600080600080600060a08688031215613a6d57600080fd5b6000613a7b88828901613740565b9550506020613a8c88828901613740565b9450506040613a9d88828901613907565b9350506060613aae88828901613907565b925050608086013567ffffffffffffffff811115613acb57600080fd5b613ad7888289016137e8565b9150509295509295909350565b60008060408385031215613af757600080fd5b6000613b0585828601613740565b9250506020613b16858286016137a9565b9150509250929050565b60008060408385031215613b3357600080fd5b6000613b4185828601613740565b9250506020613b5285828601613907565b9150509250929050565b60008060408385031215613b6f57600080fd5b600083013567ffffffffffffffff811115613b8957600080fd5b613b9585828601613755565b925050602083013567ffffffffffffffff811115613bb257600080fd5b613bbe8582860161377f565b9150509250929050565b600060208284031215613bda57600080fd5b6000613be8848285016137be565b91505092915050565b600060208284031215613c0357600080fd5b6000613c11848285016137d3565b91505092915050565b600060208284031215613c2c57600080fd5b6000613c3a84828501613812565b91505092915050565b600060208284031215613c5557600080fd5b600082015167ffffffffffffffff811115613c6f57600080fd5b613c7b84828501613851565b91505092915050565b600060208284031215613c9657600080fd5b6000613ca484828501613907565b91505092915050565b600060208284031215613cbf57600080fd5b6000613ccd8482850161391c565b91505092915050565b600080600060608486031215613ceb57600080fd5b6000613cf986828701613907565b9350506020613d0a868287016137a9565b9250506040613d1b868287016137a9565b9150509250925092565b60008060408385031215613d3857600080fd5b6000613d4685828601613907565b925050602083013567ffffffffffffffff811115613d6357600080fd5b613d6f8582860161387b565b9150509250929050565b600080600060608486031215613d8e57600080fd5b6000613d9c86828701613907565b9350506020613dad86828701613907565b9250506040613dbe868287016137a9565b9150509250925092565b6000613dd48383614396565b905092915050565b6000613de88383614583565b60208301905092915050565b613dfd81614ee7565b82525050565b613e0c81614ee7565b82525050565b6000613e1d82614d2c565b613e278185614d72565b935083602082028501613e3985614d0c565b8060005b85811015613e755784840389528151613e568582613dc8565b9450613e6183614d58565b925060208a01995050600181019050613e3d565b50829750879550505050505092915050565b6000613e9282614d37565b613e9c8185614d83565b9350613ea783614d1c565b8060005b83811015613ed8578151613ebf8882613ddc565b9750613eca83614d65565b925050600181019050613eab565b5085935050505092915050565b613eee81614ef9565b82525050565b613efd81614ef9565b82525050565b613f0c81614f05565b82525050565b6000613f1d82614d42565b613f278185614d94565b9350613f3781856020860161501f565b613f40816151d4565b840191505092915050565b613f5481614f6e565b82525050565b613f6381614f92565b82525050565b613f7281614fb6565b82525050565b613f8181614fda565b82525050565b613f9081614ffe565b82525050565b6000613fa182614d4d565b613fab8185614db0565b9350613fbb81856020860161501f565b613fc4816151d4565b840191505092915050565b6000613fda82614d4d565b613fe48185614dc1565b9350613ff481856020860161501f565b613ffd816151d4565b840191505092915050565b6000614015603483614dc1565b9150614020826151f2565b604082019050919050565b6000614038602883614dc1565b915061404382615241565b604082019050919050565b600061405b602b83614dc1565b915061406682615290565b604082019050919050565b600061407e602683614dc1565b9150614089826152df565b604082019050919050565b60006140a1602983614dc1565b91506140ac8261532e565b604082019050919050565b60006140c4600f83614dc1565b91506140cf8261537d565b602082019050919050565b60006140e7600b83614dc1565b91506140f2826153a6565b602082019050919050565b600061410a600c83614dc1565b9150614115826153cf565b602082019050919050565b600061412d602583614dc1565b9150614138826153f8565b604082019050919050565b6000614150603283614dc1565b915061415b82615447565b604082019050919050565b6000614173602a83614dc1565b915061417e82615496565b604082019050919050565b6000614196602083614dc1565b91506141a1826154e5565b602082019050919050565b60006141b9602883614dc1565b91506141c48261550e565b604082019050919050565b60006141dc601283614dc1565b91506141e78261555d565b602082019050919050565b60006141ff600e83614dc1565b915061420a82615586565b602082019050919050565b6000614222600083614da5565b915061422d826155af565b600082019050919050565b6000614245600083614dc1565b9150614250826155af565b600082019050919050565b6000614268601883614dc1565b9150614273826155b2565b602082019050919050565b600061428b602983614dc1565b9150614296826155db565b604082019050919050565b60006142ae602983614dc1565b91506142b98261562a565b604082019050919050565b60006142d1601183614dc1565b91506142dc82615679565b602082019050919050565b60006142f4602883614dc1565b91506142ff826156a2565b604082019050919050565b6000614317601583614dc1565b9150614322826156f1565b602082019050919050565b600061433a602183614dc1565b91506143458261571a565b604082019050919050565b600061435d601f83614dc1565b915061436882615769565b602082019050919050565b6000614380600d83614dc1565b915061438b82615792565b602082019050919050565b600060e0830160008301516143ae6000860182614583565b5060208301516143c16020860182613df4565b50604083015184820360408601526143d98282613f96565b915050606083015184820360608601526143f38282613f96565b91505060808301516144086080860182613f87565b5060a083015161441b60a0860182614583565b5060c083015161442e60c0860182614583565b508091505092915050565b600060e0830160008301516144516000860182614583565b5060208301516144646020860182613df4565b506040830151848203604086015261447c8282613f96565b915050606083015184820360608601526144968282613f96565b91505060808301516144ab6080860182613f87565b5060a08301516144be60a0860182614583565b5060c08301516144d160c0860182614583565b508091505092915050565b600060408301600083015184820360008601526144f98282613f96565b915050602083015184820360208601526145138282613f96565b9150508091505092915050565b60006080830160008301516145386000860182614583565b50602083015161454b6020860182613df4565b50604083015184820360408601526145638282613f96565b91505060608301516145786060860182613ee5565b508091505092915050565b61458c81614f64565b82525050565b61459b81614f64565b82525050565b60006145ac82614215565b9150819050919050565b60006020820190506145cb6000830184613e03565b92915050565b600060a0820190506145e66000830188613e03565b6145f36020830187613e03565b81810360408301526146058186613e87565b905081810360608301526146198185613e87565b9050818103608083015261462d8184613f12565b90509695505050505050565b600060a08201905061464e6000830188613e03565b61465b6020830187613e03565b6146686040830186614592565b6146756060830185614592565b81810360808301526146878184613f12565b90509695505050505050565b60006060820190506146a86000830186613e03565b81810360208301526146ba8185614520565b90506146c96040830184613ef4565b949350505050565b600060208201905081810360008301526146eb8184613e12565b905092915050565b6000602082019050818103600083015261470d8184613e87565b905092915050565b6000604082019050818103600083015261472f8185613e87565b905081810360208301526147438184613e87565b90509392505050565b60006020820190506147616000830184613ef4565b92915050565b600060208201905061477c6000830184613f03565b92915050565b60006020820190506147976000830184613f4b565b92915050565b60006020820190506147b26000830184613f5a565b92915050565b60006020820190506147cd6000830184613f69565b92915050565b60006020820190506147e86000830184613f78565b92915050565b600060208201905081810360008301526148088184613fcf565b905092915050565b6000602082019050818103600083015261482981614008565b9050919050565b600060208201905081810360008301526148498161402b565b9050919050565b600060208201905081810360008301526148698161404e565b9050919050565b6000602082019050818103600083015261488981614071565b9050919050565b600060208201905081810360008301526148a981614094565b9050919050565b600060208201905081810360008301526148c9816140b7565b9050919050565b600060208201905081810360008301526148e9816140da565b9050919050565b60006020820190508181036000830152614909816140fd565b9050919050565b6000602082019050818103600083015261492981614120565b9050919050565b6000602082019050818103600083015261494981614143565b9050919050565b6000602082019050818103600083015261496981614166565b9050919050565b6000602082019050818103600083015261498981614189565b9050919050565b600060208201905081810360008301526149a9816141ac565b9050919050565b600060208201905081810360008301526149c9816141cf565b9050919050565b600060208201905081810360008301526149e9816141f2565b9050919050565b60006020820190508181036000830152614a098161425b565b9050919050565b60006020820190508181036000830152614a298161427e565b9050919050565b60006020820190508181036000830152614a49816142a1565b9050919050565b60006020820190508181036000830152614a69816142c4565b9050919050565b60006020820190508181036000830152614a89816142e7565b9050919050565b60006020820190508181036000830152614aa98161430a565b9050919050565b60006020820190508181036000830152614ac98161432d565b9050919050565b60006020820190508181036000830152614ae981614350565b9050919050565b60006020820190508181036000830152614b0981614373565b9050919050565b60006020820190508181036000830152614b2a8184614439565b905092915050565b60006020820190508181036000830152614b4c81846144dc565b905092915050565b6000602082019050614b696000830184614592565b92915050565b6000606082019050614b846000830186614592565b614b916020830185613ef4565b614b9e6040830184613ef4565b949350505050565b6000604082019050614bbb6000830184614592565b8181036020830152614bcc81614238565b905092915050565b6000604082019050614be96000830185614592565b8181036020830152614bfb8184614520565b90509392505050565b6000604082019050614c196000830185614592565b614c266020830184614592565b9392505050565b6000614c37614c48565b9050614c43828261507c565b919050565b6000604051905090565b600067ffffffffffffffff821115614c6d57614c6c615183565b5b602082029050602081019050919050565b600067ffffffffffffffff821115614c9957614c98615183565b5b602082029050602081019050919050565b600067ffffffffffffffff821115614cc557614cc4615183565b5b614cce826151d4565b9050602081019050919050565b600067ffffffffffffffff821115614cf657614cf5615183565b5b614cff826151d4565b9050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b6000614ddd82614f64565b9150614de883614f64565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115614e1d57614e1c6150f6565b5b828201905092915050565b6000614e3382614f64565b9150614e3e83614f64565b925082614e4e57614e4d615125565b5b828204905092915050565b6000614e6482614f64565b9150614e6f83614f64565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614ea857614ea76150f6565b5b828202905092915050565b6000614ebe82614f64565b9150614ec983614f64565b925082821015614edc57614edb6150f6565b5b828203905092915050565b6000614ef282614f44565b9050919050565b60008115159050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050614f3f82615851565b919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000614f7982614f80565b9050919050565b6000614f8b82614f44565b9050919050565b6000614f9d82614fa4565b9050919050565b6000614faf82614f44565b9050919050565b6000614fc182614fc8565b9050919050565b6000614fd382614f44565b9050919050565b6000614fe582614fec565b9050919050565b6000614ff782614f44565b9050919050565b600061500982614f31565b9050919050565b82818337600083830152505050565b60005b8381101561503d578082015181840152602081019050615022565b8381111561504c576000848401525b50505050565b600061505d82614f64565b91506000821415615071576150706150f6565b5b600182039050919050565b615085826151d4565b810181811067ffffffffffffffff821117156150a4576150a3615183565b5b80604052505050565b60006150b882614f64565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156150eb576150ea6150f6565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060033d11156151d15760046000803e6151ce6000516151e5565b90505b90565b6000601f19601f8301169050919050565b60008160e01c9050919050565b7f455243313135353a207472616e7366657220746f206e6f6e204552433131353560008201527f526563656976657220696d706c656d656e746572000000000000000000000000602082015250565b7f455243313135353a204552433131353552656365697665722072656a6563746560008201527f6420746f6b656e73000000000000000000000000000000000000000000000000602082015250565b7f455243313135353a2062616c616e636520717565727920666f7220746865207a60008201527f65726f2061646472657373000000000000000000000000000000000000000000602082015250565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b7f455243313135353a2063616c6c6572206973206e6f74206f776e6572206e6f7260008201527f20617070726f7665640000000000000000000000000000000000000000000000602082015250565b7f4e4f5f43524541544f525f4d494e540000000000000000000000000000000000600082015250565b7f554e415641494c41424c45000000000000000000000000000000000000000000600082015250565b7f434f4d505f43524541544f520000000000000000000000000000000000000000600082015250565b7f455243313135353a207472616e7366657220746f20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b7f455243313135353a207472616e736665722063616c6c6572206973206e6f742060008201527f6f776e6572206e6f7220617070726f7665640000000000000000000000000000602082015250565b7f455243313135353a20696e73756666696369656e742062616c616e636520666f60008201527f72207472616e7366657200000000000000000000000000000000000000000000602082015250565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b7f455243313135353a206275726e20616d6f756e74206578636565647320746f7460008201527f616c537570706c79000000000000000000000000000000000000000000000000602082015250565b7f4f4e4c595f373758375f41434345505445440000000000000000000000000000600082015250565b7f444f45535f4e4f545f4558495354000000000000000000000000000000000000600082015250565b50565b7f494e5445524e414c5f45544845525f54585f4641494c45440000000000000000600082015250565b7f455243313135353a2073657474696e6720617070726f76616c2073746174757360008201527f20666f722073656c660000000000000000000000000000000000000000000000602082015250565b7f455243313135353a206163636f756e747320616e6420696473206c656e67746860008201527f206d69736d617463680000000000000000000000000000000000000000000000602082015250565b7f4d494e5f325f4d41585f375f574f524b53000000000000000000000000000000600082015250565b7f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060008201527f6d69736d61746368000000000000000000000000000000000000000000000000602082015250565b7f49445f434f554e545f4f55545f4f465f52414e47450000000000000000000000600082015250565b7f455243313135353a206d696e7420746f20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b7f494e56414c49445f56414c554500000000000000000000000000000000000000600082015250565b600060443d10156157cb5761584e565b6157d3614c48565b60043d036004823e80513d602482011167ffffffffffffffff821117156157fb57505061584e565b808201805167ffffffffffffffff811115615819575050505061584e565b80602083010160043d03850181111561583657505050505061584e565b6158458260200185018661507c565b82955050505050505b90565b6002811061586257615861615154565b5b50565b61586e81614ee7565b811461587957600080fd5b50565b61588581614ef9565b811461589057600080fd5b50565b61589c81614f05565b81146158a757600080fd5b50565b600281106158b757600080fd5b50565b6158c381614f64565b81146158ce57600080fd5b5056fea264697066735822122060466c411f445ed89d0fb9d682479b0fdabbb7dbaba1f8f848763b0df687befe64736f6c63430008040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ef7c89f051ac48885b240eb53934b04fcf3339ab00000000000000000000000056965521ca0fd26d1a6733a87848c00bcd56a0ac0000000000000000000000006f2ff40f793776aa559644f52e58d83e21871ec3
-----Decoded View---------------
Arg [0] : seven7x7_ (address): 0xEF7c89F051ac48885b240eb53934B04fcF3339ab
Arg [1] : seven7x7_ltnt_issuer_ (address): 0x56965521CA0fd26d1A6733a87848C00bcd56a0Ac
Arg [2] : ltnt_ (address): 0x6f2Ff40F793776Aa559644F52e58D83E21871EC3
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000ef7c89f051ac48885b240eb53934b04fcf3339ab
Arg [1] : 00000000000000000000000056965521ca0fd26d1a6733a87848c00bcd56a0ac
Arg [2] : 0000000000000000000000006f2ff40f793776aa559644f52e58d83e21871ec3
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.