false
true
0

Contract Address Details

0x7D6b778C07077d85d89842D231040223e833091F

Contract Name
PLSHoldem
Creator
0xfcafcc–9963aa at 0x27a231–3a0d19
Balance
0 tPLS
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
25350896
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
PLSHoldem




Optimization enabled
false
Compiler version
v0.8.28+commit.7893614a




EVM Version




Verified at
2026-08-20T06:39:16.685564Z

Constructor Arguments

0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000fcafcc30cdfcda7b95e8466a8776d55b9c9963aa

Arg [0] (uint16) : 100
Arg [1] (address) : 0xfcafcc30cdfcda7b95e8466a8776d55b9c9963aa

              

contracts/PLSHoldem.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {SRA} from "./lib/SRA.sol";
import {CardMerkle} from "./lib/CardMerkle.sol";
import {HandEval} from "./lib/HandEval.sol";
import {BettingLib} from "./lib/BettingLib.sol";
import "./GameTypes.sol";

/// @title PLSHoldem — trustless heads-up No-Limit Texas Hold'em
/// @notice Fully on-chain game arbiter for two-player NLHE with SRA mental
///         poker dealing. The contract enforces turn order, betting legality,
///         blinds, timeouts, showdown evaluation, cheat detection (blame
///         replay) and settlement. Card privacy lives entirely client-side:
///         the contract only ever sees ciphertexts and selectively revealed
///         per-card exponents.
/// @dev Non-upgradeable; no pause; no admin power over live tables. The only
///      owner capability is configuring rake (≤ MAX_RAKE_BPS) and the fee
///      account for FUTURE tables. See SPEC.md / README.md for the protocol.
contract PLSHoldem is ReentrancyGuard {
    // ------------------------------------------------------------------
    // Storage
    // ------------------------------------------------------------------

    uint16 public constant MAX_RAKE_BPS = 500; // hard cap: 5%
    uint32 public constant MIN_TIMEOUT = 60;
    uint32 public constant MAX_TIMEOUT = 7 days;
    uint32 public constant MAX_BUYIN_CHIPS = 1_000_000_000;

    address public owner;
    address public feeAccount;   // rake destination for future tables
    uint16 public rakeBps;       // rake for future tables

    uint256 public tableCount;
    mapping(uint256 => Table) public tables;
    mapping(uint256 => Hand) internal hands;
    mapping(uint256 => address) public tableFeeAccount; // frozen at creation
    mapping(address => uint256) public withdrawable;

    // ------------------------------------------------------------------
    // Events
    // ------------------------------------------------------------------

    event TableCreated(uint256 indexed tableId, address indexed creator, uint96 chipValue,
        uint32 buyInChips, uint32 sbChips, uint32 bbChips, uint32 actTimeout,
        uint32 cryptoTimeout, uint32 penaltyChips, uint16 rakeBps, uint8 avatar);
    event TableJoined(uint256 indexed tableId, address indexed joiner, uint8 avatar);
    event TableCancelled(uint256 indexed tableId);
    event HandStarted(uint256 indexed tableId, uint32 indexed handId, uint8 btn);
    event DeckPosted(uint256 indexed tableId, uint32 indexed handId, uint8 stage, bytes32 root);
    event HoleExpPosted(uint256 indexed tableId, uint32 indexed handId, uint8 seat);
    event ActionTaken(uint256 indexed tableId, uint32 indexed handId, uint8 seat, uint8 action, uint32 amount);
    event PhaseAdvanced(uint256 indexed tableId, uint32 indexed handId, uint8 phase, uint64 deadline);
    event BoardRevealed(uint256 indexed tableId, uint32 indexed handId, uint8 street, uint8[5] board);
    event ShowdownRevealed(uint256 indexed tableId, uint32 indexed handId, uint8 seat, uint8 c0, uint8 c1, uint32 score);
    event Mucked(uint256 indexed tableId, uint32 indexed handId, uint8 seat);
    event PotAwarded(uint256 indexed tableId, uint32 indexed handId, uint8 winner, uint32 amount, uint32 rake);
    event HandSettled(uint256 indexed tableId, uint32 indexed handId, uint32 stackC, uint32 stackJ);
    event TimeoutClaimed(uint256 indexed tableId, uint32 indexed handId, uint8 phase, uint8 staller);
    event NoShowClaimed(uint256 indexed tableId, uint32 indexed handId, uint32 chips);
    event BlameOpened(uint256 indexed tableId, uint32 indexed handId, uint8 pos, uint8 claimBy, uint8 claimIdx);
    event BlameJSubmitted(uint256 indexed tableId, uint32 indexed handId, uint8 j);
    event CheatSettled(uint256 indexed tableId, uint8 cheater);
    event PlayerLeft(uint256 indexed tableId, uint8 seat);
    event SessionSettled(uint256 indexed tableId, uint256 creatorWei, uint256 joinerWei, uint256 rakeWei);
    event Withdrawn(address indexed to, uint256 amount);
    event RakeConfigured(uint16 rakeBps, address feeAccount);

    // ------------------------------------------------------------------
    // Construction & admin (future tables only)
    // ------------------------------------------------------------------

    constructor(uint16 _rakeBps, address _feeAccount) {
        if (_rakeBps > MAX_RAKE_BPS) revert RakeCap();
        if (_feeAccount == address(0)) revert BadParam();
        owner = msg.sender;
        rakeBps = _rakeBps;
        feeAccount = _feeAccount;
    }

    /// @notice Configure rake for FUTURE tables only (hard-capped). The only
    ///         admin capability in the contract.
    function setRake(uint16 _rakeBps, address _feeAccount) external {
        if (msg.sender != owner) revert NotOwner();
        if (_rakeBps > MAX_RAKE_BPS) revert RakeCap();
        if (_feeAccount == address(0)) revert BadParam();
        rakeBps = _rakeBps;
        feeAccount = _feeAccount;
        emit RakeConfigured(_rakeBps, _feeAccount);
    }

    /// @notice Transfer ownership (address(0) permanently renounces rake
    ///         reconfiguration; existing tables are unaffected either way).
    function transferOwnership(address newOwner) external {
        if (msg.sender != owner) revert NotOwner();
        owner = newOwner;
    }

    // ------------------------------------------------------------------
    // Lobby
    // ------------------------------------------------------------------

    /// @notice Create a table and escrow the buy-in (exact native tPLS value).
    /// @param chipValue wei per chip (fixed conversion both directions)
    /// @param buyInChips whole chips both players buy in for
    /// @param sbChips small blind in chips (bb >= sb >= 1)
    /// @param bbChips big blind in chips (<= buyIn/10)
    /// @param actTimeoutS betting-action window, seconds
    /// @param cryptoTimeoutS crypto-step / reveal / next-hand window, seconds
    /// @param penaltyChips griefing compensation moved to a timeout claimer
    /// @param avatar avatar id (0..7) shown at the creator's seat
    function createTable(
        uint96 chipValue,
        uint32 buyInChips,
        uint32 sbChips,
        uint32 bbChips,
        uint32 actTimeoutS,
        uint32 cryptoTimeoutS,
        uint32 penaltyChips,
        uint8 avatar
    ) external payable returns (uint256 tableId) {
        if (chipValue == 0 || buyInChips == 0 || buyInChips > MAX_BUYIN_CHIPS) revert BadParam();
        if (sbChips < 1 || bbChips < sbChips || bbChips > buyInChips / 10) revert BadParam();
        if (actTimeoutS < MIN_TIMEOUT || actTimeoutS > MAX_TIMEOUT) revert BadParam();
        if (cryptoTimeoutS < MIN_TIMEOUT || cryptoTimeoutS > MAX_TIMEOUT) revert BadParam();
        if (penaltyChips < 1 || penaltyChips > bbChips) revert BadParam();
        if (avatar >= 8) revert BadParam();
        if (msg.value != uint256(chipValue) * buyInChips) revert WrongDeposit();

        tableId = ++tableCount;
        Table storage t = tables[tableId];
        t.creator = msg.sender;
        t.chipValue = chipValue;
        t.status = uint8(TableStatus.OPEN);
        t.creatorAvatar = avatar;
        t.rakeBps = rakeBps;
        t.buyInChips = buyInChips;
        t.sbChips = sbChips;
        t.bbChips = bbChips;
        t.penaltyChips = penaltyChips;
        t.actTimeout = actTimeoutS;
        t.cryptoTimeout = cryptoTimeoutS;
        t.stackC = buyInChips;
        t.stackJ = buyInChips;
        tableFeeAccount[tableId] = feeAccount;

        emit TableCreated(tableId, msg.sender, chipValue, buyInChips, sbChips, bbChips,
            actTimeoutS, cryptoTimeoutS, penaltyChips, rakeBps, avatar);
    }

    /// @notice Join an open table, escrowing the identical buy-in. Atomic:
    ///         a join racing a cancel simply reverts for whoever lands second.
    function joinTable(uint256 tableId, uint8 avatar) external payable {
        Table storage t = tables[tableId];
        if (t.status != uint8(TableStatus.OPEN)) revert NotOpen();
        if (msg.sender == t.creator) revert BadParam();
        if (avatar >= 8) revert BadParam();
        if (msg.value != uint256(t.chipValue) * t.buyInChips) revert WrongDeposit();
        t.joiner = msg.sender;
        t.joinerAvatar = avatar;
        t.status = uint8(TableStatus.PLAYING);
        t.lastSettleTime = uint64(block.timestamp);
        emit TableJoined(tableId, msg.sender, avatar);
    }

    /// @notice Cancel an open (unjoined) table; refunds the creator in full.
    function cancelTable(uint256 tableId) external {
        Table storage t = tables[tableId];
        if (t.status != uint8(TableStatus.OPEN)) revert NotOpen();
        if (msg.sender != t.creator) revert NotCreator();
        t.status = uint8(TableStatus.CANCELLED);
        withdrawable[t.creator] += uint256(t.chipValue) * t.buyInChips;
        emit TableCancelled(tableId);
    }

    // ------------------------------------------------------------------
    // Deck stages (SPEC 2.2)
    // ------------------------------------------------------------------

    /// @notice Post a deck stage (52 × 128-byte values). Stage 1 (creator)
    ///         starts the hand and auto-posts the blinds; stage 2 (joiner),
    ///         3 (creator), 4 (joiner) follow. The contract validates range
    ///         and distinctness and stores a Merkle root per stage.
    function postDeck(uint256 tableId, uint32 handId, uint8 stage, bytes calldata deck) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (t.status != uint8(TableStatus.PLAYING)) revert NotPlaying();
        if (handId != t.handId) revert WrongHand();

        if (stage == 1) {
            if (msg.sender != t.creator) revert NotCreator();
            if (h.phase != uint8(Phase.NONE)) revert BadPhase();
            if (t.stackC == 0 || t.stackJ == 0) revert Bust();
            h.stack[0] = t.stackC;
            h.stack[1] = t.stackJ;
            BettingLib.initHand(h, uint8(t.handId % 2), t.sbChips, t.bbChips);
            emit HandStarted(tableId, t.handId, h.btn);
            h.phase = uint8(Phase.SHUF2);
        } else if (stage == 2) {
            if (msg.sender != t.joiner) revert NotJoiner();
            if (h.phase != uint8(Phase.SHUF2)) revert BadPhase();
            h.phase = uint8(Phase.LOCK1);
        } else if (stage == 3) {
            if (msg.sender != t.creator) revert NotCreator();
            if (h.phase != uint8(Phase.LOCK1)) revert BadPhase();
            h.phase = uint8(Phase.LOCK2);
        } else if (stage == 4) {
            if (msg.sender != t.joiner) revert NotJoiner();
            if (h.phase != uint8(Phase.LOCK2)) revert BadPhase();
            h.phase = uint8(Phase.DEAL);
        } else {
            revert BadParam();
        }
        SRA.checkDeck(deck);
        bytes32 root = CardMerkle.computeRoot(deck, stage);
        h.roots[stage - 1] = root;
        _setDeadline(tableId, t, h, false);
        emit DeckPosted(tableId, handId, stage, root);
    }

    // ------------------------------------------------------------------
    // Hole-card dealing
    // ------------------------------------------------------------------

    /// @notice Post the per-card exponents unlocking the OPPONENT's hole
    ///         cards (joiner posts positions 0,1; creator posts 2,3). Not
    ///         verifiable at post time by design — a bad key is caught by
    ///         accuseHole + blame replay.
    function postHoleExp(uint256 tableId, uint32 handId, uint256 e0, uint256 e1) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (handId != t.handId) revert WrongHand();
        if (h.phase != uint8(Phase.DEAL)) revert BadPhase();
        if (!SRA.validScalar(e0) || !SRA.validScalar(e1)) revert BadScalar();
        uint8 seat = _seatOf(t, msg.sender);
        uint8 bit = seat == 1 ? 1 : 2; // joiner bit0, creator bit1
        if (h.dealMask & bit != 0) revert AlreadyPosted();
        h.dealMask |= bit;
        if (seat == 1) { h.holeExp[0] = e0; h.holeExp[1] = e1; }
        else { h.holeExp[2] = e0; h.holeExp[3] = e1; }
        emit HoleExpPosted(tableId, handId, seat);
        if (h.dealMask == 3) {
            h.phase = h.allIn ? uint8(Phase.REVEAL_FLOP) : uint8(Phase.BET_PREFLOP);
            _setDeadline(tableId, t, h, !h.allIn);
        }
    }

    // ------------------------------------------------------------------
    // Betting
    // ------------------------------------------------------------------

    /// @notice Take a betting action. `amount` = total street bet for
    ///         BET/RAISE ("raise to"); ignored otherwise. Rules (min-raise,
    ///         short all-in, uncalled returns) live in BettingLib.
    function act(uint256 tableId, uint32 handId, Action action, uint32 amount) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (handId != t.handId) revert WrongHand();
        uint8 ph = h.phase;
        if (ph != uint8(Phase.BET_PREFLOP) && ph != uint8(Phase.BET_FLOP)
            && ph != uint8(Phase.BET_TURN) && ph != uint8(Phase.BET_RIVER)) revert BadPhase();
        uint8 me = _seatOf(t, msg.sender);
        if (me != h.toAct) revert NotYourTurn();

        uint8 outcome = BettingLib.applyAction(h, me, action, amount, t.bbChips);
        emit ActionTaken(tableId, handId, me, uint8(action), amount);

        if (outcome == BettingLib.OUT_FOLDED) {
            _awardPotAndEndHand(tableId, t, h, 1 - me);
        } else if (outcome == BettingLib.OUT_CLOSED) {
            _advanceAfterBetting(tableId, t, h);
        } else {
            _setDeadline(tableId, t, h, true);
        }
    }

    function _advanceAfterBetting(uint256 tableId, Table storage t, Hand storage h) private {
        if (h.street == 0) h.phase = uint8(Phase.REVEAL_FLOP);
        else if (h.street == 1) h.phase = uint8(Phase.REVEAL_TURN);
        else if (h.street == 2) h.phase = uint8(Phase.REVEAL_RIVER);
        else {
            h.phase = uint8(Phase.SHOWDOWN_1);
            h.firstShower = h.riverAggressor != 255 ? h.riverAggressor : 1 - h.btn;
        }
        _setDeadline(tableId, t, h, false);
    }

    // ------------------------------------------------------------------
    // Board reveals
    // ------------------------------------------------------------------

    function _streetPositions(uint8 phase) private pure returns (uint8 base, uint8 n) {
        if (phase == uint8(Phase.REVEAL_FLOP)) return (4, 3);
        if (phase == uint8(Phase.REVEAL_TURN)) return (7, 1);
        return (8, 1); // REVEAL_RIVER
    }

    /// @notice Post your per-card exponents for the current board street.
    ///         The FIRST poster passes empty claim/value/proof arrays. The
    ///         SECOND poster (who can decrypt locally once both exponents are
    ///         known) must pass claimed card indices, the Merkle-proven D4
    ///         values (concatenated 128-byte blobs) and flat proofs (6 nodes
    ///         per card); the contract verifies D0[claim]^(eC*eJ) == D4[pos].
    ///         claim = 255 asserts the position opens to garbage; it must be
    ///         accompanied by 128-byte inverse exponents (invMine/invTheirs)
    ///         and opens blame replay when verified.
    function postBoardExp(
        uint256 tableId,
        uint32 handId,
        uint256[] calldata exps,
        uint8[] calldata claims,
        bytes calldata d4vals,
        bytes32[] calldata proofs,      // flat: 6 nodes per revealed card
        bytes calldata invMine,
        bytes calldata invTheirs
    ) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (handId != t.handId) revert WrongHand();
        uint8 ph = h.phase;
        if (ph != uint8(Phase.REVEAL_FLOP) && ph != uint8(Phase.REVEAL_TURN)
            && ph != uint8(Phase.REVEAL_RIVER)) revert BadPhase();
        uint8 me = _seatOf(t, msg.sender);
        (uint8 base, uint8 n) = _streetPositions(ph);
        if (exps.length != n) revert BadData();
        for (uint256 i = 0; i < n; i++) {
            if (!SRA.validScalar(exps[i])) revert BadScalar();
        }

        if (h.pendBy == 255) {
            // first poster: stash exponents; opponent completes
            for (uint256 i = 0; i < n; i++) h.pendExp[i] = exps[i];
            h.pendBy = me;
            emit PhaseAdvanced(tableId, handId, ph, h.deadline);
            return;
        }
        if (h.pendBy == me) revert AlreadyPosted();
        if (claims.length != n || proofs.length != uint256(n) * 6
            || d4vals.length != uint256(n) * 128) revert BadData();

        for (uint256 i = 0; i < n; i++) {
            uint8 pos = base + uint8(i);
            bytes memory d4v = d4vals[i * 128:(i + 1) * 128];
            if (!CardMerkle.verify(h.roots[3], 4, pos, d4v, _slice6(proofs, i))) revert BadProof();
            uint256 eC = me == 0 ? exps[i] : h.pendExp[i];
            uint256 eJ = me == 0 ? h.pendExp[i] : exps[i];
            if (claims[i] < 52) {
                if (keccak256(SRA.modexpMul(SRA.cardCode(claims[i]), eC, eJ)) != keccak256(d4v)) {
                    revert CardMismatch();
                }
                h.board[pos - 4] = claims[i];
            } else {
                // garbage claim: verify via inverse round-trip, then open blame
                if (claims[i] != 255) revert BadData();
                uint8 card = _verifiedOpen(d4v, exps[i], h.pendExp[i], invMine, invTheirs);
                if (card < 52) {
                    // opens to a real card: false garbage claim = fold + penalty
                    _falseAccusation(tableId, t, h, me);
                } else {
                    _openBlame(tableId, t, h, pos, 255, me, eC, eJ);
                }
                return;
            }
        }
        _afterBoardReveal(tableId, t, h, ph);
    }

    function _afterBoardReveal(uint256 tableId, Table storage t, Hand storage h, uint8 ph) private {
        h.pendBy = 255;
        h.pendExp[0] = 0; h.pendExp[1] = 0; h.pendExp[2] = 0;
        if (ph == uint8(Phase.REVEAL_FLOP)) h.street = 1;
        else if (ph == uint8(Phase.REVEAL_TURN)) h.street = 2;
        else h.street = 3;
        emit BoardRevealed(tableId, t.handId, h.street, h.board);
        if (h.allIn) {
            if (ph == uint8(Phase.REVEAL_FLOP)) h.phase = uint8(Phase.REVEAL_TURN);
            else if (ph == uint8(Phase.REVEAL_TURN)) h.phase = uint8(Phase.REVEAL_RIVER);
            else {
                h.phase = uint8(Phase.SHOWDOWN_1);
                h.firstShower = h.riverAggressor != 255 ? h.riverAggressor : 1 - h.btn;
            }
            _setDeadline(tableId, t, h, false);
        } else {
            if (ph == uint8(Phase.REVEAL_FLOP)) h.phase = uint8(Phase.BET_FLOP);
            else if (ph == uint8(Phase.REVEAL_TURN)) h.phase = uint8(Phase.BET_TURN);
            else h.phase = uint8(Phase.BET_RIVER);
            BettingLib.openStreet(h, t.bbChips);
            _setDeadline(tableId, t, h, true);
        }
    }

    /// @dev Open D4[pos] given both exponents + their 128-byte inverses.
    ///      Each inverse is verified by round-trip (roots are unique in the
    ///      QR subgroup). Returns card index or 255 for garbage.
    function _verifiedOpen(
        bytes memory d4v,
        uint256 eMine,
        uint256 eTheirs,
        bytes calldata invMine,
        bytes calldata invTheirs
    ) private view returns (uint8) {
        if (invMine.length != 128 || invTheirs.length != 128) revert BadData();
        bytes memory t1 = SRA.modexpBytes(d4v, invTheirs);
        if (keccak256(SRA.modexp32(t1, eTheirs)) != keccak256(d4v)) revert BadInverse();
        bytes memory t2 = SRA.modexpBytes(t1, invMine);
        if (keccak256(SRA.modexp32(t2, eMine)) != keccak256(t1)) revert BadInverse();
        return SRA.cardFromHash(keccak256(t2));
    }

    function _slice6(bytes32[] calldata proofs, uint256 i) private pure returns (bytes32[6] memory p) {
        for (uint256 d = 0; d < 6; d++) p[d] = proofs[i * 6 + d];
    }

    // ------------------------------------------------------------------
    // Showdown
    // ------------------------------------------------------------------

    /// @notice Reveal your hole cards at showdown (first shower in
    ///         SHOWDOWN_1; the other player in SHOWDOWN_2). Provide your two
    ///         per-card exponents, claimed cards and Merkle-proven D4 values
    ///         (flat proofs, 6 nodes per card).
    function showdown(
        uint256 tableId,
        uint32 handId,
        uint256[2] calldata exps,
        uint8[2] calldata claims,
        bytes calldata d4vals,
        bytes32[] calldata proofs
    ) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (handId != t.handId) revert WrongHand();
        uint8 me = _seatOf(t, msg.sender);
        if (h.phase == uint8(Phase.SHOWDOWN_1)) {
            if (me != h.firstShower) revert NotYourReveal();
        } else if (h.phase == uint8(Phase.SHOWDOWN_2)) {
            if (me != 1 - h.firstShower) revert NotYourReveal();
        } else {
            revert BadPhase();
        }
        if (d4vals.length != 256 || proofs.length != 12) revert BadData();
        if (claims[0] >= 52 || claims[1] >= 52 || claims[0] == claims[1]) revert BadData();
        for (uint256 i = 0; i < 5; i++) {
            if (h.board[i] == claims[0] || h.board[i] == claims[1]) revert BadData();
        }

        uint8 basePos = me == 0 ? 0 : 2; // creator holes 0,1; joiner 2,3
        for (uint256 i = 0; i < 2; i++) {
            if (!SRA.validScalar(exps[i])) revert BadScalar();
            uint8 pos = basePos + uint8(i);
            bytes memory d4v = d4vals[i * 128:(i + 1) * 128];
            if (!CardMerkle.verify(h.roots[3], 4, pos, d4v, _slice6(proofs, i))) revert BadProof();
            uint256 oppExp = h.holeExp[pos]; // opponent's deal exponent for my hole
            uint256 eC = me == 0 ? exps[i] : oppExp;
            uint256 eJ = me == 0 ? oppExp : exps[i];
            if (keccak256(SRA.modexpMul(SRA.cardCode(claims[i]), eC, eJ)) != keccak256(d4v)) {
                revert CardMismatch();
            }
            h.shownExp[me][i] = exps[i];
            h.shownCards[me][i] = claims[i];
        }

        uint8[7] memory seven;
        for (uint256 i = 0; i < 5; i++) seven[i] = h.board[i];
        seven[5] = claims[0];
        seven[6] = claims[1];
        uint32 sc = HandEval.evaluate7(seven);
        h.shownScore[me] = sc;
        h.shownMask |= uint8(1) << me;
        emit ShowdownRevealed(tableId, handId, me, claims[0], claims[1], sc);

        if (h.phase == uint8(Phase.SHOWDOWN_1)) {
            h.phase = uint8(Phase.SHOWDOWN_2);
            _setDeadline(tableId, t, h, false);
        } else {
            uint8 first = h.firstShower;
            uint8 second = 1 - first;
            if (h.shownScore[second] > h.shownScore[first]) {
                _awardPotAndEndHand(tableId, t, h, second);
            } else if (h.shownScore[second] < h.shownScore[first]) {
                _awardPotAndEndHand(tableId, t, h, first);
            } else {
                _splitPotAndEndHand(tableId, t, h);
            }
        }
    }

    /// @notice Concede the pot at showdown without revealing (cards stay
    ///         encrypted forever).
    function muck(uint256 tableId, uint32 handId) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (handId != t.handId) revert WrongHand();
        if (h.phase != uint8(Phase.SHOWDOWN_2)) revert BadPhase();
        uint8 me = _seatOf(t, msg.sender);
        if (me != 1 - h.firstShower) revert NotYourReveal();
        emit Mucked(tableId, handId, me);
        _awardPotAndEndHand(tableId, t, h, h.firstShower);
    }

    // ------------------------------------------------------------------
    // Accusations & blame replay (SPEC 2.5)
    // ------------------------------------------------------------------

    /// @notice Accuse: "my hole card at `pos` opens to garbage". You reveal
    ///         your own per-card exponent + both 128-byte inverse exponents.
    ///         If the card is actually valid the accusation is false and you
    ///         fold + pay the penalty (you also exposed your own card — your
    ///         choice). If it is garbage, blame replay opens and will cost
    ///         the cheater their entire stack.
    function accuseHole(
        uint256 tableId,
        uint32 handId,
        uint8 pos,
        uint256 ownExp,
        bytes calldata d4val,
        bytes32[6] calldata proof,
        bytes calldata invOwn,
        bytes calldata invTheirs
    ) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (handId != t.handId) revert WrongHand();
        uint8 ph = h.phase;
        if (ph < uint8(Phase.BET_PREFLOP) || ph > uint8(Phase.SHOWDOWN_2)) revert BadPhase();
        uint8 me = _seatOf(t, msg.sender);
        if (!((me == 0 && pos < 2) || (me == 1 && (pos == 2 || pos == 3)))) revert NotYourHole();
        if (!SRA.validScalar(ownExp)) revert BadScalar();
        if (!CardMerkle.verify(h.roots[3], 4, pos, d4val, proof)) revert BadProof();

        uint8 card = _verifiedOpen(d4val, ownExp, h.holeExp[pos], invOwn, invTheirs);
        if (card < 52) {
            _falseAccusation(tableId, t, h, me);
        } else {
            uint256 postedC = me == 0 ? ownExp : h.holeExp[pos];
            uint256 postedJ = me == 1 ? ownExp : h.holeExp[pos];
            _openBlame(tableId, t, h, pos, 255, me, postedC, postedJ);
        }
    }

    function _falseAccusation(uint256 tableId, Table storage t, Hand storage h, uint8 accuser) private {
        h.folded = accuser;
        BettingLib.closeStreet(h);
        _applyPenalty(h, accuser, t.penaltyChips);
        _awardPotAndEndHand(tableId, t, h, 1 - accuser);
    }

    function _openBlame(uint256 tableId, Table storage t, Hand storage h,
        uint8 pos, uint8 claimIdx, uint8 claimBy, uint256 postedC, uint256 postedJ) private
    {
        h.blamePos = pos;
        h.blameClaimIdx = claimIdx;
        h.blameClaimBy = claimBy;
        h.blamePostedC = postedC;
        h.blamePostedJ = postedJ;
        h.phase = uint8(Phase.BLAME_J);
        _setDeadline(tableId, t, h, false);
        emit BlameOpened(tableId, t.handId, pos, claimBy, claimIdx);
    }

    /// @notice Joiner's blame submission: their permutation source j, global
    ///         and per-card exponents, plus Merkle-proven stage values
    ///         (D1[j] ‖ D2[pos] ‖ D3[pos] ‖ D4[pos], flat proofs 6 nodes
    ///         each). Verifies Check2 (D2[pos] == D1[j]^gJ) and Check4
    ///         (D4[pos]^gJ == D3[pos]^cJ). Any failure = joiner cheated.
    function submitBlameJ(
        uint256 tableId,
        uint32 handId,
        uint8 j,
        uint256 gJ,
        uint256 cJ,
        bytes calldata vals,
        bytes32[] calldata proofs   // flat, 24 nodes
    ) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (handId != t.handId) revert WrongHand();
        if (h.phase != uint8(Phase.BLAME_J)) revert BadPhase();
        if (msg.sender != t.joiner) revert NotJoiner();
        if (j >= 52 || !SRA.validScalar(gJ) || !SRA.validScalar(cJ)) revert BadData();
        if (vals.length != 512 || proofs.length != 24) revert BadData();

        uint8 pos = h.blamePos;
        bytes memory d1j = vals[0:128];
        bytes memory d2 = vals[128:256];
        bytes memory d3 = vals[256:384];
        bytes memory d4 = vals[384:512];
        if (!CardMerkle.verify(h.roots[0], 1, j, d1j, _slice6(proofs, 0))) revert BadProof();
        if (!CardMerkle.verify(h.roots[1], 2, pos, d2, _slice6(proofs, 1))) revert BadProof();
        if (!CardMerkle.verify(h.roots[2], 3, pos, d3, _slice6(proofs, 2))) revert BadProof();
        if (!CardMerkle.verify(h.roots[3], 4, pos, d4, _slice6(proofs, 3))) revert BadProof();

        // Check2: D2[pos] == D1[j]^gJ
        if (SRA.modexpHash32(d1j, gJ) != keccak256(d2)) {
            _settleCheat(tableId, t, h, 1);
            return;
        }
        // Check4: D4[pos]^gJ == D3[pos]^cJ
        if (SRA.modexpHash32(d4, gJ) != SRA.modexpHash32(d3, cJ)) {
            _settleCheat(tableId, t, h, 1);
            return;
        }
        h.blameGJ = gJ;
        h.blameCJ = cJ;
        h.blameVals[0] = keccak256(d1j);
        h.blameVals[1] = keccak256(d2);
        h.blameVals[2] = keccak256(d3);
        h.blameVals[3] = keccak256(d4);
        h.phase = uint8(Phase.BLAME_C);
        _setDeadline(tableId, t, h, false);
        emit BlameJSubmitted(tableId, handId, j);
    }

    /// @notice Creator's blame submission: original card index k, global and
    ///         per-card exponents, plus the raw stage values (must match the
    ///         hashes pinned in submitBlameJ). Runs Check1, Check3 and the
    ///         posted-exponent checks, then assigns the cheater — someone
    ///         always pays: every check isolates a single player's work.
    function submitBlameC(
        uint256 tableId,
        uint32 handId,
        uint8 k,
        uint256 gC,
        uint256 cC,
        bytes calldata vals
    ) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (handId != t.handId) revert WrongHand();
        if (h.phase != uint8(Phase.BLAME_C)) revert BadPhase();
        if (msg.sender != t.creator) revert NotCreator();
        if (k >= 52 || !SRA.validScalar(gC) || !SRA.validScalar(cC)) revert BadData();
        if (vals.length != 512) revert BadData();
        bytes memory d1j = vals[0:128];
        bytes memory d2 = vals[128:256];
        bytes memory d3 = vals[256:384];
        if (keccak256(d1j) != h.blameVals[0] || keccak256(d2) != h.blameVals[1]
            || keccak256(d3) != h.blameVals[2] || keccak256(vals[384:512]) != h.blameVals[3]) {
            revert BadData();
        }

        // Check1: D1[j] == D0[k]^gC
        if (SRA.modexpHash32(SRA.cardCode(k), gC) != h.blameVals[0]) {
            _settleCheat(tableId, t, h, 0);
            return;
        }
        // Check3: D3[pos]^gC == D2[pos]^cC
        if (SRA.modexpHash32(d3, gC) != SRA.modexpHash32(d2, cC)) {
            _settleCheat(tableId, t, h, 0);
            return;
        }
        // Step 5: the deck is honest at pos — test the exponents POSTED
        // during play (frozen at blame-open) against the pinned true keys.
        if (keccak256(SRA.modexpMul(SRA.cardCode(k), cC, h.blamePostedJ)) != h.blameVals[3]) {
            _settleCheat(tableId, t, h, 1);
            return;
        }
        if (keccak256(SRA.modexpMul(SRA.cardCode(k), h.blamePostedC, h.blameCJ)) != h.blameVals[3]) {
            _settleCheat(tableId, t, h, 0);
            return;
        }
        // both posted exponents open the position to the true card D0[k]:
        // the disputed claim itself was the lie.
        _settleCheat(tableId, t, h, h.blameClaimBy);
    }

    // ------------------------------------------------------------------
    // Timeouts (SPEC 3.5)
    // ------------------------------------------------------------------

    /// @notice Claim the opponent timed out on the current phase. Resolution:
    ///         betting stall = fold; crypto/reveal stall = pot forfeit;
    ///         SHOWDOWN_2 stall = muck-concede; blame stall = full-stack
    ///         forfeit. Claimer additionally receives `penaltyChips`.
    ///         `andSettle` ends the whole session at the resulting stacks
    ///         (repeated absence never requires grinding hand by hand).
    function claimTimeout(uint256 tableId, uint32 handId, uint8 expectedPhase, bool andSettle) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (t.status != uint8(TableStatus.PLAYING)) revert NotPlaying();
        if (handId != t.handId) revert WrongHand();
        uint8 ph = h.phase;
        if (ph != expectedPhase || ph == uint8(Phase.NONE)) revert BadPhase();
        if (block.timestamp <= h.deadline) revert NotExpired();
        uint8 me = _seatOf(t, msg.sender);
        uint8 staller;

        if (ph == uint8(Phase.SHUF2) || ph == uint8(Phase.LOCK2)) staller = 1;
        else if (ph == uint8(Phase.LOCK1)) staller = 0;
        else if (ph == uint8(Phase.DEAL)) {
            uint8 myBit = me == 1 ? 1 : 2;
            if (h.dealMask & myBit == 0) revert PostYoursFirst();
            staller = 1 - me;
        } else if (ph == uint8(Phase.REVEAL_FLOP) || ph == uint8(Phase.REVEAL_TURN)
            || ph == uint8(Phase.REVEAL_RIVER)) {
            if (h.pendBy != me) revert PostYoursFirst();
            staller = 1 - me;
        } else if (ph == uint8(Phase.BET_PREFLOP) || ph == uint8(Phase.BET_FLOP)
            || ph == uint8(Phase.BET_TURN) || ph == uint8(Phase.BET_RIVER)) {
            staller = h.toAct;
        } else if (ph == uint8(Phase.SHOWDOWN_1)) {
            staller = h.firstShower;
        } else if (ph == uint8(Phase.SHOWDOWN_2)) {
            staller = 1 - h.firstShower;
        } else if (ph == uint8(Phase.BLAME_J)) {
            if (me != 0) revert NotCreator();
            emit TimeoutClaimed(tableId, handId, ph, 1);
            _settleCheat(tableId, t, h, 1);
            return;
        } else if (ph == uint8(Phase.BLAME_C)) {
            if (me != 1) revert NotJoiner();
            emit TimeoutClaimed(tableId, handId, ph, 0);
            _settleCheat(tableId, t, h, 0);
            return;
        } else {
            revert BadPhase();
        }
        if (staller == me) revert YouAreTheStaller();
        emit TimeoutClaimed(tableId, handId, ph, staller);
        BettingLib.closeStreet(h);
        _applyPenalty(h, staller, t.penaltyChips);
        _awardPotAndEndHand(tableId, t, h, me);
        if (andSettle && t.status == uint8(TableStatus.PLAYING)) {
            _settleSession(tableId, t);
        }
    }

    /// @notice Claim the creator failed to open the next hand in time. The
    ///         absent player pays one big blind + penalty from their escrowed
    ///         stack; the hand number advances (button rotates).
    function claimNoShow(uint256 tableId, bool andSettle) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (t.status != uint8(TableStatus.PLAYING)) revert NotPlaying();
        if (h.phase != uint8(Phase.NONE)) revert BadPhase();
        if (msg.sender != t.joiner) revert NotJoiner();
        if (block.timestamp <= t.lastSettleTime + t.cryptoTimeout) revert NotExpired();
        uint32 x = _min32(t.bbChips + t.penaltyChips, t.stackC);
        t.stackC -= x;
        t.stackJ += x;
        emit NoShowClaimed(tableId, t.handId, x);
        emit HandSettled(tableId, t.handId, t.stackC, t.stackJ);
        t.handId += 1;
        t.lastSettleTime = uint64(block.timestamp);
        if (t.stackC == 0 || andSettle) {
            _settleSession(tableId, t);
        }
    }

    function _applyPenalty(Hand storage h, uint8 staller, uint32 penalty) private {
        uint32 x = _min32(penalty, h.stack[staller]);
        h.stack[staller] -= x;
        h.stack[1 - staller] += x;
    }

    // ------------------------------------------------------------------
    // Leaving / settlement
    // ------------------------------------------------------------------

    /// @notice Leave the table. Between hands: session settles at current
    ///         stacks (either player may exit; this is the cash-out path).
    ///         Mid-hand: you forfeit the pot + penalty (never a free roll);
    ///         during blame you are treated as the cheater.
    function leaveTable(uint256 tableId) external {
        Table storage t = tables[tableId];
        Hand storage h = hands[tableId];
        if (t.status != uint8(TableStatus.PLAYING)) revert NotPlaying();
        uint8 me = _seatOf(t, msg.sender);
        uint8 ph = h.phase;
        emit PlayerLeft(tableId, me);
        if (ph == uint8(Phase.NONE)) {
            _settleSession(tableId, t);
        } else if (ph == uint8(Phase.BLAME_J) || ph == uint8(Phase.BLAME_C)) {
            _settleCheat(tableId, t, h, me);
        } else {
            BettingLib.closeStreet(h);
            _applyPenalty(h, me, t.penaltyChips);
            _awardPotAndEndHand(tableId, t, h, 1 - me);
            if (t.status == uint8(TableStatus.PLAYING)) {
                _settleSession(tableId, t);
            }
        }
    }

    function _awardPotAndEndHand(uint256 tableId, Table storage t, Hand storage h, uint8 winner) private {
        uint32 rake = uint32((uint256(h.pot) * t.rakeBps) / 10000);
        uint32 win = h.pot - rake;
        h.stack[winner] += win;
        t.rakeChips += rake;
        emit PotAwarded(tableId, t.handId, winner, win, rake);
        _endHand(tableId, t, h);
    }

    function _splitPotAndEndHand(uint256 tableId, Table storage t, Hand storage h) private {
        uint32 rake = uint32((uint256(h.pot) * t.rakeBps) / 10000);
        uint32 rem = h.pot - rake;
        uint32 half = rem / 2;
        uint8 oop = 1 - h.btn;
        h.stack[oop] += half + (rem & 1); // odd chip to the out-of-position player
        h.stack[h.btn] += half;
        t.rakeChips += rake;
        emit PotAwarded(tableId, t.handId, 2, rem, rake);
        _endHand(tableId, t, h);
    }

    function _endHand(uint256 tableId, Table storage t, Hand storage h) private {
        t.stackC = h.stack[0];
        t.stackJ = h.stack[1];
        uint32 ended = t.handId;
        t.handId = ended + 1;
        t.lastSettleTime = uint64(block.timestamp);
        delete hands[tableId];
        emit HandSettled(tableId, ended, t.stackC, t.stackJ);
        if (t.stackC == 0 || t.stackJ == 0) {
            _settleSession(tableId, t);
        }
    }

    /// @dev Cheater forfeits every chip on the table (no rake); session ends.
    function _settleCheat(uint256 tableId, Table storage t, Hand storage h, uint8 cheater) private {
        uint32 all = h.stack[0] + h.stack[1] + h.streetBet[0] + h.streetBet[1] + h.pot;
        if (cheater == 0) { t.stackC = 0; t.stackJ = all; }
        else { t.stackC = all; t.stackJ = 0; }
        delete hands[tableId];
        emit CheatSettled(tableId, cheater);
        _settleSession(tableId, t);
    }

    function _settleSession(uint256 tableId, Table storage t) private {
        t.status = uint8(TableStatus.SETTLED);
        uint256 cv = t.chipValue;
        uint256 cWei = uint256(t.stackC) * cv;
        uint256 jWei = uint256(t.stackJ) * cv;
        uint256 rWei = uint256(t.rakeChips) * cv;
        if (cWei > 0) withdrawable[t.creator] += cWei;
        if (jWei > 0) withdrawable[t.joiner] += jWei;
        if (rWei > 0) withdrawable[tableFeeAccount[tableId]] += rWei;
        delete hands[tableId];
        emit SessionSettled(tableId, cWei, jWei, rWei);
    }

    /// @notice Withdraw all credited winnings/refunds (pull-payment).
    function withdraw() external nonReentrant {
        uint256 amount = withdrawable[msg.sender];
        if (amount == 0) revert NothingToDo();
        withdrawable[msg.sender] = 0;
        (bool ok, ) = msg.sender.call{value: amount}("");
        if (!ok) revert TransferFailed();
        emit Withdrawn(msg.sender, amount);
    }

    // ------------------------------------------------------------------
    // Views
    // ------------------------------------------------------------------

    /// @notice Full hand state (UI + crash recovery).
    function getHand(uint256 tableId) external view returns (Hand memory) {
        return hands[tableId];
    }

    /// @notice Open tables for the lobby (bounded scan, newest first).
    function getOpenTables(uint256 maxN) external view returns (uint256[] memory ids) {
        uint256 n = 0;
        uint256[] memory tmp = new uint256[](maxN);
        for (uint256 id = tableCount; id >= 1 && n < maxN; id--) {
            if (tables[id].status == uint8(TableStatus.OPEN)) tmp[n++] = id;
        }
        ids = new uint256[](n);
        for (uint256 i = 0; i < n; i++) ids[i] = tmp[i];
    }

    // ------------------------------------------------------------------
    // Internals
    // ------------------------------------------------------------------

    /// @dev Set the phase deadline and emit PhaseAdvanced (single site).
    function _setDeadline(uint256 tableId, Table storage t, Hand storage h, bool betting) private {
        h.deadline = uint64(block.timestamp) + (betting ? t.actTimeout : t.cryptoTimeout);
        emit PhaseAdvanced(tableId, t.handId, h.phase, h.deadline);
    }

    function _seatOf(Table storage t, address a) private view returns (uint8) {
        if (a == t.creator) return 0;
        if (a == t.joiner) return 1;
        revert NotAPlayer();
    }

    function _min32(uint32 a, uint32 b) private pure returns (uint32) {
        return a < b ? a : b;
    }
}
        

