ETH Price: $3,179.87 (+3.21%)

Token

Homies of Web3 (HoW3)
 

Overview

Max Total Supply

690 HoW3

Holders

411

Market

Volume (24H)

0.0652 ETH

Min Price (24H)

$69.00 @ 0.021700 ETH

Max Price (24H)

$69.32 @ 0.021800 ETH
Filtered by Token Holder
mangchie.eth
Balance
5 HoW3
0xC4ed938CAeb36008493aA2E327140a8a3324d193
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
HOW

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 1000 runs

Other Settings:
london EvmVersion
File 1 of 24 : Homies.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: [EIP721] HOW NFT
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice ERC721 Implementation with:
 *         Enhanced EIP173 - Ownership via roles
 *         EIP2981 - NFT Royalties
 *         PaymentSplitter v2 - For "ETH" payments
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.17 <0.9.0;

import "./Max-721-2981-PSv2.sol";
import "./lib/721.sol";
import "./lib/Lists.sol";
import "./lib/CountersV2.sol";
import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts/utils/Base64.sol";

contract HOW is Max721 {

  using Lib721 for Lib721.Token;
  using Lists for Lists.Access;
  using CountersV2 for CountersV2.Counter;

  CountersV2.Counter internal theTokenID;

  event Claimed(uint256 index, address account, uint256 amount, string what);

  constructor(
    string memory _name
  , string memory _symbol
  , address _admin
  , address _dev
  , address _owner
  , uint256 _start
  ) {
      __Max721_init(_name, _symbol, _admin, _dev, _owner);
      theTokenID.set(_start);
  }

  // set time block
  modifier preSale() {
    if (block.timestamp < startTime + period && block.timestamp >= startTime) {
      _;
    } else {
    revert Unauthorized();
    }
  }

  modifier Sale() {
    if (block.timestamp >= startTime + period) {
      _;
    } else {
    revert Unauthorized();
    }
  }

  function setTime(
    uint256 _start
  , uint256 _period
  ) external
    onlyDev() {
    startTime = _start;
    period = _period;
  }

  function showTimes()
    external
    view
    returns (uint256, uint256) {
    return (startTime, startTime + period);
  }

  function setCap(
    uint256 _amount
  ) external
    onlyDev() {
    maxCap = _amount;
  }

  function setMerks(
    bytes32 _admin
  , bytes32 _homies
  , bytes32 _normies
  ) external
    onlyDev() {
    admin = _admin;
    homies = _homies;
    normies = _normies;
  }

  function isClaimedAdmin(
    uint256 index
  ) public
    view
    returns (bool) {
    uint256 claimedWordIndex = index / 256;
    uint256 claimedBitIndex = index % 256;
    uint256 claimedWord = claimedAdmin[claimedWordIndex];
    uint256 mask = (1 << claimedBitIndex);
    return claimedWord & mask == mask;
  }

  function isClaimedHomies(
    uint256 index
  ) public
    view
    returns (bool) {
    uint256 claimedWordIndex = index / 256;
    uint256 claimedBitIndex = index % 256;
    uint256 claimedWord = claimedHomies[claimedWordIndex];
    uint256 mask = (1 << claimedBitIndex);
    return claimedWord & mask == mask;
  }

  function isClaimedNormies(
    uint256 index
  ) public
    view
    returns (bool) {
    uint256 claimedWordIndex = index / 256;
    uint256 claimedBitIndex = index % 256;
    uint256 claimedWord = claimedNormies[claimedWordIndex];
    uint256 mask = (1 << claimedBitIndex);
    return claimedWord & mask == mask;
  }

  function _setClaimedAdmin(
    uint256 index
  ) internal {
    uint256 claimedWordIndex = index / 256;
    uint256 claimedBitIndex = index % 256;
    claimedAdmin[claimedWordIndex] = claimedAdmin[claimedWordIndex] | (1 << claimedBitIndex);
  }

  function _setClaimedHomies(
    uint256 index
  ) internal {
    uint256 claimedWordIndex = index / 256;
    uint256 claimedBitIndex = index % 256;
    claimedHomies[claimedWordIndex] = claimedHomies[claimedWordIndex] | (1 << claimedBitIndex);
  }

  function _setClaimedNormies(
    uint256 index
  ) internal {
    uint256 claimedWordIndex = index / 256;
    uint256 claimedBitIndex = index % 256;
    claimedNormies[claimedWordIndex] = claimedNormies[claimedWordIndex] | (1 << claimedBitIndex);
  }

  function adminMint(
    uint256 index
  , address account
  , uint256 amount
  , bytes32[] calldata merkleProof
  ) external
    preSale() {
    if (startTime == 0) {
      revert Unauthorized();
    }
    if (isClaimedAdmin(index)) {
      revert MaxSplaining({
        reason: "Already Claimed"
      });
    }

    // Verify the merkle proof.
    bytes32 node = keccak256(abi.encodePacked(index, account, amount));
    if (!MerkleProof.verify(merkleProof, admin, node)) {
      revert MaxSplaining({
        reason: "Invalid Proof"
      });
    }

    // Mark it claimed and send the token.
    _setClaimedAdmin(index);
    if (token721.getSupply() + amount > maxCap) {
      revert Unauthorized();
    } else {
      for (uint c = 0; c < amount;) {
        // mint each
        token721.mint(account, theTokenID.current());
        emit Transfer(address(0), account, theTokenID.current());
        theTokenID.increment();
        unchecked { ++c; }
      }
    }
    emit Claimed(index, account, amount, "Admin");
  }

  function homiesMint(
    uint256 index
  , address account
  , bytes32[] calldata merkleProof
  ) external
    preSale() {
    if (startTime == 0) {
      revert Unauthorized();
    }
    if (isClaimedHomies(index)) {
      revert MaxSplaining({
        reason: "Already Claimed"
      });
    }

    // Verify the merkle proof.
    bytes32 node = keccak256(abi.encodePacked(index, account));
    if (!MerkleProof.verify(merkleProof, homies, node)) {
      revert MaxSplaining({
        reason: "Invalid Proof"
      });
    }

    // Mark it claimed and send the token.
    _setClaimedHomies(index);
    if (token721.getSupply() + 1 > maxCap) {
      revert Unauthorized();
    } else {
      token721.mint(account, theTokenID.current());
      emit Transfer(address(0), account, theTokenID.current());
      theTokenID.increment();
    }
    emit Claimed(index, account, 1, "Homies");
  }

  function normiesMint(
    uint256 index
  , address account
  , bytes32[] calldata merkleProof
  ) external
    payable
    preSale() {
    if (startTime == 0) {
      revert Unauthorized();
    }
    if (msg.value != normiesCost) {
      revert MaxSplaining ({
        reason: "msg.value too low"
      });
    }
    if (isClaimedNormies(index)) {
      revert MaxSplaining({
        reason: "Already Claimed"
      });
    }

    // Verify the merkle proof.
    bytes32 node = keccak256(abi.encodePacked(index, account));
    if (!MerkleProof.verify(merkleProof, normies, node)) {
      revert MaxSplaining({
        reason: "Invalid Proof"
      });
    }

    // Mark it claimed and send the token.
    _setClaimedNormies(index);
    if (token721.getSupply() + 1 > maxCap) {
      revert Unauthorized();
    } else {
      token721.mint(account, theTokenID.current());
      emit Transfer(address(0), account, theTokenID.current());
      theTokenID.increment();
    }
    emit Claimed(index, account, 1, "Normies");
  }

  function publicMint(
    uint256 quant
  ) external
    payable
    Sale() {
    if (quant > 5) {
      revert Unauthorized();
    }
    if (startTime == 0) {
      revert Unauthorized();
    }
    if (msg.value != publicCost * quant) {
      revert MaxSplaining ({
        reason: "msg.value too low"
      });
    }
    if (token721.getSupply() + quant > maxCap) {
      revert Unauthorized();
    } else {
      for (uint c = 0; c < quant;) {
        // mint each
        token721.mint(msg.sender, theTokenID.current());
        emit Transfer(address(0), msg.sender, theTokenID.current());
        theTokenID.increment();
        unchecked { ++c; }
      }
    }
  }

  function setFees(
    uint256 _normies
  , uint256 _public
  ) external
    onlyDev() {
    normiesCost = _normies;
    publicCost = _public;
  }

  function setContractURI(
    string memory newURI
  ) external
    onlyDev() {
    contractURL = newURI;
  }

  function contractURI()
    public
    view
    returns (string memory) {
    return contractURL;
  }

  function setJSON(
    string memory _description
  , string memory _image
  , string memory _animation
  ) external
    onlyDev() {
    description = _description;
    image = _image;
    animationURI = _animation;
  }

  function tokenURI(
    uint256 tokenId
  ) public
    view
    virtual
    override
    returns (string memory) {
    bytes memory json = abi.encodePacked(
      "{",
      '"name": "Homies Genesis #',
      Strings.toString(uint256(tokenId)),
      '",',
      '"description": "',
      description,
      '",',
      '"image": "',
      image,
      '",',
      '"animation_url": "',
      animationURI,
      '"',
      "}"
    );

    return string(
      abi.encodePacked(
        "data:application/json;base64,",
        Base64.encode(json)
      )
    );
  }

  /// @dev Function to receive ether, msg.data must be empty
  receive()
    external
    payable {
    // From PaymentSplitter.sol
    emit PaymentReceived(msg.sender, msg.value);
  }

  /// @dev Function to receive ether, msg.data is not empty
  fallback()
    external
    payable {
    // From PaymentSplitter.sol
    emit PaymentReceived(msg.sender, msg.value);
  }

  /// @dev this is a public getter for ETH blance on contract
  function getBalance()
    external
    view
    returns (uint) {
    return address(this).balance;
  }
}

File 2 of 24 : ISplitter.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: [Not an EIP] Payment Splitter, interface for ether payments
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice: Interface for Payment Splitter
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "../../eip/165/IERC165.sol";

interface ISplitter is IERC165 {

  /// @dev returns total shares
  /// @return uint256 of all shares on contract
  function totalShares()
    external
    view
    returns (uint256);

  /// @dev returns shares of an address
  /// @param payee address of payee to return
  /// @return mapping(address => uint) of _shares
  function shares(
    address payee
  ) external
    view
    returns (uint256);

  /// @dev returns total releases in "eth"
  /// @return uint256 of all "eth" released in wei
  function totalReleased()
    external
    view
    returns (uint256);

  /// @dev returns released "eth" of an payee
  /// @param payee address of payee to look up
  /// @return mapping(address => uint) of _released
  function released(
    address payee
  ) external
    view
    returns (uint256);

  /// @dev returns amount of "eth" that can be released to payee
  /// @param payee address of payee to look up
  /// @return uint in wei of "eth" to release
  function releasable(
    address payee
  ) external
    view
    returns (uint256);

  /// @dev returns index number of payee
  /// @param payee number of index
  /// @return address at _payees[index]
  function payeeIndex(
    address payee
  ) external
    view
    returns (uint256);

  /// @dev this returns the array of payees[]
  /// @return address[] payees
  function payees()
    external
    view
    returns (address[] memory);

  /// @dev this claims all "eth" on contract for msg.sender
  function claim()
    external;

  /// @dev This pays all payees
  function payClaims()
    external;

  /// @dev This adds a payee
  /// @param payee Address of payee
  /// @param _shares Shares to send user
  function addPayee(
    address payee
  , uint256 _shares
  ) external;

  /// @dev This removes a payee
  /// @param payee Address of payee to remove
  /// @dev use payPayees() prior to use if anything is on the contract
  function removePayee(
    address payee
  ) external;

  /// @dev This removes all payees
  /// @dev use payPayees() prior to use if anything is on the contract
  function clearPayees()
    external;
}

File 3 of 24 : MaxAccess.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: [Not an EIP]: MaxFlow's 173/Dev/Roles Interface
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice: Interface for MaxAccess
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "./IMAX173.sol";
import "./IMAXDEV.sol";
import "./IRoles.sol";

interface MaxAccess is IMAX173
                     , IMAXDEV
                     , IRoles {

  ///@dev this just imports all 3 and pushes to Implementation

}

File 4 of 24 : IRoles.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: [Not an EIP]: Contract Roles Standard
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice: Interface for MaxAccess version of Roles
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "../../eip/165/IERC165.sol";

interface IRoles is IERC165 {

  /// @dev Returns `true` if `account` has been granted `role`.
  /// @param role: Bytes4 of a role
  /// @param account: Address to check
  /// @return bool true/false if account has role
  function hasRole(
    bytes4 role
  , address account
  ) external
    view
    returns (bool);

  /// @dev Returns the admin role that controls a role
  /// @param role: Role to check
  /// @return admin role
  function getRoleAdmin(
    bytes4 role
  ) external
    view 
    returns (bytes4);

  /// @dev Grants `role` to `account`
  /// @param role: Bytes4 of a role
  /// @param account: account to give role to
  function grantRole(
    bytes4 role
  , address account
  ) external;

  /// @dev Revokes `role` from `account`
  /// @param role: Bytes4 of a role
  /// @param account: account to revoke role from
  function revokeRole(
    bytes4 role
  , address account
  ) external;

  /// @dev Renounces `role` from `account`
  /// @param role: Bytes4 of a role
  function renounceRole(
    bytes4 role
  ) external;
}

File 5 of 24 : IMAXDEV.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#* 
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=: 
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%* 
 *
 * @title: [Not an EIP]: Contract Developer Standard
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice: Interface for onlyDev() role
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "../../eip/165/IERC165.sol";

interface IMAXDEV is IERC165 {

  /// @dev Classic "EIP-173" but for onlyDev()
  /// @return Developer of contract
  function developer()
    external
    view
    returns (address);

  /// @dev This renounces your role as onlyDev()
  function renounceDeveloper()
    external;

  /// @dev Classic "EIP-173" but for onlyDev()
  /// @param newDeveloper: addres of new pending Developer role
  function transferDeveloper(
    address newDeveloper
  ) external;

  /// @dev This accepts the push-pull method of onlyDev()
  function acceptDeveloper()
    external;

  /// @dev This declines the push-pull method of onlyDev()
  function declineDeveloper()
    external;

  /// @dev This starts the push-pull method of onlyDev()
  /// @param newDeveloper: addres of new pending developer role
  function pushDeveloper(
    address newDeveloper
  ) external;

}

File 6 of 24 : IMAX173.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#* 
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=: 
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%* 
 *
 * @title:  EIP-173: Contract Ownership Standard, MaxFlowO2's extension
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice: Interface for enhancing EIP-173
 * @custom:change-log UUPS Upgradable
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "../../eip/173/IERC173.sol";

interface IMAX173 is IERC173 {

  /// @dev This is the classic "EIP-173" method of renouncing onlyOwner()  
  function renounceOwnership()
    external;

  /// @dev This accepts the push-pull method of onlyOwner()
  function acceptOwnership()
    external;

  /// @dev This declines the push-pull method of onlyOwner()
  function declineOwnership()
    external;

  /// @dev This starts the push-pull method of onlyOwner()
  /// @param newOwner: addres of new pending owner role
  function pushOwnership(
    address newOwner
  ) external;

}

File 7 of 24 : IERC2981Admin.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: EIP-2981: NFT Royalty Standard, admin extension
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice: the ERC-165 identifier for this interface is unknown.
 * @custom:source https://eips.ethereum.org/EIPS/eip-2981
 * @custom:change-log MIT -> Apache-2.0
 *
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright and related rights waived via CC0.                               *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "../../eip/2981/IERC2981.sol";

interface IERC2981Admin is IERC2981 {

  /// @dev function (state storage) sets the royalty data for a token
  /// @param tokenId uint256 for the token
  /// @param receiver address for the royalty reciever for token
  /// @param permille uint16 for the permille of royalties 20 -> 2.0%
  function setRoyalties(
    uint256 tokenId
  , address receiver
  , uint16 permille
  ) external;

  /// @dev function (state storage) revokes the royalty data for a token
  /// @param tokenId uint256 for the token
  function revokeRoyalties(
    uint256 tokenId
  ) external;

  /// @dev function (state storage) sets the royalty data for a collection
  /// @param receiver address for the royalty reciever for token
  /// @param permille uint16 for the permille of royalties 20 -> 2.0%
  function setRoyalties(
    address receiver
  , uint16 permille
  ) external;

  /// @dev function (state storage) revokes the royalty data for a collection
  function revokeRoyalties()
    external;
}

File 8 of 24 : Strings.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: Strings
 * @author: OpenZeppelin
 * @notice: Strings Library
 * @custom:source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts-upgradeable/v4.7.3/contracts/utils/StringsUpgradeable.sol
 * @custom:change-log Readable, External/Public, Removed code comments, MIT -> Apache-2.0
 * @custom:change-log Added MaxSplaining
 * @custom:error-code Str:1 "hex length insufficient"
 *
 * Include with 'using Strings for <insert type>'
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

library Strings {

  bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
  uint8 private constant _ADDRESS_LENGTH = 20;

  error MaxSplaining(string reason);

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

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

  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;
    }
    if (value != 0) {
      revert MaxSplaining({
        reason: "Str:1"
      });
    }
    return string(buffer);
  }

  function toHexString(
    address addr
  ) internal
    pure
    returns (string memory) {
    return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
  }
}

File 9 of 24 : Roles.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: Roles.sol
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice: Library for MaxAcess.sol
 * @custom:change-log cleaned up variables
 *
 * Include with 'using Roles for Roles.Role;'
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

library Roles {

  bytes4 constant internal DEVS = 0xca4b208b;
  bytes4 constant internal OWNERS = 0x8da5cb5b;
  bytes4 constant internal ADMIN = 0xf851a440;

  struct Role {
    mapping(address => mapping(bytes4 => bool)) bearer;
    address owner;
    address developer;
    address admin;
  }

  event RoleChanged(bytes4 _role, address _user, bool _status);
  event AdminTransferred(address indexed previousAdmin, address indexed newAdmin);
  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
  event DeveloperTransferred(address indexed previousDeveloper, address indexed newDeveloper);

  error Unauthorized();

  function add(
    Role storage role
  , bytes4 userRole
  , address account
  ) internal {
    if (account == address(0)) {
      revert Unauthorized();
    } else if (has(role, userRole, account)) {
      revert Unauthorized();
    }
    role.bearer[account][userRole] = true;
    emit RoleChanged(userRole, account, true);
  }

  function remove(
    Role storage role
  , bytes4 userRole
  , address account
  ) internal {
    if (account == address(0)) {
      revert Unauthorized();
    } else if (!has(role, userRole, account)) {
      revert Unauthorized();
    }
    role.bearer[account][userRole] = false;
    emit RoleChanged(userRole, account, false);
  }

  function has(
    Role storage role
  , bytes4  userRole
  , address account
  ) internal
    view
    returns (bool) {
    if (account == address(0)) {
      revert Unauthorized();
    }
    return role.bearer[account][userRole];
  }

  function setAdmin(
    Role storage role
  , address account
  ) internal {
    if (has(role, ADMIN, account)) {
      address old = role.admin;
      role.admin = account;
      emit AdminTransferred(old, role.admin);
    } else if (account == address(0)) {
      address old = role.admin;
      role.admin = account;
      emit AdminTransferred(old, role.admin);
    } else {
      revert Unauthorized();
    }
  }

  function setDeveloper(
    Role storage role
  , address account
  ) internal {
    if (has(role, DEVS, account)) {
      address old = role.developer;
      role.developer = account;
      emit DeveloperTransferred(old, role.developer);
    } else if (account == address(0)) {
      address old = role.admin;
      role.admin = account;
      emit AdminTransferred(old, role.admin);
    } else {
      revert Unauthorized();
    }
  }

  function setOwner(
    Role storage role
  , address account
  ) internal {
    if (has(role, OWNERS, account)) {
      address old = role.owner;
      role.owner = account;
      emit OwnershipTransferred(old, role.owner);
    } else if (account == address(0)) {
      address old = role.admin;
      role.admin = account;
      emit AdminTransferred(old, role.admin);
    } else {
      revert Unauthorized();
    }
  }

  function getAdmin(
    Role storage role
  ) internal 
    view
    returns (address) {
    return role.admin;
  }

  function getDeveloper(
    Role storage role
  ) internal
    view
    returns (address) {
    return role.developer;
  }

  function getOwner(
    Role storage role
  ) internal
    view
    returns (address) {
    return role.owner;
  }
}

File 10 of 24 : Payments.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: [Not an EIP] Payment Splitter
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice: Library for two structs one with "ERC-20's" and one without
 * @custom:error-code PS:1 No Shares for address
 * @custom:error-code PS:2 No payment due for address
 * @custom:error-code PS:3 Can not use address(0)
 * @custom:error-code PS:4 Shares can not be 0
 * @custom:error-code PS:5 User has shares already
 * @custom:error-code PS:6 User not in payees
 * @custom:change-log added custom error-codes above
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

library Payments {

  struct GasTokens {
    uint256 totalShares;
    uint256 totalReleased;
    mapping(address => uint256) shares;
    mapping(address => uint256) released;
    address[] payees;
  }

  event PayeeAdded(address account, uint256 _shares);
  event PayeeRemoved(address account, uint256 _shares);
  event PayeesReset();
  event PaymentReleased(address to, uint256 amount);

  error MaxSplaining(string reason);

  function findIndex(
    address[] memory array
  , address query
  ) internal
    pure
    returns (bool found, uint256 index) {
    uint256 len = array.length;
    for (uint x = 0; x < len;) {
      if (array[x] == query) {
        found = true;
        index = x;
      }
      unchecked { ++x; }
    }
  }

  function getTotalReleased(
    GasTokens storage gasTokens
  ) internal
    view
    returns (uint256) {
    return gasTokens.totalReleased;
  }

  function getTotalShares(
    GasTokens storage gasTokens
  ) internal
    view
    returns (uint256) {
    return gasTokens.totalShares;
  }

  function payeeShares(
    GasTokens storage gasTokens
  , address payee
  ) internal
    view
    returns (uint256) {
    return gasTokens.shares[payee];
  }

  function payeeReleased(
    GasTokens storage gasTokens
  , address payee
  ) internal
    view
    returns (uint256) {
    return gasTokens.released[payee];
  }

  function payeeIndex(
    GasTokens storage gasTokens
  , address payee
  ) internal
    view
    returns (uint256) {
    (bool found, uint256 index) = findIndex(gasTokens.payees, payee);
    if (found) {
      return index;
    } else {
      revert MaxSplaining({
        reason: "PS:6"
      });
    }
  }

  function allPayees(
    GasTokens storage gasTokens
  ) internal
    view
    returns (address[] memory) {
    return gasTokens.payees;
  }

  function addPayee(
    GasTokens storage gasTokens
  , address payee
  , uint256 _shares
  ) internal {
    if (payee == address(0)) {
      revert MaxSplaining({
        reason: "PS:3"
      });
    } else if (_shares == 0) {
      revert MaxSplaining({
        reason: "PS:4"
      });
    } else if (gasTokens.shares[payee] > 0) {
      revert MaxSplaining({
        reason: "PS:5"
      });
    }
    gasTokens.payees.push(payee);
    gasTokens.shares[payee] = _shares;
    gasTokens.totalShares += _shares;
    emit PayeeAdded(payee, _shares);
  }

  function getPayees(
    GasTokens storage gasTokens
  ) internal
    view
    returns (address[] memory) {
    return gasTokens.payees;
  }

  function removePayee(
    GasTokens storage gasTokens
  , address payee
  ) internal {
    if (payee == address(0)) {
      revert MaxSplaining({
        reason: "PS:3"
      });
    }
    uint256 whacked = payeeIndex(gasTokens, payee);
    address last = gasTokens.payees[gasTokens.payees.length -1];
    gasTokens.payees[whacked] = last;
    gasTokens.payees.pop();
    uint256 whackedShares = gasTokens.shares[payee];
    delete gasTokens.shares[payee];
    gasTokens.totalShares -= whackedShares;
    emit PayeeRemoved(payee, whackedShares);
  }

  function clearPayees(
    GasTokens storage gasTokens
  ) internal {
    uint256 len = gasTokens.payees.length;
    for (uint x = 0; x < len;) {
      address whacked = gasTokens.payees[x];
      delete gasTokens.shares[whacked];
      unchecked { ++x; }
    }
    delete gasTokens.totalShares;
    delete gasTokens.payees;
    emit PayeesReset();
  }

  function processPayment(
    GasTokens storage gasTokens
  , address payee
  , uint256 payment
  ) internal {
    gasTokens.totalReleased += payment;
    gasTokens.released[payee] += payment;
    emit PaymentReleased(payee, payment);
  }
}

File 11 of 24 : Lists.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: [Not an EIP]: Access lists
 * @author: @MaxFlowO2 on bird app/GitHub
 * @notice: Formerly whitelists, now allowlist, or whatever it's called.
 * @custom:change-log removed end variable/functions (un-needed)
 * @custom:change-log variables renamed from lib whitelist
 * @custom:change-log internal -> internal
 * @custom:error-code A:1 "(user) is already whitelisted."
 * @custom:error-code A:2 "(user) is not whitelisted."
 * @custom:error-code A:3 "Whitelist already enabled."
 * @custom:error-code A:4 "Whitelist already disabled."
 * @custom:change-log added custom error codes
 * @custom:change-log removed import "./Strings.sol"; (un-needed)
 *
 * Include with 'using Lists for Lists.Access;'
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "./CountersV2.sol";

library Lists {

  using CountersV2 for CountersV2.Counter;

  event ListChanged(bool _old, bool _new, address _address);
  event ListStatus(bool _old, bool _new);

  error MaxSplaining(string reason);

  struct Access {
    bool _status;
    CountersV2.Counter added;
    CountersV2.Counter removed;
    mapping(address => bool) allowed;
  }

  function add(
    Access storage list
  , address user
  ) internal {
    if (list.allowed[user]) {
      revert  MaxSplaining({
        reason : "A:1"
      });
    }
    // since now all previous values are false no need for another variable
    // and add them to the list!
    list.allowed[user] = true;
    // increment counter
    list.added.increment();
    // emit event
    emit ListChanged(false, list.allowed[user], user);
  }

  function remove(
    Access storage list
  , address user
  ) internal {
    if (!list.allowed[user]) {
      revert  MaxSplaining({
        reason : "A:2"
      });
    }
    // since now all previous values are true no need for another variable
    // and remove them from the list!
    list.allowed[user] = false;
    // increment counter
    list.removed.increment();
    // emit event
    emit ListChanged(true, list.allowed[user], user);
  }

  function enable(
    Access storage list
  ) internal {
    if (list._status) {
      revert  MaxSplaining({
        reason : "A:3"
      });
    }
    list._status = true;
    emit ListStatus(false, list._status);
  }

  function disable(
    Access storage list
  ) internal {
    if (!list._status) {
      revert  MaxSplaining({
        reason : "A:4"
      });
    }
    list._status = false;
    emit ListStatus(true, list._status);
  }

  function status(
    Access storage list
  ) internal
    view
    returns (bool) {
    return list._status;
  }

  function totalAdded(
    Access storage list
  ) internal
    view
    returns (uint) {
    return list.added.current();
  }

  function totalRemoved(
    Access storage list
  ) internal
    view
    returns (uint) {
    return list.removed.current();
  }

  function onList(
    Access storage list
  , address user
  ) internal
    view
    returns (bool) {
    return list.allowed[user];
  }
}

File 12 of 24 : CountersV2.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: CountersV2.sol
 * @author Matt Condon (@shrugs)
 * @notice Provides counters that can only be incremented, decremented, reset or set. 
 * This can be used e.g. to track the number of elements in a mapping, issuing ERC721 ids
 * or counting request ids.
 * @custom:change-log MIT -> Apache-2.0
 * @custom:change-log Edited for more NFT functionality added .set(uint)
 * @custom:change-log added event CounterNumberChangedTo(uint _number).
 * @custom:change-log added error MaxSplaining(string reason).
 * @custom:change-log internal -> internal functions
 * @custom:error-code C2:1 "No negatives in uints" - overflow protection
 *
 * Include with `using CountersV2 for CountersV2.Counter;`
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

library CountersV2 {

  struct Counter {
    uint256 value;
  }

  event CounterNumberChangedTo(uint _number);

  error MaxSplaining(string reason);

  function current(
    Counter storage counter
  ) internal
    view
    returns (uint256) {
    return counter.value;
  }

  function increment(
    Counter storage counter
  ) internal {
    unchecked {
      ++counter.value;
    }
  }

  function decrement(
    Counter storage counter
  ) internal {
    if (counter.value == 0) {
      revert MaxSplaining({
        reason : "C2:1"
      });
    }
    unchecked {
      --counter.value;
    }
  }

  function reset(
    Counter storage counter
  ) internal {
    counter.value = 0;
    emit CounterNumberChangedTo(counter.value);
  }

  function set(
    Counter storage counter
  , uint number
  ) internal {
    counter.value = number;
    emit CounterNumberChangedTo(counter.value);
  }  
}

File 13 of 24 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @notice : Collection of functions related to the address type
 */