@openzeppelin/contracts/utils/ReentrancyGuard.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

import {StorageSlot} from "./StorageSlot.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 *
 * IMPORTANT: Deprecated. This storage-based reentrancy guard will be removed and replaced
 * by the {ReentrancyGuardTransient} variant in v6.0.
 *
 * @custom:stateless
 */
abstract contract ReentrancyGuard {
    using StorageSlot for bytes32;

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant REENTRANCY_GUARD_STORAGE =
        0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    /**
     * @dev A `view` only version of {nonReentrant}. Use to block view functions
     * from being called, preventing reading from inconsistent contract state.
     *
     * CAUTION: This is a "view" modifier and does not change the reentrancy
     * status. Use it only on view functions. For payable or non-payable functions,
     * use the standard {nonReentrant} modifier instead.
     */
    modifier nonReentrantView() {
        _nonReentrantBeforeView();
        _;
    }

    function _nonReentrantBeforeView() private view {
        if (_reentrancyGuardEntered()) {
            revert ReentrancyGuardReentrantCall();
        }
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        _nonReentrantBeforeView();

        // Any calls to nonReentrant after this point will fail
        _reentrancyGuardStorageSlot().getUint256Slot().value = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _reentrancyGuardStorageSlot().getUint256Slot().value == ENTERED;
    }

    function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
        return REENTRANCY_GUARD_STORAGE;
    }
}
          

@openzeppelin/contracts/utils/StorageSlot.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC-1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct Int256Slot {
        int256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Int256Slot` with member `value` located at `slot`.
     */
    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns a `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }
}
          

contracts/GameTypes.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/// @title GameTypes — shared structs, enums and errors for PLSHoldem
/// @notice File-level definitions so the main contract and external game
///         libraries share one source of truth.

enum TableStatus { NONE, OPEN, PLAYING, SETTLED, CANCELLED }

enum Phase {
    NONE,          // between hands: waiting for creator to post D1
    SHUF1,         // (never stored: D1 post transitions NONE->SHUF2)
    SHUF2,         // joiner must post D2
    LOCK1,         // creator must post D3
    LOCK2,         // joiner must post D4
    DEAL,          // both must post hole-card exponents
    BET_PREFLOP,
    REVEAL_FLOP,
    BET_FLOP,
    REVEAL_TURN,
    BET_TURN,
    REVEAL_RIVER,
    BET_RIVER,
    SHOWDOWN_1,    // first revealer must show
    SHOWDOWN_2,    // second player shows or mucks
    BLAME_J,       // joiner must submit blame data
    BLAME_C        // creator must submit blame data
}

enum Action { FOLD, CHECK, CALL, BET, RAISE }

struct Table {
    address creator;
    uint96 chipValue;        // wei per chip
    address joiner;
    uint8 status;            // TableStatus
    uint8 creatorAvatar;
    uint8 joinerAvatar;
    uint16 rakeBps;
    uint32 buyInChips;
    uint32 sbChips;
    uint32 bbChips;
    uint32 penaltyChips;
    uint32 actTimeout;       // seconds, betting actions
    uint32 cryptoTimeout;    // seconds, crypto steps / reveals / next hand
    uint32 handId;           // next / current hand number
    uint32 rakeChips;        // accrued rake
    uint32 stackC;           // creator session stack (between hands)
    uint32 stackJ;           // joiner session stack
    uint64 lastSettleTime;   // anchor for the next-hand (no-show) clock
}

struct Hand {
    uint8 phase;             // Phase
    uint8 btn;               // 0 = creator has the button, 1 = joiner
    uint64 deadline;         // current actor(s) must move before this
    // betting state (mirrors web/js/betting.mjs)
    uint32[2] stack;         // chips behind, [creator, joiner]
    uint32[2] streetBet;
    uint32 pot;
    uint32 currentBet;
    uint32 inc;              // last full raise increment
    uint8 street;            // 0..3
    uint8 toAct;
    uint8 firstToAct;
    bool reopen;
    bool bbOption;
    bool allIn;
    uint8 folded;            // 255 = none
    uint8 riverAggressor;    // 255 = none
    // dealing / reveals
    bytes32[4] roots;        // D1..D4 Merkle roots
    uint256[4] holeExp;      // per-card exps for positions 0..3 (0,1 by J; 2,3 by C)
    uint8 dealMask;          // bit0 = joiner posted, bit1 = creator posted
    uint8[5] board;          // card indices, 255 = unset
    uint256[3] pendExp;      // first poster's exps for the current reveal
    uint8 pendBy;            // 255 = none
    // showdown
    uint8 firstShower;
    uint8 shownMask;         // bit per seat
    uint256[2][2] shownExp;  // [seat][slot]
    uint8[2][2] shownCards;  // [seat][slot]
    uint32[2] shownScore;
    // blame
    uint8 blamePos;
    uint8 blameClaimIdx;     // disputed claimed card (255 = "garbage" claim)
    uint8 blameClaimBy;      // seat whose claim/accusation opened blame
    uint256 blameGJ;         // J's pinned global exponent
    uint256 blameCJ;         // J's pinned per-card exponent
    uint256 blamePostedC;    // C's per-card exponent as posted during play
    uint256 blamePostedJ;    // J's per-card exponent as posted during play
    bytes32[4] blameVals;    // keccak of Merkle-proven D1[j], D2..D4[pos]
}

// Custom errors (compact reverts), shared by contract + libraries
error AlreadyPosted();
error BadAmount();
error BadData();
error BadInverse();
error BadParam();
error BadPhase();
error BadProof();
error BadScalar();
error BetBelowMin();
error BetTooLarge();
error Bust();
error CannotCheck();
error CardMismatch();
error FacingABet();
error NotAPlayer();
error NotCreator();
error NotExpired();
error NotJoiner();
error NotOpen();
error NotOwner();
error NotPlaying();
error NotReopened();
error NotYourHole();
error NotYourReveal();
error NotYourTurn();
error NothingToCall();
error NothingToDo();
error NothingToRaise();
error OpponentAllIn();
error PostYoursFirst();
error RaiseBelowMin();
error RaiseTooSmall();
error RakeCap();
error TransferFailed();
error WrongDeposit();
error WrongHand();
error YouAreTheStaller();
          

contracts/lib/BettingLib.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Hand, Action, CannotCheck, NothingToCall, FacingABet, OpponentAllIn,
        BadAmount, BetBelowMin, NotReopened, RaiseTooSmall, BetTooLarge,
        RaiseBelowMin, BadParam} from "../GameTypes.sol";

/// @title BettingLib — heads-up NLHE betting transitions
/// @notice The exact on-chain mirror of web/js/betting.mjs (the executable
///         betting spec, cross-checked by shared vectors and integration
///         tests). Deployed as an external library to keep the main contract
///         under the EIP-170 size limit.
library BettingLib {
    uint8 internal constant OUT_TURN = 0;    // turn passed to opponent
    uint8 internal constant OUT_CLOSED = 1;  // street closed
    uint8 internal constant OUT_FOLDED = 2;  // actor folded (street closed too)

    /// @notice Initialize per-hand betting state and auto-post the blinds.
    function initHand(Hand storage h, uint8 btn, uint32 sbChips, uint32 bbChips) public {
        h.btn = btn;
        h.folded = 255;
        h.riverAggressor = 255;
        h.pendBy = 255;
        h.board = [255, 255, 255, 255, 255];
        h.inc = bbChips;
        h.reopen = true;
        h.bbOption = true;
        h.street = 0;
        uint8 opp = 1 - btn;
        uint32 sbPost = _min32(sbChips, h.stack[btn]);
        uint32 bbPost = _min32(bbChips, h.stack[opp]);
        h.stack[btn] -= sbPost;
        h.streetBet[btn] = sbPost;
        h.stack[opp] -= bbPost;
        h.streetBet[opp] = bbPost;
        h.currentBet = sbPost > bbPost ? sbPost : bbPost;
        h.toAct = btn;
        h.firstToAct = btn;
        if (_shouldAutoClose(h)) closeStreet(h);
    }

    /// @notice Apply one betting action for seat `me`; reverts if illegal.
    /// @return outcome OUT_TURN / OUT_CLOSED / OUT_FOLDED
    function applyAction(Hand storage h, uint8 me, Action action, uint32 amount, uint32 bbNominal)
        public returns (uint8 outcome)
    {
        uint8 opp = 1 - me;
        uint32 facing = h.currentBet - h.streetBet[me];
        if (h.street == 0 && me == 1 - h.btn) h.bbOption = false; // BB is acting

        if (action == Action.FOLD) {
            h.folded = me;
            closeStreet(h);
            return OUT_FOLDED;
        }
        if (action == Action.CHECK) {
            if (facing != 0) revert CannotCheck();
            if (me != h.firstToAct) {
                closeStreet(h);
                return OUT_CLOSED;
            }
            h.toAct = opp;
            if (_shouldAutoClose(h)) { closeStreet(h); return OUT_CLOSED; }
            return OUT_TURN;
        }
        if (action == Action.CALL) {
            if (facing == 0) revert NothingToCall();
            uint32 pay = _min32(facing, h.stack[me]);
            h.stack[me] -= pay;
            h.streetBet[me] += pay;
            // preflop limp: BB is still owed the option to check or raise
            if (h.street == 0 && me == h.btn && h.bbOption) {
                h.bbOption = false;
                h.toAct = opp;
                if (_shouldAutoClose(h)) { closeStreet(h); return OUT_CLOSED; }
                return OUT_TURN;
            }
            closeStreet(h);
            return OUT_CLOSED;
        }
        if (action == Action.BET) {
            if (h.currentBet != 0) revert FacingABet();
            if (h.stack[opp] == 0) revert OpponentAllIn();
            if (amount == 0 || amount > h.stack[me]) revert BadAmount();
            if (amount < bbNominal && amount != h.stack[me]) revert BetBelowMin();
            h.stack[me] -= amount;
            h.streetBet[me] = amount;
            h.currentBet = amount;
            // short all-in bet does not reopen raising for the opponent
            if (amount >= bbNominal) { h.inc = amount; h.reopen = true; }
            else { h.reopen = false; }
            if (h.street == 3) h.riverAggressor = me;
            h.toAct = opp;
            if (_shouldAutoClose(h)) { closeStreet(h); return OUT_CLOSED; }
            return OUT_TURN;
        }
        if (action == Action.RAISE) {
            if (h.currentBet == 0) revert FacingABet();
            if (!h.reopen) revert NotReopened();
            if (h.stack[opp] == 0) revert OpponentAllIn();
            if (amount <= h.currentBet) revert RaiseTooSmall();
            uint32 newMoney = amount - h.streetBet[me];
            if (newMoney > h.stack[me]) revert BetTooLarge();
            uint32 minTo = h.currentBet + h.inc;
            bool isAllIn = newMoney == h.stack[me];
            if (amount < minTo && !isAllIn) revert RaiseBelowMin();
            h.stack[me] -= newMoney;
            h.streetBet[me] = amount;
            if (amount >= minTo) { h.inc = amount - h.currentBet; h.reopen = true; }
            else { h.reopen = false; } // short all-in raise: call/fold only
            h.currentBet = amount;
            if (h.street == 3) h.riverAggressor = me;
            if (h.street == 0) h.bbOption = false;
            h.toAct = opp;
            if (_shouldAutoClose(h)) { closeStreet(h); return OUT_CLOSED; }
            return OUT_TURN;
        }
        revert BadParam();
    }

    /// @notice Open the next street's betting round (after a board reveal).
    function openStreet(Hand storage h, uint32 bbNominal) public {
        h.currentBet = 0;
        h.inc = bbNominal;
        h.reopen = true;
        h.firstToAct = 1 - h.btn;
        h.toAct = h.firstToAct;
    }

    /// @notice Return the uncalled portion, move matched chips to the pot.
    function closeStreet(Hand storage h) public {
        uint32 m = _min32(h.streetBet[0], h.streetBet[1]);
        h.stack[0] += h.streetBet[0] - m;
        h.stack[1] += h.streetBet[1] - m;
        h.pot += 2 * m;
        h.streetBet[0] = 0;
        h.streetBet[1] = 0;
        if (h.stack[0] == 0 || h.stack[1] == 0) h.allIn = true;
    }

    /// @dev Nobody can act: actor is all-in, or opponent is all-in with
    ///      nothing left to call.
    function _shouldAutoClose(Hand storage h) private view returns (bool) {
        return h.stack[h.toAct] == 0
            || (h.stack[1 - h.toAct] == 0 && h.streetBet[h.toAct] == h.currentBet);
    }

    function _min32(uint32 a, uint32 b) private pure returns (uint32) {
        return a < b ? a : b;
    }
}
          

contracts/lib/CardMerkle.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/// @title CardMerkle — 52-leaf (padded to 64) keccak Merkle tree over deck values
/// @notice leaf(i) = keccak256(uint8 stage ‖ uint8 i ‖ 128-byte value);
///         padding leaves are bytes32(0). Mirrors web/js/merkle.mjs.
library CardMerkle {
    uint256 internal constant DECK = 52;
    uint256 internal constant TREE = 64;
    uint256 internal constant DEPTH = 6;
    uint256 internal constant VALUE_BYTES = 128;

    /// @notice Compute the root of a full posted deck stage (calldata blob of
    ///         52 × 128 bytes). `stage` ∈ 1..4 domain-separates the stages.
    function computeRoot(bytes calldata deck, uint8 stage) public pure returns (bytes32) {
        require(deck.length == DECK * VALUE_BYTES, "deck len");
        bytes32[TREE] memory nodes;
        for (uint256 i = 0; i < DECK; i++) {
            nodes[i] = keccak256(
                abi.encodePacked(stage, uint8(i), deck[i * VALUE_BYTES:(i + 1) * VALUE_BYTES])
            );
        }
        // 12 zero padding leaves are bytes32(0) already
        uint256 width = TREE;
        while (width > 1) {
            for (uint256 i = 0; i < width; i += 2) {
                nodes[i / 2] = keccak256(abi.encodePacked(nodes[i], nodes[i + 1]));
            }
            width /= 2;
        }
        return nodes[0];
    }

    /// @notice Verify a single 128-byte value against a stored stage root.
    function verify(
        bytes32 root,
        uint8 stage,
        uint8 index,
        bytes memory value,
        bytes32[DEPTH] memory proof
    ) public pure returns (bool) {
        if (index >= DECK || value.length != VALUE_BYTES) return false;
        bytes32 h = keccak256(abi.encodePacked(stage, index, value));
        uint256 idx = index;
        for (uint256 d = 0; d < DEPTH; d++) {
            h = idx & 1 == 1
                ? keccak256(abi.encodePacked(proof[d], h))
                : keccak256(abi.encodePacked(h, proof[d]));
            idx >>= 1;
        }
        return h == root;
    }
}
          

contracts/lib/HandEval.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/// @title HandEval — 7-card Texas Hold'em evaluator
/// @notice Mirrors web/js/handeval.mjs exactly (cross-checked by shared and
///         randomized differential test vectors).
/// @dev Card index k = 13*suit + rank; rank 0='2' … 12='A'.
///      Score: uint32 = category << 20 | five 4-bit tiebreak nibbles.
///      Categories: 0 high, 1 pair, 2 two pair, 3 trips, 4 straight,
///      5 flush, 6 full house, 7 quads, 8 straight flush.
library HandEval {
    /// @notice Evaluate 7 distinct cards; larger score = better hand.
    function evaluate7(uint8[7] memory cards) public pure returns (uint32) {
        uint8[13] memory rankCount;
        uint8[4] memory suitCount;
        uint16[4] memory suitMask;
        uint16 rankMask;
        for (uint256 i = 0; i < 7; i++) {
            uint8 k = cards[i];
            require(k < 52, "bad card");
            uint8 r = k % 13;
            uint8 s = k / 13;
            rankCount[r]++;
            suitCount[s]++;
            suitMask[s] |= uint16(1) << r;
            rankMask |= uint16(1) << r;
        }

        // straight flush
        for (uint256 s = 0; s < 4; s++) {
            if (suitCount[s] >= 5) {
                int8 t = straightTop(suitMask[s]);
                if (t >= 0) return score(8, uint8(t), 0, 0, 0, 0);
            }
        }

        // rank groups (descending scan)
        int8 quad = -1;
        int8 trip = -1;
        int8 trip2 = -1;
        int8 pairHi = -1;
        int8 pairLo = -1;
        for (int8 r = 12; r >= 0; r--) {
            uint8 c = rankCount[uint8(r)];
            if (c == 4) quad = r;
            else if (c == 3) {
                if (trip < 0) trip = r;
                else if (trip2 < 0) trip2 = r;
            } else if (c == 2) {
                if (pairHi < 0) pairHi = r;
                else if (pairLo < 0) pairLo = r;
            }
        }

        if (quad >= 0) {
            uint16 rest = rankMask & ~(uint16(1) << uint8(quad));
            return score(7, uint8(quad), top1(rest), 0, 0, 0);
        }
        if (trip >= 0 && (trip2 >= 0 || pairHi >= 0)) {
            uint8 pr = trip2 >= 0 ? uint8(trip2) : uint8(pairHi);
            return score(6, uint8(trip), pr, 0, 0, 0);
        }
        for (uint256 s = 0; s < 4; s++) {
            if (suitCount[s] >= 5) {
                (uint8 a, uint8 b, uint8 c, uint8 d, uint8 e) = top5(suitMask[s]);
                return score(5, a, b, c, d, e);
            }
        }
        {
            int8 t = straightTop(rankMask);
            if (t >= 0) return score(4, uint8(t), 0, 0, 0, 0);
        }
        if (trip >= 0) {
            uint16 rest = rankMask & ~(uint16(1) << uint8(trip));
            (uint8 k1, uint8 k2) = top2(rest);
            return score(3, uint8(trip), k1, k2, 0, 0);
        }
        if (pairHi >= 0 && pairLo >= 0) {
            uint16 rest = rankMask & ~(uint16(1) << uint8(pairHi)) & ~(uint16(1) << uint8(pairLo));
            return score(2, uint8(pairHi), uint8(pairLo), top1(rest), 0, 0);
        }
        if (pairHi >= 0) {
            uint16 rest = rankMask & ~(uint16(1) << uint8(pairHi));
            (uint8 k1, uint8 k2) = top2(rest);
            uint8 k3 = top1(rest & ~(uint16(1) << k1) & ~(uint16(1) << k2));
            return score(1, uint8(pairHi), k1, k2, k3, 0);
        }
        (uint8 h1, uint8 h2, uint8 h3, uint8 h4, uint8 h5) = top5(rankMask);
        return score(0, h1, h2, h3, h4, h5);
    }

    /// @dev Highest straight top-rank in a 13-bit mask, or -1. Wheel top = 3.
    function straightTop(uint16 mask) internal pure returns (int8) {
        for (int8 t = 12; t >= 4; t--) {
            uint16 need = uint16(0x1f) << uint8(t - 4);
            if (mask & need == need) return t;
        }
        // wheel A-2-3-4-5: bits 12,0,1,2,3
        if (mask & 0x100f == 0x100f) return 3;
        return -1;
    }

    function score(uint8 cat, uint8 n1, uint8 n2, uint8 n3, uint8 n4, uint8 n5)
        private pure returns (uint32)
    {
        return (uint32(cat) << 20) | (uint32(n1) << 16) | (uint32(n2) << 12)
            | (uint32(n3) << 8) | (uint32(n4) << 4) | uint32(n5);
    }

    function top1(uint16 mask) private pure returns (uint8) {
        for (int8 r = 12; r >= 0; r--) {
            if (mask & (uint16(1) << uint8(r)) != 0) return uint8(r);
        }
        return 0;
    }

    function top2(uint16 mask) private pure returns (uint8, uint8) {
        uint8 a = top1(mask);
        uint8 b = top1(mask & ~(uint16(1) << a));
        return (a, b);
    }

    function top5(uint16 mask) private pure returns (uint8, uint8, uint8, uint8, uint8) {
        uint8[5] memory o;
        uint256 n = 0;
        for (int8 r = 12; r >= 0 && n < 5; r--) {
            if (mask & (uint16(1) << uint8(r)) != 0) {
                o[n++] = uint8(r);
            }
        }
        return (o[0], o[1], o[2], o[3], o[4]);
    }
}
          

contracts/lib/SRA.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/// @title SRA — commutative-encryption verification primitives
/// @notice On-chain half of the SRA mental-poker protocol (SPEC §2). All
///         deck values are 1024-bit big-endian byte strings (quadratic
///         residues mod P); all exponent checks run forward through the
///         MODEXP precompile. Mirrors web/js/sra.mjs.
library SRA {
    /// RFC 2409 Oakley Group 2 prime (1024-bit safe prime), big-endian words.
    uint256 internal constant P0 = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74;
    uint256 internal constant P1 = 0x020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437;
    uint256 internal constant P2 = 0x4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED;
    uint256 internal constant P3 = 0xEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF;

    uint256 internal constant VALUE_BYTES = 128;
    uint256 internal constant DECK = 52;

    /// @dev P as a 128-byte string (for the precompile modulus field).
    function pBytes() internal pure returns (bytes memory out) {
        out = new bytes(128);
        assembly ("memory-safe") {
            mstore(add(out, 32), P0)
            mstore(add(out, 64), P1)
            mstore(add(out, 96), P2)
            mstore(add(out, 128), P3)
        }
    }

    /// @notice base^exp mod P with a 32-byte exponent; returns 128-byte result.
    function modexp32(bytes memory base128, uint256 exp) public view returns (bytes memory) {
        return _modexp(base128, abi.encodePacked(exp));
    }

    /// @notice base^(e1*e2) mod P (512-bit exponent product of two scalars).
    function modexpMul(bytes memory base128, uint256 e1, uint256 e2)
        public view returns (bytes memory)
    {
        (uint256 hi, uint256 lo) = mul512(e1, e2);
        return _modexp(base128, abi.encodePacked(hi, lo));
    }

    /// @dev Full 512-bit product of two uint256.
    function mul512(uint256 a, uint256 b) internal pure returns (uint256 hi, uint256 lo) {
        unchecked {
            lo = a * b;
            uint256 mm = mulmod(a, b, type(uint256).max);
            hi = mm - lo;
            if (mm < lo) hi--;
        }
    }

    /// @dev MODEXP precompile call; base must be 128 bytes; mod = P.
    function _modexp(bytes memory base128, bytes memory exp)
        private view returns (bytes memory result)
    {
        require(base128.length == 128, "base len");
        bytes memory input = abi.encodePacked(
            uint256(128), uint256(exp.length), uint256(128), base128, exp, pBytes()
        );
        result = new bytes(128);
        bool ok;
        assembly ("memory-safe") {
            ok := staticcall(gas(), 0x05, add(input, 32), mload(input), add(result, 32), 128)
        }
        require(ok, "modexp failed");
    }

    /// @notice keccak of base^exp mod P — cheap equality comparisons.
    function modexpHash32(bytes memory base128, uint256 exp) public view returns (bytes32) {
        return keccak256(modexp32(base128, exp));
    }

    /// @notice base^exp mod P with an arbitrary-length exponent (used for
    ///         1024-bit inverse exponents in dispute round-trips).
    function modexpBytes(bytes memory base128, bytes memory exp) public view returns (bytes memory) {
        return _modexp(base128, exp);
    }

    /// @notice Deterministic card code for k in [0,52): full-size QR mod P.
    /// @dev h = BE(keccak(TAG‖k‖0)‖…‖keccak(TAG‖k‖3)); code = h^2 mod P.
    ///      Mirrors sra.mjs cardCode().
    function cardCode(uint8 k) public view returns (bytes memory) {
        require(k < DECK, "bad card");
        bytes memory h = new bytes(128);
        bytes memory tag = "PLSHOLDEM_CARD_V1";
        for (uint8 ctr = 0; ctr < 4; ctr++) {
            bytes32 part = keccak256(abi.encodePacked(tag, k, ctr));
            assembly ("memory-safe") {
                mstore(add(add(h, 32), mul(ctr, 32)), part)
            }
        }
        return _modexp(h, hex"02");
    }

    /// @notice keccak of cardCode(k).
    function cardCodeHash(uint8 k) internal view returns (bytes32) {
        return keccak256(cardCode(k));
    }

    /// @notice Find the card index whose code hashes to `h`; 255 if none.
    function cardFromHash(bytes32 h) public view returns (uint8) {
        for (uint8 k = 0; k < DECK; k++) {
            if (cardCodeHash(k) == h) return k;
        }
        return 255;
    }

    /// @notice Extract 128-byte value i from a packed 52-value deck blob.
    function deckValue(bytes calldata deck, uint256 i) internal pure returns (bytes memory v) {
        v = deck[i * VALUE_BYTES:(i + 1) * VALUE_BYTES];
    }

    /// @notice Validate a posted deck stage: exactly 52 values, each in
    ///         (1, P-1), all distinct. Reverts otherwise.
    function checkDeck(bytes calldata deck) public pure {
        require(deck.length == DECK * VALUE_BYTES, "deck len");
        bytes32[DECK] memory hashes;
        for (uint256 i = 0; i < DECK; i++) {
            uint256 off = i * VALUE_BYTES;
            uint256 w0;
            uint256 w1;
            uint256 w2;
            uint256 w3;
            assembly ("memory-safe") {
                w0 := calldataload(add(deck.offset, off))
                w1 := calldataload(add(deck.offset, add(off, 32)))
                w2 := calldataload(add(deck.offset, add(off, 64)))
                w3 := calldataload(add(deck.offset, add(off, 96)))
            }
            require(inRange(w0, w1, w2, w3), "value range");
            bytes32 h = keccak256(abi.encodePacked(w0, w1, w2, w3));
            for (uint256 j = 0; j < i; j++) {
                require(hashes[j] != h, "duplicate value");
            }
            hashes[i] = h;
        }
    }

    /// @dev true iff 1 < v < P-1 for v given as 4 big-endian words.
    function inRange(uint256 w0, uint256 w1, uint256 w2, uint256 w3) internal pure returns (bool) {
        // v > 1
        if (w0 == 0 && w1 == 0 && w2 == 0 && w3 <= 1) return false;
        // v < P - 1  (P3 ends in ...FFFF, so P-1 differs only in last word)
        if (w0 < P0) return true;
        if (w0 > P0) return false;
        if (w1 < P1) return true;
        if (w1 > P1) return false;
        if (w2 < P2) return true;
        if (w2 > P2) return false;
        return w3 < P3 - 1;
    }

    /// @notice Range-check a 128-byte memory value (used for proven values).
    function inRangeMem(bytes memory v) internal pure returns (bool) {
        require(v.length == 128, "len");
        uint256 w0;
        uint256 w1;
        uint256 w2;
        uint256 w3;
        assembly ("memory-safe") {
            w0 := mload(add(v, 32))
            w1 := mload(add(v, 64))
            w2 := mload(add(v, 96))
            w3 := mload(add(v, 128))
        }
        return inRange(w0, w1, w2, w3);
    }

    /// @dev Scalar exponent sanity: odd (invertible mod P-1) and nonzero.
    function validScalar(uint256 e) internal pure returns (bool) {
        return e & 1 == 1 && e > 1;
    }
}
          

Compiler Settings