library Address {
    /**
     * @notice : 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;
    }

    /**
     * @notice : 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://consensys.net/diligence/blog/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");
    }

    /**
     * @notice : 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 functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @notice : 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);
    }

    /**
     * @notice : 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");
    }

    /**
     * @notice : 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");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @notice : 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");
    }

    /**
     * @notice : 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) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @notice : 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");
    }

    /**
     * @notice : 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) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @notice : Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @notice : Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or 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 {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // 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
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 14 of 24 : 721.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: Library 721
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice: Library for EIP 721
 * @custom:error-code L:1 "non-existent tokenId" 
 * @custom:error-code L:2 "approval to current owner"
 * @custom:error-code L:3 "approve caller is not token owner nor approved for all"
 * @custom:error-code L:4 "approve to caller"
 * @custom:error-code L:5 "caller is not token owner nor approved"
 * @custom:error-code L:6 "transfer from incorrect owner"
 * @custom:error-code L:7 "transfer to the zero address"
 * @custom:error-code L:8 "mint to the zero address"
 * @custom:error-code L:9 "token already minted"
 * @custom:change-log Custom errors added above
 *
 * Include with 'using Lib721 for Lib721.Token;'
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "./Strings.sol";
import "./CountersV2.sol";

library Lib721 {

  using Strings for uint256;
  using CountersV2 for CountersV2.Counter;

  struct Token {
    mapping(uint256 => address) owners;
    mapping(address => uint256) balances;
    mapping(uint256 => address) tokenApprovals;
    mapping(address => mapping(address => bool)) operatorApprovals;
    string name;
    string symbol;
    string baseURI;
    CountersV2.Counter supply;
  }

  event NameSet(string name);
  event SymbolSet(string symbol);
  event NewBaseURI(string baseURI);

  error MaxSplaining(string reason);

  function getBalanceOf(
    Token storage token
  , address owner
  ) internal
    view
    returns (uint256) {
    return token.balances[owner];
  }

  function getOwnerOf(
    Token storage token
  , uint256 tokenId
  ) internal 
    view
    returns (address) {
    return token.owners[tokenId];
  }

  function setName(
    Token storage token
  , string memory newName
  ) internal {
    token.name = newName;
    emit NameSet(newName);
  }

  function getName(
   Token storage token
  ) internal
    view
    returns (string memory) {
    return token.name;
  }

  function setSymbol(
    Token storage token
  , string memory newSymbol
  ) internal {
    token.symbol = newSymbol;
    emit SymbolSet(newSymbol);
  }

  function getSymbol(
   Token storage token
  ) internal
    view
    returns (string memory) {
    return token.symbol;
  }

  function getSupply(
   Token storage token
  ) internal
    view
    returns (uint256) {
    return token.supply.current();
  }

  function setBaseURI(
    Token storage token
  , string memory newURI
  ) internal {
    token.baseURI = newURI;
    emit NewBaseURI(newURI);
  }

  function getTokenURI(
    Token storage token
  , uint256 tokenId
  ) internal
    view
    returns (string memory) {
    if (getOwnerOf(token, tokenId) == address(0)) {
      revert MaxSplaining({
        reason: "L:1"
      });
    }
    return bytes(token.baseURI).length > 0 ? string(abi.encodePacked(token.baseURI, tokenId.toString())) : "";
  }

  function setApprove(
    Token storage token
  , address to
  , address by
  , uint256 tokenId
  ) internal {
    address owner = getOwnerOf(token, tokenId);
    if (to == owner) {
      revert MaxSplaining({
        reason: "L:2"
      });
    } else if (!isApprovedOrOwner(token, by, tokenId)) {
      revert MaxSplaining({
        reason: "L:3"
      });
    }
    token.tokenApprovals[tokenId] = to;
  }

  function getApproved(
    Token storage token
  , uint256 tokenId
  ) internal
    view
    returns (address) {
    if (getOwnerOf(token, tokenId) == address(0)) {
      revert MaxSplaining({
        reason: "L:1"
      });
    }
    return token.tokenApprovals[tokenId];
  }

  function setApprovalForAll(
    Token storage token
  , address operator
  , address from
  , bool approved
  ) internal {
    if (from == operator) {
      revert MaxSplaining({
        reason: "L:4"
      });
    }
    token.operatorApprovals[from][operator] = approved;
  }

  function isApprovedForAll(
    Token storage token
  , address owner
  , address operator
  ) internal
    view
    returns (bool) {
    return token.operatorApprovals[owner][operator];
  }

  function isApprovedOrOwner(
    Token storage token
  , address spender
  , uint256 tokenId
  ) internal
    view
    returns (bool) {
    address owner = getOwnerOf(token, tokenId);
    return (
      spender == owner ||
      isApprovedForAll(token, owner, spender) ||
      getApproved(token, tokenId) == spender
    );
  }

  function doTransferFrom(
    Token storage token
  , address from
  , address to
  , address by
  , uint256 tokenId
  ) internal {
    if (!isApprovedOrOwner(token, by, tokenId)) {
      revert MaxSplaining({
        reason: "L:5"
      });
    }
    address owner = getOwnerOf(token, tokenId);
    if (owner != from) {
      revert MaxSplaining({
        reason: "L:6"
      });
    } else if (to == address(0)) {
      revert MaxSplaining({
        reason: "L:7"
      });
    }
    // Clear approvals from the previous owner
    setApprove(token, address(0), by, tokenId);
    // Change balances
    token.balances[from] -= 1;
    token.balances[to] += 1;
    // Move tokenId
    token.owners[tokenId] = to;
  }

  function mint(
    Token storage token
  , address to
  , uint256 tokenId
  ) internal {
    if (to == address(0)) {
      revert MaxSplaining({
        reason: "L:8"
      });
    } else if (getOwnerOf(token, tokenId) != address(0)) {
      revert MaxSplaining({
        reason: "L:9"
      });
    }
    token.balances[to] += 1;
    token.owners[tokenId] = to;
    token.supply.increment();
  }

  function burn(
    Token storage token
  , address by
  , uint256 tokenId
  ) internal {
    address owner = getOwnerOf(token, tokenId);
    // Clear approvals
    setApprove(token, address(0), by, tokenId);
    // Change balances
    token.balances[owner] -= 1;
    delete token.owners[tokenId];
    token.supply.decrement();
  }
}

File 15 of 24 : 2981c.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: Library 2981
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice: Library for EIP 2981
 * @custom:error-code R:1 Permille out of bounds
 * @custom:change-log Custom errors added above
 *
 * Include with 'using Lib2981 for Lib2981.Royalties;' -- unique per collection
 * Include with 'using Lib2981 for Lib2981.MappedRoyalties;' -- unique per token
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

library Lib2981c {

  struct Royalties {
    address receiver;
    uint16 permille;
  }

  event RoyaltiesSet(uint256 token, address recipient, uint16 value);
  event RoyaltiesSet(address recipient, uint16 value);

  error MaxSplaining(string reason);

  function setRoyalties(
    Royalties storage royalties
  , address receiver
  , uint16 permille
  ) internal {
    if (permille >= 1000 ||  permille == 0) {
      revert MaxSplaining({
        reason: "R:1"
      });
    }
    royalties.receiver = receiver;
    royalties.permille = permille;
    emit RoyaltiesSet(
           royalties.receiver
         , royalties.permille
         );
  }

  function revokeRoyalties(
    Royalties storage royalties
  ) internal {
    delete royalties.receiver;
    delete royalties.permille;
    emit RoyaltiesSet(
           royalties.receiver
         , royalties.permille
         );
  }

  function royaltyInfo(
    Royalties storage royalties
  , uint256 tokenId
  , uint256 salePrice
  ) internal
    view
    returns (
      address receiver
    , uint256 royaltyAmount
    ) {
    receiver = royalties.receiver;
    royaltyAmount = salePrice * royalties.permille / 1000;
  }
}

File 16 of 24 : IERC721TokenReceiver.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: ERC-721 Non-Fungible Token Standard, required wallet interface
 * @author: William Entriken, Dieter Shirley, Jacob Evans, Nastassia Sachs
 * @notice: the ERC-165 identifier for this interface is 0x150b7a02.
 * @custom:source https://eips.ethereum.org/EIPS/eip-721
 * @custom:change-log interface ERC721TokenReceiver -> interface IERC721TokenReceiver
 * @custom:change-log readability enhanced
 * @custom:change-log MIT -> Apache-2.0
 * @custom:change-log TypeError: Data location must be "memory" or "calldata" for parameter (line 60)
 *
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright and related rights waived via CC0.                               *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "../165/IERC165.sol";

interface IERC721TokenReceiver is IERC165 {

  /// @notice Handle the receipt of an NFT
  /// @notice The ERC721 smart contract calls this function on the recipient
  ///  after a `transfer`. This function MAY throw to revert and reject the
  ///  transfer. Return of other than the magic value MUST result in the
  ///  transaction being reverted.
  ///  Note: the contract address is always the message sender.
  /// @param _operator The address which called `safeTransferFrom` function
  /// @param _from The address which previously owned the token
  /// @param _tokenId The NFT identifier which is being transferred
  /// @param _data Additional data with no specified format
  /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
  ///  unless throwing
  function onERC721Received(
    address _operator
  , address _from
  , uint256 _tokenId
  , bytes calldata _data
  ) external
    returns(bytes4);
}

File 17 of 24 : IERC721Metadata.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @author: William Entriken, Dieter Shirley, Jacob Evans, Nastassia Sachs
 * @notice: the ERC-165 identifier for this interface is 0x5b5e139f.
 * @custom:source https://eips.ethereum.org/EIPS/eip-721
 * @custom:change-log interface ERC721Metadata * is ERC721 * -> interface IERC721Metadata
 * @custom:change-log readability enhanced
 * @custom:change-log MIT -> Apache-2.0
 * @custom:change-log  Data location must be "memory" or "calldata" for return parameter (lines 48, 54, 64)
 *
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright and related rights waived via CC0.                               *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "./IERC721.sol";

interface IERC721Metadata is IERC721 {

  /// @notice A descriptive name for a collection of NFTs in this contract
  function name()
    external
    view
    returns (string memory _name);

  /// @notice An abbreviated name for NFTs in this contract
  function symbol()
    external
    view
    returns (string memory _symbol);

  /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
  /// @notice Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
  ///  3986. The URI may point to a JSON file that conforms to the "ERC721
  ///  Metadata JSON Schema".
  function tokenURI(
    uint256 _tokenId
  ) external
    view
    returns (string memory);
}

File 18 of 24 : IERC721.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: ERC-721 Non-Fungible Token Standard
 * @author: William Entriken, Dieter Shirley, Jacob Evans, Nastassia Sachs
 * @notice: the ERC-165 identifier for this interface is 0x80ac58cd.
 * @custom:source https://eips.ethereum.org/EIPS/eip-721
 * @custom:change-log interface ERC721 * is ERC165 * -> interface IERC721
 * @custom:change-log removed payable from IERC721 
 * @custom:change-log removed events from IERC721 (handled in Lib721)
 * @custom:change-log readability enhanced
 * @custom:change-log MIT -> Apache-2.0
 * @custom:change-log TypeError: Data location must be "memory" or "calldata" for parameter (line 84)
 *
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright and related rights waived via CC0.                               *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "../165/IERC165.sol";

interface IERC721 is IERC165 {

  /// @dev This emits when ownership of any NFT changes by any mechanism.
  ///  This event emits when NFTs are created (`from` == 0) and destroyed
  ///  (`to` == 0). Exception: during contract creation, any number of NFTs
  ///  may be created and assigned without emitting Transfer. At the time of
  ///  any transfer, the approved address for that NFT (if any) is reset to none.
  event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

  /// @dev This emits when the approved address for an NFT is changed or
  ///  reaffirmed. The zero address indicates there is no approved address.
  ///  When a Transfer event emits, this also indicates that the approved
  ///  address for that NFT (if any) is reset to none.
  event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);

  /// @dev This emits when an operator is enabled or disabled for an owner.
  ///  The operator can manage all NFTs of the owner.
  event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

  /// @notice Count all NFTs assigned to an owner
  /// @notice NFTs assigned to the zero address are considered invalid, and this
  ///  function throws for queries about the zero address.
  /// @param _owner An address for whom to query the balance
  /// @return The number of NFTs owned by `_owner`, possibly zero
  function balanceOf(
    address _owner
  ) external
    view
    returns (uint256);

  /// @notice Find the owner of an NFT
  /// @notice NFTs assigned to zero address are considered invalid, and queries
  ///  about them do throw.
  /// @param _tokenId The identifier for an NFT
  /// @return The address of the owner of the NFT
  function ownerOf(
    uint256 _tokenId
  ) external
    view
    returns (address);

  /// @notice Transfers the ownership of an NFT from one address to another address
  /// @notice Throws unless `msg.sender` is the current owner, an authorized
  ///  operator, or the approved address for this NFT. Throws if `_from` is
  ///  not the current owner. Throws if `_to` is the zero address. Throws if
  ///  `_tokenId` is not a valid NFT. When transfer is complete, this function
  ///  checks if `_to` is a smart contract (code size > 0). If so, it calls
  ///  `onERC721Received` on `_to` and throws if the return value is not
  ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
  /// @param _from The current owner of the NFT
  /// @param _to The new owner
  /// @param _tokenId The NFT to transfer
  /// @param data Additional data with no specified format, sent in call to `_to`
  function safeTransferFrom(
    address _from
  , address _to
  , uint256 _tokenId
  , bytes calldata data
  ) external;

  /// @notice Transfers the ownership of an NFT from one address to another address
  /// @notice This works identically to the other function with an extra data parameter,
  ///  except this function just sets data to "".
  /// @param _from The current owner of the NFT
  /// @param _to The new owner
  /// @param _tokenId The NFT to transfer
  function safeTransferFrom(
    address _from
  , address _to
  , uint256 _tokenId
  ) external;

  /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
  ///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
  ///  THEY MAY BE PERMANENTLY LOST
  /// @notice Throws unless `msg.sender` is the current owner, an authorized
  ///  operator, or the approved address for this NFT. Throws if `_from` is
  ///  not the current owner. Throws if `_to` is the zero address. Throws if
  ///  `_tokenId` is not a valid NFT.
  /// @param _from The current owner of the NFT
  /// @param _to The new owner
  /// @param _tokenId The NFT to transfer
  function transferFrom(
    address _from
  , address _to
  , uint256 _tokenId
  ) external;

  /// @notice Change or reaffirm the approved address for an NFT
  /// @notice The zero address indicates there is no approved address.
  ///  Throws unless `msg.sender` is the current NFT owner, or an authorized
  ///  operator of the current owner.
  /// @param _approved The new approved NFT controller
  /// @param _tokenId The NFT to approve
  function approve(
    address _approved
  , uint256 _tokenId
  ) external;

  /// @notice Enable or disable approval for a third party ("operator") to manage
  ///  all of `msg.sender`'s assets
  /// @notice Emits the ApprovalForAll event. The contract MUST allow
  ///  multiple operators per owner.
  /// @param _operator Address to add to the set of authorized operators
  /// @param _approved True if the operator is approved, false to revoke approval
  function setApprovalForAll(
    address _operator
  , bool _approved
  ) external;

  /// @notice Get the approved address for a single NFT
  /// @notice Throws if `_tokenId` is not a valid NFT.
  /// @param _tokenId The NFT to find the approved address for
  /// @return The approved address for this NFT, or the zero address if there is none
  function getApproved(
    uint256 _tokenId
  ) external
    view
    returns (address);

  /// @notice Query if an address is an authorized operator for another address
  /// @param _owner The address that owns the NFTs
  /// @param _operator The address that acts on behalf of the owner
  /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
  function isApprovedForAll(
    address _owner
  , address _operator
  ) external
    view
    returns (bool);
}

File 19 of 24 : IERC2981.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: EIP-2981: NFT Royalty Standard
 * @author: Zach Burks, James Morgan, Blaine Malone, James Seibel
 * @notice: the ERC-165 identifier for this interface is 0x2a55205a.
 * @custom:source https://eips.ethereum.org/EIPS/eip-2981
 * @custom:change-log MIT -> Apache-2.0
 *
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright and related rights waived via CC0.                               *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "../165/IERC165.sol";

interface IERC2981 is IERC165 {

  /// ERC165 bytes to add to interface array - set in parent contract
  /// implementing this standard

  /// bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
  /// bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;
  /// _registerInterface(_INTERFACE_ID_ERC2981);

  /// @notice Called with the sale price to determine how much royalty
  ///         is owed and to whom.
  /// @param _tokenId - the NFT asset queried for royalty information
  /// @param _salePrice - the sale price of the NFT asset specified by _tokenId
  /// @return receiver - address of who should be sent the royalty payment
  /// @return royaltyAmount - the royalty payment amount for _salePrice
  function royaltyInfo(
    uint256 _tokenId,
    uint256 _salePrice
  ) external
    view
    returns (
      address receiver,
      uint256 royaltyAmount
    );
}

File 20 of 24 : IERC173.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: EIP-173: Contract Ownership Standard
 * @author: Nick Mudge, Dan Finlay
 * @notice: This specification defines standard functions for owning or controlling a contract.
 *          the ERC-165 identifier for this interface is 0x7f5828d0
 * @custom:URI https://eips.ethereum.org/EIPS/eip-173
 * @custom:change-log MIT -> Apache-2.0
 * @custom:change-log readability modification
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright and related rights waived via CC0.                               *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

import "../../eip/165/IERC165.sol";

interface IERC173 is IERC165 {

  /// @dev This emits when ownership of a contract changes.    
  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  /// @notice Get the address of the owner    
  /// @return The address of the owner.
  function owner()
    view
    external
    returns(address);
	
  /// @notice Set the address of the new owner of the contract
  /// @dev Set _newOwner to address(0) to renounce any ownership.
  /// @param _newOwner The address of the new owner of the contract    
  function transferOwnership(
    address _newOwner
  ) external;	
}

File 21 of 24 : IERC165.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: EIP-165: Standard Interface Detection
 * @author: Christian Reitwießner, Nick Johnson, Fabian Vogelsteller, Jordi Baylina, Konrad Feldmeier, William Entriken
 * @notice: Creates a standard method to publish and detect what interfaces a smart contract implements.
 * @custom:source https://eips.ethereum.org/EIPS/eip-165
 * @custom:change-log interface ERC165 -> interface IERC165
 * @custom:change-log readability enhanced
 * @custom:change-log MIT -> Apache-2.0

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright and related rights waived via CC0.                               *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.0 <0.9.0;

interface IERC165 {

  /// @notice Query if a contract implements an interface
  /// @param interfaceID The interface identifier, as specified in ERC-165
  /// @notice Interface identification is specified in ERC-165. This function
  ///  uses less than 30,000 gas.
  /// @return `true` if the contract implements `interfaceID` and
  ///  `interfaceID` is not 0xffffffff, `false` otherwise
  function supportsInterface(
    bytes4 interfaceID
  ) external
    view
    returns (bool);
}

File 22 of 24 : Max-721-2981-PSv2.sol
/*     +%%#-                           ##.        =+.    .+#%#+:       *%%#:    .**+-      =+
 *   .%@@*#*:                          @@: *%-   #%*=  .*@@=.  =%.   .%@@*%*   +@@=+=%   .%##
 *  .%@@- -=+                         *@% :@@-  #@=#  -@@*     +@-  :@@@: ==* -%%. ***   #@=*
 *  %@@:  -.*  :.                    +@@-.#@#  =@%#.   :.     -@*  :@@@.  -:# .%. *@#   *@#*
 * *%@-   +++ +@#.-- .*%*. .#@@*@#  %@@%*#@@: .@@=-.         -%-   #%@:   +*-   =*@*   -@%=:
 * @@%   =##  +@@#-..%%:%.-@@=-@@+  ..   +@%  #@#*+@:      .*=     @@%   =#*   -*. +#. %@#+*@
 * @@#  +@*   #@#  +@@. -+@@+#*@% =#:    #@= :@@-.%#      -=.  :   @@# .*@*  =@=  :*@:=@@-:@+
 * -#%+@#-  :@#@@+%++@*@*:=%+..%%#=      *@  *@++##.    =%@%@%%#-  =#%+@#-   :*+**+=: %%++%*
 *
 * @title: [EIP721] Max-721 Implementation, using EIP 1822
 * @author: Max Flow O2 -> @MaxFlowO2 on bird app/GitHub
 * @notice ERC721 Implementation with:
 *         Enhanced EIP173 - Ownership via roles
 *         EIP2981 - NFT Royalties
 *         PsuedoRandom Engine - Expansion of BAYC engine
 *         TimeCop + Lists - For presales
 *         PaymentSplitter v2 - For "ETH" payments
 */

// SPDX-License-Identifier: Apache-2.0

/******************************************************************************
 * Copyright 2022 Max Flow O2                                                 *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 *     http://www.apache.org/licenses/LICENSE-2.0                             *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

pragma solidity >=0.8.17 <0.9.0;

import "./eip/721/IERC721TokenReceiver.sol";//
import "./eip/721/IERC721Metadata.sol";//
import "./eip/721/IERC721.sol";//
import "./modules/2981/IERC2981Admin.sol";//
import "./modules/access/MaxAccess.sol";//
import "./modules/splitter/ISplitter.sol";//
import "./lib/Address.sol";//
import "./lib/721.sol";//
import "./lib/Roles.sol";//
import "./lib/2981c.sol";//
import "./lib/Payments.sol";//

abstract contract Max721 is MaxAccess
                          , IERC721
                          , IERC721Metadata
                          , IERC721TokenReceiver
                          , IERC2981Admin
                          , ISplitter {

  using Lib721 for Lib721.Token;
  using Roles for Roles.Role;
  using Lib2981c for Lib2981c.Royalties;
  using Payments for Payments.GasTokens;
  using Address for address;

  // The Structs...
  Lib721.Token internal token721;
  Roles.Role internal contractRoles;
  Lib2981c.Royalties internal royalties;
  Payments.GasTokens internal splitter;

  // The rest (got to have a few)
  bytes4 constant internal DEVS = 0xca4b208b;
  bytes4 constant internal PENDING_DEVS = 0xca4b208a; // DEVS - 1
  bytes4 constant internal OWNERS = 0x8da5cb5b;
  bytes4 constant internal PENDING_OWNERS = 0x8da5cb5a; // OWNERS - 1
  bytes4 constant internal ADMIN = 0xf851a440;

  uint256 startTime; // Set to opening (can +48h for secondary)
  uint256 period; // Set to the period
  uint256 maxCap; // Cpacity of minter
  bytes32 internal admin;
  mapping(uint256 => uint256) internal claimedAdmin;
  bytes32 internal homies;
  mapping(uint256 => uint256) internal claimedHomies;
  bytes32 internal normies;
  mapping(uint256 => uint256) internal claimedNormies;
  string internal contractURL;
  string internal image;
  string internal description;
  string internal animationURI;
  uint256 public normiesCost = 0.069 ether;
  uint256 public publicCost = 0.1 ether;

  event PaymentReceived(address indexed _payee, uint256 _amount);

  /// @dev this is Unauthorized(), basically a catch all, zero description
  /// @notice 0x82b42900 bytes4 of this
  error Unauthorized();

  /// @dev this is MaxSplaining(), giving you a reason, aka require(param, "reason")
  /// @param reason: Use the "Contract name: error"
  /// @notice 0x0661b792 bytes4 of this
  error MaxSplaining(
    string reason
  );

  /// @dev this is TooSoonJunior(), using times
  /// @param yourTime: should almost always be block.timestamp
  /// @param hitTime: the time you should have started
  /// @notice 0xf3f82ac5 bytes4 of this
  error TooSoonJunior(
    uint yourTime
  , uint hitTime
  );

  /// @dev this is TooLateBoomer(), using times
  /// @param yourTime: should almost always be block.timestamp
  /// @param hitTime: the time you should have ended
  /// @notice 0x43c540ef bytes4 of this
  error TooLateBoomer(
    uint yourTime
  , uint hitTime
  );

  ///////////////////////
  /// MAX-721: Modifiers
  ///////////////////////

  modifier onlyRole(bytes4 role) {
    if (contractRoles.has(role, msg.sender) || contractRoles.has(ADMIN, msg.sender)) {
      _;
    } else {
    revert Unauthorized();
    }
  }

  modifier onlyOwner() {
    if (contractRoles.has(OWNERS, msg.sender)) {
      _;
    } else {
    revert Unauthorized();
    }
  }

  modifier onlyDev() {
    if (contractRoles.has(DEVS, msg.sender)) {
      _;
    } else {
    revert Unauthorized();
    }
  }

  ///////////////////////
  /// MAX-721: Internals
  ///////////////////////

  function __Max721_init(
    string memory _name
  , string memory _symbol
  , address _admin
  , address _dev
  , address _owner
  ) internal {
    token721.setName(_name);
    token721.setSymbol(_symbol);
    contractRoles.add(ADMIN, _admin);
    contractRoles.setAdmin(_admin);
    contractRoles.add(DEVS, _dev);
    contractRoles.setDeveloper(_dev);
    contractRoles.add(OWNERS, _owner);
    contractRoles.setOwner(_owner);
  }

  function safeHook(
    address from,
    address to,
    uint256 tokenId,
    bytes memory data
  ) internal
    returns (bool) {
    if (to.isContract()) {
      try IERC721TokenReceiver(to).onERC721Received(msg.sender, from, tokenId, data)
        returns (bytes4 retval) {
        return retval == IERC721TokenReceiver.onERC721Received.selector;
      } catch (bytes memory reason) {
        if (reason.length == 0) {
          revert Unauthorized();
        } else {
          assembly {
            revert(add(32, reason), mload(reason))
          }
        }
      }
    } else {
      return true;
    }
  }

  /////////////////////////////////////////
  /// EIP-173: Contract Ownership Standard
  /////////////////////////////////////////

  /// @notice Get the address of the owner    
  /// @return The address of the owner.
  function owner()
    view
    external
    returns(address) {
    return contractRoles.getOwner();
  }
	
  /// @notice Set the address of the new owner of the contract
  /// @dev Set _newOwner to address(0) to renounce any ownership.
  /// @param _newOwner The address of the new owner of the contract    
  function transferOwnership(
    address _newOwner
  ) external
    onlyRole(OWNERS) {
    contractRoles.add(OWNERS, _newOwner);
    contractRoles.setOwner(_newOwner);
    contractRoles.remove(OWNERS, msg.sender);
  }

  ////////////////////////////////////////////////////////////////
  /// EIP-173: Contract Ownership Standard, MaxFlowO2's extension
  ////////////////////////////////////////////////////////////////

  /// @dev This is the classic "EIP-173" method of renouncing onlyOwner()  
  function renounceOwnership()
    external 
    onlyRole(OWNERS) {
    contractRoles.setOwner(address(0));
    contractRoles.remove(OWNERS, msg.sender);
  }

  /// @dev This accepts the push-pull method of onlyOwner()
  function acceptOwnership()
    external
    onlyRole(PENDING_OWNERS) {
    contractRoles.add(OWNERS, msg.sender);
    contractRoles.setOwner(msg.sender);
    contractRoles.remove(PENDING_OWNERS, msg.sender);
  }

  /// @dev This declines the push-pull method of onlyOwner()
  function declineOwnership()
    external
    onlyRole(PENDING_OWNERS) {
    contractRoles.remove(PENDING_OWNERS, msg.sender);
  }

  /// @dev This starts the push-pull method of onlyOwner()
  /// @param newOwner: addres of new pending owner role
  function pushOwnership(
    address newOwner
  ) external
    onlyRole(OWNERS) {
    contractRoles.add(PENDING_OWNERS, newOwner);
  }

  //////////////////////////////////////////////
  /// [Not an EIP]: Contract Developer Standard
  //////////////////////////////////////////////

  /// @dev Classic "EIP-173" but for onlyDev()
  /// @return Developer of contract
  function developer()
    external
    view
    returns (address) {
    return contractRoles.getDeveloper();
  }

  /// @dev This renounces your role as onlyDev()
  function renounceDeveloper()
    external
    onlyRole(DEVS) {
    contractRoles.setDeveloper(address(0));
    contractRoles.remove(DEVS, msg.sender);
  }

  /// @dev Classic "EIP-173" but for onlyDev()
  /// @param newDeveloper: addres of new pending Developer role
  function transferDeveloper(
    address newDeveloper
  ) external
    onlyRole(DEVS) {
    contractRoles.add(DEVS, newDeveloper);
    contractRoles.setDeveloper(newDeveloper);
    contractRoles.remove(DEVS, msg.sender);
  }

  /// @dev This accepts the push-pull method of onlyDev()
  function acceptDeveloper()
    external
    onlyRole(PENDING_DEVS) {
    contractRoles.add(DEVS, msg.sender);
    contractRoles.setDeveloper(msg.sender);
    contractRoles.remove(PENDING_DEVS, msg.sender);
  }

  /// @dev This declines the push-pull method of onlyDev()
  function declineDeveloper()
    external
    onlyRole(PENDING_DEVS) {
    contractRoles.remove(PENDING_DEVS, msg.sender);
  }

  /// @dev This starts the push-pull method of onlyDev()
  /// @param newDeveloper: addres of new pending developer role
  function pushDeveloper(
    address newDeveloper
  ) external
    onlyRole(DEVS) {
    contractRoles.add(PENDING_DEVS, newDeveloper);
  }

  //////////////////////////////////////////
  /// [Not an EIP]: Contract Roles Standard
  //////////////////////////////////////////

  /// @dev Returns `true` if `account` has been granted `role`.
  /// @param role: Bytes4 of a role
  /// @param account: Address to check
  /// @return bool true/false if account has role
  function hasRole(
    bytes4 role
  , address account
  ) external
    view
    returns (bool) {
    return contractRoles.has(role, account);
  }

  /// @dev Returns the admin role that controls a role
  /// @param role: Role to check
  /// @return admin role
  function getRoleAdmin(
    bytes4 role
  ) external
    view 
    returns (bytes4) {
    return ADMIN;
  }

  /// @dev Grants `role` to `account`
  /// @param role: Bytes4 of a role
  /// @param account: account to give role to
  function grantRole(
    bytes4 role
  , address account
  ) external
    onlyRole(role) {
    if (role == PENDING_DEVS || role == PENDING_OWNERS) {
      revert Unauthorized();
    } else {
      contractRoles.add(role, account);
    }
  }

  /// @dev Revokes `role` from `account`
  /// @param role: Bytes4 of a role
  /// @param account: account to revoke role from
  function revokeRole(
    bytes4 role
  , address account
  ) external
    onlyRole(role) {
    if (role == PENDING_DEVS || role == PENDING_OWNERS) {
      if (account == msg.sender) {
        contractRoles.remove(role, account);
      } else {
        revert Unauthorized();
      }
    } else {
      contractRoles.remove(role, account);
    }
  }

  /// @dev Renounces `role` from `account`
  /// @param role: Bytes4 of a role
  function renounceRole(
    bytes4 role
  ) external
    onlyRole(role) {
    contractRoles.remove(role, msg.sender);
  }

  ////////////////////////////////////////////////////////////////////////
  /// ERC-721 Non-Fungible Token Standard, optional enumeration extension
  /// @dev may be added, but not fully supported see ERC-165 below
  ////////////////////////////////////////////////////////////////////////

  /// @notice Count NFTs tracked by this contract
  /// @return A count of valid NFTs tracked by this contract, where each one of
  ///  them has an assigned and queryable owner not equal to the zero address
  function totalSupply()
    external
    view
    virtual
    returns (uint256) {
    return token721.getSupply();
  }

  /////////////////////////////////////////////////
  /// ERC721 Metadata, optional metadata extension
  /////////////////////////////////////////////////

  /// @notice A descriptive name for a collection of NFTs in this contract
  function name()
    external
    view
    virtual
    override
    returns (string memory _name) {
    return token721.getName();
  }

  /// @notice An abbreviated name for NFTs in this contract
  function symbol()
    external
    view
    virtual
    override
    returns (string memory _symbol) {
    return token721.getSymbol();
  }

  /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
  /// @notice Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
  ///  3986. The URI may point to a JSON file that conforms to the "ERC721
  ///  Metadata JSON Schema".
  function tokenURI(
    uint256 _tokenId
  ) external
    view
    virtual
    override
    returns (string memory) {
    return token721.getTokenURI(_tokenId);
  }

  ////////////////////////////////////////
  /// ERC-721 Non-Fungible Token Standard
  ////////////////////////////////////////

  /// @notice Count all NFTs assigned to an owner
  /// @notice NFTs assigned to the zero address are considered invalid, and this
  ///  function throws for queries about the zero address.
  /// @param _owner An address for whom to query the balance
  /// @return The number of NFTs owned by `_owner`, possibly zero
  function balanceOf(
    address _owner
  ) external
    view
    virtual
    override
    returns (uint256) {
    return token721.getBalanceOf(_owner);
  }

  /// @notice Find the owner of an NFT
  /// @notice NFTs assigned to zero address are considered invalid, and queries
  ///  about them do throw.
  /// @param _tokenId The identifier for an NFT
  /// @return The address of the owner of the NFT
  function ownerOf(
    uint256 _tokenId
  ) external
    view
    virtual
    override
    returns (address) {
    return token721.getOwnerOf(_tokenId);
  }

  /// @notice Transfers the ownership of an NFT from one address to another address
  /// @notice Throws unless `msg.sender` is the current owner, an authorized
  ///  operator, or the approved address for this NFT. Throws if `_from` is
  ///  not the current owner. Throws if `_to` is the zero address. Throws if
  ///  `_tokenId` is not a valid NFT. When transfer is complete, this function
  ///  checks if `_to` is a smart contract (code size > 0). If so, it calls
  ///  `onERC721Received` on `_to` and throws if the return value is not
  ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
  /// @param _from The current owner of the NFT
  /// @param _to The new owner
  /// @param _tokenId The NFT to transfer
  /// @param data Additional data with no specified format, sent in call to `_to`
  function safeTransferFrom(
    address _from
  , address _to
  , uint256 _tokenId
  , bytes calldata data
  ) external
    virtual
    override {
    token721.doTransferFrom(_from, _to, msg.sender, _tokenId);
    safeHook(_from, _to, _tokenId, data);
    emit Transfer(_from, _to, _tokenId);
  }

  /// @notice Transfers the ownership of an NFT from one address to another address
  /// @notice This works identically to the other function with an extra data parameter,
  ///  except this function just sets data to "".
  /// @param _from The current owner of the NFT
  /// @param _to The new owner
  /// @param _tokenId The NFT to transfer
  function safeTransferFrom(
    address _from
  , address _to
  , uint256 _tokenId
  ) external
    virtual
    override {
    this.safeTransferFrom(_from, _to, _tokenId, "");
  }

  /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
  ///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
  ///  THEY MAY BE PERMANENTLY LOST
  /// @notice Throws unless `msg.sender` is the current owner, an authorized
  ///  operator, or the approved address for this NFT. Throws if `_from` is
  ///  not the current owner. Throws if `_to` is the zero address. Throws if
  ///  `_tokenId` is not a valid NFT.
  /// @param _from The current owner of the NFT
  /// @param _to The new owner
  /// @param _tokenId The NFT to transfer
  function transferFrom(
    address _from
  , address _to
  , uint256 _tokenId
  ) external
    virtual
    override {
    token721.doTransferFrom(_from, _to, msg.sender, _tokenId);
    emit Transfer(_from, _to, _tokenId);
  }

  /// @notice Change or reaffirm the approved address for an NFT
  /// @notice The zero address indicates there is no approved address.
  ///  Throws unless `msg.sender` is the current NFT owner, or an authorized
  ///  operator of the current owner.
  /// @param _approved The new approved NFT controller
  /// @param _tokenId The NFT to approve
  function approve(
    address _approved
  , uint256 _tokenId
  ) external
    virtual
    override {
    token721.setApprove(_approved, msg.sender, _tokenId);
    emit Approval(msg.sender, _approved, _tokenId);
  }

  /// @notice Enable or disable approval for a third party ("operator") to manage
  ///  all of `msg.sender`'s assets
  /// @notice Emits the ApprovalForAll event. The contract MUST allow
  ///  multiple operators per owner.
  /// @param _operator Address to add to the set of authorized operators
  /// @param _approved True if the operator is approved, false to revoke approval
  function setApprovalForAll(
    address _operator
  , bool _approved
  ) external
    virtual
    override {
    token721.setApprovalForAll(_operator, msg.sender, _approved);
    emit ApprovalForAll(msg.sender, _operator, _approved);
  }

  /// @notice Get the approved address for a single NFT
  /// @notice Throws if `_tokenId` is not a valid NFT.
  /// @param _tokenId The NFT to find the approved address for
  /// @return The approved address for this NFT, or the zero address if there is none
  function getApproved(
    uint256 _tokenId
  ) external
    view
    virtual
    override
    returns (address) {
    return token721.getApproved(_tokenId);
  }

  /// @notice Query if an address is an authorized operator for another address
  /// @param _owner The address that owns the NFTs
  /// @param _operator The address that acts on behalf of the owner
  /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
  function isApprovedForAll(
    address _owner
  , address _operator
  ) external
    view
    virtual
    override
    returns (bool) {
    return token721.isApprovedForAll(_owner, _operator);
  }

  ///////////////////////////////////////////////////////////////////
  /// ERC-721 Non-Fungible Token Standard, required wallet interface
  /// @dev This is to disable all safe transfers to this contract
  ///////////////////////////////////////////////////////////////////

  /// @notice Handle the receipt of an NFT
  /// @notice The ERC721 smart contract calls this function on the recipient
  ///  after a `transfer`. This function MAY throw to revert and reject the
  ///  transfer. Return of other than the magic value MUST result in the
  ///  transaction being reverted.
  ///  Note: the contract address is always the message sender.
  /// @param _operator The address which called `safeTransferFrom` function
  /// @param _from The address which previously owned the token
  /// @param _tokenId The NFT identifier which is being transferred
  /// @param _data Additional data with no specified format
  /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
  ///  unless throwing
  function onERC721Received(
    address _operator
  , address _from
  , uint256 _tokenId
  , bytes calldata _data
  ) external
    virtual
    override
    returns(bytes4) {
    revert Unauthorized();
  }

  ///////////////////////////////////
  /// EIP-2981: NFT Royalty Standard
  ///////////////////////////////////

  /// @notice Called with the sale price to determine how much royalty
  ///         is owed and to whom.
  /// @param _tokenId - the NFT asset queried for royalty information
  /// @param _salePrice - the sale price of the NFT asset specified by _tokenId
  /// @return receiver - address of who should be sent the royalty payment
  /// @return royaltyAmount - the royalty payment amount for _salePrice
  function royaltyInfo(
    uint256 _tokenId,
    uint256 _salePrice
  ) external
    view
    virtual
    override
    returns (
      address receiver,
      uint256 royaltyAmount
    ) {
    (receiver, royaltyAmount) = royalties.royaltyInfo(_tokenId,_salePrice);
  }

  ////////////////////////////////////////////////////
  /// EIP-2981: NFT Royalty Standard, admin extension
  /// @dev Using the collection standard
  ////////////////////////////////////////////////////

  /// @dev function (state storage) sets the royalty data for a token
  /// @param tokenId uint256 for the token
  /// @param receiver address for the royalty reciever for token
  /// @param permille uint16 for the permille of royalties 20 -> 2.0%
  function setRoyalties(
    uint256 tokenId
  , address receiver
  , uint16 permille
  ) external
    virtual
    override {
    revert Unauthorized();
  }

  /// @dev function (state storage) revokes the royalty data for a token
  /// @param tokenId uint256 for the token
  function revokeRoyalties(
    uint256 tokenId
  ) external
    virtual
    override {
    revert Unauthorized();
  }

  /// @dev function (state storage) sets the royalty data for a collection
  /// @param receiver address for the royalty reciever for token
  /// @param permille uint16 for the permille of royalties 20 -> 2.0%
  function setRoyalties(
    address receiver
  , uint16 permille
  ) external
    virtual
    onlyOwner()
    override {
    royalties.setRoyalties(receiver, permille);
  }

  /// @dev function (state storage) revokes the royalty data for a collection
  function revokeRoyalties()
    external
    virtual
    onlyOwner()
    override {
    royalties.revokeRoyalties();
  }

  ////////////////////////////////////////////////////////////////
  /// [Not an EIP] Payment Splitter, interface for ether payments
  ////////////////////////////////////////////////////////////////

  /// @dev returns total shares
  /// @return uint256 of all shares on contract
  function totalShares()
    external
    view
    virtual
    override
    returns (uint256) {
    return splitter.getTotalShares();
  }

  /// @dev returns shares of an address
  /// @param payee address of payee to return
  /// @return mapping(address => uint) of _shares
  function shares(
    address payee
  ) external
    view
    virtual
    override
    returns (uint256) {
    return splitter.payeeShares(payee);
  }

  /// @dev returns total releases in "eth"
  /// @return uint256 of all "eth" released in wei
  function totalReleased()
    external
    view
    virtual
    override
    returns (uint256) {
    return splitter.getTotalReleased();
  }

  /// @dev returns released "eth" of an payee
  /// @param payee address of payee to look up
  /// @return mapping(address => uint) of _released
  function released(
    address payee
  ) external
    view
    virtual
    override
    returns (uint256) {
    return splitter.payeeReleased(payee);
  }

  /// @dev returns amount of "eth" that can be released to payee
  /// @param payee address of payee to look up
  /// @return uint in wei of "eth" to release
  function releasable(
    address payee
  ) external
    view
    virtual
    override
    returns (uint256) {
    uint totalReceived
      = address(this).balance
      + this.totalReleased();
    return 
      totalReceived
    * this.shares(payee)
    / this.totalShares()
    - this.released(payee);
  }

  /// @dev returns index number of payee
  /// @param payee number of index
  /// @return address at _payees[index]
  function payeeIndex(
    address payee
  ) external
    view
    virtual
    override
    returns (uint256) {
    return splitter.payeeIndex(payee);
  }

  /// @dev this returns the array of payees[]
  /// @return address[] payees
  function payees()
    external
    view
    virtual
    override
    returns (address[] memory) {
    return splitter.getPayees();
  }

  /// @dev this claims all "eth" on contract for msg.sender
  function claim()
    external
    virtual
    override {
    if (this.shares(msg.sender) == 0) {
      revert Unauthorized();
    }
    uint256 payment = this.releasable(msg.sender);
    if (payment == 0) {
      revert Unauthorized();
    }
    splitter.processPayment(msg.sender, payment);
    Address.sendValue(payable(msg.sender), payment);
  }

  /// @dev This pays all payees
  function payClaims()
    external
    virtual
    override {
    address[] memory toPay = splitter.getPayees();
    uint256 len = toPay.length;
    for (uint x = 0 ; x < len ;) {
      uint256 payment = this.releasable(toPay[x]);
      splitter.processPayment(toPay[x], payment);
      Address.sendValue(payable(toPay[x]), payment);
      unchecked { ++x; }
    }
  }

  /// @dev This adds a payee
  /// @param payee Address of payee
  /// @param _shares Shares to send user
  function addPayee(
    address payee
  , uint256 _shares
  ) external
    virtual
    onlyDev()
    override {
    splitter.addPayee(payee, _shares);
  }

  /// @dev This removes a payee
  /// @param payee Address of payee to remove
  /// @notice use payPayees() prior to use if anything is on the contract
  function removePayee(
    address payee
  ) external
    virtual
    onlyDev()
    override {
    splitter.removePayee(payee);
  }

  /// @dev This removes all payees
  /// @notice use payPayees() prior to use if anything is on the contract
  function clearPayees()
    external
    virtual
    onlyDev()
    override {
    splitter.clearPayees();
  }

  //////////////////////////////////////////
  /// EIP-165: Standard Interface Detection
  //////////////////////////////////////////

  /// @dev Query if a contract implements an interface
  /// @param interfaceID The interface identifier, as specified in ERC-165
  /// @notice Interface identification is specified in ERC-165. This function
  ///  uses less than 30,000 gas.
  /// @return `true` if the contract implements `interfaceID` and
  ///  `interfaceID` is not 0xffffffff, `false` otherwise
  function supportsInterface(
    bytes4 interfaceID
  ) external
    view
    virtual
    override
    returns (bool) {
    return (
      interfaceID == type(IERC173).interfaceId  ||
      interfaceID == type(IERC721).interfaceId  ||
      interfaceID == type(IERC2981).interfaceId  ||
      interfaceID == type(IERC721Metadata).interfaceId
    );
  }
}

File 23 of 24 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates merkle trees that are safe
 * against this attack out of the box.
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Calldata version of {verify}
     *
     * _Available since v4.7._
     */
    function verifyCalldata(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     *
     * _Available since v4.4._
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Calldata version of {processProof}
     *
     * _Available since v4.7._
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * _Available since v4.7._
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * _Available since v4.7._
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     *
     * _Available since v4.7._
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}.
     *
     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * _Available since v4.7._
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

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

pragma solidity ^0.8.0;

/**
 * @dev Provides a set of functions to operate with Base64 strings.
 *
 * _Available since v4.5._
 */
library Base64 {
    /**
     * @dev Base64 Encoding/Decoding Table
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    /**
     * @dev Converts a `bytes` to its Bytes64 `string` representation.
     */
    function encode(bytes memory data) internal pure returns (string memory) {
        /**
         * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
         * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
         */
        if (data.length == 0) return "";

        // Loads the table into memory
        string memory table = _TABLE;

        // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
        // and split into 4 numbers of 6 bits.
        // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
        // - `data.length + 2`  -> Round up
        // - `/ 3`              -> Number of 3-bytes chunks
        // - `4 *`              -> 4 characters for each chunk
        string memory result = new string(4 * ((data.length + 2) / 3));

        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the lookup table (skip the first "length" byte)
            let tablePtr := add(table, 1)

            // Prepare result pointer, jump over length
            let resultPtr := add(result, 32)

            // Run over the input, 3 bytes at a time
            for {
                let dataPtr := data
                let endPtr := add(data, mload(data))
            } lt(dataPtr, endPtr) {

            } {
                // Advance 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

                // To write each character, shift the 3 bytes (18 bits) chunk
                // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
                // and apply logical AND with 0x3F which is the number of
                // the previous character in the ASCII table prior to the Base64 Table
                // The result is then added to the table to get the character to write,
                // and finally write it in the result pointer but with a left shift
                // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits

                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance
            }

            // When data `bytes` is not exactly 3 bytes long
            // it is padded with `=` characters at the end
            switch mod(mload(data), 3)
            case 1 {
                mstore8(sub(resultPtr, 1), 0x3d)
                mstore8(sub(resultPtr, 2), 0x3d)
            }
            case 2 {
                mstore8(sub(resultPtr, 1), 0x3d)
            }
        }

        return result;
    }
}