{"viaIR":true,"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":1,"enabled":true},"libraries":{"contracts/lib/SRA.sol":{"SRA":"0xb04c1e546d7cf8dc39e10dfc1714847573790806"},"contracts/lib/HandEval.sol":{"HandEval":"0x85c53cbfc7f3425f5328d05a6732f659f468592a"},"contracts/lib/CardMerkle.sol":{"CardMerkle":"0x76a5e1d2e03838dabdce38f3372510ba53cabf08"},"contracts/lib/BettingLib.sol":{"BettingLib":"0xecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc"}},"evmVersion":"paris"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"uint16","name":"_rakeBps","internalType":"uint16"},{"type":"address","name":"_feeAccount","internalType":"address"}]},{"type":"error","name":"AlreadyPosted","inputs":[]},{"type":"error","name":"BadData","inputs":[]},{"type":"error","name":"BadInverse","inputs":[]},{"type":"error","name":"BadParam","inputs":[]},{"type":"error","name":"BadPhase","inputs":[]},{"type":"error","name":"BadProof","inputs":[]},{"type":"error","name":"BadScalar","inputs":[]},{"type":"error","name":"Bust","inputs":[]},{"type":"error","name":"CardMismatch","inputs":[]},{"type":"error","name":"NotAPlayer","inputs":[]},{"type":"error","name":"NotCreator","inputs":[]},{"type":"error","name":"NotExpired","inputs":[]},{"type":"error","name":"NotJoiner","inputs":[]},{"type":"error","name":"NotOpen","inputs":[]},{"type":"error","name":"NotOwner","inputs":[]},{"type":"error","name":"NotPlaying","inputs":[]},{"type":"error","name":"NotYourHole","inputs":[]},{"type":"error","name":"NotYourReveal","inputs":[]},{"type":"error","name":"NotYourTurn","inputs":[]},{"type":"error","name":"NothingToDo","inputs":[]},{"type":"error","name":"PostYoursFirst","inputs":[]},{"type":"error","name":"RakeCap","inputs":[]},{"type":"error","name":"ReentrancyGuardReentrantCall","inputs":[]},{"type":"error","name":"TransferFailed","inputs":[]},{"type":"error","name":"WrongDeposit","inputs":[]},{"type":"error","name":"WrongHand","inputs":[]},{"type":"error","name":"YouAreTheStaller","inputs":[]},{"type":"event","name":"ActionTaken","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"seat","internalType":"uint8","indexed":false},{"type":"uint8","name":"action","internalType":"uint8","indexed":false},{"type":"uint32","name":"amount","internalType":"uint32","indexed":false}],"anonymous":false},{"type":"event","name":"BlameJSubmitted","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"j","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"BlameOpened","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"pos","internalType":"uint8","indexed":false},{"type":"uint8","name":"claimBy","internalType":"uint8","indexed":false},{"type":"uint8","name":"claimIdx","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"BoardRevealed","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"street","internalType":"uint8","indexed":false},{"type":"uint8[5]","name":"board","internalType":"uint8[5]","indexed":false}],"anonymous":false},{"type":"event","name":"CheatSettled","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint8","name":"cheater","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"DeckPosted","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"stage","internalType":"uint8","indexed":false},{"type":"bytes32","name":"root","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"HandSettled","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint32","name":"stackC","internalType":"uint32","indexed":false},{"type":"uint32","name":"stackJ","internalType":"uint32","indexed":false}],"anonymous":false},{"type":"event","name":"HandStarted","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"btn","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"HoleExpPosted","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"seat","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"Mucked","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"seat","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"NoShowClaimed","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint32","name":"chips","internalType":"uint32","indexed":false}],"anonymous":false},{"type":"event","name":"PhaseAdvanced","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"phase","internalType":"uint8","indexed":false},{"type":"uint64","name":"deadline","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"PlayerLeft","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint8","name":"seat","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"PotAwarded","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"winner","internalType":"uint8","indexed":false},{"type":"uint32","name":"amount","internalType":"uint32","indexed":false},{"type":"uint32","name":"rake","internalType":"uint32","indexed":false}],"anonymous":false},{"type":"event","name":"RakeConfigured","inputs":[{"type":"uint16","name":"rakeBps","internalType":"uint16","indexed":false},{"type":"address","name":"feeAccount","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SessionSettled","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint256","name":"creatorWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"joinerWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"rakeWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ShowdownRevealed","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"seat","internalType":"uint8","indexed":false},{"type":"uint8","name":"c0","internalType":"uint8","indexed":false},{"type":"uint8","name":"c1","internalType":"uint8","indexed":false},{"type":"uint32","name":"score","internalType":"uint32","indexed":false}],"anonymous":false},{"type":"event","name":"TableCancelled","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"TableCreated","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"address","name":"creator","internalType":"address","indexed":true},{"type":"uint96","name":"chipValue","internalType":"uint96","indexed":false},{"type":"uint32","name":"buyInChips","internalType":"uint32","indexed":false},{"type":"uint32","name":"sbChips","internalType":"uint32","indexed":false},{"type":"uint32","name":"bbChips","internalType":"uint32","indexed":false},{"type":"uint32","name":"actTimeout","internalType":"uint32","indexed":false},{"type":"uint32","name":"cryptoTimeout","internalType":"uint32","indexed":false},{"type":"uint32","name":"penaltyChips","internalType":"uint32","indexed":false},{"type":"uint16","name":"rakeBps","internalType":"uint16","indexed":false},{"type":"uint8","name":"avatar","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"TableJoined","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"address","name":"joiner","internalType":"address","indexed":true},{"type":"uint8","name":"avatar","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"TimeoutClaimed","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256","indexed":true},{"type":"uint32","name":"handId","internalType":"uint32","indexed":true},{"type":"uint8","name":"phase","internalType":"uint8","indexed":false},{"type":"uint8","name":"staller","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"Withdrawn","inputs":[{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"MAX_BUYIN_CHIPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"MAX_RAKE_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"MAX_TIMEOUT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"MIN_TIMEOUT","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"accuseHole","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"uint32","name":"handId","internalType":"uint32"},{"type":"uint8","name":"pos","internalType":"uint8"},{"type":"uint256","name":"ownExp","internalType":"uint256"},{"type":"bytes","name":"d4val","internalType":"bytes"},{"type":"bytes32[6]","name":"proof","internalType":"bytes32[6]"},{"type":"bytes","name":"invOwn","internalType":"bytes"},{"type":"bytes","name":"invTheirs","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"act","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"uint32","name":"handId","internalType":"uint32"},{"type":"uint8","name":"action","internalType":"enum Action"},{"type":"uint32","name":"amount","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelTable","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimNoShow","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"bool","name":"andSettle","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimTimeout","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"uint32","name":"handId","internalType":"uint32"},{"type":"uint8","name":"expectedPhase","internalType":"uint8"},{"type":"bool","name":"andSettle","internalType":"bool"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"tableId","internalType":"uint256"}],"name":"createTable","inputs":[{"type":"uint96","name":"chipValue","internalType":"uint96"},{"type":"uint32","name":"buyInChips","internalType":"uint32"},{"type":"uint32","name":"sbChips","internalType":"uint32"},{"type":"uint32","name":"bbChips","internalType":"uint32"},{"type":"uint32","name":"actTimeoutS","internalType":"uint32"},{"type":"uint32","name":"cryptoTimeoutS","internalType":"uint32"},{"type":"uint32","name":"penaltyChips","internalType":"uint32"},{"type":"uint8","name":"avatar","internalType":"uint8"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeAccount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct Hand","components":[{"type":"uint8","name":"phase","internalType":"uint8"},{"type":"uint8","name":"btn","internalType":"uint8"},{"type":"uint64","name":"deadline","internalType":"uint64"},{"type":"uint32[2]","name":"stack","internalType":"uint32[2]"},{"type":"uint32[2]","name":"streetBet","internalType":"uint32[2]"},{"type":"uint32","name":"pot","internalType":"uint32"},{"type":"uint32","name":"currentBet","internalType":"uint32"},{"type":"uint32","name":"inc","internalType":"uint32"},{"type":"uint8","name":"street","internalType":"uint8"},{"type":"uint8","name":"toAct","internalType":"uint8"},{"type":"uint8","name":"firstToAct","internalType":"uint8"},{"type":"bool","name":"reopen","internalType":"bool"},{"type":"bool","name":"bbOption","internalType":"bool"},{"type":"bool","name":"allIn","internalType":"bool"},{"type":"uint8","name":"folded","internalType":"uint8"},{"type":"uint8","name":"riverAggressor","internalType":"uint8"},{"type":"bytes32[4]","name":"roots","internalType":"bytes32[4]"},{"type":"uint256[4]","name":"holeExp","internalType":"uint256[4]"},{"type":"uint8","name":"dealMask","internalType":"uint8"},{"type":"uint8[5]","name":"board","internalType":"uint8[5]"},{"type":"uint256[3]","name":"pendExp","internalType":"uint256[3]"},{"type":"uint8","name":"pendBy","internalType":"uint8"},{"type":"uint8","name":"firstShower","internalType":"uint8"},{"type":"uint8","name":"shownMask","internalType":"uint8"},{"type":"uint256[2][2]","name":"shownExp","internalType":"uint256[2][2]"},{"type":"uint8[2][2]","name":"shownCards","internalType":"uint8[2][2]"},{"type":"uint32[2]","name":"shownScore","internalType":"uint32[2]"},{"type":"uint8","name":"blamePos","internalType":"uint8"},{"type":"uint8","name":"blameClaimIdx","internalType":"uint8"},{"type":"uint8","name":"blameClaimBy","internalType":"uint8"},{"type":"uint256","name":"blameGJ","internalType":"uint256"},{"type":"uint256","name":"blameCJ","internalType":"uint256"},{"type":"uint256","name":"blamePostedC","internalType":"uint256"},{"type":"uint256","name":"blamePostedJ","internalType":"uint256"},{"type":"bytes32[4]","name":"blameVals","internalType":"bytes32[4]"}]}],"name":"getHand","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"ids","internalType":"uint256[]"}],"name":"getOpenTables","inputs":[{"type":"uint256","name":"maxN","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"joinTable","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"uint8","name":"avatar","internalType":"uint8"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"leaveTable","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"muck","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"uint32","name":"handId","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"postBoardExp","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"uint32","name":"handId","internalType":"uint32"},{"type":"uint256[]","name":"exps","internalType":"uint256[]"},{"type":"uint8[]","name":"claims","internalType":"uint8[]"},{"type":"bytes","name":"d4vals","internalType":"bytes"},{"type":"bytes32[]","name":"proofs","internalType":"bytes32[]"},{"type":"bytes","name":"invMine","internalType":"bytes"},{"type":"bytes","name":"invTheirs","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"postDeck","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"uint32","name":"handId","internalType":"uint32"},{"type":"uint8","name":"stage","internalType":"uint8"},{"type":"bytes","name":"deck","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"postHoleExp","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"uint32","name":"handId","internalType":"uint32"},{"type":"uint256","name":"e0","internalType":"uint256"},{"type":"uint256","name":"e1","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"rakeBps","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRake","inputs":[{"type":"uint16","name":"_rakeBps","internalType":"uint16"},{"type":"address","name":"_feeAccount","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"showdown","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"uint32","name":"handId","internalType":"uint32"},{"type":"uint256[2]","name":"exps","internalType":"uint256[2]"},{"type":"uint8[2]","name":"claims","internalType":"uint8[2]"},{"type":"bytes","name":"d4vals","internalType":"bytes"},{"type":"bytes32[]","name":"proofs","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"submitBlameC","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"uint32","name":"handId","internalType":"uint32"},{"type":"uint8","name":"k","internalType":"uint8"},{"type":"uint256","name":"gC","internalType":"uint256"},{"type":"uint256","name":"cC","internalType":"uint256"},{"type":"bytes","name":"vals","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"submitBlameJ","inputs":[{"type":"uint256","name":"tableId","internalType":"uint256"},{"type":"uint32","name":"handId","internalType":"uint32"},{"type":"uint8","name":"j","internalType":"uint8"},{"type":"uint256","name":"gJ","internalType":"uint256"},{"type":"uint256","name":"cJ","internalType":"uint256"},{"type":"bytes","name":"vals","internalType":"bytes"},{"type":"bytes32[]","name":"proofs","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tableCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tableFeeAccount","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"creator","internalType":"address"},{"type":"uint96","name":"chipValue","internalType":"uint96"},{"type":"address","name":"joiner","internalType":"address"},{"type":"uint8","name":"status","internalType":"uint8"},{"type":"uint8","name":"creatorAvatar","internalType":"uint8"},{"type":"uint8","name":"joinerAvatar","internalType":"uint8"},{"type":"uint16","name":"rakeBps","internalType":"uint16"},{"type":"uint32","name":"buyInChips","internalType":"uint32"},{"type":"uint32","name":"sbChips","internalType":"uint32"},{"type":"uint32","name":"bbChips","internalType":"uint32"},{"type":"uint32","name":"penaltyChips","internalType":"uint32"},{"type":"uint32","name":"actTimeout","internalType":"uint32"},{"type":"uint32","name":"cryptoTimeout","internalType":"uint32"},{"type":"uint32","name":"handId","internalType":"uint32"},{"type":"uint32","name":"rakeChips","internalType":"uint32"},{"type":"uint32","name":"stackC","internalType":"uint32"},{"type":"uint32","name":"stackJ","internalType":"uint32"},{"type":"uint64","name":"lastSettleTime","internalType":"uint64"}],"name":"tables","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"withdrawable","inputs":[{"type":"address","name":"","internalType":"address"}]}]
              

Contract Creation Code

Verify & Publish
0x6080346100fe57601f615fd138819003918201601f19168301916001600160401b038311848410176101035780849260409485528339810103126100fe57805161ffff8116918282036100fe57602001516001600160a01b03811692908390036100fe576101f49060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055116100ed5781156100dc57600080546001600160a01b03191633179055600180546001600160b01b03191660a09290921b61ffff60a01b1691909117919091179055604051615eb7908161011a8239f35b63de17a3af60e01b60005260046000fd5b63c6c3513b60e01b60005260046000fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe6102c0604052600436101561001357600080fd5b6000803560e01c806301bf32dc14612d6857806308ce201114612be8578063102672ba14612bcb5780631162384c146122db57806317cf8c0d146122bc57806321c9c44a14612297578063264f5c01146121bb57806327e5e0c114611f0e5780633ccfd60b14611e0b5780633f637e8614611dd05780634155fc5b14611db2578063543ad1df14611d9657806365e17c9d14611d6d578063668fd78214611b1a578063704b25271461168857806370a4e95b1461165557806371671bf214611523578063763c8cd91461142457806381c908581461133a578063898acd1f146110285780638da5cb5b146110015780639492264514610ee4578063b3a5c8c814610e8c578063ce513b6f14610e53578063d1e9e14014610d39578063d47f269e14610547578063d924cb931461046a578063de38eb3a1461044c578063dfa170e7146103c9578063f2fde38b146103715763f42452581461017357600080fd5b3461036e57604036600319011261036e57600435602435801515810361036c5781835260036020526040832090828452600460205260408420600183015490600260ff8360a01c160361035d575460ff1661034e576001600160a01b0316330361033f576003820180546002840180549092916001600160401b039061020990608084901c63ffffffff169060201c83166151ee565b1642111561033057906102f36102ed7f50038a922c31e04bdb655c3d957330398521774f6656bf130c3fcb3303102d1d602089600080516020615da28339815191528761028b61028561027e61027363ffffffff6103039d60401c1663ffffffff868a1c1661521f565b9360e01c8094615cc6565b8093615239565b8b61322f565b63ffffffff61029d82828b541661521f565b1663ffffffff198954161788558954908363ffffffff8360a01c16968796879363ffffffff60405191168152a363ffffffff885416906102e560405192839260e01c83615253565b0390a3615207565b8461526a565b426001600160401b03169061430c565b5460e01c15908115610328575b50610319578280f35b6103229161552c565b38808280f35b905038610310565b63d0404f8560e01b8752600487fd5b6338b72ae960e11b8452600484fd5b63301c306b60e01b8552600485fd5b63126ab15560e01b8652600486fd5b825b80fd5b503461036e57602036600319011261036e5761038b61316b565b8154906001600160a01b03821633036103ba576001600160a01b03166001600160a01b03199190911617815580f35b6330cd747160e01b8352600483fd5b503461036e5760e036600319011261036e576103e36130d8565b6103eb6130fe565b60a4356001600160401b0381116104485761040a90369060040161310e565b60c43593916001600160401b0385116104445761042e61044195369060040161313b565b949093608435916064359160043561496f565b80f35b8580fd5b8380fd5b503461036e578060031936011261036e57602060405162093a808152f35b503461036e57604036600319011261036e5760043561ffff81169081810361036c576024356001600160a01b03811691908290036104485783546001600160a01b03163303610538576101f4831161052957811561051a57600180546001600160b01b03191660a09290921b61ffff60a01b1691909117821790556040805192835260208301919091527fb5add0bb8de8016e167bf0c471fb32731f765637e15e0156d13ee6853f6a064391a180f35b63de17a3af60e01b8452600484fd5b63c6c3513b60e01b8452600484fd5b6330cd747160e01b8452600484fd5b503461036e57602036600319011261036e5760405161056581613252565b8181528160208201528160408201526040918251610583848261329f565b8336823760608301528251610598848261329f565b8336823760808301528060a08301528060c08301528060e08301528061010083015280610120830152806101408301528061016083015280610180830152806101a0830152806101c0830152806101e083015260809280516105fa858261329f565b843682376102008401528051610610858261329f565b843682376102208401528161024084015260a0815161062f828261329f565b813682376102608501526060938251610648868261329f565b85368237610280820152836102a0820152836102c0820152836102e08201528251610673848261329f565b845b848110610d1c5750610300820152825161068f848261329f565b845b848110610cff575061032082015282516106ab848261329f565b833682376103408201528361036082015283610380820152836103a0820152836103c0820152836103e082015283610400820152836104208201526104408351916106f6888461329f565b873684370152600435835260046020528183209482519561071687613252565b805460ff8082168952600882901c16602089015260101c6001600160401b031684880152610746600182016148e1565b86880152610756600282016148e1565b8288015260ff600382015463ffffffff8116858a015263ffffffff8160201c1660c08a015263ffffffff81871c1660e08a01528181891c166101008a0152818160681c166101208a0152818160701c166101408a0152818160781c1615156101608a01528181851c1615156101808a0152818160881c1615156101a08a0152818160901c166101c08a015260981c166101e08801526107f760048201614905565b61020088015283516008820186825b60048210610ce95750505061081b838261329f565b61022088015260ff600c82015416610240880152835161083e81600d840161493a565b610848848261329f565b6102608801528351600e820186825b60038210610cd35750505061086c878261329f565b61028088015260ff60118201548181166102a08a0152818160081c166102c08a015260101c166102e088015283516108a381613284565b6012820186825b60028210610c8c5750505061030088015283516108c681613284565b6016820186825b60028210610c5b575050509161095b601e6109a49363ffffffff96956103208c01526108fb601882016148e1565b6103408c015260ff60198201548c6103608383169101528c610380838360081c1691015260101c166103a08c0152601a8101546103c08c0152601b8101546103e08c0152601c8101546104008c0152601d8101546104208c015201614905565b61044089015261099885519760ff8a5116895260ff60208b01511660208a015260018060401b03878b015116878a0152808a015190890190613181565b87015182870190613181565b8501511660e084015263ffffffff60c08501511661010084015263ffffffff60e08501511661012084015260ff6101008501511661014084015260ff6101208501511661016084015260ff6101408501511661018084015261016084015115156101a084015261018084015115156101c08401526101a084015115156101e084015260ff6101c08501511661020084015260ff6101e085015116610220840152610a586102008501516102408501906131af565b610220840151826102c085015b60048210610c455750505061024084015160ff166103408401526102608401518261036085015b60058210610c2c575050506102808401518261040085015b60038210610c165750505060ff6102a08501511661046084015260ff6102c08501511661048084015260ff6102e0850151166104a08401526103008401516104c0840183905b60028210610bd85750505061032084015190829061054085015b60028310610b975761076086610b956104408a610b2b6103408201516105c0860190613181565b60ff6103608201511661060085015260ff6103808201511661062085015260ff6103a0820151166106408501526103c08101516106608501526103e08101516106808501526104008101516106a08501526104208101516106c085015201516106e08301906131af565bf35b818451829087915b60028310610bbc5750505060209060019201940192019192610b04565b815160ff16815285935060019092019160209182019101610b9f565b838351829087915b60028310610bfd5750505060209060019201930191019091610aea565b8151815287935060019092019160209182019101610be0565b6020806001928551815201930191019091610aa4565b60208060019260ff865116815201930191019091610a8c565b6020806001928551815201930191019091610a65565b6001602081928a5160ff8754818116835260081c1683820152610c7e8c8261329f565b8152019301910190916108cd565b87518984825b60028310610cbd57505050602060019282610caf8c60029561329f565b8152019301910190916108aa565b6001602081928454815201920192019190610c92565b6001602081928554815201930191019091610857565b6001602081928554815201930191019091610806565b6020908551610d0e878261329f565b863682378184015201610691565b6020908551610d2b878261329f565b863682378184015201610675565b503461036e57602036600319011261036e576004359080610d598361489b565b906002545b600181101580610e4a575b15610dc8578084526003602052600160ff8160408720015460a01c1614610dae575b8015610d9a5760001901610d5e565b634e487b7160e01b84526011600452602484fd5b80610dc2610dbb84613200565b93856148cd565b52610d8b565b50908290610dd58361489b565b92825b818110610e2657505050604051918291602083016020845282518091526020604085019301915b818110610e0d575050500390f35b8251845285945060209384019390920191600101610dff565b80610e356001928597956148cd565b51610e4082866148cd565b5201939193610dd8565b50848210610d69565b503461036e57602036600319011261036e576020906040906001600160a01b03610e7b61316b565b168152600683522054604051908152f35b503461036e5760c036600319011261036e57610ea66130d8565b610eae6130fe565b60a435916001600160401b03831161044857610ed161044193369060040161310e565b9290916084359160643591600435614351565b50604036600319011261036e576004356024359060ff821691828103610448578184526003602052604084209060018201908154600160ff8260a01c1603610ff257835490336001600160a01b03831614610fe3576008871015610fe3579063ffffffff610f599260c81c169060a01c6131d7565b3403610fd457815462ff00ff60a01b193316600161ff0160a81b03199091161760b09190911b60ff60b01b1617600160a11b179055610fa590426001600160401b03169060030161430c565b6040519182527f396423bd1651bba635e3419ce325aa401229452a6b2be1768843d2e8dea8177860203393a380f35b634366b25d60e01b8652600486fd5b63de17a3af60e01b8852600488fd5b631bb5f5b360e31b8752600487fd5b503461036e578060031936011261036e57546040516001600160a01b039091168152602090f35b503461036e576101a036600319011261036e576004356110466130d8565b61104e6130fe565b906064356084356001600160401b0381116104445761107190369060040161310e565b9093366101641161133657610164356001600160401b0381116113325761109c90369060040161310e565b9095909390610184356001600160401b03811161132e576110c190369060040161310e565b90898b52600360205260408b20968a8c52600460205260408c209863ffffffff8060028b015460a01c1691160361131f5760ff89541660068110908115611314575b5061130557611112338961528d565b9960ff8b169788159586806112f8575b80156112cb575b156112bc57600180891614806112b2575b156112a3578e60078d01546040519063af0586a360e01b825260048201526004602482015260ff8b1660448201526101406064820152602081806111836101448201888861399d565b60c060a4608484013703817376a5e1d2e03838dabdce38f3372510ba53cabf085af49182156112975791611268575b5015611259579360ff936111ee938a9897938a8f6034996111da60086111e993019d8e61341a565b90549060031b1c9336916133e3565b615981565b16101561120357505050505061044193615c2a565b9261044198979592918195979460001461124057600183985b0361122957505095615b97565b611233925061341a565b90549060031b1c95615b97565b600161124c838361341a565b90549060031b1c9861121c565b637ca55c7760e01b8f5260048ffd5b61128a915060203d602011611290575b611282818361329f565b81019061342a565b386111b2565b503d611278565b604051903d90823e3d90fd5b63284f145b60e11b8f5260048ffd5b506001881161113a565b631749e6cd60e11b8f5260048ffd5b5060018a148015611129575060ff8916600281149081156112ed575b50611129565b6003915014386112e7565b50600260ff8a1610611122565b63301c306b60e01b8c5260048cfd5b600e91501138611103565b636226556b60e01b8c5260048cfd5b8980fd5b8780fd5b8680fd5b503461036e57604036600319011261036e57600435906113586130d8565b8282526003602052604082208383526004602052604083209063ffffffff80600283015460a01c16931692830361141557600e60ff835416036114065761139f338261528d565b9460ff601184015460081c169360ff806113b8876132c2565b1697169687036113f757817f50295138b8e123fbfba534eabbb8054c406902fa7aadac163b85767230452e7e60206104419899604051908152a3615350565b630304193d60e11b8652600486fd5b63301c306b60e01b8452600484fd5b636226556b60e01b8452600484fd5b503461036e5761010036600319011261036e5761143f6130d8565b6044356001600160401b03811161036c5761145e90369060040161313b565b916064356001600160401b03811161151f5761147e90369060040161313b565b906084356001600160401b0381116113365761149e90369060040161310e565b9060a4356001600160401b03811161151b576114be90369060040161313b565b92909160c4356001600160401b038111611517576114e090369060040161310e565b60e4359a90979196906001600160401b038c11611513576115086104419c369060040161310e565b9b909a6004356139fb565b8c80fd5b8a80fd5b8880fd5b8480fd5b503461036e57602036600319011261036e57604061024091600435815260036020522080549060018101549063ffffffff60036002830154920154926040519460018060a01b038116865260a01c602086015260018060a01b038116604086015260ff8160a01c16606086015260ff8160a81c16608086015260ff8160b01c1660a086015261ffff8160b81c1660c086015260c81c1660e084015263ffffffff811661010084015263ffffffff8160201c1661012084015263ffffffff8160401c1661014084015263ffffffff8160601c1661016084015263ffffffff8160801c1661018084015263ffffffff8160a01c166101a084015263ffffffff8160c01c166101c084015260e01c6101e083015263ffffffff811661020083015260018060401b039060201c16610220820152f35b503461036e57602036600319011261036e57602090600435815260058252604060018060a01b0391205416604051908152f35b503461036e57608036600319011261036e576004356116a56130d8565b906116ae6130fe565b6064356001600160401b03811161151f576116cd90369060040161310e565b838652600360205260408620848752600460205260408720916001820194855495600260ff8860a01c1603611b0b57600284019163ffffffff80845460a01c169a16998a03611afc5760ff169660018803611a1d57505082546001600160a01b03163303611a0e5760ff8454166119ff57805460e01c801580156119ed575b6119de576117769061176360018701918c836135b5565b600463ffffffff600387015416916135b5565b8873ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc8254813b1561036c5763ffffffff60848492604051948593849263074bdbe560e01b84528c600485015260018160a01c166024850152818116604485015260201c1660648301525af480156119ba576119c9575b505063ffffffff905460a01c16867fbfeb6d84abeccf1947b6157b7ac00b04d40817b53e2440dcfa49f712fa234810602060ff875460081c16604051908152a3825460ff191660021783555b8773b04c1e546d7cf8dc39e10dfc1714847573790806803b156119c557816040518092626a007d60e01b825260206004830152818061186f60248201898d61399d565b03915af480156119ba576119a5575b50506118aa93602091604051958692839263b65c02d360e01b845260406004850152604484019161399d565b87602483015203817376a5e1d2e03838dabdce38f3372510ba53cabf085af492831561199a578793611961575b50600019840160ff811161194d5782849260409561193761192061193f9560047ff4169c826e1cd0db9f677dc2ffe40cc7cae264e9ecb54b4cc220cff5b82bbfc69b990161341a565b819391549060031b91821b91600019901b19161790565b9055876158ad565b82519182526020820152a380f35b634e487b7160e01b88526011600452602488fd5b9092506020813d602011611992575b8161197d6020938361329f565b8101031261198d575191386118d7565b600080fd5b3d9150611970565b6040513d89823e3d90fd5b816119af9161329f565b61133257873861187e565b6040513d84823e3d90fd5b5080fd5b816119d39161329f565b61151b5788386117e0565b6309107e2560e31b8a5260048afd5b5063ffffffff6003850154161561174c565b63301c306b60e01b8952600489fd5b6393687c0b60e01b8952600489fd5b90915060028703611a735750546001600160a01b03163303611a6457600260ff84541603611a5557825460ff1916600317835561182c565b63301c306b60e01b8852600488fd5b6338b72ae960e11b8852600488fd5b905060038603611aba575081546001600160a01b03163303611aab57600360ff84541603611a5557825460ff1916600417835561182c565b6393687c0b60e01b8852600488fd5b60048603611aed576001600160a01b03163303611a6457600460ff84541603611a5557825460ff1916600517835561182c565b63de17a3af60e01b8952600489fd5b636226556b60e01b8b5260048bfd5b63126ab15560e01b8a5260048afd5b503461036e57608036600319011261036e57600435611b376130d8565b90604435606435908285526003602052604085209383865260046020526040862092600286019563ffffffff80885460a01c169316928303611d5e57600560ff86541603611a555760018085161480611d54575b158015611d37575b611d2857611ba460ff91339061528d565b1690600182149384600014611d20576001945b600c870195865460ff82821616611d11579460ff96948a947fe47a1a70cd8e25e08c403d1b29c6e7f3f5625c8899a042b3d6c0971ebf8b4cad94896020958160039d9b1617168a198a5416178955600014611d025760088b015560098a01555b604051908152a3541614611c29578380f35b60ff81816003600080516020615e62833981519152940181815460881c16600014611cfa578160075b1682198454161783555460881c1615600014611ce257611cd863ffffffff611c8c8180895460601c165b16426001600160401b03166151ee565b835462010000600160501b03198116601092831b62010000600160501b03161794859055975460405160a09190911c92909216979194859490911c6001600160401b03169116836139de565b0390a33880808380f35b611cd863ffffffff611c8c8180895460801c16611c7c565b816006611c52565b600a8b0155600b8a0155611c17565b63e9f155db60e01b8c5260048cfd5b600294611bb7565b63284f145b60e11b8852600488fd5b5060018083161480611d4a575b15611b93565b5060018211611d44565b5060018411611b8b565b636226556b60e01b8852600488fd5b503461036e578060031936011261036e576001546040516001600160a01b039091168152602090f35b503461036e578060031936011261036e576020604051603c8152f35b503461036e578060031936011261036e576020600254604051908152f35b503461036e57608036600319011261036e57611dea6130d8565b611df26130fe565b6064359081151582036104485761044192600435613601565b503461036e578060031936011261036e576002600080516020615e428339815191525414611eff576002600080516020615e4283398151915255338152600660205260408120548015611ef05733825260066020528160408120558180808084335af13d15611eeb573d611e7e8161338d565b90611e8c604051928361329f565b81528360203d92013e5b15611edc576040519081527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d560203392a26001600080516020615e428339815191525580f35b6312171d8360e31b8252600482fd5b611e96565b630b8a550d60e31b8252600482fd5b633ee5aeb560e01b8152600490fd5b503461036e57608036600319011261036e57600435611f2b6130d8565b60443590600582101561044857611f406130eb565b90838552600360205260408520918486526004602052604086209363ffffffff600285015493169263ffffffff8160a01c168403611d5e5760ff865416600681141590816121af575b816121a3575b81612197575b50611a5557611fa4338661528d565b93600387019360ff855460681c1660ff87169081036121885763ffffffff80604051936370807d8760e11b85528b6004860152836024860152611fe68861320f565b876044860152169485606485015260201c16608483015260208260a48173ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc5af493841561217d5760ff958b938d96612133575b5091606091878461204c600080516020615dc28339815191529661320f565b6040519384521660208301526040820152a3166002810361207e575050906120786104419493926132c2565b92615350565b90949150600103612129578360ff610441955460601c1680156000146120b0575050825460ff191660071783556158ad565b600181036120ca575050825460ff191660091783556158ad565b6002036120e25750825460ff1916600b1783556158ad565b835460ff1916600d1784555460981c60ff9081169081146121105761210b905b6011850161591b565b6158ad565b5061210b61212460ff855460081c166132c2565b612102565b61044193506158e4565b600080516020615dc283398151915293919650918761216b60609460203d602011612176575b612163818361329f565b8101906135e8565b97929450509161202d565b503d612159565b6040513d8d823e3d90fd5b631cc191eb60e31b8b5260048bfd5b600c9150141538611f95565b600a8114159150611f8f565b60088114159150611f89565b503461036e57602036600319011261036e576004358082526003602052604082206001810190600160ff835460a01c16036122885780546001600160a01b0316330361227957815460ff60a01b1916600160a21b1791829055549061222d9060c81c63ffffffff1660a083901c6131d7565b6001600160a01b0390911683526006602052604083208054909161225091613368565b90557f8bd66138689095e38b45ec45363241e614b91b8e6fb90f7c15dfdeb93f34fcfe8280a280f35b6393687c0b60e01b8452600484fd5b631bb5f5b360e31b8452600484fd5b503461036e578060031936011261036e57602061ffff60015460a01c16604051908152f35b503461036e578060031936011261036e576020604051633b9aca008152f35b503461036e5761010036600319011261036e576122f66130d8565b366084116119c5573660c4116119c55760c4356001600160401b03811161036c5761232590369060040161310e565b9060e4356001600160401b03811161151f5761234590369060040161313b565b60049291923586526003602052604086209260043587526004602052604087209463ffffffff600286015460a01c1663ffffffff881603611d5e5761238a338661528d565b9460ff875416600d8114600014612b96575060ff601188015460081c1660ff871603612b87575b6101008214801590612b7c575b612b3b57603460ff6123ce61330d565b1610801590612b67575b8015612b4a575b612b3b57885b60058110612acd575060ff8616612ac55788905b895b600281101561271f5761240d816132d3565b356001808216149081612714575b50156127055761242e60ff821684613354565b818060071b04608014821517156126f157600182018083116126dd57808060071b04608014811517156126dd57908c8b6020838a6124b16124968f8f61248b8f612484908e9460079e8f1b918f87901b91613375565b36916133e3565b9a8b9801549461584b565b60405163af0586a360e01b81529586948594600486016134b2565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af491821561129757916126bf575b50156126b0576124ea9060088c0161341a565b90549060031b1c60ff8a16156000146126a9578c612507846132d3565b35915b60ff8c1661269857915b612525612520866132fb565b61332d565b60ff604051916349b11d3760e01b8352166004820152828160248173b04c1e546d7cf8dc39e10dfc17148475737908065af490811561268d578391612673575b5061258460405194859384936340604be760e01b85526004850161354f565b038173b04c1e546d7cf8dc39e10dfc17148475737908065af4908115612668578d91612646575b5060208151910120906020815191012003612637576125c9816132d3565b35600289101561262357906001916125eb6119208360128e8e881b0101613571565b905561261d8a8d61260b8c6016612604612520886132fb565b9401613571565b509050601f8416908460051c01613581565b016123fb565b634e487b7160e01b8c52603260045260248cfd5b6399f4b04160e01b8b5260048bfd5b61266291503d808f833e61265a818361329f565b8101906134ee565b386125ab565b6040513d8f823e3d90fd5b61268791503d8085833e61265a818361329f565b38612565565b6040513d85823e3d90fd5b506126a2846132d3565b3591612514565b8c8161250a565b637ca55c7760e01b8d5260048dfd5b6126d7915060203d811161129057611282818361329f565b386124d7565b634e487b7160e01b8d52601160045260248dfd5b634e487b7160e01b8c52601160045260248cfd5b63284f145b60e11b8b5260048bfd5b60019150113861241b565b8a888a848d6040519361273360e08661329f565b60e0368637855b60058110612a81575060ff61274d61330d565b1660a086015260ff61275d61331d565b1660c08601526040516342b9d18160e11b81529486600487015b60078210612a685750505060208560e4817385c53cbfc7f3425f5328d05a6732f659f468592a5af4948515612a5d578695612a1c575b5063ffffffff60188501926127cc876127c68587613599565b906135b5565b8160118701976127ed60ff60018188161b1660ff8b5460101c16178a6135d0565b60ff6127f761330d565b8161280061331d565b91816040519916895216602088015216604086015216606084015216907fe656b3a671b1d5b27cba2c8f42d1b11df035c0a6f0fc7ffcb2bfb7f5c51657fd608060043592a382549360ff8516600d0361286d575050815460ff1916600e17825561044192506004356158ad565b5460081c60ff169390929190612882856132c2565b9363ffffffff6128928683613599565b90549060031b1c1663ffffffff6128a98884613599565b90549060031b1c16106000146128c85750506104419350600435615350565b909192936128ee8663ffffffff6128e0819486613599565b90549060031b1c1693613599565b90549060031b1c161160001461290d5750906104419291600435615350565b610441935063ffffffff600384015416906129b461294a63ffffffff61271061294161ffff600189015460b81c16876131d7565b04168094615239565b916129a061298b61296a60ff637fffffff8760011c169460081c166132c2565b6129a661297a600188168661521f565b6129a061298b60018d019485613599565b91909263ffffffff84548460031b1c1661521f565b916135b5565b60ff895460081c1690613599565b6129d76129ce8363ffffffff600287015460c01c1661521f565b6002850161532d565b63ffffffff600284015460a01c169163ffffffff60405192600284521660208301526040820152600080516020615e02833981519152606060043592a3600435615ce6565b9094506020813d602011612a55575b81612a386020938361329f565b81010312610444575163ffffffff811681036104445793866127ad565b3d9150612a2b565b6040513d88823e3d90fd5b60208060019260ff865116815201930191019091612777565b60ff612a9082600d880161333b565b90549060031b1c166007821015612ab157600582901b87015260010161273a565b634e487b7160e01b88526032600452602488fd5b6002906123f9565b60ff612adc82600d8b0161333b565b90549060031b1c1660ff612aee61330d565b16148015612b12575b612b03576001016123e5565b63a554dcdf60e01b8a5260048afd5b5060ff612b2282600d8b0161333b565b90549060031b1c1660ff612b3461331d565b1614612af7565b63a554dcdf60e01b8952600489fd5b50612b5361330d565b60ff80612b5e61331d565b169116146123df565b50603460ff612b7461331d565b1610156123d8565b50600c8414156123be565b630304193d60e11b8952600489fd5b600e036119ff5760ff612bb18160118a015460081c166132c2565b1660ff871603156123b157630304193d60e11b8952600489fd5b503461036e578060031936011261036e5760206040516101f48152f35b503461036e57602036600319011261036e576004358082526003602052604082208183526004602052604083206001820190600260ff835460a01c1603612d5957612c33338461528d565b9160ff825416857f410304baf564e21c104cbc1ab0a0f9c155f9a5119091083c05d2a6e2b0fd54b5602060405160ff88168152a280612c7957505050506104419161552c565b600f819593949514908115612d4e575b5015612c995750610441936157a3565b91909273ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc86813b1561036e5760249160405192838092631067a2ef60e11b82528760048301525af4801561199a57612d2a575b5091612d1260ff92612d0a600295612d0563ffffffff888a015460401c1682856152d1565b6132c2565b908688615350565b5460a01c1614612d2157505080f35b6104419161552c565b60ff92612d0a88612d42600297959a612d129561329f565b98939550509250612ce0565b601091501438612c89565b63126ab15560e01b8552600485fd5b5061010036600319011261036e576004356001600160601b03811680820361036c57612d926130d8565b916044359063ffffffff821680920361151f57612dad6130eb565b946084359563ffffffff87169081880361036c5760a4359463ffffffff86169384870361036e5760c4359563ffffffff87169687810361036c5760e4359a60ff8c16998a8d0361151f578b1580156130ca575b80156130b7575b613058576001861080156130a8575b801561308e575b61305857603c88108015613082575b61305857603c89108015613076575b6130585760018a108015613067575b6130585760088b1015613058578b9c9d612e6e63ffffffff849e9d9e16809d6131d7565b3403610fd457600254612e8090613200565b9e8f80600255875260036020526040872095600160a01b600190033316600160a01b6001900319885416178755865490600160a01b60019003199060a01b1690600160a01b60019003161786556001860190600160a01b60ff60a01b1983541617825581549060ff60a81b9060a81b168060ff60a81b19831617835561ffff60b81b60015460181b169063ffffffff60c81b8760c81b169267ffffffffffff00ff60a81b1916171717905560028501938763ffffffff1986541617855584549263ffffffff60801b9060801b169263ffffffff60801b199063ffffffff60201b8b60201b1690600160201b600160801b03191617169063ffffffff60401b9060401b16179063ffffffff60601b9060601b1617178255612f9f9161322f565b6003018763ffffffff19825416179055600160a01b6001900360015416908a815260056020526040902090600160a01b6001900316600160a01b600190031982541617905560015460a01c61ffff16956040519889526020890152604088015263ffffffff166060870152608086015260a085015260c084015260e08301526101008201528133916101207f420317bb06dc9f1eea6d42235fffbfe838d3bef49aba0b479ecb45b332dd6dbb91a3604051908152602090f35b63de17a3af60e01b8552600485fd5b5063ffffffff87168a11612e4a565b5062093a808911612e3b565b5062093a808811612e2c565b5063ffffffff600a818416041663ffffffff881611612e1d565b508563ffffffff881610612e16565b50633b9aca0063ffffffff831611612e07565b5063ffffffff821615612e00565b6024359063ffffffff8216820361198d57565b6064359063ffffffff8216820361198d57565b6044359060ff8216820361198d57565b9181601f8401121561198d578235916001600160401b03831161198d576020838186019501011161198d57565b9181601f8401121561198d578235916001600160401b03831161198d576020808501948460051b01011161198d57565b600435906001600160a01b038216820361198d57565b906000905b6002821061319357505050565b60208060019263ffffffff865116815201930191019091613186565b906000905b600482106131c157505050565b60208060019285518152019301910190916131b4565b818102929181159184041417156131ea57565b634e487b7160e01b600052601160045260246000fd5b60001981146131ea5760010190565b6005111561321957565b634e487b7160e01b600052602160045260246000fd5b80546001600160e01b031660e09290921b6001600160e01b031916919091179055565b61046081019081106001600160401b0382111761326e57604052565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761326e57604052565b601f909101601f19168101906001600160401b0382119082101761326e57604052565b60ff166001039060ff82116131ea57565b60028110156132e55760051b60440190565b634e487b7160e01b600052603260045260246000fd5b60028110156132e55760051b60840190565b60843560ff8116810361198d5790565b60a43560ff8116810361198d5790565b3560ff8116810361198d5790565b91909160058310156132e557601f908360051c01921690565b9060ff8091169116019060ff82116131ea57565b919082018092116131ea57565b9093929384831161198d57841161198d578101920390565b6001600160401b03811161326e57601f01601f191660200190565b9190916133b5608061338d565b906133c3604051928361329f565b819360808352608082011161198d5781608060a092602060009501370152565b9291926133ef8261338d565b916133fd604051938461329f565b82948184528183011161198d578281602093846000960137010152565b60048210156132e5570190600090565b9081602091031261198d5751801515810361198d5790565b60005b8381106134555750506000910152565b8181015183820152602001613445565b9060209161347e81518092818552858086019101613442565b601f01601f1916010190565b906000905b6006821061349c57505050565b602080600192855181520193019101909161348f565b9493916134ec9360ff6134e4926080948952600460208a01521660408801526101406060880152610140870190613465565b94019061348a565b565b60208183031261198d578051906001600160401b03821161198d570181601f8201121561198d5780516135208161338d565b9261352e604051948561329f565b8184526020828401011161198d5761354c9160208085019101613442565b90565b61356760409295949395606083526060830190613465565b9460208201520152565b60028210156132e5570190600090565b919060ff8084549260031b9316831b921b1916179055565b91909160028310156132e557601c908360031c019260021b1690565b919063ffffffff8084549260031b9316831b921b1916179055565b9062ff000082549160101b169062ff00001916179055565b9081602091031261198d575160ff8116810361198d5790565b929091600084815260036020526040812093858252600460205260408220906001860191600260ff845460a01c160361398e57600287019463ffffffff80875460a01c16931692830361397f57815460ff80821692168214801590613977575b6139685760101c6001600160401b031642111561395957613682338961528d565b9260028214801561394f575b1561378a576001915b60ff831660ff8616811461377b5760408c92600080516020615de28339815191529282519182526020820152a373ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc803b15610444578560249160405192838092631067a2ef60e11b82528760048301525af48015612a5d57613759575b506137249063ffffffff61372b9596975460401c1690836152d1565b8688615350565b82613744575b505061373b575050565b6134ec9161552c565b5460a01c60ff16600214915038905080613731565b9063ffffffff8661377161372b97986137249561329f565b9695505090613708565b635f07a36960e11b8852600488fd5b60038203613799578591613697565b600582036137e45760ff84166001036137db5760ff60015b600c8501541616156137cc576137c6846132c2565b91613697565b632a0e78a360e01b8652600486fd5b60ff60026137b1565b600782148015613945575b801561393b575b156138155760ff60118401541660ff8516036137cc576137c6846132c2565b600682148015613931575b8015613927575b801561391d575b156138445760ff600384015460681c1691613697565b600d820361385d5760ff601184015460081c1691613697565b600e8203613878576137c660ff601185015460081c166132c2565b949350600f919796508099989550146000146138ce5760ff166138bf575081600080516020615de283398151915260406134ec9798815190815260016020820152a3615722565b6393687c0b60e01b8152600490fd5b601088929814600014611a555760ff600191160361390e57600080516020615de2833981519152604084926134ec989982519182526020820152a3615670565b6338b72ae960e11b8752600487fd5b50600c821461382e565b50600a8214613827565b5060088214613820565b50600b82146137f6565b50600982146137ef565b506004821461368e565b63d0404f8560e01b8552600485fd5b63301c306b60e01b8652600486fd5b508115613661565b636226556b60e01b8552600485fd5b63126ab15560e01b8452600484fd5b908060209392818452848401376000828201840152601f01601f1916010190565b91908110156132e55760051b0190565b60038210156132e5570190600090565b60ff90911681526001600160401b03909116602082015260400190565b9c9491979a9998959c9b93909b969296610220526101a0526101c0526102a0526101405261016052600061020052610220516102005152600360205260406102005120610240526102205161020051526004602052604061020051206102605263ffffffff600261024051015460a01c1663ffffffff8816036142f75760ff610260515416610280526007610280511415806142e9575b806142db575b6142c657613aa9336102405161528d565b61018052613ab961028051615931565b6101e0529660ff6101e0511683036140f257610200515b60ff6101e05116811061427f575060ff80601161026051015416146141d5575060ff60116102605101541660ff6101805116146141c05760ff6101e051166101c0511480159061419c575b801561416b575b6140f257610200515b60ff6101e051168110613dd25750506102605160118101805460ff191660ff17905561020051600e8201819055600f8201819055601090910155505061028051600714159450613d8d93505050505761026051600301805460ff60601b1916600160601b1790555b63ffffffff600261024051015460a01c1660ff6003610260510191825490604051838360601c168152613bcf60208201600d610260510161493a565b7ff6c035c10ac1e9a6d54a4228a066116b018fcb4d11df171c9a55665c47de523760c06102205192a360881c1615613ca25761028051600703613c31575061026051805460ff191660091790555b6134ec6102605161024051610220516158ad565b61028051600903613c51575061026051805460ff1916600b179055613c1d565b61026051805460ff1916600d1790555460981c60ff908116908114613c8657613c81905b6011610260510161591b565b613c1d565b50613c81613c9d60ff610260515460081c166132c2565b613c75565b5061028051600703613d5a5761026051805460ff191660081790555b610240516002015460201c63ffffffff1673ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc803b15613d53576040519163441271fb60e11b835261026051600484015260248301528160448161020051935af48015613d4557613d32575b506134ec6102605161024051610220516158e4565b61020051613d3f9161329f565b38613d1d565b6040513d61020051823e3d90fd5b6102005180fd5b61028051600903613d795761026051805460ff1916600a179055613cbe565b61026051805460ff1916600c179055613cbe565b61028051600903613db55761026051600301805460ff60601b1916600160611b179055613b93565b61026051600301805460ff60601b1916600360601b179055613b93565b613ddf60ff821689613354565b90808060071b0460801481151715613fe15760018101808211613fe157808060071b0460801481151715613fe157612484613e269160071b8360071b8d6102a05190613375565b806020848b613e41612496878a60076102605101549461584b565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af4908115613d4557610200519161414d575b50156141385761020051610120526101805160ff1661411857613e8f8286886139be565b35610120525b6101805160ff1661410757613eb082600e61026051016139ce565b90549060031b1c5b603460ff613ed0612520866101c0516101a0516139be565b16101561404c57613eeb612520846101c0516101a0516139be565b9060ff604051926349b11d3760e01b8452166004830152610200518260248173b04c1e546d7cf8dc39e10dfc17148475737908065af4908115613d4557613f5b92610200519261402d575b50604051809381926340604be760e01b8352610200519461012051906004850161354f565b038173b04c1e546d7cf8dc39e10dfc17148475737908065af4908115613d45576102005191614010575b5060208151910120906020815191012003613ffb57613fae612520826101c0516101a0516139be565b9160ff90811660031901908111613fe157600192613fd5613fdb92600d610260510161333b565b90613581565b01613b2b565b634e487b7160e01b61020051526011600452602461020051fd5b6399f4b04160e01b6102005152600461020051fd5b61402791503d8061020051833e61265a818361329f565b38613f85565b6140459192503d8061020051833e61265a818361329f565b9038613f36565b99509496925092949650975060ff8061406f612520856101c0516101a0516139be565b16036140f25760349561409961408b846140b29760ff996139be565b3593600e61026051016139ce565b94909361016051956101405195549060031b1c91615981565b1610156140d35750506134ec61018051610260516102405161022051615c2a565b6134ec9161012051906101805190610260516102405161022051615b97565b63a554dcdf60e01b6102005152600461020051fd5b6141128286886139be565b35613eb8565b61412882600e61026051016139ce565b90549060031b1c61012052613e95565b637ca55c7760e01b6102005152600461020051fd5b614165915060203d811161129057611282818361329f565b38613e6b565b50617f806101e05160071b1660ff6101e05116810460801460ff6101e05116151715613fe1576102a0511415613b22565b506101e05160ff1660068181029180159083049091141715613fe157811415613b1b565b63e9f155db60e01b6102005152600461020051fd5b9750509350935050506102005190600e6102605101915b60ff6101e05116811061425b575050505060ff610180511660ff1960116102605101541617601161026051015560018060401b03610260515460101c16600080516020615e6283398151915263ffffffff60405193169280614256610220519461028051836139de565b0390a3565b8061426960019284876139be565b3561427761192083876139ce565b9055016141ec565b61428a8185876139be565b3560018082161490816142bb575b50156142a657600101613ad0565b63284f145b60e11b6102005152600461020051fd5b600191501138614298565b63301c306b60e01b6102005152600461020051fd5b50600b610280511415613a98565b506009610280511415613a92565b636226556b60e01b6102005152600461020051fd5b8054600160201b600160601b03191660209290921b600160201b600160601b0316919091179055565b92919061434c602091604086526040860190613465565b930152565b95949193909486600052600360205260406000209487600052600460205260406000209663ffffffff80600289015460a01c1691160361487357601060ff885416036148625785546001600160a01b031633036148515760ff169360348510801590614834575b8015614817575b6147ac5761020082036147ac578160801161198d576143de36856133a8565b826101001161198d576143f436608087016133a8565b92806101801161198d5761440c3661010088016133a8565b916020815191012095601e8a019687541491821592614802575b82156147ec575b82156147bd575b50506147ac576040516349b11d3760e01b81526004810187905273b04c1e546d7cf8dc39e10dfc1714847573790806956000826024818a5af48015614667578460209161449f94600091614791575b50604051630f237ed160e21b8152948592839260048401614335565b03818a5af49182156146675760009261475d575b50540361474e57604051630f237ed160e21b81529291602091849182916144de919060048401614335565b0381875af4908115614667578392600092614715575b50604051630f237ed160e21b81529260209184918291614518919060048401614335565b0381875af4918215614667576000926146e1575b50036146d5576040516349b11d3760e01b81526004810184905290600082602481865af4918215614667576000926146b6575b50601d8601546040516340604be760e01b8152926000928492839261458892906004850161354f565b0381855af49081156146675760009161469b575b506020815191012091602185019283540361468f57604051906349b11d3760e01b82526004820152600081602481855af480156146675761460a926000928392614673575b50601c870154601b8801546040516340604be760e01b815295869485938493916004850161354f565b03915af49081156146675760009161464c575b506020815191012090540361464357906134ec929160ff601983015460101c16926157a3565b6134ec92615670565b61466191503d806000833e61265a818361329f565b3861461d565b6040513d6000823e3d90fd5b6146889192503d8085833e61265a818361329f565b90386145e1565b5050506134ec92615722565b6146b091503d806000833e61265a818361329f565b3861459c565b60009192506146ce903d8084833e61265a818361329f565b919061455f565b5050506134ec92615670565b9091506020813d60201161470d575b816146fd6020938361329f565b8101031261198d5751903861452c565b3d91506146f0565b925090506020823d602011614746575b816147326020938361329f565b8101031261198d57905182916145186144f4565b3d9150614725565b5050505050506134ec92615670565b9091506020813d602011614789575b816147796020938361329f565b8101031261198d575190386144b3565b3d915061476c565b6147a691503d806000833e61265a818361329f565b38614483565b63a554dcdf60e01b60005260046000fd5b9091506102001161198d576147d7906101803691016133a8565b60208151910120602189015414153880614434565b91508251602084012060208b015414159161442d565b85516020870120601f8c015414159250614426565b506001808416148061482a575b156143bf565b5060018311614824565b5060018082161480614847575b156143b8565b5060018111614841565b6393687c0b60e01b60005260046000fd5b63301c306b60e01b60005260046000fd5b636226556b60e01b60005260046000fd5b6001600160401b03811161326e5760051b60200190565b906148a582614884565b6148b2604051918261329f565b82815280926148c3601f1991614884565b0190602036910137565b80518210156132e55760209160051b010190565b9063ffffffff6040519254818116845260201c1660208301526134ec60408361329f565b60405191906000835b60048210614924575050506134ec60808361329f565b600160208192855481520193019101909161490e565b60ff608091548181168452818160081c166020850152818160101c166040850152818160181c16606085015260201c16910152565b939096919497929895986101e05260e0526102405261026052600061028052806102805152600360205260406102805120948161028051526004602052604061028051209663ffffffff600288015460a01c1663ffffffff8716036151d957600f60ff895416036151c45760018701546001600160a01b031633036151af57603460ff85161080159061518c575b801561516b575b61514857610200811480159061515d575b6151485760ff6019890154166080528060801161514157614a3636836133a8565b61010052806101001161514157614a5036608084016133a8565b6101c052806101801161514157614a6b3661010084016133a8565b6101a0526102001161514157614a86906101803691016133a8565b60048701546102a05260c0808052604051610220819052919591614aaa919061329f565b60c0516102205136903761028051610200525b6006610200511015614b2d5761028051614b13576102005150600061028052614af06102005161026051610240516139be565b3561028051506102005160051b6102205101526001610200510161020052614abd565b634e487b7160e01b61028051526011600452602461028051fd5b60405163af0586a360e01b81526102a05160048201526001602482015260ff84166044820152610140606482015260208180614b70610144820161010051613465565b614b80608483016102205161348a565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af490811561502c576102805191615122575b50156150b05760058701546101605260c051604051610180819052614bcf919061329f565b60c05161018051369037610280515b6006811015614c205761028051614b13578060060190816006116131ea57614c0f60019261026051610240516139be565b358160051b61018051015201614bde565b5090919293949560405163af0586a360e01b8152610160516004820152600260248201526080516044820152610140606482015260208180614c6961014482016101c051613465565b614c79608483016101805161348a565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af490811561502c576102805191615103575b50156150b05760068101546101205260c051604051610140819052614cc8919061329f565b60c05161014051369037610280515b6006811015614d195761028051614b135780600c019081600c116131ea57614d0860019261026051610240516139be565b358160051b61014051015201614cd7565b5090919293949560405163af0586a360e01b8152610120516004820152600360248201526080516044820152610140606482015260208180614d6261014482016101a051613465565b614d72608483016101405161348a565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af490811561502c5761028051916150e4575b50156150b057600782015460c05160405160a0819052919891614dbf919061329f565b60c05160a051369037610280515b6006811015614e0e5761028051614b13578060120190816012116131ea57614dfe60019261026051610240516139be565b358160051b60a051015201614dcd565b50909192939495966020614e3f916040518093819263af0586a360e01b83528660a0519160805190600486016134b2565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af490811561502c5761028051916150c5575b50156150b05773b04c1e546d7cf8dc39e10dfc171484757379080660405190630f237ed160e21b825260208280614eaa6101e0516101005160048401614335565b0381845af491821561502c57610280519261507c575b506101c051519160206101c051019283200361506c57604051630f237ed160e21b815260208180614ef86101e0518860048401614335565b0381855af490811561502c57610280519161503a575b5060206040518093630f237ed160e21b82528180614f3560e0516101a05160048401614335565b03915af491821561502c576102805192614ff8575b5003614fe9576101e051601a85015560e051601b850155610100518051602091820120601e8601556101c05151909120601f8501556101a051805190820120848201558151918101919091206021840155825460ff191660101783557f1b2ab5b594fd7d4b1494f908fa143ff6f2f9879b399e1d17f68ec54f44241b8f93909263ffffffff92614fdb9190876158ad565b60ff604051961686521693a3565b50509150916134ec9350615722565b9091506020813d602011615024575b816150146020938361329f565b8101031261198d57519038614f4a565b3d9150615007565b6040513d61028051823e3d90fd5b90506020813d602011615064575b816150556020938361329f565b8101031261198d575138614f0e565b3d9150615048565b5050509150916134ec9350615722565b9091506020813d6020116150a8575b816150986020938361329f565b8101031261198d57519038614ec0565b3d915061508b565b637ca55c7760e01b6102805152600461028051fd5b6150de915060203d60201161129057611282818361329f565b38614e69565b6150fd915060203d60201161129057611282818361329f565b38614d9c565b61511c915060203d60201161129057611282818361329f565b38614ca3565b61513b915060203d60201161129057611282818361329f565b38614baa565b6102805180fd5b63a554dcdf60e01b6102805152600461028051fd5b506018610260511415614a15565b5060018060e051161480615180575b15614a04565b50600160e0511161517a565b506001806101e0511614806151a2575b156149fd565b5060016101e0511161519c565b6338b72ae960e11b6102805152600461028051fd5b63301c306b60e01b6102805152600461028051fd5b636226556b60e01b6102805152600461028051fd5b6001600160401b0391821690821601919082116131ea57565b63ffffffff60019116019063ffffffff82116131ea57565b9063ffffffff8091169116019063ffffffff82116131ea57565b9063ffffffff8091169116039063ffffffff82116131ea57565b63ffffffff91821681529116602082015260400190565b805463ffffffff60a01b191660a09290921b63ffffffff60a01b16919091179055565b80546001600160a01b03928316921682146152ca57600101546001600160a01b0316146152c55763abca351760e01b60005260046000fd5b600190565b5050600090565b61298b6134ec9361532761530360016129a095019263ffffffff6152f58886613599565b90549060031b1c1690615cc6565b94612d056153118285613599565b6129a08963ffffffff84548460031b1c16615239565b90613599565b805463ffffffff60c01b191660c09290921b63ffffffff60c01b16919091179055565b6134ec9381600080516020615e02833981519152606063ffffffff6003880154169361539b63ffffffff61271061539261ffff60018c015460b81c16896131d7565b04168096615239565b946153c26153ac8360018c01613599565b6129a08963ffffffff84548460031b1c1661521f565b63ffffffff8060028a016153e56153df8584845460c01c1661521f565b8261532d565b5460a01c169660ff604051941684521660208301526040820152a3615ce6565b818110615410575050565b60008155600101615405565b60048101905b81811061542d575050565b60008155600101615422565b6000815561544d6002820160018301615405565b61545d6003820160028301615405565b600060038201556154706004820161541c565b6000600c82016154838160088501615405565b556000600e820161549781600d8501615405565b6154a5601184018092615405565b5560168101601282015b818110615517575060188201905b81811061550257506134ec916154d9601e926019830190615405565b600060198201556000601a8201556000601b8201556000601c8201556000601d8201550161541c565b80615511600180930182615405565b016154bd565b80615526600280930182615405565b016154af565b60018201805460ff60a01b1916600360a01b1781558254600284015492937ffabca260174d01cb14c0ba7f3a1678d899165a405e9f9781f2d21cc5ab7bdab8936060939192916155a760a084901c63ffffffff61559d828260036155948360e08b901c6131d7565b9a0154166131d7565b9460c01c166131d7565b9284615648575b508161561b575b50816155e5575b8560005260046020526155d26040600020615439565b60405192835260208301526040820152a2565b85600052600560205260018060a01b036040600020541660005260066020526040600020615614838254613368565b90556155bc565b546001600160a01b031660009081526006602052604090208054615640908390613368565b9055386155b5565b60018060a01b031660005260066020526040600020615668858254613368565b9055386155ae565b80600080516020615e2283398151915260206134ec956156dc600182019163ffffffff60036156d26156b1600096848082541691546004861b1c169061521f565b836156c46002870192828454169061521f565b91546004851b1c169061521f565b920154169061521f565b6002870160018060e01b03815416905563ffffffff60038801911663ffffffff198254161790558381526004825261571660408220615439565b604051908152a261552c565b61575f6134ec93615754600182019163ffffffff60036156d26156b1600096848082541691546004861b1c169061521f565b90506002840161322f565b6003820163ffffffff1981541690558060005260046020526157846040600020615439565b80600080516020615e22833981519152602060405160018152a261552c565b600080516020615e2283398151915260206134ec95615716604085969760ff6157ed600183019263ffffffff60036156d26156b1600097848082541691546004861b1c169061521f565b9416938461582a5760028a0160018060e01b03815416905563ffffffff60038b01911663ffffffff198254161790555b8681526004855220615439565b6158379060028b0161322f565b60038901805463ffffffff1916905561581d565b6040519193929060c061585e818561329f565b3684378260005b60068110156158a5576006840290848204600614851517156131ea5761589761589082600194613368565b89866139be565b358160051b87015201615865565b509450505050565b9060ff6002600080516020615e6283398151915292019361425663ffffffff611c8c81885460801c1660018060401b0342166151ee565b9060ff6002600080516020615e6283398151915292019361425663ffffffff611c8c81885460601c1660018060401b0342166151ee565b9061ff0082549160081b169061ff001916179055565b60ff16600781146159535760091461594b57600890600190565b600790600190565b50600490600390565b9161597361354c9492604085526040850190613465565b92602081850391015261399d565b9092919593949560808614801590615b8c575b6147ac5760006159d09573b04c1e546d7cf8dc39e10dfc171484757379080698604051978892839263d325c5b160e01b8452876004850161595c565b03818a5af494851561466757600095615b6a575b506000615a06916040518093819263631ec63f60e01b83528960048401614335565b03818a5af490811561466757600091615b4f575b5060208151910120906020815191012003615b005760405163d325c5b160e01b81529360009185918291615a539190876004850161595c565b0381875af492831561466757600093615b2c575b506000615a89916040518093819263631ec63f60e01b83528760048401614335565b0381875af490811561466757600091615b11575b5060208151910120906020815191012003615b0057806020809251910120602460405180948193633b8c1f2d60e21b835260048301525af490811561466757600091615ae7575090565b61354c915060203d60201161217657612163818361329f565b638ba09fd960e01b60005260046000fd5b615b2691503d806000833e61265a818361329f565b38615a9d565b615a89919350615b476000913d8084833e61265a818361329f565b939150615a67565b615b6491503d806000833e61265a818361329f565b38615a1a565b615b84600091615a0693973d8091833e61265a818361329f565b9591506159e4565b506080851415615994565b94600260ff92615c0b606096957fd3060bf93343487b796703319013dda402debbb3819e37ca26f987571ca09805989a63ffffffff95615bf08d601985018a8c168b1982541617815561ff0080198254161781556135d0565b601c830155601d820155600f8619825416178155828a6158ad565b015460a01c1695816040519316835216602082015260ff6040820152a3565b60038301805460ff60901b1916609086901b60ff60901b16179055600094939092919073ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc86813b1561036e5760249160405192838092631067a2ef60e11b82528860048301525af4801561199a579661207892916134ec9798615cb6575b5050612d0563ffffffff600285015460401c1682866152d1565b81615cc09161329f565b38615c9c565b9063ffffffff811663ffffffff831610600014615ce1575090565b905090565b9160010160009063ffffffff808083541692615d0660028701948561322f565b54600460031b1c1691816003860193168219845416178355615d5c604083835460a01c1695615d3d615d3788615207565b8561526a565b615d4e600180841b0342168761430c565b888152600460205220615439565b5460e01c9154169184600080516020615da283398151915260405180615d83878783615253565b0390a315908115615d98575b5061373b575050565b90501538615d8f56fe59d3350cb221a36e23b483076e38f2c093b609b0aebdfdeb03d0512d7d5a2315134e07fe001e0bc82a08476763b074f743a6d3b7aa79f27bf2deff8f576129c66d007a5bc0a881f142027c9c5a95f04f9f8ec48e7f9c4b538aef7ac8d8397ede30e1dec6db2d80ec3e362df6665049ac592e8cc98d7b236d0c61681304da81340cd5cc6eac0dc3c714a186b81c618ab602c9b02830ba885dc7af3e76dbfc5c349b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f008e0405abb6bd265a8563b4e6fb2118d701c6055b85e736e6b75e062b5d2e0f28a2646970667358221220ffcb69456a0b24ba9cd329cc2d2b2d5233221b9e3a8286b72c65191b8641030664736f6c634300081c00330000000000000000000000000000000000000000000000000000000000000064000000000000000000000000fcafcc30cdfcda7b95e8466a8776d55b9c9963aa

Deployed ByteCode

0x6102c0604052600436101561001357600080fd5b6000803560e01c806301bf32dc14612d6857806308ce201114612be8578063102672ba14612bcb5780631162384c146122db57806317cf8c0d146122bc57806321c9c44a14612297578063264f5c01146121bb57806327e5e0c114611f0e5780633ccfd60b14611e0b5780633f637e8614611dd05780634155fc5b14611db2578063543ad1df14611d9657806365e17c9d14611d6d578063668fd78214611b1a578063704b25271461168857806370a4e95b1461165557806371671bf214611523578063763c8cd91461142457806381c908581461133a578063898acd1f146110285780638da5cb5b146110015780639492264514610ee4578063b3a5c8c814610e8c578063ce513b6f14610e53578063d1e9e14014610d39578063d47f269e14610547578063d924cb931461046a578063de38eb3a1461044c578063dfa170e7146103c9578063f2fde38b146103715763f42452581461017357600080fd5b3461036e57604036600319011261036e57600435602435801515810361036c5781835260036020526040832090828452600460205260408420600183015490600260ff8360a01c160361035d575460ff1661034e576001600160a01b0316330361033f576003820180546002840180549092916001600160401b039061020990608084901c63ffffffff169060201c83166151ee565b1642111561033057906102f36102ed7f50038a922c31e04bdb655c3d957330398521774f6656bf130c3fcb3303102d1d602089600080516020615da28339815191528761028b61028561027e61027363ffffffff6103039d60401c1663ffffffff868a1c1661521f565b9360e01c8094615cc6565b8093615239565b8b61322f565b63ffffffff61029d82828b541661521f565b1663ffffffff198954161788558954908363ffffffff8360a01c16968796879363ffffffff60405191168152a363ffffffff885416906102e560405192839260e01c83615253565b0390a3615207565b8461526a565b426001600160401b03169061430c565b5460e01c15908115610328575b50610319578280f35b6103229161552c565b38808280f35b905038610310565b63d0404f8560e01b8752600487fd5b6338b72ae960e11b8452600484fd5b63301c306b60e01b8552600485fd5b63126ab15560e01b8652600486fd5b825b80fd5b503461036e57602036600319011261036e5761038b61316b565b8154906001600160a01b03821633036103ba576001600160a01b03166001600160a01b03199190911617815580f35b6330cd747160e01b8352600483fd5b503461036e5760e036600319011261036e576103e36130d8565b6103eb6130fe565b60a4356001600160401b0381116104485761040a90369060040161310e565b60c43593916001600160401b0385116104445761042e61044195369060040161313b565b949093608435916064359160043561496f565b80f35b8580fd5b8380fd5b503461036e578060031936011261036e57602060405162093a808152f35b503461036e57604036600319011261036e5760043561ffff81169081810361036c576024356001600160a01b03811691908290036104485783546001600160a01b03163303610538576101f4831161052957811561051a57600180546001600160b01b03191660a09290921b61ffff60a01b1691909117821790556040805192835260208301919091527fb5add0bb8de8016e167bf0c471fb32731f765637e15e0156d13ee6853f6a064391a180f35b63de17a3af60e01b8452600484fd5b63c6c3513b60e01b8452600484fd5b6330cd747160e01b8452600484fd5b503461036e57602036600319011261036e5760405161056581613252565b8181528160208201528160408201526040918251610583848261329f565b8336823760608301528251610598848261329f565b8336823760808301528060a08301528060c08301528060e08301528061010083015280610120830152806101408301528061016083015280610180830152806101a0830152806101c0830152806101e083015260809280516105fa858261329f565b843682376102008401528051610610858261329f565b843682376102208401528161024084015260a0815161062f828261329f565b813682376102608501526060938251610648868261329f565b85368237610280820152836102a0820152836102c0820152836102e08201528251610673848261329f565b845b848110610d1c5750610300820152825161068f848261329f565b845b848110610cff575061032082015282516106ab848261329f565b833682376103408201528361036082015283610380820152836103a0820152836103c0820152836103e082015283610400820152836104208201526104408351916106f6888461329f565b873684370152600435835260046020528183209482519561071687613252565b805460ff8082168952600882901c16602089015260101c6001600160401b031684880152610746600182016148e1565b86880152610756600282016148e1565b8288015260ff600382015463ffffffff8116858a015263ffffffff8160201c1660c08a015263ffffffff81871c1660e08a01528181891c166101008a0152818160681c166101208a0152818160701c166101408a0152818160781c1615156101608a01528181851c1615156101808a0152818160881c1615156101a08a0152818160901c166101c08a015260981c166101e08801526107f760048201614905565b61020088015283516008820186825b60048210610ce95750505061081b838261329f565b61022088015260ff600c82015416610240880152835161083e81600d840161493a565b610848848261329f565b6102608801528351600e820186825b60038210610cd35750505061086c878261329f565b61028088015260ff60118201548181166102a08a0152818160081c166102c08a015260101c166102e088015283516108a381613284565b6012820186825b60028210610c8c5750505061030088015283516108c681613284565b6016820186825b60028210610c5b575050509161095b601e6109a49363ffffffff96956103208c01526108fb601882016148e1565b6103408c015260ff60198201548c6103608383169101528c610380838360081c1691015260101c166103a08c0152601a8101546103c08c0152601b8101546103e08c0152601c8101546104008c0152601d8101546104208c015201614905565b61044089015261099885519760ff8a5116895260ff60208b01511660208a015260018060401b03878b015116878a0152808a015190890190613181565b87015182870190613181565b8501511660e084015263ffffffff60c08501511661010084015263ffffffff60e08501511661012084015260ff6101008501511661014084015260ff6101208501511661016084015260ff6101408501511661018084015261016084015115156101a084015261018084015115156101c08401526101a084015115156101e084015260ff6101c08501511661020084015260ff6101e085015116610220840152610a586102008501516102408501906131af565b610220840151826102c085015b60048210610c455750505061024084015160ff166103408401526102608401518261036085015b60058210610c2c575050506102808401518261040085015b60038210610c165750505060ff6102a08501511661046084015260ff6102c08501511661048084015260ff6102e0850151166104a08401526103008401516104c0840183905b60028210610bd85750505061032084015190829061054085015b60028310610b975761076086610b956104408a610b2b6103408201516105c0860190613181565b60ff6103608201511661060085015260ff6103808201511661062085015260ff6103a0820151166106408501526103c08101516106608501526103e08101516106808501526104008101516106a08501526104208101516106c085015201516106e08301906131af565bf35b818451829087915b60028310610bbc5750505060209060019201940192019192610b04565b815160ff16815285935060019092019160209182019101610b9f565b838351829087915b60028310610bfd5750505060209060019201930191019091610aea565b8151815287935060019092019160209182019101610be0565b6020806001928551815201930191019091610aa4565b60208060019260ff865116815201930191019091610a8c565b6020806001928551815201930191019091610a65565b6001602081928a5160ff8754818116835260081c1683820152610c7e8c8261329f565b8152019301910190916108cd565b87518984825b60028310610cbd57505050602060019282610caf8c60029561329f565b8152019301910190916108aa565b6001602081928454815201920192019190610c92565b6001602081928554815201930191019091610857565b6001602081928554815201930191019091610806565b6020908551610d0e878261329f565b863682378184015201610691565b6020908551610d2b878261329f565b863682378184015201610675565b503461036e57602036600319011261036e576004359080610d598361489b565b906002545b600181101580610e4a575b15610dc8578084526003602052600160ff8160408720015460a01c1614610dae575b8015610d9a5760001901610d5e565b634e487b7160e01b84526011600452602484fd5b80610dc2610dbb84613200565b93856148cd565b52610d8b565b50908290610dd58361489b565b92825b818110610e2657505050604051918291602083016020845282518091526020604085019301915b818110610e0d575050500390f35b8251845285945060209384019390920191600101610dff565b80610e356001928597956148cd565b51610e4082866148cd565b5201939193610dd8565b50848210610d69565b503461036e57602036600319011261036e576020906040906001600160a01b03610e7b61316b565b168152600683522054604051908152f35b503461036e5760c036600319011261036e57610ea66130d8565b610eae6130fe565b60a435916001600160401b03831161044857610ed161044193369060040161310e565b9290916084359160643591600435614351565b50604036600319011261036e576004356024359060ff821691828103610448578184526003602052604084209060018201908154600160ff8260a01c1603610ff257835490336001600160a01b03831614610fe3576008871015610fe3579063ffffffff610f599260c81c169060a01c6131d7565b3403610fd457815462ff00ff60a01b193316600161ff0160a81b03199091161760b09190911b60ff60b01b1617600160a11b179055610fa590426001600160401b03169060030161430c565b6040519182527f396423bd1651bba635e3419ce325aa401229452a6b2be1768843d2e8dea8177860203393a380f35b634366b25d60e01b8652600486fd5b63de17a3af60e01b8852600488fd5b631bb5f5b360e31b8752600487fd5b503461036e578060031936011261036e57546040516001600160a01b039091168152602090f35b503461036e576101a036600319011261036e576004356110466130d8565b61104e6130fe565b906064356084356001600160401b0381116104445761107190369060040161310e565b9093366101641161133657610164356001600160401b0381116113325761109c90369060040161310e565b9095909390610184356001600160401b03811161132e576110c190369060040161310e565b90898b52600360205260408b20968a8c52600460205260408c209863ffffffff8060028b015460a01c1691160361131f5760ff89541660068110908115611314575b5061130557611112338961528d565b9960ff8b169788159586806112f8575b80156112cb575b156112bc57600180891614806112b2575b156112a3578e60078d01546040519063af0586a360e01b825260048201526004602482015260ff8b1660448201526101406064820152602081806111836101448201888861399d565b60c060a4608484013703817376a5e1d2e03838dabdce38f3372510ba53cabf085af49182156112975791611268575b5015611259579360ff936111ee938a9897938a8f6034996111da60086111e993019d8e61341a565b90549060031b1c9336916133e3565b615981565b16101561120357505050505061044193615c2a565b9261044198979592918195979460001461124057600183985b0361122957505095615b97565b611233925061341a565b90549060031b1c95615b97565b600161124c838361341a565b90549060031b1c9861121c565b637ca55c7760e01b8f5260048ffd5b61128a915060203d602011611290575b611282818361329f565b81019061342a565b386111b2565b503d611278565b604051903d90823e3d90fd5b63284f145b60e11b8f5260048ffd5b506001881161113a565b631749e6cd60e11b8f5260048ffd5b5060018a148015611129575060ff8916600281149081156112ed575b50611129565b6003915014386112e7565b50600260ff8a1610611122565b63301c306b60e01b8c5260048cfd5b600e91501138611103565b636226556b60e01b8c5260048cfd5b8980fd5b8780fd5b8680fd5b503461036e57604036600319011261036e57600435906113586130d8565b8282526003602052604082208383526004602052604083209063ffffffff80600283015460a01c16931692830361141557600e60ff835416036114065761139f338261528d565b9460ff601184015460081c169360ff806113b8876132c2565b1697169687036113f757817f50295138b8e123fbfba534eabbb8054c406902fa7aadac163b85767230452e7e60206104419899604051908152a3615350565b630304193d60e11b8652600486fd5b63301c306b60e01b8452600484fd5b636226556b60e01b8452600484fd5b503461036e5761010036600319011261036e5761143f6130d8565b6044356001600160401b03811161036c5761145e90369060040161313b565b916064356001600160401b03811161151f5761147e90369060040161313b565b906084356001600160401b0381116113365761149e90369060040161310e565b9060a4356001600160401b03811161151b576114be90369060040161313b565b92909160c4356001600160401b038111611517576114e090369060040161310e565b60e4359a90979196906001600160401b038c11611513576115086104419c369060040161310e565b9b909a6004356139fb565b8c80fd5b8a80fd5b8880fd5b8480fd5b503461036e57602036600319011261036e57604061024091600435815260036020522080549060018101549063ffffffff60036002830154920154926040519460018060a01b038116865260a01c602086015260018060a01b038116604086015260ff8160a01c16606086015260ff8160a81c16608086015260ff8160b01c1660a086015261ffff8160b81c1660c086015260c81c1660e084015263ffffffff811661010084015263ffffffff8160201c1661012084015263ffffffff8160401c1661014084015263ffffffff8160601c1661016084015263ffffffff8160801c1661018084015263ffffffff8160a01c166101a084015263ffffffff8160c01c166101c084015260e01c6101e083015263ffffffff811661020083015260018060401b039060201c16610220820152f35b503461036e57602036600319011261036e57602090600435815260058252604060018060a01b0391205416604051908152f35b503461036e57608036600319011261036e576004356116a56130d8565b906116ae6130fe565b6064356001600160401b03811161151f576116cd90369060040161310e565b838652600360205260408620848752600460205260408720916001820194855495600260ff8860a01c1603611b0b57600284019163ffffffff80845460a01c169a16998a03611afc5760ff169660018803611a1d57505082546001600160a01b03163303611a0e5760ff8454166119ff57805460e01c801580156119ed575b6119de576117769061176360018701918c836135b5565b600463ffffffff600387015416916135b5565b8873ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc8254813b1561036c5763ffffffff60848492604051948593849263074bdbe560e01b84528c600485015260018160a01c166024850152818116604485015260201c1660648301525af480156119ba576119c9575b505063ffffffff905460a01c16867fbfeb6d84abeccf1947b6157b7ac00b04d40817b53e2440dcfa49f712fa234810602060ff875460081c16604051908152a3825460ff191660021783555b8773b04c1e546d7cf8dc39e10dfc1714847573790806803b156119c557816040518092626a007d60e01b825260206004830152818061186f60248201898d61399d565b03915af480156119ba576119a5575b50506118aa93602091604051958692839263b65c02d360e01b845260406004850152604484019161399d565b87602483015203817376a5e1d2e03838dabdce38f3372510ba53cabf085af492831561199a578793611961575b50600019840160ff811161194d5782849260409561193761192061193f9560047ff4169c826e1cd0db9f677dc2ffe40cc7cae264e9ecb54b4cc220cff5b82bbfc69b990161341a565b819391549060031b91821b91600019901b19161790565b9055876158ad565b82519182526020820152a380f35b634e487b7160e01b88526011600452602488fd5b9092506020813d602011611992575b8161197d6020938361329f565b8101031261198d575191386118d7565b600080fd5b3d9150611970565b6040513d89823e3d90fd5b816119af9161329f565b61133257873861187e565b6040513d84823e3d90fd5b5080fd5b816119d39161329f565b61151b5788386117e0565b6309107e2560e31b8a5260048afd5b5063ffffffff6003850154161561174c565b63301c306b60e01b8952600489fd5b6393687c0b60e01b8952600489fd5b90915060028703611a735750546001600160a01b03163303611a6457600260ff84541603611a5557825460ff1916600317835561182c565b63301c306b60e01b8852600488fd5b6338b72ae960e11b8852600488fd5b905060038603611aba575081546001600160a01b03163303611aab57600360ff84541603611a5557825460ff1916600417835561182c565b6393687c0b60e01b8852600488fd5b60048603611aed576001600160a01b03163303611a6457600460ff84541603611a5557825460ff1916600517835561182c565b63de17a3af60e01b8952600489fd5b636226556b60e01b8b5260048bfd5b63126ab15560e01b8a5260048afd5b503461036e57608036600319011261036e57600435611b376130d8565b90604435606435908285526003602052604085209383865260046020526040862092600286019563ffffffff80885460a01c169316928303611d5e57600560ff86541603611a555760018085161480611d54575b158015611d37575b611d2857611ba460ff91339061528d565b1690600182149384600014611d20576001945b600c870195865460ff82821616611d11579460ff96948a947fe47a1a70cd8e25e08c403d1b29c6e7f3f5625c8899a042b3d6c0971ebf8b4cad94896020958160039d9b1617168a198a5416178955600014611d025760088b015560098a01555b604051908152a3541614611c29578380f35b60ff81816003600080516020615e62833981519152940181815460881c16600014611cfa578160075b1682198454161783555460881c1615600014611ce257611cd863ffffffff611c8c8180895460601c165b16426001600160401b03166151ee565b835462010000600160501b03198116601092831b62010000600160501b03161794859055975460405160a09190911c92909216979194859490911c6001600160401b03169116836139de565b0390a33880808380f35b611cd863ffffffff611c8c8180895460801c16611c7c565b816006611c52565b600a8b0155600b8a0155611c17565b63e9f155db60e01b8c5260048cfd5b600294611bb7565b63284f145b60e11b8852600488fd5b5060018083161480611d4a575b15611b93565b5060018211611d44565b5060018411611b8b565b636226556b60e01b8852600488fd5b503461036e578060031936011261036e576001546040516001600160a01b039091168152602090f35b503461036e578060031936011261036e576020604051603c8152f35b503461036e578060031936011261036e576020600254604051908152f35b503461036e57608036600319011261036e57611dea6130d8565b611df26130fe565b6064359081151582036104485761044192600435613601565b503461036e578060031936011261036e576002600080516020615e428339815191525414611eff576002600080516020615e4283398151915255338152600660205260408120548015611ef05733825260066020528160408120558180808084335af13d15611eeb573d611e7e8161338d565b90611e8c604051928361329f565b81528360203d92013e5b15611edc576040519081527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d560203392a26001600080516020615e428339815191525580f35b6312171d8360e31b8252600482fd5b611e96565b630b8a550d60e31b8252600482fd5b633ee5aeb560e01b8152600490fd5b503461036e57608036600319011261036e57600435611f2b6130d8565b60443590600582101561044857611f406130eb565b90838552600360205260408520918486526004602052604086209363ffffffff600285015493169263ffffffff8160a01c168403611d5e5760ff865416600681141590816121af575b816121a3575b81612197575b50611a5557611fa4338661528d565b93600387019360ff855460681c1660ff87169081036121885763ffffffff80604051936370807d8760e11b85528b6004860152836024860152611fe68861320f565b876044860152169485606485015260201c16608483015260208260a48173ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc5af493841561217d5760ff958b938d96612133575b5091606091878461204c600080516020615dc28339815191529661320f565b6040519384521660208301526040820152a3166002810361207e575050906120786104419493926132c2565b92615350565b90949150600103612129578360ff610441955460601c1680156000146120b0575050825460ff191660071783556158ad565b600181036120ca575050825460ff191660091783556158ad565b6002036120e25750825460ff1916600b1783556158ad565b835460ff1916600d1784555460981c60ff9081169081146121105761210b905b6011850161591b565b6158ad565b5061210b61212460ff855460081c166132c2565b612102565b61044193506158e4565b600080516020615dc283398151915293919650918761216b60609460203d602011612176575b612163818361329f565b8101906135e8565b97929450509161202d565b503d612159565b6040513d8d823e3d90fd5b631cc191eb60e31b8b5260048bfd5b600c9150141538611f95565b600a8114159150611f8f565b60088114159150611f89565b503461036e57602036600319011261036e576004358082526003602052604082206001810190600160ff835460a01c16036122885780546001600160a01b0316330361227957815460ff60a01b1916600160a21b1791829055549061222d9060c81c63ffffffff1660a083901c6131d7565b6001600160a01b0390911683526006602052604083208054909161225091613368565b90557f8bd66138689095e38b45ec45363241e614b91b8e6fb90f7c15dfdeb93f34fcfe8280a280f35b6393687c0b60e01b8452600484fd5b631bb5f5b360e31b8452600484fd5b503461036e578060031936011261036e57602061ffff60015460a01c16604051908152f35b503461036e578060031936011261036e576020604051633b9aca008152f35b503461036e5761010036600319011261036e576122f66130d8565b366084116119c5573660c4116119c55760c4356001600160401b03811161036c5761232590369060040161310e565b9060e4356001600160401b03811161151f5761234590369060040161313b565b60049291923586526003602052604086209260043587526004602052604087209463ffffffff600286015460a01c1663ffffffff881603611d5e5761238a338661528d565b9460ff875416600d8114600014612b96575060ff601188015460081c1660ff871603612b87575b6101008214801590612b7c575b612b3b57603460ff6123ce61330d565b1610801590612b67575b8015612b4a575b612b3b57885b60058110612acd575060ff8616612ac55788905b895b600281101561271f5761240d816132d3565b356001808216149081612714575b50156127055761242e60ff821684613354565b818060071b04608014821517156126f157600182018083116126dd57808060071b04608014811517156126dd57908c8b6020838a6124b16124968f8f61248b8f612484908e9460079e8f1b918f87901b91613375565b36916133e3565b9a8b9801549461584b565b60405163af0586a360e01b81529586948594600486016134b2565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af491821561129757916126bf575b50156126b0576124ea9060088c0161341a565b90549060031b1c60ff8a16156000146126a9578c612507846132d3565b35915b60ff8c1661269857915b612525612520866132fb565b61332d565b60ff604051916349b11d3760e01b8352166004820152828160248173b04c1e546d7cf8dc39e10dfc17148475737908065af490811561268d578391612673575b5061258460405194859384936340604be760e01b85526004850161354f565b038173b04c1e546d7cf8dc39e10dfc17148475737908065af4908115612668578d91612646575b5060208151910120906020815191012003612637576125c9816132d3565b35600289101561262357906001916125eb6119208360128e8e881b0101613571565b905561261d8a8d61260b8c6016612604612520886132fb565b9401613571565b509050601f8416908460051c01613581565b016123fb565b634e487b7160e01b8c52603260045260248cfd5b6399f4b04160e01b8b5260048bfd5b61266291503d808f833e61265a818361329f565b8101906134ee565b386125ab565b6040513d8f823e3d90fd5b61268791503d8085833e61265a818361329f565b38612565565b6040513d85823e3d90fd5b506126a2846132d3565b3591612514565b8c8161250a565b637ca55c7760e01b8d5260048dfd5b6126d7915060203d811161129057611282818361329f565b386124d7565b634e487b7160e01b8d52601160045260248dfd5b634e487b7160e01b8c52601160045260248cfd5b63284f145b60e11b8b5260048bfd5b60019150113861241b565b8a888a848d6040519361273360e08661329f565b60e0368637855b60058110612a81575060ff61274d61330d565b1660a086015260ff61275d61331d565b1660c08601526040516342b9d18160e11b81529486600487015b60078210612a685750505060208560e4817385c53cbfc7f3425f5328d05a6732f659f468592a5af4948515612a5d578695612a1c575b5063ffffffff60188501926127cc876127c68587613599565b906135b5565b8160118701976127ed60ff60018188161b1660ff8b5460101c16178a6135d0565b60ff6127f761330d565b8161280061331d565b91816040519916895216602088015216604086015216606084015216907fe656b3a671b1d5b27cba2c8f42d1b11df035c0a6f0fc7ffcb2bfb7f5c51657fd608060043592a382549360ff8516600d0361286d575050815460ff1916600e17825561044192506004356158ad565b5460081c60ff169390929190612882856132c2565b9363ffffffff6128928683613599565b90549060031b1c1663ffffffff6128a98884613599565b90549060031b1c16106000146128c85750506104419350600435615350565b909192936128ee8663ffffffff6128e0819486613599565b90549060031b1c1693613599565b90549060031b1c161160001461290d5750906104419291600435615350565b610441935063ffffffff600384015416906129b461294a63ffffffff61271061294161ffff600189015460b81c16876131d7565b04168094615239565b916129a061298b61296a60ff637fffffff8760011c169460081c166132c2565b6129a661297a600188168661521f565b6129a061298b60018d019485613599565b91909263ffffffff84548460031b1c1661521f565b916135b5565b60ff895460081c1690613599565b6129d76129ce8363ffffffff600287015460c01c1661521f565b6002850161532d565b63ffffffff600284015460a01c169163ffffffff60405192600284521660208301526040820152600080516020615e02833981519152606060043592a3600435615ce6565b9094506020813d602011612a55575b81612a386020938361329f565b81010312610444575163ffffffff811681036104445793866127ad565b3d9150612a2b565b6040513d88823e3d90fd5b60208060019260ff865116815201930191019091612777565b60ff612a9082600d880161333b565b90549060031b1c166007821015612ab157600582901b87015260010161273a565b634e487b7160e01b88526032600452602488fd5b6002906123f9565b60ff612adc82600d8b0161333b565b90549060031b1c1660ff612aee61330d565b16148015612b12575b612b03576001016123e5565b63a554dcdf60e01b8a5260048afd5b5060ff612b2282600d8b0161333b565b90549060031b1c1660ff612b3461331d565b1614612af7565b63a554dcdf60e01b8952600489fd5b50612b5361330d565b60ff80612b5e61331d565b169116146123df565b50603460ff612b7461331d565b1610156123d8565b50600c8414156123be565b630304193d60e11b8952600489fd5b600e036119ff5760ff612bb18160118a015460081c166132c2565b1660ff871603156123b157630304193d60e11b8952600489fd5b503461036e578060031936011261036e5760206040516101f48152f35b503461036e57602036600319011261036e576004358082526003602052604082208183526004602052604083206001820190600260ff835460a01c1603612d5957612c33338461528d565b9160ff825416857f410304baf564e21c104cbc1ab0a0f9c155f9a5119091083c05d2a6e2b0fd54b5602060405160ff88168152a280612c7957505050506104419161552c565b600f819593949514908115612d4e575b5015612c995750610441936157a3565b91909273ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc86813b1561036e5760249160405192838092631067a2ef60e11b82528760048301525af4801561199a57612d2a575b5091612d1260ff92612d0a600295612d0563ffffffff888a015460401c1682856152d1565b6132c2565b908688615350565b5460a01c1614612d2157505080f35b6104419161552c565b60ff92612d0a88612d42600297959a612d129561329f565b98939550509250612ce0565b601091501438612c89565b63126ab15560e01b8552600485fd5b5061010036600319011261036e576004356001600160601b03811680820361036c57612d926130d8565b916044359063ffffffff821680920361151f57612dad6130eb565b946084359563ffffffff87169081880361036c5760a4359463ffffffff86169384870361036e5760c4359563ffffffff87169687810361036c5760e4359a60ff8c16998a8d0361151f578b1580156130ca575b80156130b7575b613058576001861080156130a8575b801561308e575b61305857603c88108015613082575b61305857603c89108015613076575b6130585760018a108015613067575b6130585760088b1015613058578b9c9d612e6e63ffffffff849e9d9e16809d6131d7565b3403610fd457600254612e8090613200565b9e8f80600255875260036020526040872095600160a01b600190033316600160a01b6001900319885416178755865490600160a01b60019003199060a01b1690600160a01b60019003161786556001860190600160a01b60ff60a01b1983541617825581549060ff60a81b9060a81b168060ff60a81b19831617835561ffff60b81b60015460181b169063ffffffff60c81b8760c81b169267ffffffffffff00ff60a81b1916171717905560028501938763ffffffff1986541617855584549263ffffffff60801b9060801b169263ffffffff60801b199063ffffffff60201b8b60201b1690600160201b600160801b03191617169063ffffffff60401b9060401b16179063ffffffff60601b9060601b1617178255612f9f9161322f565b6003018763ffffffff19825416179055600160a01b6001900360015416908a815260056020526040902090600160a01b6001900316600160a01b600190031982541617905560015460a01c61ffff16956040519889526020890152604088015263ffffffff166060870152608086015260a085015260c084015260e08301526101008201528133916101207f420317bb06dc9f1eea6d42235fffbfe838d3bef49aba0b479ecb45b332dd6dbb91a3604051908152602090f35b63de17a3af60e01b8552600485fd5b5063ffffffff87168a11612e4a565b5062093a808911612e3b565b5062093a808811612e2c565b5063ffffffff600a818416041663ffffffff881611612e1d565b508563ffffffff881610612e16565b50633b9aca0063ffffffff831611612e07565b5063ffffffff821615612e00565b6024359063ffffffff8216820361198d57565b6064359063ffffffff8216820361198d57565b6044359060ff8216820361198d57565b9181601f8401121561198d578235916001600160401b03831161198d576020838186019501011161198d57565b9181601f8401121561198d578235916001600160401b03831161198d576020808501948460051b01011161198d57565b600435906001600160a01b038216820361198d57565b906000905b6002821061319357505050565b60208060019263ffffffff865116815201930191019091613186565b906000905b600482106131c157505050565b60208060019285518152019301910190916131b4565b818102929181159184041417156131ea57565b634e487b7160e01b600052601160045260246000fd5b60001981146131ea5760010190565b6005111561321957565b634e487b7160e01b600052602160045260246000fd5b80546001600160e01b031660e09290921b6001600160e01b031916919091179055565b61046081019081106001600160401b0382111761326e57604052565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761326e57604052565b601f909101601f19168101906001600160401b0382119082101761326e57604052565b60ff166001039060ff82116131ea57565b60028110156132e55760051b60440190565b634e487b7160e01b600052603260045260246000fd5b60028110156132e55760051b60840190565b60843560ff8116810361198d5790565b60a43560ff8116810361198d5790565b3560ff8116810361198d5790565b91909160058310156132e557601f908360051c01921690565b9060ff8091169116019060ff82116131ea57565b919082018092116131ea57565b9093929384831161198d57841161198d578101920390565b6001600160401b03811161326e57601f01601f191660200190565b9190916133b5608061338d565b906133c3604051928361329f565b819360808352608082011161198d5781608060a092602060009501370152565b9291926133ef8261338d565b916133fd604051938461329f565b82948184528183011161198d578281602093846000960137010152565b60048210156132e5570190600090565b9081602091031261198d5751801515810361198d5790565b60005b8381106134555750506000910152565b8181015183820152602001613445565b9060209161347e81518092818552858086019101613442565b601f01601f1916010190565b906000905b6006821061349c57505050565b602080600192855181520193019101909161348f565b9493916134ec9360ff6134e4926080948952600460208a01521660408801526101406060880152610140870190613465565b94019061348a565b565b60208183031261198d578051906001600160401b03821161198d570181601f8201121561198d5780516135208161338d565b9261352e604051948561329f565b8184526020828401011161198d5761354c9160208085019101613442565b90565b61356760409295949395606083526060830190613465565b9460208201520152565b60028210156132e5570190600090565b919060ff8084549260031b9316831b921b1916179055565b91909160028310156132e557601c908360031c019260021b1690565b919063ffffffff8084549260031b9316831b921b1916179055565b9062ff000082549160101b169062ff00001916179055565b9081602091031261198d575160ff8116810361198d5790565b929091600084815260036020526040812093858252600460205260408220906001860191600260ff845460a01c160361398e57600287019463ffffffff80875460a01c16931692830361397f57815460ff80821692168214801590613977575b6139685760101c6001600160401b031642111561395957613682338961528d565b9260028214801561394f575b1561378a576001915b60ff831660ff8616811461377b5760408c92600080516020615de28339815191529282519182526020820152a373ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc803b15610444578560249160405192838092631067a2ef60e11b82528760048301525af48015612a5d57613759575b506137249063ffffffff61372b9596975460401c1690836152d1565b8688615350565b82613744575b505061373b575050565b6134ec9161552c565b5460a01c60ff16600214915038905080613731565b9063ffffffff8661377161372b97986137249561329f565b9695505090613708565b635f07a36960e11b8852600488fd5b60038203613799578591613697565b600582036137e45760ff84166001036137db5760ff60015b600c8501541616156137cc576137c6846132c2565b91613697565b632a0e78a360e01b8652600486fd5b60ff60026137b1565b600782148015613945575b801561393b575b156138155760ff60118401541660ff8516036137cc576137c6846132c2565b600682148015613931575b8015613927575b801561391d575b156138445760ff600384015460681c1691613697565b600d820361385d5760ff601184015460081c1691613697565b600e8203613878576137c660ff601185015460081c166132c2565b949350600f919796508099989550146000146138ce5760ff166138bf575081600080516020615de283398151915260406134ec9798815190815260016020820152a3615722565b6393687c0b60e01b8152600490fd5b601088929814600014611a555760ff600191160361390e57600080516020615de2833981519152604084926134ec989982519182526020820152a3615670565b6338b72ae960e11b8752600487fd5b50600c821461382e565b50600a8214613827565b5060088214613820565b50600b82146137f6565b50600982146137ef565b506004821461368e565b63d0404f8560e01b8552600485fd5b63301c306b60e01b8652600486fd5b508115613661565b636226556b60e01b8552600485fd5b63126ab15560e01b8452600484fd5b908060209392818452848401376000828201840152601f01601f1916010190565b91908110156132e55760051b0190565b60038210156132e5570190600090565b60ff90911681526001600160401b03909116602082015260400190565b9c9491979a9998959c9b93909b969296610220526101a0526101c0526102a0526101405261016052600061020052610220516102005152600360205260406102005120610240526102205161020051526004602052604061020051206102605263ffffffff600261024051015460a01c1663ffffffff8816036142f75760ff610260515416610280526007610280511415806142e9575b806142db575b6142c657613aa9336102405161528d565b61018052613ab961028051615931565b6101e0529660ff6101e0511683036140f257610200515b60ff6101e05116811061427f575060ff80601161026051015416146141d5575060ff60116102605101541660ff6101805116146141c05760ff6101e051166101c0511480159061419c575b801561416b575b6140f257610200515b60ff6101e051168110613dd25750506102605160118101805460ff191660ff17905561020051600e8201819055600f8201819055601090910155505061028051600714159450613d8d93505050505761026051600301805460ff60601b1916600160601b1790555b63ffffffff600261024051015460a01c1660ff6003610260510191825490604051838360601c168152613bcf60208201600d610260510161493a565b7ff6c035c10ac1e9a6d54a4228a066116b018fcb4d11df171c9a55665c47de523760c06102205192a360881c1615613ca25761028051600703613c31575061026051805460ff191660091790555b6134ec6102605161024051610220516158ad565b61028051600903613c51575061026051805460ff1916600b179055613c1d565b61026051805460ff1916600d1790555460981c60ff908116908114613c8657613c81905b6011610260510161591b565b613c1d565b50613c81613c9d60ff610260515460081c166132c2565b613c75565b5061028051600703613d5a5761026051805460ff191660081790555b610240516002015460201c63ffffffff1673ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc803b15613d53576040519163441271fb60e11b835261026051600484015260248301528160448161020051935af48015613d4557613d32575b506134ec6102605161024051610220516158e4565b61020051613d3f9161329f565b38613d1d565b6040513d61020051823e3d90fd5b6102005180fd5b61028051600903613d795761026051805460ff1916600a179055613cbe565b61026051805460ff1916600c179055613cbe565b61028051600903613db55761026051600301805460ff60601b1916600160611b179055613b93565b61026051600301805460ff60601b1916600360601b179055613b93565b613ddf60ff821689613354565b90808060071b0460801481151715613fe15760018101808211613fe157808060071b0460801481151715613fe157612484613e269160071b8360071b8d6102a05190613375565b806020848b613e41612496878a60076102605101549461584b565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af4908115613d4557610200519161414d575b50156141385761020051610120526101805160ff1661411857613e8f8286886139be565b35610120525b6101805160ff1661410757613eb082600e61026051016139ce565b90549060031b1c5b603460ff613ed0612520866101c0516101a0516139be565b16101561404c57613eeb612520846101c0516101a0516139be565b9060ff604051926349b11d3760e01b8452166004830152610200518260248173b04c1e546d7cf8dc39e10dfc17148475737908065af4908115613d4557613f5b92610200519261402d575b50604051809381926340604be760e01b8352610200519461012051906004850161354f565b038173b04c1e546d7cf8dc39e10dfc17148475737908065af4908115613d45576102005191614010575b5060208151910120906020815191012003613ffb57613fae612520826101c0516101a0516139be565b9160ff90811660031901908111613fe157600192613fd5613fdb92600d610260510161333b565b90613581565b01613b2b565b634e487b7160e01b61020051526011600452602461020051fd5b6399f4b04160e01b6102005152600461020051fd5b61402791503d8061020051833e61265a818361329f565b38613f85565b6140459192503d8061020051833e61265a818361329f565b9038613f36565b99509496925092949650975060ff8061406f612520856101c0516101a0516139be565b16036140f25760349561409961408b846140b29760ff996139be565b3593600e61026051016139ce565b94909361016051956101405195549060031b1c91615981565b1610156140d35750506134ec61018051610260516102405161022051615c2a565b6134ec9161012051906101805190610260516102405161022051615b97565b63a554dcdf60e01b6102005152600461020051fd5b6141128286886139be565b35613eb8565b61412882600e61026051016139ce565b90549060031b1c61012052613e95565b637ca55c7760e01b6102005152600461020051fd5b614165915060203d811161129057611282818361329f565b38613e6b565b50617f806101e05160071b1660ff6101e05116810460801460ff6101e05116151715613fe1576102a0511415613b22565b506101e05160ff1660068181029180159083049091141715613fe157811415613b1b565b63e9f155db60e01b6102005152600461020051fd5b9750509350935050506102005190600e6102605101915b60ff6101e05116811061425b575050505060ff610180511660ff1960116102605101541617601161026051015560018060401b03610260515460101c16600080516020615e6283398151915263ffffffff60405193169280614256610220519461028051836139de565b0390a3565b8061426960019284876139be565b3561427761192083876139ce565b9055016141ec565b61428a8185876139be565b3560018082161490816142bb575b50156142a657600101613ad0565b63284f145b60e11b6102005152600461020051fd5b600191501138614298565b63301c306b60e01b6102005152600461020051fd5b50600b610280511415613a98565b506009610280511415613a92565b636226556b60e01b6102005152600461020051fd5b8054600160201b600160601b03191660209290921b600160201b600160601b0316919091179055565b92919061434c602091604086526040860190613465565b930152565b95949193909486600052600360205260406000209487600052600460205260406000209663ffffffff80600289015460a01c1691160361487357601060ff885416036148625785546001600160a01b031633036148515760ff169360348510801590614834575b8015614817575b6147ac5761020082036147ac578160801161198d576143de36856133a8565b826101001161198d576143f436608087016133a8565b92806101801161198d5761440c3661010088016133a8565b916020815191012095601e8a019687541491821592614802575b82156147ec575b82156147bd575b50506147ac576040516349b11d3760e01b81526004810187905273b04c1e546d7cf8dc39e10dfc1714847573790806956000826024818a5af48015614667578460209161449f94600091614791575b50604051630f237ed160e21b8152948592839260048401614335565b03818a5af49182156146675760009261475d575b50540361474e57604051630f237ed160e21b81529291602091849182916144de919060048401614335565b0381875af4908115614667578392600092614715575b50604051630f237ed160e21b81529260209184918291614518919060048401614335565b0381875af4918215614667576000926146e1575b50036146d5576040516349b11d3760e01b81526004810184905290600082602481865af4918215614667576000926146b6575b50601d8601546040516340604be760e01b8152926000928492839261458892906004850161354f565b0381855af49081156146675760009161469b575b506020815191012091602185019283540361468f57604051906349b11d3760e01b82526004820152600081602481855af480156146675761460a926000928392614673575b50601c870154601b8801546040516340604be760e01b815295869485938493916004850161354f565b03915af49081156146675760009161464c575b506020815191012090540361464357906134ec929160ff601983015460101c16926157a3565b6134ec92615670565b61466191503d806000833e61265a818361329f565b3861461d565b6040513d6000823e3d90fd5b6146889192503d8085833e61265a818361329f565b90386145e1565b5050506134ec92615722565b6146b091503d806000833e61265a818361329f565b3861459c565b60009192506146ce903d8084833e61265a818361329f565b919061455f565b5050506134ec92615670565b9091506020813d60201161470d575b816146fd6020938361329f565b8101031261198d5751903861452c565b3d91506146f0565b925090506020823d602011614746575b816147326020938361329f565b8101031261198d57905182916145186144f4565b3d9150614725565b5050505050506134ec92615670565b9091506020813d602011614789575b816147796020938361329f565b8101031261198d575190386144b3565b3d915061476c565b6147a691503d806000833e61265a818361329f565b38614483565b63a554dcdf60e01b60005260046000fd5b9091506102001161198d576147d7906101803691016133a8565b60208151910120602189015414153880614434565b91508251602084012060208b015414159161442d565b85516020870120601f8c015414159250614426565b506001808416148061482a575b156143bf565b5060018311614824565b5060018082161480614847575b156143b8565b5060018111614841565b6393687c0b60e01b60005260046000fd5b63301c306b60e01b60005260046000fd5b636226556b60e01b60005260046000fd5b6001600160401b03811161326e5760051b60200190565b906148a582614884565b6148b2604051918261329f565b82815280926148c3601f1991614884565b0190602036910137565b80518210156132e55760209160051b010190565b9063ffffffff6040519254818116845260201c1660208301526134ec60408361329f565b60405191906000835b60048210614924575050506134ec60808361329f565b600160208192855481520193019101909161490e565b60ff608091548181168452818160081c166020850152818160101c166040850152818160181c16606085015260201c16910152565b939096919497929895986101e05260e0526102405261026052600061028052806102805152600360205260406102805120948161028051526004602052604061028051209663ffffffff600288015460a01c1663ffffffff8716036151d957600f60ff895416036151c45760018701546001600160a01b031633036151af57603460ff85161080159061518c575b801561516b575b61514857610200811480159061515d575b6151485760ff6019890154166080528060801161514157614a3636836133a8565b61010052806101001161514157614a5036608084016133a8565b6101c052806101801161514157614a6b3661010084016133a8565b6101a0526102001161514157614a86906101803691016133a8565b60048701546102a05260c0808052604051610220819052919591614aaa919061329f565b60c0516102205136903761028051610200525b6006610200511015614b2d5761028051614b13576102005150600061028052614af06102005161026051610240516139be565b3561028051506102005160051b6102205101526001610200510161020052614abd565b634e487b7160e01b61028051526011600452602461028051fd5b60405163af0586a360e01b81526102a05160048201526001602482015260ff84166044820152610140606482015260208180614b70610144820161010051613465565b614b80608483016102205161348a565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af490811561502c576102805191615122575b50156150b05760058701546101605260c051604051610180819052614bcf919061329f565b60c05161018051369037610280515b6006811015614c205761028051614b13578060060190816006116131ea57614c0f60019261026051610240516139be565b358160051b61018051015201614bde565b5090919293949560405163af0586a360e01b8152610160516004820152600260248201526080516044820152610140606482015260208180614c6961014482016101c051613465565b614c79608483016101805161348a565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af490811561502c576102805191615103575b50156150b05760068101546101205260c051604051610140819052614cc8919061329f565b60c05161014051369037610280515b6006811015614d195761028051614b135780600c019081600c116131ea57614d0860019261026051610240516139be565b358160051b61014051015201614cd7565b5090919293949560405163af0586a360e01b8152610120516004820152600360248201526080516044820152610140606482015260208180614d6261014482016101a051613465565b614d72608483016101405161348a565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af490811561502c5761028051916150e4575b50156150b057600782015460c05160405160a0819052919891614dbf919061329f565b60c05160a051369037610280515b6006811015614e0e5761028051614b13578060120190816012116131ea57614dfe60019261026051610240516139be565b358160051b60a051015201614dcd565b50909192939495966020614e3f916040518093819263af0586a360e01b83528660a0519160805190600486016134b2565b03817376a5e1d2e03838dabdce38f3372510ba53cabf085af490811561502c5761028051916150c5575b50156150b05773b04c1e546d7cf8dc39e10dfc171484757379080660405190630f237ed160e21b825260208280614eaa6101e0516101005160048401614335565b0381845af491821561502c57610280519261507c575b506101c051519160206101c051019283200361506c57604051630f237ed160e21b815260208180614ef86101e0518860048401614335565b0381855af490811561502c57610280519161503a575b5060206040518093630f237ed160e21b82528180614f3560e0516101a05160048401614335565b03915af491821561502c576102805192614ff8575b5003614fe9576101e051601a85015560e051601b850155610100518051602091820120601e8601556101c05151909120601f8501556101a051805190820120848201558151918101919091206021840155825460ff191660101783557f1b2ab5b594fd7d4b1494f908fa143ff6f2f9879b399e1d17f68ec54f44241b8f93909263ffffffff92614fdb9190876158ad565b60ff604051961686521693a3565b50509150916134ec9350615722565b9091506020813d602011615024575b816150146020938361329f565b8101031261198d57519038614f4a565b3d9150615007565b6040513d61028051823e3d90fd5b90506020813d602011615064575b816150556020938361329f565b8101031261198d575138614f0e565b3d9150615048565b5050509150916134ec9350615722565b9091506020813d6020116150a8575b816150986020938361329f565b8101031261198d57519038614ec0565b3d915061508b565b637ca55c7760e01b6102805152600461028051fd5b6150de915060203d60201161129057611282818361329f565b38614e69565b6150fd915060203d60201161129057611282818361329f565b38614d9c565b61511c915060203d60201161129057611282818361329f565b38614ca3565b61513b915060203d60201161129057611282818361329f565b38614baa565b6102805180fd5b63a554dcdf60e01b6102805152600461028051fd5b506018610260511415614a15565b5060018060e051161480615180575b15614a04565b50600160e0511161517a565b506001806101e0511614806151a2575b156149fd565b5060016101e0511161519c565b6338b72ae960e11b6102805152600461028051fd5b63301c306b60e01b6102805152600461028051fd5b636226556b60e01b6102805152600461028051fd5b6001600160401b0391821690821601919082116131ea57565b63ffffffff60019116019063ffffffff82116131ea57565b9063ffffffff8091169116019063ffffffff82116131ea57565b9063ffffffff8091169116039063ffffffff82116131ea57565b63ffffffff91821681529116602082015260400190565b805463ffffffff60a01b191660a09290921b63ffffffff60a01b16919091179055565b80546001600160a01b03928316921682146152ca57600101546001600160a01b0316146152c55763abca351760e01b60005260046000fd5b600190565b5050600090565b61298b6134ec9361532761530360016129a095019263ffffffff6152f58886613599565b90549060031b1c1690615cc6565b94612d056153118285613599565b6129a08963ffffffff84548460031b1c16615239565b90613599565b805463ffffffff60c01b191660c09290921b63ffffffff60c01b16919091179055565b6134ec9381600080516020615e02833981519152606063ffffffff6003880154169361539b63ffffffff61271061539261ffff60018c015460b81c16896131d7565b04168096615239565b946153c26153ac8360018c01613599565b6129a08963ffffffff84548460031b1c1661521f565b63ffffffff8060028a016153e56153df8584845460c01c1661521f565b8261532d565b5460a01c169660ff604051941684521660208301526040820152a3615ce6565b818110615410575050565b60008155600101615405565b60048101905b81811061542d575050565b60008155600101615422565b6000815561544d6002820160018301615405565b61545d6003820160028301615405565b600060038201556154706004820161541c565b6000600c82016154838160088501615405565b556000600e820161549781600d8501615405565b6154a5601184018092615405565b5560168101601282015b818110615517575060188201905b81811061550257506134ec916154d9601e926019830190615405565b600060198201556000601a8201556000601b8201556000601c8201556000601d8201550161541c565b80615511600180930182615405565b016154bd565b80615526600280930182615405565b016154af565b60018201805460ff60a01b1916600360a01b1781558254600284015492937ffabca260174d01cb14c0ba7f3a1678d899165a405e9f9781f2d21cc5ab7bdab8936060939192916155a760a084901c63ffffffff61559d828260036155948360e08b901c6131d7565b9a0154166131d7565b9460c01c166131d7565b9284615648575b508161561b575b50816155e5575b8560005260046020526155d26040600020615439565b60405192835260208301526040820152a2565b85600052600560205260018060a01b036040600020541660005260066020526040600020615614838254613368565b90556155bc565b546001600160a01b031660009081526006602052604090208054615640908390613368565b9055386155b5565b60018060a01b031660005260066020526040600020615668858254613368565b9055386155ae565b80600080516020615e2283398151915260206134ec956156dc600182019163ffffffff60036156d26156b1600096848082541691546004861b1c169061521f565b836156c46002870192828454169061521f565b91546004851b1c169061521f565b920154169061521f565b6002870160018060e01b03815416905563ffffffff60038801911663ffffffff198254161790558381526004825261571660408220615439565b604051908152a261552c565b61575f6134ec93615754600182019163ffffffff60036156d26156b1600096848082541691546004861b1c169061521f565b90506002840161322f565b6003820163ffffffff1981541690558060005260046020526157846040600020615439565b80600080516020615e22833981519152602060405160018152a261552c565b600080516020615e2283398151915260206134ec95615716604085969760ff6157ed600183019263ffffffff60036156d26156b1600097848082541691546004861b1c169061521f565b9416938461582a5760028a0160018060e01b03815416905563ffffffff60038b01911663ffffffff198254161790555b8681526004855220615439565b6158379060028b0161322f565b60038901805463ffffffff1916905561581d565b6040519193929060c061585e818561329f565b3684378260005b60068110156158a5576006840290848204600614851517156131ea5761589761589082600194613368565b89866139be565b358160051b87015201615865565b509450505050565b9060ff6002600080516020615e6283398151915292019361425663ffffffff611c8c81885460801c1660018060401b0342166151ee565b9060ff6002600080516020615e6283398151915292019361425663ffffffff611c8c81885460601c1660018060401b0342166151ee565b9061ff0082549160081b169061ff001916179055565b60ff16600781146159535760091461594b57600890600190565b600790600190565b50600490600390565b9161597361354c9492604085526040850190613465565b92602081850391015261399d565b9092919593949560808614801590615b8c575b6147ac5760006159d09573b04c1e546d7cf8dc39e10dfc171484757379080698604051978892839263d325c5b160e01b8452876004850161595c565b03818a5af494851561466757600095615b6a575b506000615a06916040518093819263631ec63f60e01b83528960048401614335565b03818a5af490811561466757600091615b4f575b5060208151910120906020815191012003615b005760405163d325c5b160e01b81529360009185918291615a539190876004850161595c565b0381875af492831561466757600093615b2c575b506000615a89916040518093819263631ec63f60e01b83528760048401614335565b0381875af490811561466757600091615b11575b5060208151910120906020815191012003615b0057806020809251910120602460405180948193633b8c1f2d60e21b835260048301525af490811561466757600091615ae7575090565b61354c915060203d60201161217657612163818361329f565b638ba09fd960e01b60005260046000fd5b615b2691503d806000833e61265a818361329f565b38615a9d565b615a89919350615b476000913d8084833e61265a818361329f565b939150615a67565b615b6491503d806000833e61265a818361329f565b38615a1a565b615b84600091615a0693973d8091833e61265a818361329f565b9591506159e4565b506080851415615994565b94600260ff92615c0b606096957fd3060bf93343487b796703319013dda402debbb3819e37ca26f987571ca09805989a63ffffffff95615bf08d601985018a8c168b1982541617815561ff0080198254161781556135d0565b601c830155601d820155600f8619825416178155828a6158ad565b015460a01c1695816040519316835216602082015260ff6040820152a3565b60038301805460ff60901b1916609086901b60ff60901b16179055600094939092919073ecfafd597d0ffe9d9ba32feaa2f12f12f2bb86dc86813b1561036e5760249160405192838092631067a2ef60e11b82528860048301525af4801561199a579661207892916134ec9798615cb6575b5050612d0563ffffffff600285015460401c1682866152d1565b81615cc09161329f565b38615c9c565b9063ffffffff811663ffffffff831610600014615ce1575090565b905090565b9160010160009063ffffffff808083541692615d0660028701948561322f565b54600460031b1c1691816003860193168219845416178355615d5c604083835460a01c1695615d3d615d3788615207565b8561526a565b615d4e600180841b0342168761430c565b888152600460205220615439565b5460e01c9154169184600080516020615da283398151915260405180615d83878783615253565b0390a315908115615d98575b5061373b575050565b90501538615d8f56fe59d3350cb221a36e23b483076e38f2c093b609b0aebdfdeb03d0512d7d5a2315134e07fe001e0bc82a08476763b074f743a6d3b7aa79f27bf2deff8f576129c66d007a5bc0a881f142027c9c5a95f04f9f8ec48e7f9c4b538aef7ac8d8397ede30e1dec6db2d80ec3e362df6665049ac592e8cc98d7b236d0c61681304da81340cd5cc6eac0dc3c714a186b81c618ab602c9b02830ba885dc7af3e76dbfc5c349b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f008e0405abb6bd265a8563b4e6fb2118d701c6055b85e736e6b75e062b5d2e0f28a2646970667358221220ffcb69456a0b24ba9cd329cc2d2b2d5233221b9e3a8286b72c65191b8641030664736f6c634300081c0033