Settings
{
  "remappings": [],
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "evmVersion": "london",
  "libraries": {},
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_dev","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_start","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"name":"MaxSplaining","type":"error"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"name":"MaxSplaining","type":"error"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"name":"MaxSplaining","type":"error"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"name":"MaxSplaining","type":"error"},{"inputs":[{"internalType":"uint256","name":"yourTime","type":"uint256"},{"internalType":"uint256","name":"hitTime","type":"uint256"}],"name":"TooLateBoomer","type":"error"},{"inputs":[{"internalType":"uint256","name":"yourTime","type":"uint256"},{"internalType":"uint256","name":"hitTime","type":"uint256"}],"name":"TooSoonJunior","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","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":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"what","type":"string"}],"name":"Claimed","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":"_payee","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"PaymentReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"acceptDeveloper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"payee","type":"address"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"addPayee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"adminMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_approved","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"clearPayees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"declineDeveloper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"declineOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"developer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"homiesMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"isClaimedAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"isClaimedHomies","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"isClaimedNormies","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"_name","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"normiesCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"normiesMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payClaims","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"payee","type":"address"}],"name":"payeeIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payees","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quant","type":"uint256"}],"name":"publicMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newDeveloper","type":"address"}],"name":"pushDeveloper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"pushOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"payee","type":"address"}],"name":"releasable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"payee","type":"address"}],"name":"released","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"payee","type":"address"}],"name":"removePayee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceDeveloper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"role","type":"bytes4"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"revokeRoyalties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokeRoyalties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","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":"uint256","name":"_amount","type":"uint256"}],"name":"setCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newURI","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_normies","type":"uint256"},{"internalType":"uint256","name":"_public","type":"uint256"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_description","type":"string"},{"internalType":"string","name":"_image","type":"string"},{"internalType":"string","name":"_animation","type":"string"}],"name":"setJSON","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_admin","type":"bytes32"},{"internalType":"bytes32","name":"_homies","type":"bytes32"},{"internalType":"bytes32","name":"_normies","type":"bytes32"}],"name":"setMerks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint16","name":"permille","type":"uint16"}],"name":"setRoyalties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint16","name":"permille","type":"uint16"}],"name":"setRoyalties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_period","type":"uint256"}],"name":"setTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"payee","type":"address"}],"name":"shares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"showTimes","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalReleased","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newDeveloper","type":"address"}],"name":"transferDeveloper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405266f5232269808000601f5567016345785d8a00006020553480156200002857600080fd5b5060405162005171380380620051718339810160408190526200004b9162000612565b6200005a868686868662000081565b620000758160216200017260201b620026031790919060201c565b5050505050506200084c565b6200009c856000620001ad60201b6200263e1790919060201c565b620000b7846000620001ef60201b6200267c1790919060201c565b620000d860086303e1469160e61b8562000231602090811b620026ba17901c565b620000f38360086200030160201b6200278a1790919060201c565b62000114600863ca4b208b60e01b8462000231602090811b620026ba17901c565b6200012f826008620003ec60201b620028591790919060201c565b620001506008638da5cb5b60e01b8362000231602090811b620026ba17901c565b6200016b8160086200045b60201b620028c51790919060201c565b5050505050565b8082556040518181527f83b179bd5cb3a111f82ac98510d3c66f48f77679e657302f4f253d4c32d6d672906020015b60405180910390a15050565b60048201620001bd82826200074b565b507f13c98778b0c1a086bb98d7f1986e15788b5d3a1ad4c492e1d78f1c4cc51c20cf81604051620001a1919062000817565b60058201620001ff82826200074b565b507f3e46ff90086ee29856e77591e82c82ff8ed513379b0fd82e84fc5290dd633c9981604051620001a1919062000817565b6001600160a01b03811662000258576040516282b42960e81b815260040160405180910390fd5b62000265838383620004ca565b1562000283576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0381166000818152602085815260408083206001600160e01b03198716808552908352928190208054600160ff1990911681179091558151938452918301939093528183015290517fc8bed56f8e046b5a3f2c2b2be85045ea5c972dc18ad669157957897b4d26e9f79181900360600190a1505050565b62000315826303e1469160e61b83620004ca565b1562000370576003820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec690600090a3505050565b6001600160a01b038116620003d4576003820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec690600090a3505050565b6040516282b42960e81b815260040160405180910390fd5b620004008263ca4b208b60e01b83620004ca565b1562000370576002820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f2cfca82ac51c2fc6b6db547820d28d526a505e12d230afb8bf112a5aeefa9a4c90600090a3505050565b6200046f82638da5cb5b60e01b83620004ca565b1562000370576001820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b60006001600160a01b038216620004f3576040516282b42960e81b815260040160405180910390fd5b506001600160a01b03166000908152602092835260408082206001600160e01b03199390931682529190925290205460ff1690565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200055b57818101518382015260200162000541565b50506000910152565b600082601f8301126200057657600080fd5b81516001600160401b038082111562000593576200059362000528565b604051601f8301601f19908116603f01168101908282118183101715620005be57620005be62000528565b81604052838152866020858801011115620005d857600080fd5b620005eb8460208301602089016200053e565b9695505050505050565b80516001600160a01b03811681146200060d57600080fd5b919050565b60008060008060008060c087890312156200062c57600080fd5b86516001600160401b03808211156200064457600080fd5b620006528a838b0162000564565b975060208901519150808211156200066957600080fd5b506200067889828a0162000564565b9550506200068960408801620005f5565b93506200069960608801620005f5565b9250620006a960808801620005f5565b915060a087015190509295509295509295565b600181811c90821680620006d157607f821691505b602082108103620006f257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200074657600081815260208120601f850160051c81016020861015620007215750805b601f850160051c820191505b8181101562000742578281556001016200072d565b5050505b505050565b81516001600160401b0381111562000767576200076762000528565b6200077f81620007788454620006bc565b84620006f8565b602080601f831160018114620007b757600084156200079e5750858301515b600019600386901b1c1916600185901b17855562000742565b600085815260208120601f198616915b82811015620007e857888601518255948401946001909101908401620007c7565b5085821015620008075787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020815260008251806020840152620008388160408501602087016200053e565b601f01601f19169190910160400192915050565b614915806200085c6000396000f3fe6080604052600436106104185760003560e01c806376d7fc0711610228578063b88d4fde11610128578063dcd4ab77116100bb578063e8a3d4851161008a578063ec1ffdd81161006f578063ec1ffdd814610c1a578063f2fde38b14610c44578063f950233314610c6457610455565b8063e8a3d48514610be5578063e985e9c514610bfa57610455565b8063dcd4ab7714610b7b578063de02cde714610b90578063e33b7de314610bb0578063e7b7544014610bc557610455565b8063ca4b208b116100f7578063ca4b208b14610b0a578063ce7c2ac214610b28578063d39ce77c14610b48578063d601f1dc14610b6857610455565b8063b88d4fde14610a8a578063bb5027f714610aaa578063c3b8e34514610aca578063c87b56dd14610aea57610455565b806396d32915116101bb578063a22cb4651161018a578063a6b6cb371161016f578063a6b6cb3714610a4a578063a86ff96014610a60578063ad6d9c1714610a7557610455565b8063a22cb46514610a0a578063a3f8eace14610a2a57610455565b806396d329151461098f5780639852595c146109af5780639bce3944146109cf578063a0355eca146109ea57610455565b80638bb2b65a116101f75780638bb2b65a1461091c5780638da5cb5b1461093c578063938e3d7b1461095a57806395d89b411461097a57610455565b806376d7fc07146108bc57806379ba5097146108d15780638159324c146108e65780638693da201461090657610455565b80632db11544116103335780634e8086aa116102c65780636352211e1161029557806366278a6c1161027a57806366278a6c1461086757806370a0823114610887578063715018a6146108a757610455565b80636352211e1461082757806364cb4edb1461084757610455565b80634e8086aa1461079e57806350d604e3146107c05780635ba5e9f0146107e05780636149d8711461080757610455565b806342842e0e1161030257806342842e0e1461072957806344faded01461074957806347786d37146107695780634e71d92d1461078957610455565b80632db11544146106cc57806331e26cfd146106df5780633a98ef39146106f45780633ed358551461070957610455565b8063150b7a02116103ab57806323b872dd1161037a57806323b872dd14610643578063266dcbf6146106635780632a55205a146106785780632bfcf0f2146106b757610455565b8063150b7a02146105b557806318160ddd146105ee57806318f9b023146106035780631fcb02f31461062357610455565b80630b78f9c0116103e75780630b78f9c0146105385780630c222ee51461055857806310ab94321461057857806312065fe01461059857610455565b806301ffc9a71461048757806306fdde03146104bc578063081812fc146104de578063095ea7b31461051657610455565b366104555760405134815233907f6ef95f06320e7a25a04a175ca677b7052bdd97131872c2192525a629f51be770906020015b60405180910390a2005b60405134815233907f6ef95f06320e7a25a04a175ca677b7052bdd97131872c2192525a629f51be7709060200161044b565b34801561049357600080fd5b506104a76104a2366004613df4565b610c84565b60405190151581526020015b60405180910390f35b3480156104c857600080fd5b506104d1610d55565b6040516104b39190613e61565b3480156104ea57600080fd5b506104fe6104f9366004613e74565b610d66565b6040516001600160a01b0390911681526020016104b3565b34801561052257600080fd5b50610536610531366004613ea9565b610d72565b005b34801561054457600080fd5b50610536610553366004613ed3565b610dbb565b34801561056457600080fd5b50610536610573366004613f07565b610df6565b34801561058457600080fd5b506104a7610593366004613f3a565b610e1e565b3480156105a457600080fd5b50475b6040519081526020016104b3565b3480156105c157600080fd5b506105d56105d0366004613f66565b610e33565b6040516001600160e01b031990911681526020016104b3565b3480156105fa57600080fd5b506105a7610e4d565b34801561060f57600080fd5b5061053661061e366004613ea9565b610e59565b34801561062f57600080fd5b5061053661063e366004614001565b610dde565b34801561064f57600080fd5b5061053661065e36600461403d565b610e7d565b34801561066f57600080fd5b50610536610ed1565b34801561068457600080fd5b50610698610693366004613ed3565b610fe6565b604080516001600160a01b0390931683526020830191909152016104b3565b3480156106c357600080fd5b50610536611000565b6105366106da366004613e74565b611066565b3480156106eb57600080fd5b506105366111be565b34801561070057600080fd5b506105a7611203565b34801561071557600080fd5b50610536610724366004614079565b61120e565b34801561073557600080fd5b5061053661074436600461403d565b611231565b34801561075557600080fd5b50610536610764366004613f3a565b6112c5565b34801561077557600080fd5b50610536610784366004613e74565b61134c565b34801561079557600080fd5b50610536611369565b3480156107aa57600080fd5b506107b361149a565b6040516104b39190614094565b3480156107cc57600080fd5b506104a76107db366004613e74565b6114a6565b3480156107ec57600080fd5b506105d56107fb366004613df4565b506303e1469160e61b90565b34801561081357600080fd5b50610536610822366004614079565b6114e7565b34801561083357600080fd5b506104fe610842366004613e74565b61152c565b34801561085357600080fd5b50610536610862366004614079565b611549565b34801561087357600080fd5b50610536610882366004613df4565b6115ac565b34801561089357600080fd5b506105a76108a2366004614079565b6115e3565b3480156108b357600080fd5b50610536611601565b3480156108c857600080fd5b50610536611652565b3480156108dd57600080fd5b50610536611676565b3480156108f257600080fd5b5061053661090136600461412d565b6116d9565b34801561091257600080fd5b506105a760205481565b34801561092857600080fd5b50610536610937366004614238565b61195f565b34801561094857600080fd5b506009546001600160a01b03166104fe565b34801561096657600080fd5b506105366109753660046142c0565b6119a3565b34801561098657600080fd5b506104d16119c7565b34801561099b57600080fd5b506104a76109aa366004613e74565b6119d3565b3480156109bb57600080fd5b506105a76109ca366004614079565b611a14565b3480156109db57600080fd5b5061053661063e366004613e74565b3480156109f657600080fd5b50610536610a05366004613ed3565b611a32565b348015610a1657600080fd5b50610536610a253660046142f5565b611a55565b348015610a3657600080fd5b506105a7610a45366004614079565b611aa8565b348015610a5657600080fd5b506105a7601f5481565b348015610a6c57600080fd5b50610536611c83565b348015610a8157600080fd5b50610536611cc8565b348015610a9657600080fd5b50610536610aa5366004613f66565b611d19565b348015610ab657600080fd5b50610536610ac5366004614331565b611db2565b348015610ad657600080fd5b506104a7610ae5366004613e74565b612024565b348015610af657600080fd5b506104d1610b05366004613e74565b612065565b348015610b1657600080fd5b50600a546001600160a01b03166104fe565b348015610b3457600080fd5b506105a7610b43366004614079565b6120cc565b348015610b5457600080fd5b50610536610b63366004614079565b6120ea565b610536610b76366004614331565b61212f565b348015610b8757600080fd5b506105366123e8565b348015610b9c57600080fd5b50610536610bab366004613f3a565b61240a565b348015610bbc57600080fd5b50600e546105a7565b348015610bd157600080fd5b506105a7610be0366004614079565b61248d565b348015610bf157600080fd5b506104d161249a565b348015610c0657600080fd5b506104a7610c1536600461438b565b61252c565b348015610c2657600080fd5b50610c2f61255c565b604080519283526020830191909152016104b3565b348015610c5057600080fd5b50610536610c5f366004614079565b61257a565b348015610c7057600080fd5b50610536610c7f3660046143a7565b6125dd565b60006001600160e01b031982167f7f5828d0000000000000000000000000000000000000000000000000000000001480610ce757506001600160e01b031982167f80ac58cd00000000000000000000000000000000000000000000000000000000145b80610d1b57506001600160e01b031982167f2a55205a00000000000000000000000000000000000000000000000000000000145b80610d4f57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b92915050565b6060610d616000612931565b905090565b6000610d4f81836129c7565b610d7f6000833384612a4c565b60405181906001600160a01b0384169033907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590600090a45050565b610dce600863ca4b208b60e01b33612b45565b15610dde57601f91909155602055565b6040516282b42960e81b815260040160405180910390fd5b610e096008638da5cb5b60e01b33612b45565b15610dde57610e1a600c8383612ba2565b5050565b6000610e2c60088484612b45565b9392505050565b60006040516282b42960e81b815260040160405180910390fd5b6000610d616000612c83565b610e6c600863ca4b208b60e01b33612b45565b15610dde57610e1a600d8383612c90565b610e8b600084843385612e27565b80826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b6000610edd600d612fe4565b805190915060005b81811015610fe1576000306001600160a01b031663a3f8eace858481518110610f1057610f106143d3565b60200260200101516040518263ffffffff1660e01b8152600401610f4391906001600160a01b0391909116815260200190565b602060405180830381865afa158015610f60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8491906143e9565b9050610fb5848381518110610f9b57610f9b6143d3565b602002602001015182600d6130499092919063ffffffff16565b610fd8848381518110610fca57610fca6143d3565b6020026020010151826130d0565b50600101610ee5565b505050565b600080610ff5600c85856131e9565b909590945092505050565b636525904560e11b61101460088233612b45565b8061102d575061102d60086303e1469160e61b33612b45565b15610dde57611045600863ca4b208b60e01b336126ba565b611050600833612859565b6110636008636525904560e11b33613226565b50565b6013546012546110769190614418565b4210610dde57600581111561109d576040516282b42960e81b815260040160405180910390fd5b6012546000036110bf576040516282b42960e81b815260040160405180910390fd5b806020546110cd919061442b565b341461112157604051630330dbc960e11b815260206004820152601160248201527f6d73672e76616c756520746f6f206c6f7700000000000000000000000000000060448201526064015b60405180910390fd5b6014548161112f6000612c83565b6111399190614418565b1115611157576040516282b42960e81b815260040160405180910390fd5b60005b81811015610e1a576111783361116f60215490565b600091906132e2565b60215460405133906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46111b6602180546001019055565b60010161115a565b636525904560e11b6111d260088233612b45565b806111eb57506111eb60086303e1469160e61b33612b45565b15610dde576110636008636525904560e11b33613226565b6000610d61600d5490565b611221600863ca4b208b60e01b33612b45565b15610dde57611063600d82613407565b6040517fb88d4fde0000000000000000000000000000000000000000000000000000000081526001600160a01b03808516600483015283166024820152604481018290526080606482015260006084820152309063b88d4fde9060a401600060405180830381600087803b1580156112a857600080fd5b505af11580156112bc573d6000803e3d6000fd5b50505050505050565b816112d260088233612b45565b806112eb57506112eb60086303e1469160e61b33612b45565b15610dde576001600160e01b03198316636525904560e11b148061131f57506001600160e01b031983166346d2e5ad60e11b145b1561134057336001600160a01b03831603610dde57610fe160088484613226565b610fe160088484613226565b61135f600863ca4b208b60e01b33612b45565b15610dde57601455565b60405163673e156160e11b8152336004820152309063ce7c2ac290602401602060405180830381865afa1580156113a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c891906143e9565b6000036113e7576040516282b42960e81b815260040160405180910390fd5b6040517fa3f8eace000000000000000000000000000000000000000000000000000000008152336004820152600090309063a3f8eace90602401602060405180830381865afa15801561143e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061146291906143e9565b905080600003611484576040516282b42960e81b815260040160405180910390fd5b611490600d3383613049565b61106333826130d0565b6060610d61600d612fe4565b6000806114b561010084614458565b905060006114c56101008561446c565b60009283526016602052604090922054600190921b9182169091149392505050565b63ca4b208b60e01b6114fb60088233612b45565b80611514575061151460086303e1469160e61b33612b45565b15610dde57610e1a6008636525904560e11b846126ba565b6000818152602081905260408120546001600160a01b0316610d4f565b63ca4b208b60e01b61155d60088233612b45565b80611576575061157660086303e1469160e61b33612b45565b15610dde5761158e600863ca4b208b60e01b846126ba565b611599600883612859565b610e1a600863ca4b208b60e01b33613226565b806115b960088233612b45565b806115d257506115d260086303e1469160e61b33612b45565b15610dde57610e1a60088333613226565b6001600160a01b038116600090815260016020526040812054610d4f565b638da5cb5b60e01b61161560088233612b45565b8061162e575061162e60086303e1469160e61b33612b45565b15610dde5761163f600860006128c5565b6110636008638da5cb5b60e01b33613226565b611665600863ca4b208b60e01b33612b45565b15610dde57611674600d613587565b565b6346d2e5ad60e11b61168a60088233612b45565b806116a357506116a360086303e1469160e61b33612b45565b15610dde576116bb6008638da5cb5b60e01b336126ba565b6116c66008336128c5565b61106360086346d2e5ad60e11b33613226565b6013546012546116e99190614418565b421080156116f957506012544210155b15610dde57601254600003611720576040516282b42960e81b815260040160405180910390fd5b611729856114a6565b1561176957604051630330dbc960e11b815260206004820152600f60248201526e105b1c9958591e4810db185a5b5959608a1b6044820152606401611118565b60408051602081018790526bffffffffffffffffffffffff19606087901b1691810191909152605481018490526000906074016040516020818303038152906040528051906020012090506117f583838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050601554915084905061361c565b61183257604051630330dbc960e11b815260206004820152600d60248201526c24b73b30b634b210283937b7b360991b6044820152606401611118565b61183b86613632565b601454846118496000612c83565b6118539190614418565b1115611871576040516282b42960e81b815260040160405180910390fd5b60005b848110156118d8576118898661116f60215490565b6021546040516001600160a01b038816906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46118d0602180546001019055565b600101611874565b50604080518781526001600160a01b03871660208201529081018590526080606082018190526005908201527f41646d696e00000000000000000000000000000000000000000000000000000060a08201527fee563d8e532abc293fca2fdeb41c25180305bddcf9206c167dab3e155aaf17139060c00160405180910390a1505050505050565b611972600863ca4b208b60e01b33612b45565b15610dde57601d6119838482614508565b50601c6119908382614508565b50601e61199d8282614508565b50505050565b6119b6600863ca4b208b60e01b33612b45565b15610dde57601b610e1a8282614508565b6060610d616000613670565b6000806119e261010084614458565b905060006119f26101008561446c565b6000928352601a602052604090922054600190921b9182169091149392505050565b6001600160a01b038116600090815260106020526040812054610d4f565b611a45600863ca4b208b60e01b33612b45565b15610dde57601291909155601355565b611a626000833384613681565b60405181151581526001600160a01b0383169033907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319060200160405180910390a35050565b600080306001600160a01b031663e33b7de36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ae9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0d91906143e9565b611b179047614418565b6040517f9852595c0000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201529091503090639852595c90602401602060405180830381865afa158015611b77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9b91906143e9565b306001600160a01b0316633a98ef396040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bfd91906143e9565b60405163673e156160e11b81526001600160a01b0386166004820152309063ce7c2ac290602401602060405180830381865afa158015611c41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c6591906143e9565b611c6f908461442b565b611c799190614458565b610e2c91906145c8565b6346d2e5ad60e11b611c9760088233612b45565b80611cb05750611cb060086303e1469160e61b33612b45565b15610dde5761106360086346d2e5ad60e11b33613226565b63ca4b208b60e01b611cdc60088233612b45565b80611cf55750611cf560086303e1469160e61b33612b45565b15610dde57611d0660086000612859565b611063600863ca4b208b60e01b33613226565b611d27600086863387612e27565b611d6985858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061372192505050565b5082846001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505050565b601354601254611dc29190614418565b42108015611dd257506012544210155b15610dde57601254600003611df9576040516282b42960e81b815260040160405180910390fd5b611e0284612024565b15611e4257604051630330dbc960e11b815260206004820152600f60248201526e105b1c9958591e4810db185a5b5959608a1b6044820152606401611118565b60008484604051602001611e7292919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b604051602081830303815290604052805190602001209050611ecb83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050601754915084905061361c565b611f0857604051630330dbc960e11b815260206004820152600d60248201526c24b73b30b634b210283937b7b360991b6044820152606401611118565b611f1185613823565b601454611f1e6000612c83565b611f29906001614418565b1115611f47576040516282b42960e81b815260040160405180910390fd5b611f548461116f60215490565b6021546040516001600160a01b038616906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4611f9b602180546001019055565b604080518681526001600160a01b03861660208201526001918101919091526080606082018190526006908201527f486f6d696573000000000000000000000000000000000000000000000000000060a08201527fee563d8e532abc293fca2fdeb41c25180305bddcf9206c167dab3e155aaf17139060c0015b60405180910390a15050505050565b60008061203361010084614458565b905060006120436101008561446c565b60009283526018602052604090922054600190921b9182169091149392505050565b6060600061207283613861565b601d601c601e60405160200161208b949392919061464e565b60405160208183030381529060405290506120a581613996565b6040516020016120b591906147d2565b604051602081830303815290604052915050919050565b6001600160a01b0381166000908152600f6020526040812054610d4f565b638da5cb5b60e01b6120fe60088233612b45565b80612117575061211760086303e1469160e61b33612b45565b15610dde57610e1a60086346d2e5ad60e11b846126ba565b60135460125461213f9190614418565b4210801561214f57506012544210155b15610dde57601254600003612176576040516282b42960e81b815260040160405180910390fd5b601f5434146121c857604051630330dbc960e11b815260206004820152601160248201527f6d73672e76616c756520746f6f206c6f770000000000000000000000000000006044820152606401611118565b6121d1846119d3565b1561221157604051630330dbc960e11b815260206004820152600f60248201526e105b1c9958591e4810db185a5b5959608a1b6044820152606401611118565b6000848460405160200161224192919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b60405160208183030381529060405280519060200120905061229a83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050601954915084905061361c565b6122d757604051630330dbc960e11b815260206004820152600d60248201526c24b73b30b634b210283937b7b360991b6044820152606401611118565b6122e085613ae9565b6014546122ed6000612c83565b6122f8906001614418565b1115612316576040516282b42960e81b815260040160405180910390fd5b6123238461116f60215490565b6021546040516001600160a01b038616906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a461236a602180546001019055565b604080518681526001600160a01b03861660208201526001918101919091526080606082018190526007908201527f4e6f726d6965730000000000000000000000000000000000000000000000000060a08201527fee563d8e532abc293fca2fdeb41c25180305bddcf9206c167dab3e155aaf17139060c001612015565b6123fb6008638da5cb5b60e01b33612b45565b15610dde57611674600c613b27565b8161241760088233612b45565b80612430575061243060086303e1469160e61b33612b45565b15610dde576001600160e01b03198316636525904560e11b148061246457506001600160e01b031983166346d2e5ad60e11b145b15612481576040516282b42960e81b815260040160405180910390fd5b610fe1600884846126ba565b6000610d4f600d83613b8c565b6060601b80546124a990614480565b80601f01602080910402602001604051908101604052809291908181526020018280546124d590614480565b80156125225780601f106124f757610100808354040283529160200191612522565b820191906000526020600020905b81548152906001019060200180831161250557829003601f168201915b5050505050905090565b6001600160a01b03808316600090815260036020908152604080832093851683529290529081205460ff16610e2c565b6000806012546013546012546125729190614418565b915091509091565b638da5cb5b60e01b61258e60088233612b45565b806125a757506125a760086303e1469160e61b33612b45565b15610dde576125bf6008638da5cb5b60e01b846126ba565b6125ca6008836128c5565b610e1a6008638da5cb5b60e01b33613226565b6125f0600863ca4b208b60e01b33612b45565b15610dde57601592909255601755601955565b8082556040518181527f83b179bd5cb3a111f82ac98510d3c66f48f77679e657302f4f253d4c32d6d672906020015b60405180910390a15050565b6004820161264c8282614508565b507f13c98778b0c1a086bb98d7f1986e15788b5d3a1ad4c492e1d78f1c4cc51c20cf816040516126329190613e61565b6005820161268a8282614508565b507f3e46ff90086ee29856e77591e82c82ff8ed513379b0fd82e84fc5290dd633c99816040516126329190613e61565b6001600160a01b0381166126e0576040516282b42960e81b815260040160405180910390fd5b6126eb838383612b45565b15612708576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0381166000818152602085815260408083206001600160e01b0319871680855290835292819020805460ff19166001908117909155815193845291830193909352918101919091527fc8bed56f8e046b5a3f2c2b2be85045ea5c972dc18ad669157957897b4d26e9f7906060015b60405180910390a1505050565b61279c826303e1469160e61b83612b45565b156127f6576003820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec690600090a3505050565b6001600160a01b038116610dde576003820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec690600090a3505050565b61286b8263ca4b208b60e01b83612b45565b156127f6576002820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f2cfca82ac51c2fc6b6db547820d28d526a505e12d230afb8bf112a5aeefa9a4c90600090a3505050565b6128d782638da5cb5b60e01b83612b45565b156127f6576001820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b606081600401805461294290614480565b80601f016020809104026020016040519081016040528092919081815260200182805461296e90614480565b80156129bb5780601f10612990576101008083540402835291602001916129bb565b820191906000526020600020905b81548152906001019060200180831161299e57829003601f168201915b50505050509050919050565b6000818152602083905260408120546001600160a01b0316612a2c57604051630330dbc960e11b815260206004820152600360248201527f4c3a3100000000000000000000000000000000000000000000000000000000006044820152606401611118565b50600090815260029190910160205260409020546001600160a01b031690565b6000818152602085905260409020546001600160a01b03908116908416819003612ab957604051630330dbc960e11b815260206004820152600360248201527f4c3a3200000000000000000000000000000000000000000000000000000000006044820152606401611118565b612ac4858484613c55565b612b1157604051630330dbc960e11b815260206004820152600360248201527f4c3a3300000000000000000000000000000000000000000000000000000000006044820152606401611118565b50600090815260029390930160205250604090912080546001600160a01b0319166001600160a01b03909216919091179055565b60006001600160a01b038216612b6d576040516282b42960e81b815260040160405180910390fd5b506001600160a01b03166000908152602092835260408082206001600160e01b03199390931682529190925290205460ff1690565b6103e88161ffff16101580612bb9575061ffff8116155b15612c0757604051630330dbc960e11b815260206004820152600360248201527f523a3100000000000000000000000000000000000000000000000000000000006044820152606401611118565b82546001600160a01b0383811675ffffffffffffffffffffffffffffffffffffffffffff1990921691909117600160a01b61ffff84811682029290921780875560408051948216855291900490911660208301527f712ca2ffb17da9e3b90d98d54938dee8be84b528cbdec691d680c1df8b78538a910161277d565b6000610d4f826007015490565b6001600160a01b038216612cd057604051630330dbc960e11b81526004016111189060208082526004908201526350533a3360e01b604082015260600190565b80600003612d2357604051630330dbc960e11b81526004016111189060208082526004908201527f50533a3400000000000000000000000000000000000000000000000000000000604082015260600190565b6001600160a01b038216600090815260028401602052604090205415612d8e57604051630330dbc960e11b81526004016111189060208082526004908201527f50533a3500000000000000000000000000000000000000000000000000000000604082015260600190565b6004830180546001810182556000918252602080832090910180546001600160a01b0319166001600160a01b038616908117909155825260028501905260408120829055835482918591612de3908490614418565b9091555050604080516001600160a01b0384168152602081018390527f40c340f65e17194d14ddddb073d3c9f888e3cb52b5aae0c6c7706b4fbc905fac910161277d565b612e32858383613c55565b612e7f57604051630330dbc960e11b815260206004820152600360248201527f4c3a3500000000000000000000000000000000000000000000000000000000006044820152606401611118565b6000818152602086905260409020546001600160a01b039081169085168114612eeb57604051630330dbc960e11b815260206004820152600360248201527f4c3a3600000000000000000000000000000000000000000000000000000000006044820152606401611118565b6001600160a01b038416612f4257604051630330dbc960e11b815260206004820152600360248201527f4c3a3700000000000000000000000000000000000000000000000000000000006044820152606401611118565b612f4f8660008585612a4c565b6001600160a01b0385166000908152600187810160205260408220805491929091612f7b9084906145c8565b90915550506001600160a01b0384166000908152600187810160205260408220805491929091612fac908490614418565b909155505050600090815260209490945250604090922080546001600160a01b0319166001600160a01b039093169290921790915550565b6060816004018054806020026020016040519081016040528092919081815260200182805480156129bb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116130205750505050509050919050565b8083600101600082825461305d9190614418565b90915550506001600160a01b03821660009081526003840160205260408120805483929061308c908490614418565b9091555050604080516001600160a01b0384168152602081018390527fdf20fd1e76bc69d672e4814fafb2c449bba3a5369d8359adf9e05e6fde87b056910161277d565b804710156131205760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401611118565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461316d576040519150601f19603f3d011682016040523d82523d6000602084013e613172565b606091505b5050905080610fe15760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401611118565b82546001600160a01b038116906000906103e89061321290600160a01b900461ffff168561442b565b61321c9190614458565b9050935093915050565b6001600160a01b03811661324c576040516282b42960e81b815260040160405180910390fd5b613257838383612b45565b613273576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0381166000818152602085815260408083206001600160e01b03198716808552908352818420805460ff19169055815190815291820193909352918201527fc8bed56f8e046b5a3f2c2b2be85045ea5c972dc18ad669157957897b4d26e9f79060600161277d565b6001600160a01b03821661333957604051630330dbc960e11b815260206004820152600360248201527f4c3a3800000000000000000000000000000000000000000000000000000000006044820152606401611118565b6000818152602084905260409020546001600160a01b03161561339f57604051630330dbc960e11b815260206004820152600360248201527f4c3a3900000000000000000000000000000000000000000000000000000000006044820152606401611118565b6001600160a01b03821660009081526001848101602052604082208054919290916133cb908490614418565b9091555050600081815260208490526040902080546001600160a01b0319166001600160a01b0384161790556007830180546001019055505050565b6001600160a01b03811661344757604051630330dbc960e11b81526004016111189060208082526004908201526350533a3360e01b604082015260600190565b60006134538383613b8c565b60048401805491925060009161346b906001906145c8565b8154811061347b5761347b6143d3565b6000918252602090912001546004850180546001600160a01b0390921692508291849081106134ac576134ac6143d3565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550836004018054806134ed576134ed614817565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0385168252600286019052604081208054908290558554909182918791906135439084906145c8565b9091555050604080516001600160a01b0386168152602081018390527f104b8837ec12e86f303ac7ce5e3bf20c6790f843fabd7451943f3390fc8376cb9101612015565b600481015460005b818110156135db5760008360040182815481106135ae576135ae6143d3565b60009182526020808320909101546001600160a01b0316825260028601905260408120555060010161358f565b5060008083556135ef906004840190613dac565b6040517f3407fd525bf6581e0ae8e3a3636bd90d02112bea34d66802743c28ced73f910e90600090a15050565b6000826136298584613cd4565b14949350505050565b600061364061010083614458565b905060006136506101008461446c565b6000928352601660205260409092208054600190931b9092179091555050565b606081600501805461294290614480565b826001600160a01b0316826001600160a01b0316036136e357604051630330dbc960e11b815260206004820152600360248201527f4c3a3400000000000000000000000000000000000000000000000000000000006044820152606401611118565b6001600160a01b0391821660009081526003949094016020908152604080862094909316855292909252909120805460ff1916911515919091179055565b60006001600160a01b0384163b1561381757604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061376590339089908890889060040161482d565b6020604051808303816000875af19250505080156137a0575060408051601f3d908101601f1916820190925261379d91810190614869565b60015b6137fd573d8080156137ce576040519150601f19603f3d011682016040523d82523d6000602084013e6137d3565b606091505b5080516000036137f5576040516282b42960e81b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061381b565b5060015b949350505050565b600061383161010083614458565b905060006138416101008461446c565b6000928352601860205260409092208054600190931b9092179091555050565b6060816000036138a457505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156138ce57806138b881614886565b91506138c79050600a83614458565b91506138a8565b60008167ffffffffffffffff8111156138e9576138e9614195565b6040519080825280601f01601f191660200182016040528015613913576020820181803683370190505b5090505b841561381b576139286001836145c8565b9150613935600a8661446c565b613940906030614418565b60f81b818381518110613955576139556143d3565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061398f600a86614458565b9450613917565b606081516000036139b557505060408051602081019091526000815290565b60006040518060600160405280604081526020016148a060409139905060006003845160026139e49190614418565b6139ee9190614458565b6139f990600461442b565b67ffffffffffffffff811115613a1157613a11614195565b6040519080825280601f01601f191660200182016040528015613a3b576020820181803683370190505b509050600182016020820185865187015b80821015613aa7576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250613a4c565b5050600386510660018114613ac35760028114613ad657613ade565b603d6001830353603d6002830353613ade565b603d60018303535b509195945050505050565b6000613af761010083614458565b90506000613b076101008461446c565b6000928352601a60205260409092208054600190931b9092179091555050565b805475ffffffffffffffffffffffffffffffffffffffffffff19168082556040805160008152600160a01b90920461ffff1660208301527f712ca2ffb17da9e3b90d98d54938dee8be84b528cbdec691d680c1df8b78538a910160405180910390a150565b6000806000613bf785600401805480602002602001604051908101604052809291908181526020018280548015613bec57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613bce575b505050505085613d21565b915091508115613c0a579150610d4f9050565b604051630330dbc960e11b81526004016111189060208082526004908201527f50533a3600000000000000000000000000000000000000000000000000000000604082015260600190565b6000818152602084905260408120546001600160a01b03908116908416811480613ca657506001600160a01b03808216600090815260038701602090815260408083209388168352929052205460ff165b80613ccb5750836001600160a01b0316613cc086856129c7565b6001600160a01b0316145b95945050505050565b600081815b8451811015613d1957613d0582868381518110613cf857613cf86143d3565b6020026020010151613d7d565b915080613d1181614886565b915050613cd9565b509392505050565b81516000908190815b81811015613d7457846001600160a01b0316868281518110613d4e57613d4e6143d3565b60200260200101516001600160a01b031603613d6c57600193508092505b600101613d2a565b50509250929050565b6000818310613d99576000828152602084905260409020610e2c565b6000838152602083905260409020610e2c565b508054600082559060005260206000209081019061106391905b80821115613dda5760008155600101613dc6565b5090565b6001600160e01b03198116811461106357600080fd5b600060208284031215613e0657600080fd5b8135610e2c81613dde565b60005b83811015613e2c578181015183820152602001613e14565b50506000910152565b60008151808452613e4d816020860160208601613e11565b601f01601f19169290920160200192915050565b602081526000610e2c6020830184613e35565b600060208284031215613e8657600080fd5b5035919050565b80356001600160a01b0381168114613ea457600080fd5b919050565b60008060408385031215613ebc57600080fd5b613ec583613e8d565b946020939093013593505050565b60008060408385031215613ee657600080fd5b50508035926020909101359150565b803561ffff81168114613ea457600080fd5b60008060408385031215613f1a57600080fd5b613f2383613e8d565b9150613f3160208401613ef5565b90509250929050565b60008060408385031215613f4d57600080fd5b8235613f5881613dde565b9150613f3160208401613e8d565b600080600080600060808688031215613f7e57600080fd5b613f8786613e8d565b9450613f9560208701613e8d565b935060408601359250606086013567ffffffffffffffff80821115613fb957600080fd5b818801915088601f830112613fcd57600080fd5b813581811115613fdc57600080fd5b896020828501011115613fee57600080fd5b9699959850939650602001949392505050565b60008060006060848603121561401657600080fd5b8335925061402660208501613e8d565b915061403460408501613ef5565b90509250925092565b60008060006060848603121561405257600080fd5b61405b84613e8d565b925061406960208501613e8d565b9150604084013590509250925092565b60006020828403121561408b57600080fd5b610e2c82613e8d565b6020808252825182820181905260009190848201906040850190845b818110156140d55783516001600160a01b0316835292840192918401916001016140b0565b50909695505050505050565b60008083601f8401126140f357600080fd5b50813567ffffffffffffffff81111561410b57600080fd5b6020830191508360208260051b850101111561412657600080fd5b9250929050565b60008060008060006080868803121561414557600080fd5b8535945061415560208701613e8d565b935060408601359250606086013567ffffffffffffffff81111561417857600080fd5b614184888289016140e1565b969995985093965092949392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126141bc57600080fd5b813567ffffffffffffffff808211156141d7576141d7614195565b604051601f8301601f19908116603f011681019082821181831017156141ff576141ff614195565b8160405283815286602085880101111561421857600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060006060848603121561424d57600080fd5b833567ffffffffffffffff8082111561426557600080fd5b614271878388016141ab565b9450602086013591508082111561428757600080fd5b614293878388016141ab565b935060408601359150808211156142a957600080fd5b506142b6868287016141ab565b9150509250925092565b6000602082840312156142d257600080fd5b813567ffffffffffffffff8111156142e957600080fd5b61381b848285016141ab565b6000806040838503121561430857600080fd5b61431183613e8d565b91506020830135801515811461432657600080fd5b809150509250929050565b6000806000806060858703121561434757600080fd5b8435935061435760208601613e8d565b9250604085013567ffffffffffffffff81111561437357600080fd5b61437f878288016140e1565b95989497509550505050565b6000806040838503121561439e57600080fd5b613f5883613e8d565b6000806000606084860312156143bc57600080fd5b505081359360208301359350604090920135919050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156143fb57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610d4f57610d4f614402565b8082028115828204841417610d4f57610d4f614402565b634e487b7160e01b600052601260045260246000fd5b60008261446757614467614442565b500490565b60008261447b5761447b614442565b500690565b600181811c9082168061449457607f821691505b6020821081036144b457634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610fe157600081815260208120601f850160051c810160208610156144e15750805b601f850160051c820191505b81811015614500578281556001016144ed565b505050505050565b815167ffffffffffffffff81111561452257614522614195565b614536816145308454614480565b846144ba565b602080601f83116001811461456b57600084156145535750858301515b600019600386901b1c1916600185901b178555614500565b600085815260208120601f198616915b8281101561459a5788860151825594840194600190910190840161457b565b50858210156145b85787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b81810381811115610d4f57610d4f614402565b600081546145e881614480565b60018281168015614600576001811461461557614644565b60ff1984168752821515830287019450614644565b8560005260208060002060005b8581101561463b5781548a820152908401908201614622565b50505082870194505b5050505092915050565b7f7b0000000000000000000000000000000000000000000000000000000000000081527f226e616d65223a2022486f6d6965732047656e657369732023000000000000006001820152600085516146ac81601a850160208a01613e11565b80830190507f222c00000000000000000000000000000000000000000000000000000000000080601a8301527f226465736372697074696f6e223a202200000000000000000000000000000000601c83015261470b602c8301886145db565b91508082527f22696d616765223a2022000000000000000000000000000000000000000000006002830152614743600c8301876145db565b9081527f22616e696d6174696f6e5f75726c223a202200000000000000000000000000006002820152905061477b60148201856145db565b7f220000000000000000000000000000000000000000000000000000000000000081527f7d000000000000000000000000000000000000000000000000000000000000006001820152600201979650505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081526000825161480a81601d850160208701613e11565b91909101601d0192915050565b634e487b7160e01b600052603160045260246000fd5b60006001600160a01b0380871683528086166020840152508360408301526080606083015261485f6080830184613e35565b9695505050505050565b60006020828403121561487b57600080fd5b8151610e2c81613dde565b60006001820161489857614898614402565b506001019056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220ed328c08ff18b159f7e3d70e6781cd2a14eded050466f4014276ca6751db6b2c64736f6c6343000811003300000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000004ce69fd760ad0c07490178f9a47863dc0358cccd0000000000000000000000004ce69fd760ad0c07490178f9a47863dc0358cccd000000000000000000000000e318cde62513f8c21e91e5211ff33a7eedf78a2f0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000e486f6d696573206f6620576562330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004486f573300000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106104185760003560e01c806376d7fc0711610228578063b88d4fde11610128578063dcd4ab77116100bb578063e8a3d4851161008a578063ec1ffdd81161006f578063ec1ffdd814610c1a578063f2fde38b14610c44578063f950233314610c6457610455565b8063e8a3d48514610be5578063e985e9c514610bfa57610455565b8063dcd4ab7714610b7b578063de02cde714610b90578063e33b7de314610bb0578063e7b7544014610bc557610455565b8063ca4b208b116100f7578063ca4b208b14610b0a578063ce7c2ac214610b28578063d39ce77c14610b48578063d601f1dc14610b6857610455565b8063b88d4fde14610a8a578063bb5027f714610aaa578063c3b8e34514610aca578063c87b56dd14610aea57610455565b806396d32915116101bb578063a22cb4651161018a578063a6b6cb371161016f578063a6b6cb3714610a4a578063a86ff96014610a60578063ad6d9c1714610a7557610455565b8063a22cb46514610a0a578063a3f8eace14610a2a57610455565b806396d329151461098f5780639852595c146109af5780639bce3944146109cf578063a0355eca146109ea57610455565b80638bb2b65a116101f75780638bb2b65a1461091c5780638da5cb5b1461093c578063938e3d7b1461095a57806395d89b411461097a57610455565b806376d7fc07146108bc57806379ba5097146108d15780638159324c146108e65780638693da201461090657610455565b80632db11544116103335780634e8086aa116102c65780636352211e1161029557806366278a6c1161027a57806366278a6c1461086757806370a0823114610887578063715018a6146108a757610455565b80636352211e1461082757806364cb4edb1461084757610455565b80634e8086aa1461079e57806350d604e3146107c05780635ba5e9f0146107e05780636149d8711461080757610455565b806342842e0e1161030257806342842e0e1461072957806344faded01461074957806347786d37146107695780634e71d92d1461078957610455565b80632db11544146106cc57806331e26cfd146106df5780633a98ef39146106f45780633ed358551461070957610455565b8063150b7a02116103ab57806323b872dd1161037a57806323b872dd14610643578063266dcbf6146106635780632a55205a146106785780632bfcf0f2146106b757610455565b8063150b7a02146105b557806318160ddd146105ee57806318f9b023146106035780631fcb02f31461062357610455565b80630b78f9c0116103e75780630b78f9c0146105385780630c222ee51461055857806310ab94321461057857806312065fe01461059857610455565b806301ffc9a71461048757806306fdde03146104bc578063081812fc146104de578063095ea7b31461051657610455565b366104555760405134815233907f6ef95f06320e7a25a04a175ca677b7052bdd97131872c2192525a629f51be770906020015b60405180910390a2005b60405134815233907f6ef95f06320e7a25a04a175ca677b7052bdd97131872c2192525a629f51be7709060200161044b565b34801561049357600080fd5b506104a76104a2366004613df4565b610c84565b60405190151581526020015b60405180910390f35b3480156104c857600080fd5b506104d1610d55565b6040516104b39190613e61565b3480156104ea57600080fd5b506104fe6104f9366004613e74565b610d66565b6040516001600160a01b0390911681526020016104b3565b34801561052257600080fd5b50610536610531366004613ea9565b610d72565b005b34801561054457600080fd5b50610536610553366004613ed3565b610dbb565b34801561056457600080fd5b50610536610573366004613f07565b610df6565b34801561058457600080fd5b506104a7610593366004613f3a565b610e1e565b3480156105a457600080fd5b50475b6040519081526020016104b3565b3480156105c157600080fd5b506105d56105d0366004613f66565b610e33565b6040516001600160e01b031990911681526020016104b3565b3480156105fa57600080fd5b506105a7610e4d565b34801561060f57600080fd5b5061053661061e366004613ea9565b610e59565b34801561062f57600080fd5b5061053661063e366004614001565b610dde565b34801561064f57600080fd5b5061053661065e36600461403d565b610e7d565b34801561066f57600080fd5b50610536610ed1565b34801561068457600080fd5b50610698610693366004613ed3565b610fe6565b604080516001600160a01b0390931683526020830191909152016104b3565b3480156106c357600080fd5b50610536611000565b6105366106da366004613e74565b611066565b3480156106eb57600080fd5b506105366111be565b34801561070057600080fd5b506105a7611203565b34801561071557600080fd5b50610536610724366004614079565b61120e565b34801561073557600080fd5b5061053661074436600461403d565b611231565b34801561075557600080fd5b50610536610764366004613f3a565b6112c5565b34801561077557600080fd5b50610536610784366004613e74565b61134c565b34801561079557600080fd5b50610536611369565b3480156107aa57600080fd5b506107b361149a565b6040516104b39190614094565b3480156107cc57600080fd5b506104a76107db366004613e74565b6114a6565b3480156107ec57600080fd5b506105d56107fb366004613df4565b506303e1469160e61b90565b34801561081357600080fd5b50610536610822366004614079565b6114e7565b34801561083357600080fd5b506104fe610842366004613e74565b61152c565b34801561085357600080fd5b50610536610862366004614079565b611549565b34801561087357600080fd5b50610536610882366004613df4565b6115ac565b34801561089357600080fd5b506105a76108a2366004614079565b6115e3565b3480156108b357600080fd5b50610536611601565b3480156108c857600080fd5b50610536611652565b3480156108dd57600080fd5b50610536611676565b3480156108f257600080fd5b5061053661090136600461412d565b6116d9565b34801561091257600080fd5b506105a760205481565b34801561092857600080fd5b50610536610937366004614238565b61195f565b34801561094857600080fd5b506009546001600160a01b03166104fe565b34801561096657600080fd5b506105366109753660046142c0565b6119a3565b34801561098657600080fd5b506104d16119c7565b34801561099b57600080fd5b506104a76109aa366004613e74565b6119d3565b3480156109bb57600080fd5b506105a76109ca366004614079565b611a14565b3480156109db57600080fd5b5061053661063e366004613e74565b3480156109f657600080fd5b50610536610a05366004613ed3565b611a32565b348015610a1657600080fd5b50610536610a253660046142f5565b611a55565b348015610a3657600080fd5b506105a7610a45366004614079565b611aa8565b348015610a5657600080fd5b506105a7601f5481565b348015610a6c57600080fd5b50610536611c83565b348015610a8157600080fd5b50610536611cc8565b348015610a9657600080fd5b50610536610aa5366004613f66565b611d19565b348015610ab657600080fd5b50610536610ac5366004614331565b611db2565b348015610ad657600080fd5b506104a7610ae5366004613e74565b612024565b348015610af657600080fd5b506104d1610b05366004613e74565b612065565b348015610b1657600080fd5b50600a546001600160a01b03166104fe565b348015610b3457600080fd5b506105a7610b43366004614079565b6120cc565b348015610b5457600080fd5b50610536610b63366004614079565b6120ea565b610536610b76366004614331565b61212f565b348015610b8757600080fd5b506105366123e8565b348015610b9c57600080fd5b50610536610bab366004613f3a565b61240a565b348015610bbc57600080fd5b50600e546105a7565b348015610bd157600080fd5b506105a7610be0366004614079565b61248d565b348015610bf157600080fd5b506104d161249a565b348015610c0657600080fd5b506104a7610c1536600461438b565b61252c565b348015610c2657600080fd5b50610c2f61255c565b604080519283526020830191909152016104b3565b348015610c5057600080fd5b50610536610c5f366004614079565b61257a565b348015610c7057600080fd5b50610536610c7f3660046143a7565b6125dd565b60006001600160e01b031982167f7f5828d0000000000000000000000000000000000000000000000000000000001480610ce757506001600160e01b031982167f80ac58cd00000000000000000000000000000000000000000000000000000000145b80610d1b57506001600160e01b031982167f2a55205a00000000000000000000000000000000000000000000000000000000145b80610d4f57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b92915050565b6060610d616000612931565b905090565b6000610d4f81836129c7565b610d7f6000833384612a4c565b60405181906001600160a01b0384169033907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590600090a45050565b610dce600863ca4b208b60e01b33612b45565b15610dde57601f91909155602055565b6040516282b42960e81b815260040160405180910390fd5b610e096008638da5cb5b60e01b33612b45565b15610dde57610e1a600c8383612ba2565b5050565b6000610e2c60088484612b45565b9392505050565b60006040516282b42960e81b815260040160405180910390fd5b6000610d616000612c83565b610e6c600863ca4b208b60e01b33612b45565b15610dde57610e1a600d8383612c90565b610e8b600084843385612e27565b80826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b6000610edd600d612fe4565b805190915060005b81811015610fe1576000306001600160a01b031663a3f8eace858481518110610f1057610f106143d3565b60200260200101516040518263ffffffff1660e01b8152600401610f4391906001600160a01b0391909116815260200190565b602060405180830381865afa158015610f60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8491906143e9565b9050610fb5848381518110610f9b57610f9b6143d3565b602002602001015182600d6130499092919063ffffffff16565b610fd8848381518110610fca57610fca6143d3565b6020026020010151826130d0565b50600101610ee5565b505050565b600080610ff5600c85856131e9565b909590945092505050565b636525904560e11b61101460088233612b45565b8061102d575061102d60086303e1469160e61b33612b45565b15610dde57611045600863ca4b208b60e01b336126ba565b611050600833612859565b6110636008636525904560e11b33613226565b50565b6013546012546110769190614418565b4210610dde57600581111561109d576040516282b42960e81b815260040160405180910390fd5b6012546000036110bf576040516282b42960e81b815260040160405180910390fd5b806020546110cd919061442b565b341461112157604051630330dbc960e11b815260206004820152601160248201527f6d73672e76616c756520746f6f206c6f7700000000000000000000000000000060448201526064015b60405180910390fd5b6014548161112f6000612c83565b6111399190614418565b1115611157576040516282b42960e81b815260040160405180910390fd5b60005b81811015610e1a576111783361116f60215490565b600091906132e2565b60215460405133906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46111b6602180546001019055565b60010161115a565b636525904560e11b6111d260088233612b45565b806111eb57506111eb60086303e1469160e61b33612b45565b15610dde576110636008636525904560e11b33613226565b6000610d61600d5490565b611221600863ca4b208b60e01b33612b45565b15610dde57611063600d82613407565b6040517fb88d4fde0000000000000000000000000000000000000000000000000000000081526001600160a01b03808516600483015283166024820152604481018290526080606482015260006084820152309063b88d4fde9060a401600060405180830381600087803b1580156112a857600080fd5b505af11580156112bc573d6000803e3d6000fd5b50505050505050565b816112d260088233612b45565b806112eb57506112eb60086303e1469160e61b33612b45565b15610dde576001600160e01b03198316636525904560e11b148061131f57506001600160e01b031983166346d2e5ad60e11b145b1561134057336001600160a01b03831603610dde57610fe160088484613226565b610fe160088484613226565b61135f600863ca4b208b60e01b33612b45565b15610dde57601455565b60405163673e156160e11b8152336004820152309063ce7c2ac290602401602060405180830381865afa1580156113a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c891906143e9565b6000036113e7576040516282b42960e81b815260040160405180910390fd5b6040517fa3f8eace000000000000000000000000000000000000000000000000000000008152336004820152600090309063a3f8eace90602401602060405180830381865afa15801561143e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061146291906143e9565b905080600003611484576040516282b42960e81b815260040160405180910390fd5b611490600d3383613049565b61106333826130d0565b6060610d61600d612fe4565b6000806114b561010084614458565b905060006114c56101008561446c565b60009283526016602052604090922054600190921b9182169091149392505050565b63ca4b208b60e01b6114fb60088233612b45565b80611514575061151460086303e1469160e61b33612b45565b15610dde57610e1a6008636525904560e11b846126ba565b6000818152602081905260408120546001600160a01b0316610d4f565b63ca4b208b60e01b61155d60088233612b45565b80611576575061157660086303e1469160e61b33612b45565b15610dde5761158e600863ca4b208b60e01b846126ba565b611599600883612859565b610e1a600863ca4b208b60e01b33613226565b806115b960088233612b45565b806115d257506115d260086303e1469160e61b33612b45565b15610dde57610e1a60088333613226565b6001600160a01b038116600090815260016020526040812054610d4f565b638da5cb5b60e01b61161560088233612b45565b8061162e575061162e60086303e1469160e61b33612b45565b15610dde5761163f600860006128c5565b6110636008638da5cb5b60e01b33613226565b611665600863ca4b208b60e01b33612b45565b15610dde57611674600d613587565b565b6346d2e5ad60e11b61168a60088233612b45565b806116a357506116a360086303e1469160e61b33612b45565b15610dde576116bb6008638da5cb5b60e01b336126ba565b6116c66008336128c5565b61106360086346d2e5ad60e11b33613226565b6013546012546116e99190614418565b421080156116f957506012544210155b15610dde57601254600003611720576040516282b42960e81b815260040160405180910390fd5b611729856114a6565b1561176957604051630330dbc960e11b815260206004820152600f60248201526e105b1c9958591e4810db185a5b5959608a1b6044820152606401611118565b60408051602081018790526bffffffffffffffffffffffff19606087901b1691810191909152605481018490526000906074016040516020818303038152906040528051906020012090506117f583838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050601554915084905061361c565b61183257604051630330dbc960e11b815260206004820152600d60248201526c24b73b30b634b210283937b7b360991b6044820152606401611118565b61183b86613632565b601454846118496000612c83565b6118539190614418565b1115611871576040516282b42960e81b815260040160405180910390fd5b60005b848110156118d8576118898661116f60215490565b6021546040516001600160a01b038816906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46118d0602180546001019055565b600101611874565b50604080518781526001600160a01b03871660208201529081018590526080606082018190526005908201527f41646d696e00000000000000000000000000000000000000000000000000000060a08201527fee563d8e532abc293fca2fdeb41c25180305bddcf9206c167dab3e155aaf17139060c00160405180910390a1505050505050565b611972600863ca4b208b60e01b33612b45565b15610dde57601d6119838482614508565b50601c6119908382614508565b50601e61199d8282614508565b50505050565b6119b6600863ca4b208b60e01b33612b45565b15610dde57601b610e1a8282614508565b6060610d616000613670565b6000806119e261010084614458565b905060006119f26101008561446c565b6000928352601a602052604090922054600190921b9182169091149392505050565b6001600160a01b038116600090815260106020526040812054610d4f565b611a45600863ca4b208b60e01b33612b45565b15610dde57601291909155601355565b611a626000833384613681565b60405181151581526001600160a01b0383169033907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319060200160405180910390a35050565b600080306001600160a01b031663e33b7de36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ae9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0d91906143e9565b611b179047614418565b6040517f9852595c0000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201529091503090639852595c90602401602060405180830381865afa158015611b77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9b91906143e9565b306001600160a01b0316633a98ef396040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bfd91906143e9565b60405163673e156160e11b81526001600160a01b0386166004820152309063ce7c2ac290602401602060405180830381865afa158015611c41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c6591906143e9565b611c6f908461442b565b611c799190614458565b610e2c91906145c8565b6346d2e5ad60e11b611c9760088233612b45565b80611cb05750611cb060086303e1469160e61b33612b45565b15610dde5761106360086346d2e5ad60e11b33613226565b63ca4b208b60e01b611cdc60088233612b45565b80611cf55750611cf560086303e1469160e61b33612b45565b15610dde57611d0660086000612859565b611063600863ca4b208b60e01b33613226565b611d27600086863387612e27565b611d6985858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061372192505050565b5082846001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a45050505050565b601354601254611dc29190614418565b42108015611dd257506012544210155b15610dde57601254600003611df9576040516282b42960e81b815260040160405180910390fd5b611e0284612024565b15611e4257604051630330dbc960e11b815260206004820152600f60248201526e105b1c9958591e4810db185a5b5959608a1b6044820152606401611118565b60008484604051602001611e7292919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b604051602081830303815290604052805190602001209050611ecb83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050601754915084905061361c565b611f0857604051630330dbc960e11b815260206004820152600d60248201526c24b73b30b634b210283937b7b360991b6044820152606401611118565b611f1185613823565b601454611f1e6000612c83565b611f29906001614418565b1115611f47576040516282b42960e81b815260040160405180910390fd5b611f548461116f60215490565b6021546040516001600160a01b038616906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4611f9b602180546001019055565b604080518681526001600160a01b03861660208201526001918101919091526080606082018190526006908201527f486f6d696573000000000000000000000000000000000000000000000000000060a08201527fee563d8e532abc293fca2fdeb41c25180305bddcf9206c167dab3e155aaf17139060c0015b60405180910390a15050505050565b60008061203361010084614458565b905060006120436101008561446c565b60009283526018602052604090922054600190921b9182169091149392505050565b6060600061207283613861565b601d601c601e60405160200161208b949392919061464e565b60405160208183030381529060405290506120a581613996565b6040516020016120b591906147d2565b604051602081830303815290604052915050919050565b6001600160a01b0381166000908152600f6020526040812054610d4f565b638da5cb5b60e01b6120fe60088233612b45565b80612117575061211760086303e1469160e61b33612b45565b15610dde57610e1a60086346d2e5ad60e11b846126ba565b60135460125461213f9190614418565b4210801561214f57506012544210155b15610dde57601254600003612176576040516282b42960e81b815260040160405180910390fd5b601f5434146121c857604051630330dbc960e11b815260206004820152601160248201527f6d73672e76616c756520746f6f206c6f770000000000000000000000000000006044820152606401611118565b6121d1846119d3565b1561221157604051630330dbc960e11b815260206004820152600f60248201526e105b1c9958591e4810db185a5b5959608a1b6044820152606401611118565b6000848460405160200161224192919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b60405160208183030381529060405280519060200120905061229a83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050601954915084905061361c565b6122d757604051630330dbc960e11b815260206004820152600d60248201526c24b73b30b634b210283937b7b360991b6044820152606401611118565b6122e085613ae9565b6014546122ed6000612c83565b6122f8906001614418565b1115612316576040516282b42960e81b815260040160405180910390fd5b6123238461116f60215490565b6021546040516001600160a01b038616906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a461236a602180546001019055565b604080518681526001600160a01b03861660208201526001918101919091526080606082018190526007908201527f4e6f726d6965730000000000000000000000000000000000000000000000000060a08201527fee563d8e532abc293fca2fdeb41c25180305bddcf9206c167dab3e155aaf17139060c001612015565b6123fb6008638da5cb5b60e01b33612b45565b15610dde57611674600c613b27565b8161241760088233612b45565b80612430575061243060086303e1469160e61b33612b45565b15610dde576001600160e01b03198316636525904560e11b148061246457506001600160e01b031983166346d2e5ad60e11b145b15612481576040516282b42960e81b815260040160405180910390fd5b610fe1600884846126ba565b6000610d4f600d83613b8c565b6060601b80546124a990614480565b80601f01602080910402602001604051908101604052809291908181526020018280546124d590614480565b80156125225780601f106124f757610100808354040283529160200191612522565b820191906000526020600020905b81548152906001019060200180831161250557829003601f168201915b5050505050905090565b6001600160a01b03808316600090815260036020908152604080832093851683529290529081205460ff16610e2c565b6000806012546013546012546125729190614418565b915091509091565b638da5cb5b60e01b61258e60088233612b45565b806125a757506125a760086303e1469160e61b33612b45565b15610dde576125bf6008638da5cb5b60e01b846126ba565b6125ca6008836128c5565b610e1a6008638da5cb5b60e01b33613226565b6125f0600863ca4b208b60e01b33612b45565b15610dde57601592909255601755601955565b8082556040518181527f83b179bd5cb3a111f82ac98510d3c66f48f77679e657302f4f253d4c32d6d672906020015b60405180910390a15050565b6004820161264c8282614508565b507f13c98778b0c1a086bb98d7f1986e15788b5d3a1ad4c492e1d78f1c4cc51c20cf816040516126329190613e61565b6005820161268a8282614508565b507f3e46ff90086ee29856e77591e82c82ff8ed513379b0fd82e84fc5290dd633c99816040516126329190613e61565b6001600160a01b0381166126e0576040516282b42960e81b815260040160405180910390fd5b6126eb838383612b45565b15612708576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0381166000818152602085815260408083206001600160e01b0319871680855290835292819020805460ff19166001908117909155815193845291830193909352918101919091527fc8bed56f8e046b5a3f2c2b2be85045ea5c972dc18ad669157957897b4d26e9f7906060015b60405180910390a1505050565b61279c826303e1469160e61b83612b45565b156127f6576003820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec690600090a3505050565b6001600160a01b038116610dde576003820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec690600090a3505050565b61286b8263ca4b208b60e01b83612b45565b156127f6576002820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f2cfca82ac51c2fc6b6db547820d28d526a505e12d230afb8bf112a5aeefa9a4c90600090a3505050565b6128d782638da5cb5b60e01b83612b45565b156127f6576001820180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b606081600401805461294290614480565b80601f016020809104026020016040519081016040528092919081815260200182805461296e90614480565b80156129bb5780601f10612990576101008083540402835291602001916129bb565b820191906000526020600020905b81548152906001019060200180831161299e57829003601f168201915b50505050509050919050565b6000818152602083905260408120546001600160a01b0316612a2c57604051630330dbc960e11b815260206004820152600360248201527f4c3a3100000000000000000000000000000000000000000000000000000000006044820152606401611118565b50600090815260029190910160205260409020546001600160a01b031690565b6000818152602085905260409020546001600160a01b03908116908416819003612ab957604051630330dbc960e11b815260206004820152600360248201527f4c3a3200000000000000000000000000000000000000000000000000000000006044820152606401611118565b612ac4858484613c55565b612b1157604051630330dbc960e11b815260206004820152600360248201527f4c3a3300000000000000000000000000000000000000000000000000000000006044820152606401611118565b50600090815260029390930160205250604090912080546001600160a01b0319166001600160a01b03909216919091179055565b60006001600160a01b038216612b6d576040516282b42960e81b815260040160405180910390fd5b506001600160a01b03166000908152602092835260408082206001600160e01b03199390931682529190925290205460ff1690565b6103e88161ffff16101580612bb9575061ffff8116155b15612c0757604051630330dbc960e11b815260206004820152600360248201527f523a3100000000000000000000000000000000000000000000000000000000006044820152606401611118565b82546001600160a01b0383811675ffffffffffffffffffffffffffffffffffffffffffff1990921691909117600160a01b61ffff84811682029290921780875560408051948216855291900490911660208301527f712ca2ffb17da9e3b90d98d54938dee8be84b528cbdec691d680c1df8b78538a910161277d565b6000610d4f826007015490565b6001600160a01b038216612cd057604051630330dbc960e11b81526004016111189060208082526004908201526350533a3360e01b604082015260600190565b80600003612d2357604051630330dbc960e11b81526004016111189060208082526004908201527f50533a3400000000000000000000000000000000000000000000000000000000604082015260600190565b6001600160a01b038216600090815260028401602052604090205415612d8e57604051630330dbc960e11b81526004016111189060208082526004908201527f50533a3500000000000000000000000000000000000000000000000000000000604082015260600190565b6004830180546001810182556000918252602080832090910180546001600160a01b0319166001600160a01b038616908117909155825260028501905260408120829055835482918591612de3908490614418565b9091555050604080516001600160a01b0384168152602081018390527f40c340f65e17194d14ddddb073d3c9f888e3cb52b5aae0c6c7706b4fbc905fac910161277d565b612e32858383613c55565b612e7f57604051630330dbc960e11b815260206004820152600360248201527f4c3a3500000000000000000000000000000000000000000000000000000000006044820152606401611118565b6000818152602086905260409020546001600160a01b039081169085168114612eeb57604051630330dbc960e11b815260206004820152600360248201527f4c3a3600000000000000000000000000000000000000000000000000000000006044820152606401611118565b6001600160a01b038416612f4257604051630330dbc960e11b815260206004820152600360248201527f4c3a3700000000000000000000000000000000000000000000000000000000006044820152606401611118565b612f4f8660008585612a4c565b6001600160a01b0385166000908152600187810160205260408220805491929091612f7b9084906145c8565b90915550506001600160a01b0384166000908152600187810160205260408220805491929091612fac908490614418565b909155505050600090815260209490945250604090922080546001600160a01b0319166001600160a01b039093169290921790915550565b6060816004018054806020026020016040519081016040528092919081815260200182805480156129bb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116130205750505050509050919050565b8083600101600082825461305d9190614418565b90915550506001600160a01b03821660009081526003840160205260408120805483929061308c908490614418565b9091555050604080516001600160a01b0384168152602081018390527fdf20fd1e76bc69d672e4814fafb2c449bba3a5369d8359adf9e05e6fde87b056910161277d565b804710156131205760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401611118565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461316d576040519150601f19603f3d011682016040523d82523d6000602084013e613172565b606091505b5050905080610fe15760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401611118565b82546001600160a01b038116906000906103e89061321290600160a01b900461ffff168561442b565b61321c9190614458565b9050935093915050565b6001600160a01b03811661324c576040516282b42960e81b815260040160405180910390fd5b613257838383612b45565b613273576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0381166000818152602085815260408083206001600160e01b03198716808552908352818420805460ff19169055815190815291820193909352918201527fc8bed56f8e046b5a3f2c2b2be85045ea5c972dc18ad669157957897b4d26e9f79060600161277d565b6001600160a01b03821661333957604051630330dbc960e11b815260206004820152600360248201527f4c3a3800000000000000000000000000000000000000000000000000000000006044820152606401611118565b6000818152602084905260409020546001600160a01b03161561339f57604051630330dbc960e11b815260206004820152600360248201527f4c3a3900000000000000000000000000000000000000000000000000000000006044820152606401611118565b6001600160a01b03821660009081526001848101602052604082208054919290916133cb908490614418565b9091555050600081815260208490526040902080546001600160a01b0319166001600160a01b0384161790556007830180546001019055505050565b6001600160a01b03811661344757604051630330dbc960e11b81526004016111189060208082526004908201526350533a3360e01b604082015260600190565b60006134538383613b8c565b60048401805491925060009161346b906001906145c8565b8154811061347b5761347b6143d3565b6000918252602090912001546004850180546001600160a01b0390921692508291849081106134ac576134ac6143d3565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550836004018054806134ed576134ed614817565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0385168252600286019052604081208054908290558554909182918791906135439084906145c8565b9091555050604080516001600160a01b0386168152602081018390527f104b8837ec12e86f303ac7ce5e3bf20c6790f843fabd7451943f3390fc8376cb9101612015565b600481015460005b818110156135db5760008360040182815481106135ae576135ae6143d3565b60009182526020808320909101546001600160a01b0316825260028601905260408120555060010161358f565b5060008083556135ef906004840190613dac565b6040517f3407fd525bf6581e0ae8e3a3636bd90d02112bea34d66802743c28ced73f910e90600090a15050565b6000826136298584613cd4565b14949350505050565b600061364061010083614458565b905060006136506101008461446c565b6000928352601660205260409092208054600190931b9092179091555050565b606081600501805461294290614480565b826001600160a01b0316826001600160a01b0316036136e357604051630330dbc960e11b815260206004820152600360248201527f4c3a3400000000000000000000000000000000000000000000000000000000006044820152606401611118565b6001600160a01b0391821660009081526003949094016020908152604080862094909316855292909252909120805460ff1916911515919091179055565b60006001600160a01b0384163b1561381757604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061376590339089908890889060040161482d565b6020604051808303816000875af19250505080156137a0575060408051601f3d908101601f1916820190925261379d91810190614869565b60015b6137fd573d8080156137ce576040519150601f19603f3d011682016040523d82523d6000602084013e6137d3565b606091505b5080516000036137f5576040516282b42960e81b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061381b565b5060015b949350505050565b600061383161010083614458565b905060006138416101008461446c565b6000928352601860205260409092208054600190931b9092179091555050565b6060816000036138a457505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156138ce57806138b881614886565b91506138c79050600a83614458565b91506138a8565b60008167ffffffffffffffff8111156138e9576138e9614195565b6040519080825280601f01601f191660200182016040528015613913576020820181803683370190505b5090505b841561381b576139286001836145c8565b9150613935600a8661446c565b613940906030614418565b60f81b818381518110613955576139556143d3565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061398f600a86614458565b9450613917565b606081516000036139b557505060408051602081019091526000815290565b60006040518060600160405280604081526020016148a060409139905060006003845160026139e49190614418565b6139ee9190614458565b6139f990600461442b565b67ffffffffffffffff811115613a1157613a11614195565b6040519080825280601f01601f191660200182016040528015613a3b576020820181803683370190505b509050600182016020820185865187015b80821015613aa7576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250613a4c565b5050600386510660018114613ac35760028114613ad657613ade565b603d6001830353603d6002830353613ade565b603d60018303535b509195945050505050565b6000613af761010083614458565b90506000613b076101008461446c565b6000928352601a60205260409092208054600190931b9092179091555050565b805475ffffffffffffffffffffffffffffffffffffffffffff19168082556040805160008152600160a01b90920461ffff1660208301527f712ca2ffb17da9e3b90d98d54938dee8be84b528cbdec691d680c1df8b78538a910160405180910390a150565b6000806000613bf785600401805480602002602001604051908101604052809291908181526020018280548015613bec57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613bce575b505050505085613d21565b915091508115613c0a579150610d4f9050565b604051630330dbc960e11b81526004016111189060208082526004908201527f50533a3600000000000000000000000000000000000000000000000000000000604082015260600190565b6000818152602084905260408120546001600160a01b03908116908416811480613ca657506001600160a01b03808216600090815260038701602090815260408083209388168352929052205460ff165b80613ccb5750836001600160a01b0316613cc086856129c7565b6001600160a01b0316145b95945050505050565b600081815b8451811015613d1957613d0582868381518110613cf857613cf86143d3565b6020026020010151613d7d565b915080613d1181614886565b915050613cd9565b509392505050565b81516000908190815b81811015613d7457846001600160a01b0316868281518110613d4e57613d4e6143d3565b60200260200101516001600160a01b031603613d6c57600193508092505b600101613d2a565b50509250929050565b6000818310613d99576000828152602084905260409020610e2c565b6000838152602083905260409020610e2c565b508054600082559060005260206000209081019061106391905b80821115613dda5760008155600101613dc6565b5090565b6001600160e01b03198116811461106357600080fd5b600060208284031215613e0657600080fd5b8135610e2c81613dde565b60005b83811015613e2c578181015183820152602001613e14565b50506000910152565b60008151808452613e4d816020860160208601613e11565b601f01601f19169290920160200192915050565b602081526000610e2c6020830184613e35565b600060208284031215613e8657600080fd5b5035919050565b80356001600160a01b0381168114613ea457600080fd5b919050565b60008060408385031215613ebc57600080fd5b613ec583613e8d565b946020939093013593505050565b60008060408385031215613ee657600080fd5b50508035926020909101359150565b803561ffff81168114613ea457600080fd5b60008060408385031215613f1a57600080fd5b613f2383613e8d565b9150613f3160208401613ef5565b90509250929050565b60008060408385031215613f4d57600080fd5b8235613f5881613dde565b9150613f3160208401613e8d565b600080600080600060808688031215613f7e57600080fd5b613f8786613e8d565b9450613f9560208701613e8d565b935060408601359250606086013567ffffffffffffffff80821115613fb957600080fd5b818801915088601f830112613fcd57600080fd5b813581811115613fdc57600080fd5b896020828501011115613fee57600080fd5b9699959850939650602001949392505050565b60008060006060848603121561401657600080fd5b8335925061402660208501613e8d565b915061403460408501613ef5565b90509250925092565b60008060006060848603121561405257600080fd5b61405b84613e8d565b925061406960208501613e8d565b9150604084013590509250925092565b60006020828403121561408b57600080fd5b610e2c82613e8d565b6020808252825182820181905260009190848201906040850190845b818110156140d55783516001600160a01b0316835292840192918401916001016140b0565b50909695505050505050565b60008083601f8401126140f357600080fd5b50813567ffffffffffffffff81111561410b57600080fd5b6020830191508360208260051b850101111561412657600080fd5b9250929050565b60008060008060006080868803121561414557600080fd5b8535945061415560208701613e8d565b935060408601359250606086013567ffffffffffffffff81111561417857600080fd5b614184888289016140e1565b969995985093965092949392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126141bc57600080fd5b813567ffffffffffffffff808211156141d7576141d7614195565b604051601f8301601f19908116603f011681019082821181831017156141ff576141ff614195565b8160405283815286602085880101111561421857600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060006060848603121561424d57600080fd5b833567ffffffffffffffff8082111561426557600080fd5b614271878388016141ab565b9450602086013591508082111561428757600080fd5b614293878388016141ab565b935060408601359150808211156142a957600080fd5b506142b6868287016141ab565b9150509250925092565b6000602082840312156142d257600080fd5b813567ffffffffffffffff8111156142e957600080fd5b61381b848285016141ab565b6000806040838503121561430857600080fd5b61431183613e8d565b91506020830135801515811461432657600080fd5b809150509250929050565b6000806000806060858703121561434757600080fd5b8435935061435760208601613e8d565b9250604085013567ffffffffffffffff81111561437357600080fd5b61437f878288016140e1565b95989497509550505050565b6000806040838503121561439e57600080fd5b613f5883613e8d565b6000806000606084860312156143bc57600080fd5b505081359360208301359350604090920135919050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156143fb57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610d4f57610d4f614402565b8082028115828204841417610d4f57610d4f614402565b634e487b7160e01b600052601260045260246000fd5b60008261446757614467614442565b500490565b60008261447b5761447b614442565b500690565b600181811c9082168061449457607f821691505b6020821081036144b457634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610fe157600081815260208120601f850160051c810160208610156144e15750805b601f850160051c820191505b81811015614500578281556001016144ed565b505050505050565b815167ffffffffffffffff81111561452257614522614195565b614536816145308454614480565b846144ba565b602080601f83116001811461456b57600084156145535750858301515b600019600386901b1c1916600185901b178555614500565b600085815260208120601f198616915b8281101561459a5788860151825594840194600190910190840161457b565b50858210156145b85787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b81810381811115610d4f57610d4f614402565b600081546145e881614480565b60018281168015614600576001811461461557614644565b60ff1984168752821515830287019450614644565b8560005260208060002060005b8581101561463b5781548a820152908401908201614622565b50505082870194505b5050505092915050565b7f7b0000000000000000000000000000000000000000000000000000000000000081527f226e616d65223a2022486f6d6965732047656e657369732023000000000000006001820152600085516146ac81601a850160208a01613e11565b80830190507f222c00000000000000000000000000000000000000000000000000000000000080601a8301527f226465736372697074696f6e223a202200000000000000000000000000000000601c83015261470b602c8301886145db565b91508082527f22696d616765223a2022000000000000000000000000000000000000000000006002830152614743600c8301876145db565b9081527f22616e696d6174696f6e5f75726c223a202200000000000000000000000000006002820152905061477b60148201856145db565b7f220000000000000000000000000000000000000000000000000000000000000081527f7d000000000000000000000000000000000000000000000000000000000000006001820152600201979650505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081526000825161480a81601d850160208701613e11565b91909101601d0192915050565b634e487b7160e01b600052603160045260246000fd5b60006001600160a01b0380871683528086166020840152508360408301526080606083015261485f6080830184613e35565b9695505050505050565b60006020828403121561487b57600080fd5b8151610e2c81613dde565b60006001820161489857614898614402565b506001019056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220ed328c08ff18b159f7e3d70e6781cd2a14eded050466f4014276ca6751db6b2c64736f6c63430008110033

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

00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000004ce69fd760ad0c07490178f9a47863dc0358cccd0000000000000000000000004ce69fd760ad0c07490178f9a47863dc0358cccd000000000000000000000000e318cde62513f8c21e91e5211ff33a7eedf78a2f0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000e486f6d696573206f6620576562330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004486f573300000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _name (string): Homies of Web3
Arg [1] : _symbol (string): HoW3
Arg [2] : _admin (address): 0x4CE69fd760AD0c07490178f9a47863Dc0358cCCD
Arg [3] : _dev (address): 0x4CE69fd760AD0c07490178f9a47863Dc0358cCCD
Arg [4] : _owner (address): 0xE318Cde62513F8C21e91E5211ff33A7eedF78A2F
Arg [5] : _start (uint256): 1

-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [2] : 0000000000000000000000004ce69fd760ad0c07490178f9a47863dc0358cccd
Arg [3] : 0000000000000000000000004ce69fd760ad0c07490178f9a47863dc0358cccd
Arg [4] : 000000000000000000000000e318cde62513f8c21e91e5211ff33a7eedf78a2f
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [6] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [7] : 486f6d696573206f662057656233000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [9] : 486f573300000000000000000000000000000000000000000000000000000000


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.