xDAI Price: $0.999993 (-0.03%)
Gas: 0 GWei

Contract

0xc12C1E50ABB450d6205Ea2C3Fa861b3B834d13e8

Overview

xDAI Balance

Gnosis Chain LogoGnosis Chain LogoGnosis Chain Logo0 xDAI

xDAI Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Wrap391938012025-03-24 3:44:103 mins ago1742787850IN
0xc12C1E50...B834d13e8
0 xDAI0.000085841
Wrap391937852025-03-24 3:42:504 mins ago1742787770IN
0xc12C1E50...B834d13e8
0 xDAI0.000085921
Safe Transfer Fr...391937842025-03-24 3:42:404 mins ago1742787760IN
0xc12C1E50...B834d13e8
0 xDAI0.000140161
Wrap391937802025-03-24 3:42:205 mins ago1742787740IN
0xc12C1E50...B834d13e8
0 xDAI0.00008591
Safe Transfer Fr...391937782025-03-24 3:42:105 mins ago1742787730IN
0xc12C1E50...B834d13e8
0 xDAI0.000140111
Wrap391937762025-03-24 3:42:005 mins ago1742787720IN
0xc12C1E50...B834d13e8
0 xDAI0.000092811
Safe Transfer Fr...391937742025-03-24 3:41:505 mins ago1742787710IN
0xc12C1E50...B834d13e8
0 xDAI0.000160641
Wrap391910752025-03-23 23:52:253 hrs ago1742773945IN
0xc12C1E50...B834d13e8
0 xDAI0.000087981
Wrap391910572025-03-23 23:50:553 hrs ago1742773855IN
0xc12C1E50...B834d13e8
0 xDAI0.000088061
Wrap391910502025-03-23 23:50:203 hrs ago1742773820IN
0xc12C1E50...B834d13e8
0 xDAI0.000088061
Wrap391910482025-03-23 23:50:103 hrs ago1742773810IN
0xc12C1E50...B834d13e8
0 xDAI0.000085871
Wrap391910482025-03-23 23:50:103 hrs ago1742773810IN
0xc12C1E50...B834d13e8
0 xDAI0.000088061
Safe Transfer Fr...391910462025-03-23 23:50:003 hrs ago1742773800IN
0xc12C1E50...B834d13e8
0 xDAI0.000140161
Wrap391910302025-03-23 23:48:403 hrs ago1742773720IN
0xc12C1E50...B834d13e8
0 xDAI0.000085861.00000001
Safe Transfer Fr...391910292025-03-23 23:48:353 hrs ago1742773715IN
0xc12C1E50...B834d13e8
0 xDAI0.000140131.00000001
Wrap391910272025-03-23 23:48:253 hrs ago1742773705IN
0xc12C1E50...B834d13e8
0 xDAI0.000085781
Wrap391909942025-03-23 23:45:354 hrs ago1742773535IN
0xc12C1E50...B834d13e8
0 xDAI0.000085871
Safe Transfer Fr...391909932025-03-23 23:45:304 hrs ago1742773530IN
0xc12C1E50...B834d13e8
0 xDAI0.000140161
Wrap391909862025-03-23 23:44:554 hrs ago1742773495IN
0xc12C1E50...B834d13e8
0 xDAI0.000085841
Safe Transfer Fr...391909842025-03-23 23:44:454 hrs ago1742773485IN
0xc12C1E50...B834d13e8
0 xDAI0.000140111
Wrap391909822025-03-23 23:44:354 hrs ago1742773475IN
0xc12C1E50...B834d13e8
0 xDAI0.000085871
Safe Transfer Fr...391909802025-03-23 23:44:254 hrs ago1742773465IN
0xc12C1E50...B834d13e8
0 xDAI0.000140161
Wrap391907232025-03-23 23:22:354 hrs ago1742772155IN
0xc12C1E50...B834d13e8
0 xDAI0.000087981
Wrap391906942025-03-23 23:20:004 hrs ago1742772000IN
0xc12C1E50...B834d13e8
0 xDAI0.000085781
Wrap391906932025-03-23 23:19:554 hrs ago1742771995IN
0xc12C1E50...B834d13e8
0 xDAI0.000088071
View all transactions

View more zero value Internal Transactions in Advanced View mode

Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x2200542D...3EEDE24FA
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Hub

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion, GNU AGPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at gnosisscan.io on 2024-10-12
*/

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.24 ^0.8.0 ^0.8.20;

// lib/abdk-libraries-solidity/ABDKMath64x64.sol

/*
 * ABDK Math 64.64 Smart Contract Library.  Copyright © 2019 by ABDK Consulting.
 * Author: Mikhail Vladimirov <[email protected]>
 */

/**
 * Smart contract library of mathematical functions operating with signed
 * 64.64-bit fixed point numbers.  Signed 64.64-bit fixed point number is
 * basically a simple fraction whose numerator is signed 128-bit integer and
 * denominator is 2^64.  As long as denominator is always the same, there is no
 * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are
 * represented by int128 type holding only the numerator.
 */
library ABDKMath64x64 {
  /*
   * Minimum value signed 64.64-bit fixed point number may have. 
   */
  int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;

  /*
   * Maximum value signed 64.64-bit fixed point number may have. 
   */
  int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

  /**
   * Convert signed 256-bit integer number into signed 64.64-bit fixed point
   * number.  Revert on overflow.
   *
   * @param x signed 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function fromInt (int256 x) internal pure returns (int128) {
    unchecked {
      require (x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF);
      return int128 (x << 64);
    }
  }

  /**
   * Convert signed 64.64 fixed point number into signed 64-bit integer number
   * rounding down.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64-bit integer number
   */
  function toInt (int128 x) internal pure returns (int64) {
    unchecked {
      return int64 (x >> 64);
    }
  }

  /**
   * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point
   * number.  Revert on overflow.
   *
   * @param x unsigned 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function fromUInt (uint256 x) internal pure returns (int128) {
    unchecked {
      require (x <= 0x7FFFFFFFFFFFFFFF);
      return int128 (int256 (x << 64));
    }
  }

  /**
   * Convert signed 64.64 fixed point number into unsigned 64-bit integer
   * number rounding down.  Revert on underflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return unsigned 64-bit integer number
   */
  function toUInt (int128 x) internal pure returns (uint64) {
    unchecked {
      require (x >= 0);
      return uint64 (uint128 (x >> 64));
    }
  }

  /**
   * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point
   * number rounding down.  Revert on overflow.
   *
   * @param x signed 128.128-bin fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function from128x128 (int256 x) internal pure returns (int128) {
    unchecked {
      int256 result = x >> 64;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Convert signed 64.64 fixed point number into signed 128.128 fixed point
   * number.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 128.128 fixed point number
   */
  function to128x128 (int128 x) internal pure returns (int256) {
    unchecked {
      return int256 (x) << 64;
    }
  }

  /**
   * Calculate x + y.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function add (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) + y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x - y.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function sub (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) - y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x * y rounding down.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function mul (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) * y >> 64;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point
   * number and y is signed 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64 fixed point number
   * @param y signed 256-bit integer number
   * @return signed 256-bit integer number
   */
  function muli (int128 x, int256 y) internal pure returns (int256) {
    unchecked {
      if (x == MIN_64x64) {
        require (y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF &&
          y <= 0x1000000000000000000000000000000000000000000000000);
        return -y << 63;
      } else {
        bool negativeResult = false;
        if (x < 0) {
          x = -x;
          negativeResult = true;
        }
        if (y < 0) {
          y = -y; // We rely on overflow behavior here
          negativeResult = !negativeResult;
        }
        uint256 absoluteResult = mulu (x, uint256 (y));
        if (negativeResult) {
          require (absoluteResult <=
            0x8000000000000000000000000000000000000000000000000000000000000000);
          return -int256 (absoluteResult); // We rely on overflow behavior here
        } else {
          require (absoluteResult <=
            0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
          return int256 (absoluteResult);
        }
      }
    }
  }

  /**
   * Calculate x * y rounding down, where x is signed 64.64 fixed point number
   * and y is unsigned 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64 fixed point number
   * @param y unsigned 256-bit integer number
   * @return unsigned 256-bit integer number
   */
  function mulu (int128 x, uint256 y) internal pure returns (uint256) {
    unchecked {
      if (y == 0) return 0;

      require (x >= 0);

      uint256 lo = (uint256 (int256 (x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;
      uint256 hi = uint256 (int256 (x)) * (y >> 128);

      require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
      hi <<= 64;

      require (hi <=
        0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo);
      return hi + lo;
    }
  }

  /**
   * Calculate x / y rounding towards zero.  Revert on overflow or when y is
   * zero.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function div (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);
      int256 result = (int256 (x) << 64) / y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are signed 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x signed 256-bit integer number
   * @param y signed 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function divi (int256 x, int256 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);

      bool negativeResult = false;
      if (x < 0) {
        x = -x; // We rely on overflow behavior here
        negativeResult = true;
      }
      if (y < 0) {
        y = -y; // We rely on overflow behavior here
        negativeResult = !negativeResult;
      }
      uint128 absoluteResult = divuu (uint256 (x), uint256 (y));
      if (negativeResult) {
        require (absoluteResult <= 0x80000000000000000000000000000000);
        return -int128 (absoluteResult); // We rely on overflow behavior here
      } else {
        require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
        return int128 (absoluteResult); // We rely on overflow behavior here
      }
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x unsigned 256-bit integer number
   * @param y unsigned 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function divu (uint256 x, uint256 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);
      uint128 result = divuu (x, y);
      require (result <= uint128 (MAX_64x64));
      return int128 (result);
    }
  }

  /**
   * Calculate -x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function neg (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != MIN_64x64);
      return -x;
    }
  }

  /**
   * Calculate |x|.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function abs (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != MIN_64x64);
      return x < 0 ? -x : x;
    }
  }

  /**
   * Calculate 1 / x rounding towards zero.  Revert on overflow or when x is
   * zero.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function inv (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != 0);
      int256 result = int256 (0x100000000000000000000000000000000) / x;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function avg (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      return int128 ((int256 (x) + int256 (y)) >> 1);
    }
  }

  /**
   * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.
   * Revert on overflow or in case x * y is negative.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function gavg (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 m = int256 (x) * int256 (y);
      require (m >= 0);
      require (m <
          0x4000000000000000000000000000000000000000000000000000000000000000);
      return int128 (sqrtu (uint256 (m)));
    }
  }

  /**
   * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number
   * and y is unsigned 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y uint256 value
   * @return signed 64.64-bit fixed point number
   */
  function pow (int128 x, uint256 y) internal pure returns (int128) {
    unchecked {
      bool negative = x < 0 && y & 1 == 1;

      uint256 absX = uint128 (x < 0 ? -x : x);
      uint256 absResult;
      absResult = 0x100000000000000000000000000000000;

      if (absX <= 0x10000000000000000) {
        absX <<= 63;
        while (y != 0) {
          if (y & 0x1 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x2 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x4 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x8 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          y >>= 4;
        }

        absResult >>= 64;
      } else {
        uint256 absXShift = 63;
        if (absX < 0x1000000000000000000000000) { absX <<= 32; absXShift -= 32; }
        if (absX < 0x10000000000000000000000000000) { absX <<= 16; absXShift -= 16; }
        if (absX < 0x1000000000000000000000000000000) { absX <<= 8; absXShift -= 8; }
        if (absX < 0x10000000000000000000000000000000) { absX <<= 4; absXShift -= 4; }
        if (absX < 0x40000000000000000000000000000000) { absX <<= 2; absXShift -= 2; }
        if (absX < 0x80000000000000000000000000000000) { absX <<= 1; absXShift -= 1; }

        uint256 resultShift = 0;
        while (y != 0) {
          require (absXShift < 64);

          if (y & 0x1 != 0) {
            absResult = absResult * absX >> 127;
            resultShift += absXShift;
            if (absResult > 0x100000000000000000000000000000000) {
              absResult >>= 1;
              resultShift += 1;
            }
          }
          absX = absX * absX >> 127;
          absXShift <<= 1;
          if (absX >= 0x100000000000000000000000000000000) {
              absX >>= 1;
              absXShift += 1;
          }

          y >>= 1;
        }

        require (resultShift < 64);
        absResult >>= 64 - resultShift;
      }
      int256 result = negative ? -int256 (absResult) : int256 (absResult);
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate sqrt (x) rounding down.  Revert if x < 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function sqrt (int128 x) internal pure returns (int128) {
    unchecked {
      require (x >= 0);
      return int128 (sqrtu (uint256 (int256 (x)) << 64));
    }
  }

  /**
   * Calculate binary logarithm of x.  Revert if x <= 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function log_2 (int128 x) internal pure returns (int128) {
    unchecked {
      require (x > 0);

      int256 msb = 0;
      int256 xc = x;
      if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; }
      if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
      if (xc >= 0x10000) { xc >>= 16; msb += 16; }
      if (xc >= 0x100) { xc >>= 8; msb += 8; }
      if (xc >= 0x10) { xc >>= 4; msb += 4; }
      if (xc >= 0x4) { xc >>= 2; msb += 2; }
      if (xc >= 0x2) msb += 1;  // No need to shift xc anymore

      int256 result = msb - 64 << 64;
      uint256 ux = uint256 (int256 (x)) << uint256 (127 - msb);
      for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {
        ux *= ux;
        uint256 b = ux >> 255;
        ux >>= 127 + b;
        result += bit * int256 (b);
      }

      return int128 (result);
    }
  }

  /**
   * Calculate natural logarithm of x.  Revert if x <= 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function ln (int128 x) internal pure returns (int128) {
    unchecked {
      require (x > 0);

      return int128 (int256 (
          uint256 (int256 (log_2 (x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128));
    }
  }

  /**
   * Calculate binary exponent of x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function exp_2 (int128 x) internal pure returns (int128) {
    unchecked {
      require (x < 0x400000000000000000); // Overflow

      if (x < -0x400000000000000000) return 0; // Underflow

      uint256 result = 0x80000000000000000000000000000000;

      if (x & 0x8000000000000000 > 0)
        result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128;
      if (x & 0x4000000000000000 > 0)
        result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128;
      if (x & 0x2000000000000000 > 0)
        result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128;
      if (x & 0x1000000000000000 > 0)
        result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128;
      if (x & 0x800000000000000 > 0)
        result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128;
      if (x & 0x400000000000000 > 0)
        result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128;
      if (x & 0x200000000000000 > 0)
        result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128;
      if (x & 0x100000000000000 > 0)
        result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128;
      if (x & 0x80000000000000 > 0)
        result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128;
      if (x & 0x40000000000000 > 0)
        result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128;
      if (x & 0x20000000000000 > 0)
        result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128;
      if (x & 0x10000000000000 > 0)
        result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128;
      if (x & 0x8000000000000 > 0)
        result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128;
      if (x & 0x4000000000000 > 0)
        result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128;
      if (x & 0x2000000000000 > 0)
        result = result * 0x1000162E525EE054754457D5995292026 >> 128;
      if (x & 0x1000000000000 > 0)
        result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128;
      if (x & 0x800000000000 > 0)
        result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128;
      if (x & 0x400000000000 > 0)
        result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128;
      if (x & 0x200000000000 > 0)
        result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128;
      if (x & 0x100000000000 > 0)
        result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128;
      if (x & 0x80000000000 > 0)
        result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128;
      if (x & 0x40000000000 > 0)
        result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128;
      if (x & 0x20000000000 > 0)
        result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128;
      if (x & 0x10000000000 > 0)
        result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128;
      if (x & 0x8000000000 > 0)
        result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128;
      if (x & 0x4000000000 > 0)
        result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128;
      if (x & 0x2000000000 > 0)
        result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128;
      if (x & 0x1000000000 > 0)
        result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128;
      if (x & 0x800000000 > 0)
        result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128;
      if (x & 0x400000000 > 0)
        result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128;
      if (x & 0x200000000 > 0)
        result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128;
      if (x & 0x100000000 > 0)
        result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128;
      if (x & 0x80000000 > 0)
        result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128;
      if (x & 0x40000000 > 0)
        result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128;
      if (x & 0x20000000 > 0)
        result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128;
      if (x & 0x10000000 > 0)
        result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128;
      if (x & 0x8000000 > 0)
        result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128;
      if (x & 0x4000000 > 0)
        result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128;
      if (x & 0x2000000 > 0)
        result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128;
      if (x & 0x1000000 > 0)
        result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128;
      if (x & 0x800000 > 0)
        result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128;
      if (x & 0x400000 > 0)
        result = result * 0x100000000002C5C85FDF477B662B26945 >> 128;
      if (x & 0x200000 > 0)
        result = result * 0x10000000000162E42FEFA3AE53369388C >> 128;
      if (x & 0x100000 > 0)
        result = result * 0x100000000000B17217F7D1D351A389D40 >> 128;
      if (x & 0x80000 > 0)
        result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128;
      if (x & 0x40000 > 0)
        result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128;
      if (x & 0x20000 > 0)
        result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128;
      if (x & 0x10000 > 0)
        result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128;
      if (x & 0x8000 > 0)
        result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128;
      if (x & 0x4000 > 0)
        result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128;
      if (x & 0x2000 > 0)
        result = result * 0x1000000000000162E42FEFA39F02B772C >> 128;
      if (x & 0x1000 > 0)
        result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128;
      if (x & 0x800 > 0)
        result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128;
      if (x & 0x400 > 0)
        result = result * 0x100000000000002C5C85FDF473DEA871F >> 128;
      if (x & 0x200 > 0)
        result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128;
      if (x & 0x100 > 0)
        result = result * 0x100000000000000B17217F7D1CF79E949 >> 128;
      if (x & 0x80 > 0)
        result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128;
      if (x & 0x40 > 0)
        result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128;
      if (x & 0x20 > 0)
        result = result * 0x100000000000000162E42FEFA39EF366F >> 128;
      if (x & 0x10 > 0)
        result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128;
      if (x & 0x8 > 0)
        result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128;
      if (x & 0x4 > 0)
        result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128;
      if (x & 0x2 > 0)
        result = result * 0x1000000000000000162E42FEFA39EF358 >> 128;
      if (x & 0x1 > 0)
        result = result * 0x10000000000000000B17217F7D1CF79AB >> 128;

      result >>= uint256 (int256 (63 - (x >> 64)));
      require (result <= uint256 (int256 (MAX_64x64)));

      return int128 (int256 (result));
    }
  }

  /**
   * Calculate natural exponent of x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function exp (int128 x) internal pure returns (int128) {
    unchecked {
      require (x < 0x400000000000000000); // Overflow

      if (x < -0x400000000000000000) return 0; // Underflow

      return exp_2 (
          int128 (int256 (x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128));
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x unsigned 256-bit integer number
   * @param y unsigned 256-bit integer number
   * @return unsigned 64.64-bit fixed point number
   */
  function divuu (uint256 x, uint256 y) private pure returns (uint128) {
    unchecked {
      require (y != 0);

      uint256 result;

      if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
        result = (x << 64) / y;
      else {
        uint256 msb = 192;
        uint256 xc = x >> 192;
        if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
        if (xc >= 0x10000) { xc >>= 16; msb += 16; }
        if (xc >= 0x100) { xc >>= 8; msb += 8; }
        if (xc >= 0x10) { xc >>= 4; msb += 4; }
        if (xc >= 0x4) { xc >>= 2; msb += 2; }
        if (xc >= 0x2) msb += 1;  // No need to shift xc anymore

        result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1);
        require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

        uint256 hi = result * (y >> 128);
        uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

        uint256 xh = x >> 192;
        uint256 xl = x << 64;

        if (xl < lo) xh -= 1;
        xl -= lo; // We rely on overflow behavior here
        lo = hi << 128;
        if (xl < lo) xh -= 1;
        xl -= lo; // We rely on overflow behavior here

        result += xh == hi >> 128 ? xl / y : 1;
      }

      require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
      return uint128 (result);
    }
  }

  /**
   * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
   * number.
   *
   * @param x unsigned 256-bit integer number
   * @return unsigned 128-bit integer number
   */
  function sqrtu (uint256 x) private pure returns (uint128) {
    unchecked {
      if (x == 0) return 0;
      else {
        uint256 xx = x;
        uint256 r = 1;
        if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; }
        if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; }
        if (xx >= 0x100000000) { xx >>= 32; r <<= 16; }
        if (xx >= 0x10000) { xx >>= 16; r <<= 8; }
        if (xx >= 0x100) { xx >>= 8; r <<= 4; }
        if (xx >= 0x10) { xx >>= 4; r <<= 2; }
        if (xx >= 0x4) { r <<= 1; }
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1; // Seven iterations should be enough
        uint256 r1 = x / r;
        return uint128 (r < r1 ? r : r1);
      }
    }
  }
}

// lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol

// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

// lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol

// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// lib/openzeppelin-contracts/contracts/utils/Context.sol

// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

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

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

/**
 * @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 ERC1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     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;
 *     }
 * }
 * ```
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 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) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

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

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

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

    /**
     * @dev Returns an `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            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) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            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) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }
}

// lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

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

// lib/openzeppelin-contracts/contracts/utils/math/Math.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// src/errors/Errors.sol

// Explainer on error codes: 3 leading bits for the error type, 5 bits for the error code.
// +------------+-------------------+-------------+
// | Error Type | Hex Code Range    | Occurances  |
// +------------+-------------------+-------------+
// |     0      | 0x00 to 0x1F      |     32      |
// |     1      | 0x20 to 0x3F      |     32      |
// |     2      | 0x40 to 0x5F      |     32      |
// |     3      | 0x60 to 0x7F      |     32      |
// |     4      | 0x80 to 0x9F      |     32      |
// |     5      | 0xA0 to 0xBF      |     32      |
// |     6      | 0xC0 to 0xDF      |     32      |
// |     7      | 0xE0 to 0xFF      |     32      |
// +------------+-------------------+-------------+
//
// for convenience a reference table for the 32 occurances hex conversions;
// so you can "add" the error type easily
// +------------+------------+------------+------------+------------+------------+------------+------------+
// | Occurrence | Hex Code   | Occurrence | Hex Code   | Occurrence | Hex Code   | Occurrence | Hex Code   |
// +------------+------------+------------+------------+------------+------------+------------+------------+
// |     0      |   0x00     |     1      |   0x01     |     2      |   0x02     |     3      |   0x03     |
// |     4      |   0x04     |     5      |   0x05     |     6      |   0x06     |     7      |   0x07     |
// |     8      |   0x08     |     9      |   0x09     |    10      |   0x0A     |    11      |   0x0B     |
// |    12      |   0x0C     |    13      |   0x0D     |    14      |   0x0E     |    15      |   0x0F     |
// |    16      |   0x10     |    17      |   0x11     |    18      |   0x12     |    19      |   0x13     |
// |    20      |   0x14     |    21      |   0x15     |    22      |   0x16     |    23      |   0x17     |
// |    24      |   0x18     |    25      |   0x19     |    26      |   0x1A     |    27      |   0x1B     |
// |    28      |   0x1C     |    29      |   0x1D     |    30      |   0x1E     |    31      |   0x1F     |
// +------------+------------+------------+------------+------------+------------+------------+------------+

interface ICirclesCompactErrors {
    /**
     * @dev CirclesErrorNoArgs is a generic error that does not require any arguments.
     * error type:
     * 0: 0x00 -> 0x1F CirclesAddressCannotBeZero
     * 1: 0x20 -> 0x3F CirclesArrayMustNotBeEmpty (no occurances anymore; freed up)
     * 2: 0x40 -> 0x5F CirclesAmountMustNotBeZero
     * 3: 0x60 -> 0x7F CirclesHubFlowVerticesMustBeSorted
     * 4: 0x80 -> 0x9F CirclesLogicAssertion
     * 5: 0xA0 -> 0xBF CirclesArraysLengthMismatch
     */
    error CirclesErrorNoArgs(uint8);

    /**
     * @dev CirclesErrorOneAddressArg is a generic error that requires one address argument.
     * error type:
     * 0: 0x00 -> 0x1F CirclesHubMustBeHuman(avatar)
     * 1: 0x20 -> 0x3F CirclesAvatarMustBeRegistered(avatar)
     * 2: 0x40 -> 0x5F CirclesHubGroupIsNotRegistered(group)
     * 3: 0x60 -> 0x7F CirclesHubRegisterAvatarV1MustBeStoppedBeforeEndOfInvitationPeriod(avatar)
     * 4: 0x80 -> 0x9F CirclesHubAvatarAlreadyRegistered(avatar)
     * 5: 0xA0 -> 0xBF CirclesHubInvalidTrustReceiver(trustReceiver)
     * 6: 0xC0 -> 0xDF CirclesERC1155MintBlocked(human, ~mintV1Status~)
     * 7: 0xE0 -> 0xFF CirclesInvalidFunctionCaller(caller)
     */
    error CirclesErrorOneAddressArg(address, uint8);

    /**
     * @dev CirclesErrorAddressUintArgs is a generic error that provides an address and a uint256 as arguments.
     * error type:
     * 0: 0x00 -> 0x1F CirclesHubOperatorNotApprovedForSource(source, streamIndex)
     * 1: 0x20 -> 0x3F CirclesHubFlowEdgeIsNotPermitted(receiver, circlesId)
     * 2: 0x40 -> 0x5F CirclesHubGroupMintPolicyRejectedBurn(burner, toTokenId(group))
     * 3: 0x60 -> 0x7F CirclesHubGroupMintPolicyRejectedMint(minter, toTokenId)
     * 4: 0x80 -> 0x9F CirclesDemurrageAmountExceedsMaxUint192(account, circlesId)
     * 5: 0xA0 -> 0xBF CirclesDemurrageDayBeforeLastUpdatedDay(account, lastDayUpdated)
     */
    error CirclesErrorAddressUintArgs(address, uint256, uint8);
}

interface IHubErrors {
    // CirclesErrorOneAddressArg 3
    // error CirclesHubRegisterAvatarV1MustBeStoppedBeforeEndOfInvitationPeriod(address avatar, uint8 code);

    // CirclesErrorOneAddressArg 4
    // error CirclesHubAvatarAlreadyRegistered(address avatar, uint8 code);

    // CirclesErrorOneAddressArg 0
    // error CirclesHubMustBeHuman(address avatar, uint8 code);

    // CirclesErrorOneAddressArg 2
    // error CirclesHubGroupIsNotRegistered(address group, uint8 code);

    // CirclesErrorOneAddressArg 5
    // error CirclesHubInvalidTrustReceiver(address trustReceiver, uint8 code);

    // CirclesErrorAddressUintArgs 3
    // error CirclesHubGroupMintPolicyRejectedMint(
    //     address minter, address group, uint256[] collateral, uint256[] amounts, bytes data, uint8 code
    // );

    // CirclesErrorAddressUintArgs 2
    // error CirclesHubGroupMintPolicyRejectedBurn(address burner, address group, uint256 amount, bytes data, uint8 code);

    // CirclesErrorAddressUintArgs 0
    // error CirclesHubOperatorNotApprovedForSource(address operator, address source, uint16 streamIndex, uint8 code);

    // CirclesErrorAddressUintArgs 1
    // error CirclesHubFlowEdgeIsNotPermitted(address receiver, uint256 circlesId, uint8 code);

    // CirclesErrorNoArgs 3
    // error CirclesHubFlowVerticesMustBeSorted();

    error CirclesHubFlowEdgeStreamMismatch(uint256 flowEdgeId, uint256 streamId, uint8 code);

    error CirclesHubStreamMismatch(uint256 streamId);

    error CirclesHubNettedFlowMismatch(uint256 vertexPosition, int256 matrixNettedFlow, int256 streamNettedFlow);
}

interface ICirclesDemurrageErrors {
    // CirclesErrorOneAddressArg 6
    // error CirclesERC1155MintBlocked(address human, address mintV1Status);

    // CirclesErrorAddressUintArgs 4
    // error CirclesDemurrageAmountExceedsMaxUint192(address account, uint256 circlesId, uint256 amount, uint8 code);

    // CirclesErrorAddressUintArgs 5
    // error CirclesDemurrageDayBeforeLastUpdatedDay(
    //     address account, uint256 circlesId, uint64 day, uint64 lastUpdatedDay, uint8 code
    // );

    error CirclesERC1155CannotReceiveBatch(uint8 code);
}

interface ICirclesErrors {
    // CirclesErrorOneAddressArg 1
    // error CirclesAvatarMustBeRegistered(address avatar, uint8 code);

    // CirclesErrorNoArgs 0
    // error CirclesAddressCannotBeZero(uint8 code);

    // CirclesErrorOneAddressArg
    // error CirclesInvalidFunctionCaller(address caller, address expectedCaller, uint8 code);

    error CirclesInvalidCirclesId(uint256 id, uint8 code);

    error CirclesInvalidParameter(uint256 parameter, uint8 code);

    error CirclesAmountOverflow(uint256 amount, uint8 code);

    // CirclesErrorNoArgs 5
    // error CirclesArraysLengthMismatch(uint256 lengthArray1, uint256 lengthArray2, uint8 code);

    // CirclesErrorNoArgs 1
    // error CirclesArrayMustNotBeEmpty(uint8 code);

    // CirclesErrorNoArgs 2
    // error CirclesAmountMustNotBeZero(uint8 code);

    error CirclesProxyAlreadyInitialized();

    // CirclesErrorNoArgs 4
    // error CirclesLogicAssertion(uint8 code);

    error CirclesIdMustBeDerivedFromAddress(uint256 providedId, uint8 code);

    error CirclesReentrancyGuard(uint8 code);
}

interface IStandardTreasuryErrors {
    error CirclesStandardTreasuryGroupHasNoVault(address group);

    error CirclesStandardTreasuryRedemptionCollateralMismatch(
        uint256 circlesId, uint256[] redemptionIds, uint256[] redemptionValues, uint256[] burnIds, uint256[] burnValues
    );

    error CirclesStandardTreasuryInvalidMetadataType(bytes32 metadataType, uint8 code);

    error CirclesStandardTreasuryInvalidMetadata(bytes metadata, uint8 code);
}

interface INameRegistryErrors {
    error CirclesNamesInvalidName(address avatar, string name, uint8 code);

    error CirclesNamesShortNameAlreadyAssigned(address avatar, uint72 shortName, uint8 code);

    error CirclesNamesShortNameWithNonceTaken(address avatar, uint256 nonce, uint72 shortName, address takenByAvatar);

    error CirclesNamesAvatarAlreadyHasCustomNameOrSymbol(address avatar, string nameOrSymbol, uint8 code);

    error CirclesNamesOrganizationHasNoSymbol(address organization, uint8 code);

    error CirclesNamesShortNameZero(address avatar, uint256 nonce);
}

interface IMigrationErrors {
    error CirclesMigrationAmountMustBeGreaterThanZero();
}

// src/groups/IMintPolicy.sol

interface IMintPolicy {
    function beforeMintPolicy(
        address minter,
        address group,
        uint256[] calldata collateral,
        uint256[] calldata amounts,
        bytes calldata data
    ) external returns (bool);

    function beforeRedeemPolicy(address operator, address redeemer, address group, uint256 value, bytes calldata data)
        external
        returns (
            uint256[] memory redemptionIds,
            uint256[] memory redemptionValues,
            uint256[] memory burnIds,
            uint256[] memory burnValues
        );

    function beforeBurnPolicy(address burner, address group, uint256 value, bytes calldata data)
        external
        returns (bool);
}

// src/hub/TypeDefinitions.sol

contract TypeDefinitions {
    // Type declarations

    /**
     * @notice TrustMarker stores the expiry of a trust relation as uint96,
     * and is iterable as a linked list of trust markers.
     * @dev This is used to store the directional trust relation between two avatars,
     * and the expiry of the trust relation as uint96 in unix time.
     */
    struct TrustMarker {
        address previous;
        uint96 expiry;
    }

    struct FlowEdge {
        uint16 streamSinkId;
        uint192 amount;
    }

    struct Stream {
        uint16 sourceCoordinate;
        uint16[] flowEdgeIds; // todo: this can possible be packed more compactly manually, evaluate
        bytes data;
    }

    struct Metadata {
        bytes32 metadataType;
        bytes metadata;
        bytes erc1155UserData;
    }

    struct GroupMintMetadata {
        address group;
    }

    // note: Redemption does not require Metadata

    // Constants

    bytes32 internal constant METADATATYPE_GROUPMINT = keccak256("CIRCLESv2:RESERVED_DATA:CirclesGroupMint");
    bytes32 internal constant METADATATYPE_GROUPREDEEM = keccak256("CIRCLESv2:RESERVED_DATA:CirclesGroupRedeem");
}

// src/lift/IERC20Lift.sol

enum CirclesType {
    Demurrage,
    Inflation
}

interface IERC20Lift {
    function ensureERC20(address avatar, CirclesType circlesType) external returns (address);
}

// src/migration/IHub.sol

/**
 * @title IHub v1
 * @author Circles
 * @notice legacy interface of Hub contract in Circles v1
 */
interface IHubV1 {
    function signup() external;
    function signupBonus() external view returns (uint256);
    function organizationSignup() external;
    function symbol() external view returns (string memory);
    function name() external view returns (string memory);

    function tokenToUser(address token) external view returns (address);
    function userToToken(address user) external view returns (address);
    function limits(address truster, address trustee) external returns (uint256);

    function trust(address trustee, uint256 limit) external;

    function deployedAt() external view returns (uint256);
    function initialIssuance() external view returns (uint256);
    function issuance() external view returns (uint256);
    function issuanceByStep(uint256 periods) external view returns (uint256);
    function inflate(uint256 initial, uint256 periods) external view returns (uint256);
    function inflation() external view returns (uint256);
    function divisor() external view returns (uint256);
    function period() external view returns (uint256);
    function periods() external view returns (uint256);
    function timeout() external view returns (uint256);
}

// src/names/INameRegistry.sol

interface INameRegistry {
    function setMetadataDigest(address avatar, bytes32 metadataDigest) external;
    function registerCustomName(address avatar, string calldata name) external;
    function registerCustomSymbol(address avatar, string calldata symbol) external;

    function name(address avatar) external view returns (string memory);
    function symbol(address avatar) external view returns (string memory);
    function getMetadataDigest(address _avatar) external view returns (bytes32);

    function isValidName(string calldata name) external pure returns (bool);
    function isValidSymbol(string calldata symbol) external pure returns (bool);
}

// lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol

// OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the value of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155Received} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `value` amount.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.
     *
     * Requirements:
     *
     * - `ids` and `values` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external;
}

// lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol

// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)

/**
 * @dev Interface that must be implemented by smart contracts in order to receive
 * ERC-1155 token transfers.
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

// lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// src/migration/IToken.sol

/**
 * @title IToken v1
 * @author Circles UBI
 * @notice legacy interface of Hub contract in Circles v1
 */
interface ITokenV1 is IERC20 {
    function owner() external view returns (address);

    function stop() external;
    function stopped() external view returns (bool);

    function update() external;

    function lastTouched() external view returns (uint256);
}

// lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol

// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol)

/**
 * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
 * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
 */
interface IERC1155MetadataURI is IERC1155 {
    /**
     * @dev Returns the URI for token type `id`.
     *
     * If the `\{id\}` substring is present in the URI, it must be replaced by
     * clients with the actual token type ID.
     */
    function uri(uint256 id) external view returns (string memory);
}

// lib/openzeppelin-contracts/contracts/utils/Arrays.sol

// OpenZeppelin Contracts (last updated v5.0.0) (utils/Arrays.sol)

/**
 * @dev Collection of functions related to array types.
 */
library Arrays {
    using StorageSlot for bytes32;

    /**
     * @dev Searches a sorted `array` and returns the first index that contains
     * a value greater or equal to `element`. If no such index exists (i.e. all
     * values in the array are strictly less than `element`), the array length is
     * returned. Time complexity O(log n).
     *
     * `array` is expected to be sorted in ascending order, and to contain no
     * repeated elements.
     */
    function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeAccess(array, mid).value > element) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
        if (low > 0 && unsafeAccess(array, low - 1).value == element) {
            return low - 1;
        } else {
            return low;
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
        bytes32 slot;
        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
        // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.

        /// @solidity memory-safe-assembly
        assembly {
            mstore(0, arr.slot)
            slot := add(keccak256(0, 0x20), pos)
        }
        return slot.getAddressSlot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
        bytes32 slot;
        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
        // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.

        /// @solidity memory-safe-assembly
        assembly {
            mstore(0, arr.slot)
            slot := add(keccak256(0, 0x20), pos)
        }
        return slot.getBytes32Slot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
        bytes32 slot;
        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
        // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.

        /// @solidity memory-safe-assembly
        assembly {
            mstore(0, arr.slot)
            slot := add(keccak256(0, 0x20), pos)
        }
        return slot.getUint256Slot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }
}

// src/circles/Demurrage.sol

contract Demurrage is ICirclesCompactErrors, ICirclesDemurrageErrors {
    // Type declarations

    /**
     * @dev Discounted balance with a last updated timestamp.
     * Note: The balance is stored as a 192-bit unsigned integer.
     * The last updated timestamp is stored as a 64-bit unsigned integer counting the days
     * since `inflation_day_zero` (for elegance, to not start the clock in 1970 with unix time).
     * We ensure that they combine to 32 bytes for a single Ethereum storage slot.
     * Note: The maximum total supply of CRC is ~10^5 per human, with 10**10 humans,
     * so even if all humans would pool all their tokens into a single group and then a single account
     * the total resolution required is 10^(10 + 5 + 18) = 10^33 << 10**57 (~ max uint192).
     */
    struct DiscountedBalance {
        uint192 balance;
        uint64 lastUpdatedDay;
    }

    // Constants

    /**
     * @notice Demurrage window reduces the resolution for calculating
     * the demurrage of balances from once per second (block.timestamp)
     * to once per day.
     */
    uint256 private constant DEMURRAGE_WINDOW = 1 days;

    /**
     * @dev Maximum value that can be stored or transferred
     */
    uint256 internal constant MAX_VALUE = type(uint192).max;

    /**
     * @dev Reduction factor GAMMA for applying demurrage to balances
     *   demurrage_balance(d) = GAMMA^d * inflationary_balance
     * where 'd' is expressed in days (DEMURRAGE_WINDOW) since demurrage_day_zero,
     * and GAMMA < 1.
     * GAMMA_64x64 stores the numerator for the signed 128bit 64.64
     * fixed decimal point expression:
     *   GAMMA = GAMMA_64x64 / 2**64.
     * To obtain GAMMA for a daily accounting of 7% p.a. demurrage
     *   => GAMMA = (0.93)^(1/365.25)
     *            = 0.99980133200859895743...
     * and expressed in 64.64 fixed point representation:
     *   => GAMMA_64x64 = 18443079296116538654
     * For more details, see ./specifications/TCIP009-demurrage.md
     */
    int128 internal constant GAMMA_64x64 = int128(18443079296116538654);

    /**
     * @dev For calculating the inflationary mint amount on day `d`
     * since demurrage_day_zero, a person can mint
     *   (1/GAMMA)^d CRC / hour
     * As GAMMA is a constant, to save gas costs store the inverse
     * as BETA = 1 / GAMMA.
     * BETA_64x64 is the 64.64 fixed point representation:
     *   BETA_64x64 = 2**64 / ((0.93)^(1/365.25))
     *              = 18450409579521241655
     * For more details, see ./specifications/TCIP009-demurrage.md
     */
    int128 internal constant BETA_64x64 = int128(18450409579521241655);

    /**
     * @dev ERC1155 tokens MUST be 18 decimals.
     */
    uint8 internal constant DECIMALS = uint8(18);

    /**
     * @dev EXA factor as 10^18
     */
    uint256 internal constant EXA = uint256(10 ** DECIMALS);

    /**
     * @dev Store the signed 128-bit 64.64 representation of 1 as a constant
     */
    int128 internal constant ONE_64x64 = int128(2 ** 64);

    uint8 internal constant R_TABLE_LOOKUP = uint8(14);

    // State variables

    /**
     * @notice Inflation day zero stores the start of the global inflation curve
     * As Circles Hub v1 was deployed on Thursday 15th October 2020 at 6:25:30 pm UTC,
     * or 1602786330 unix time, in production this value MUST be set to 1602720000 unix time,
     * or midnight prior of the same day of deployment, marking the start of the first day
     * where there was no inflation on one CRC per hour.
     */
    uint256 public inflationDayZero;

    /**
     * @dev Store a lookup table T(n) for computing issuance.
     * T is only accessed for minting in Hub.sol, so it is initialized in
     * storage of Hub.sol during the constructor, by copying these values.
     * (It is not properly intialized in a ERC20 Proxy contract, but we never need
     * to access it there, so it is not a problem - it is only initialized in the
     * storage of the mastercopy during deployment.)
     * See ../../specifications/TCIP009-demurrage.md for more details.
     */
    int128[15] internal T = [
        int128(442721857769029238784),
        int128(885355760875826166476),
        int128(1327901726794166863126),
        int128(1770359772994355928788),
        int128(2212729916943227173193),
        int128(2655012176104144305282),
        int128(3097206567937001622606),
        int128(3539313109898224700583),
        int128(3981331819440771081628),
        int128(4423262714014130964135),
        int128(4865105811064327891331),
        int128(5306861128033919439986),
        int128(5748528682361997908993),
        int128(6190108491484191007805),
        int128(6631600572832662544739)
    ];

    /**
     * @dev Store a lookup table R(n) for computing issuance and demurrage.
     * This table is computed in the constructor of Hub.sol and mastercopy deployments,
     * and lazily computed in the ERC20 Demurrage proxy contracts, then cached into their storage.
     * The non-trivial situation for R(n) (vs T(n)) is that R is accessed
     * from the ERC20 Demurrage proxy contracts, so their storage will not yet
     * have been initialized with the constructor. (Counter to T which is only
     * accessed for minting in Hub.sol, and as such initialized in the constructor
     * of Hub.sol by Solidity by copying the python calculated values stored above.)
     *
     * Computing R in contract is done with .64bits precision, whereas the python computed
     * table is slightly more accurate, but equal within dust (10^-18). See unit tests.
     * However, we want to ensure that Hub.sol and the ERC20 Demurrage proxy contracts
     * use the exact same R values (even if the difference would not matter).
     * So for R we rely on the in-contract computed values.
     * In the unit tests, the table of python computed values is stored in HIGHER_ACCURACY_R,
     * and matched against the solidity computed values.
     * See ../../specifications/TCIP009-demurrage.md for more details.
     */
    int128[15] internal R;

    // Constructor

    constructor() {
        // we need to fill the R table upon construction so that
        // in Hub.sol personalMint has the R table available
        for (uint8 i = 0; i <= R_TABLE_LOOKUP; i++) {
            R[i] = ABDKMath64x64.pow(GAMMA_64x64, i);
        }
    }

    // Public functions

    /**
     * @notice Calculate the day since inflation_day_zero for a given timestamp.
     * @param _timestamp Timestamp for which to calculate the day since inflation_day_zero.
     */
    function day(uint256 _timestamp) public view returns (uint64) {
        // calculate which day the timestamp is in, rounding down
        // note: max uint64 is 2^64 - 1, so we can safely cast the result
        return uint64((_timestamp - inflationDayZero) / DEMURRAGE_WINDOW);
    }

    /**
     * @notice Casts an avatar address to a tokenId uint256.
     * @param _avatar avatar address to convert to tokenId
     */
    function toTokenId(address _avatar) public pure returns (uint256) {
        return uint256(uint160(_avatar));
    }

    /**
     * @notice Converts an inflationary value to a demurrage value for a given day since inflation_day_zero.
     * @param _inflationaryValue Inflationary value to convert to demurrage value.
     * @param _day Day since inflation_day_zero to convert the inflationary value to a demurrage value.
     */
    function convertInflationaryToDemurrageValue(uint256 _inflationaryValue, uint64 _day)
        public
        pure
        returns (uint256)
    {
        // calculate the demurrage value by multiplying the value by GAMMA^days
        // note: GAMMA < 1, so multiplying by a power of it, returns a smaller number,
        //       so we lose the least significant bits, but our ground truth is the demurrage value,
        //       and the inflationary value is a numerical approximation (where the least significant digits
        //       are not reliable).
        int128 r = ABDKMath64x64.pow(GAMMA_64x64, uint256(_day));
        return ABDKMath64x64.mulu(r, _inflationaryValue);
    }

    /**
     * @notice Converts a demurrage value to an inflationary value for a given day since inflation_day_zero.
     * @param _demurrageValue Demurrage value to convert to inflationary value
     * @param _dayUpdated The day the demurrage value was last updated since inflation_day_zero
     */
    function convertDemurrageToInflationaryValue(uint256 _demurrageValue, uint64 _dayUpdated)
        public
        pure
        returns (uint256)
    {
        // calculate the inflationary value by dividing the value by GAMMA^days
        // note: GAMMA < 1, so dividing by a power of it, returns a bigger number,
        //       so the numerical imprecision is introduced in the least significant bits.
        int128 f = ABDKMath64x64.pow(BETA_64x64, uint256(_dayUpdated));
        return ABDKMath64x64.mulu(f, _demurrageValue);
    }

    // Internal functions

    /**
     * @dev Calculates the discounted balance given a number of days to discount
     * @param _balance balance to calculate the discounted balance of
     * @param _daysDifference days of difference between the last updated day and the day of interest
     */
    function _calculateDiscountedBalance(uint256 _balance, uint256 _daysDifference) internal view returns (uint256) {
        if (_daysDifference == 0) {
            return _balance;
        }
        int128 r = _calculateDemurrageFactor(_daysDifference);
        return ABDKMath64x64.mulu(r, _balance);
    }

    function _calculateDiscountedBalanceAndCache(uint256 _balance, uint256 _daysDifference)
        internal
        returns (uint256)
    {
        if (_daysDifference == 0) {
            return _balance;
        }
        int128 r = _calculateDemurrageFactorAndCache(_daysDifference);
        return ABDKMath64x64.mulu(r, _balance);
    }

    function _calculateDemurrageFactor(uint256 _dayDifference) internal view returns (int128) {
        if (_dayDifference <= R_TABLE_LOOKUP) {
            // if the day difference is in the lookup table, return the value from the table
            int128 demurrageFactor = R[_dayDifference];
            if (demurrageFactor != 0) {
                return demurrageFactor;
            }
        }
        // if the day difference is not in the lookup table, calculate the value
        return ABDKMath64x64.pow(GAMMA_64x64, _dayDifference);
    }

    function _calculateDemurrageFactorAndCache(uint256 _dayDifference) internal returns (int128) {
        if (_dayDifference <= R_TABLE_LOOKUP) {
            int128 demurrageFactor = R[_dayDifference];
            if (demurrageFactor == 0) {
                // for proxy ERC20 contracts, the storage does not contain the R table yet
                // so compute it lazily and store it in the table
                demurrageFactor = ABDKMath64x64.pow(GAMMA_64x64, _dayDifference);
                R[_dayDifference] = demurrageFactor;
            }
            return demurrageFactor;
        }
        // if the day difference is for older than 14 days, calculate the value
        // and do not cache it
        return ABDKMath64x64.pow(GAMMA_64x64, _dayDifference);
    }
}

// src/circles/DiscountedBalances.sol

contract DiscountedBalances is Demurrage {
    // State variables

    /**
     * @dev stores the discounted balances of the accounts privately.
     * Mapping from Circles identifiers to accounts to the discounted balance.
     */
    mapping(uint256 => mapping(address => DiscountedBalance)) internal discountedBalances;

    /**
     * @dev stores the total supply for each Circles identifier
     */
    mapping(uint256 => DiscountedBalance) internal discountedTotalSupplies;

    // Events

    event DiscountCost(address indexed account, uint256 indexed id, uint256 discountCost);

    // Constructor

    /**
     * @dev Constructor to set the start of the global inflationary curve.
     * @param _inflation_day_zero Timestamp of midgnight day zero for the global inflationary curve.
     */
    constructor(uint256 _inflation_day_zero) {
        inflationDayZero = _inflation_day_zero;
    }

    // Public functions

    /**
     * @notice Balance of a Circles identifier for a given account on a (future) day.
     * @param _account Address of the account to calculate the balance of
     * @param _id Circles identifier for which to calculate the balance
     * @param _day Day since inflation_day_zero to calculate the balance for
     * @return balanceOnDay_ The discounted balance of the account for the Circles identifier on specified day
     * @return discountCost_ The discount cost of the demurrage of the balance since the last update
     */
    function balanceOfOnDay(address _account, uint256 _id, uint64 _day)
        public
        view
        returns (uint256 balanceOnDay_, uint256 discountCost_)
    {
        DiscountedBalance memory discountedBalance = discountedBalances[_id][_account];
        if (_day < discountedBalance.lastUpdatedDay) {
            // DiscountedBalances: day is before last updated day
            // revert CirclesDemurrageDayBeforeLastUpdatedDay(_account, _id, _day, discountedBalance.lastUpdatedDay, 0);
            revert CirclesErrorAddressUintArgs(_account, discountedBalance.lastUpdatedDay, 0xA0);
        }
        uint256 dayDifference;
        unchecked {
            dayDifference = _day - discountedBalance.lastUpdatedDay;
        }
        // Calculate the discounted balance
        balanceOnDay_ = _calculateDiscountedBalance(discountedBalance.balance, dayDifference);
        // Calculate the discount cost; this can be unchecked as cost is strict positive
        unchecked {
            discountCost_ = discountedBalance.balance - balanceOnDay_;
        }
        return (balanceOnDay_, discountCost_);
    }

    /**
     * @notice Total supply of a Circles identifier.
     * @param _id Circles identifier for which to calculate the total supply
     */
    function totalSupply(uint256 _id) public view returns (uint256) {
        DiscountedBalance memory totalSupplyBalance = discountedTotalSupplies[_id];
        uint64 today = day(block.timestamp);
        return _calculateDiscountedBalance(totalSupplyBalance.balance, today - totalSupplyBalance.lastUpdatedDay);
    }

    // Internal functions

    /**
     * @dev Update the balance of an account for a given Circles identifier
     * @param _account Address of the account to update the balance of
     * @param _id Circles identifier for which to update the balance
     * @param _balance New balance to set
     * @param _day Day since inflation_day_zero to set as last updated day
     */
    function _updateBalance(address _account, uint256 _id, uint256 _balance, uint64 _day) internal {
        if (_balance > MAX_VALUE) {
            // DiscountedBalances: balance exceeds maximum value
            // revert CirclesDemurrageAmountExceedsMaxUint192(_account, _id, _balance, 0);
            revert CirclesErrorAddressUintArgs(_account, _id, 0x81);
        }
        DiscountedBalance memory discountedBalance = discountedBalances[_id][_account];
        discountedBalance.balance = uint192(_balance);
        discountedBalance.lastUpdatedDay = _day;
        discountedBalances[_id][_account] = discountedBalance;
    }

    /**
     * @dev Discount to the given day and add to the balance of an account for a given Circles identifier
     * @param _account Address of the account to update the balance of
     * @param _id Circles identifier for which to update the balance
     * @param _value Value to add to the discounted balance
     * @param _day Day since inflation_day_zero to discount the balance to
     */
    function _discountAndAddToBalance(address _account, uint256 _id, uint256 _value, uint64 _day) internal {
        DiscountedBalance memory discountedBalance = discountedBalances[_id][_account];
        if (_day < discountedBalance.lastUpdatedDay) {
            // DiscountedBalances: day is before last updated day
            // revert CirclesDemurrageDayBeforeLastUpdatedDay(_account, _id, _day, discountedBalance.lastUpdatedDay, 1);
            revert CirclesErrorAddressUintArgs(_account, discountedBalance.lastUpdatedDay, 0xA1);
        }
        uint256 dayDifference;
        unchecked {
            dayDifference = _day - discountedBalance.lastUpdatedDay;
        }
        uint256 discountedBalanceOnDay = _calculateDiscountedBalance(discountedBalance.balance, dayDifference);
        // Calculate the discount cost; this can be unchecked as cost is strict positive
        unchecked {
            uint256 discountCost = discountedBalance.balance - discountedBalanceOnDay;
            if (discountCost > 0) {
                emit IERC1155.TransferSingle(msg.sender, _account, address(0), _id, discountCost);
                emit DiscountCost(_account, _id, discountCost);
            }
        }
        uint256 updatedBalance = discountedBalanceOnDay + _value;
        if (updatedBalance > MAX_VALUE) {
            // DiscountedBalances: balance exceeds maximum value
            // revert CirclesDemurrageAmountExceedsMaxUint190(_account, _id, updatedBalance, 1);
            revert CirclesErrorAddressUintArgs(_account, _id, 0x82);
        }
        discountedBalance.balance = uint192(updatedBalance);
        discountedBalance.lastUpdatedDay = _day;
        discountedBalances[_id][_account] = discountedBalance;
    }
}

// src/circles/ERC1155.sol

// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/ERC1155.sol)

/**
 * @dev Implementation of the basic standard multi-token for demurraged and inflationary balances.
 * See https://eips.ethereum.org/EIPS/eip-1155
 * This code is modified from the open-zeppelin implementation v5.0.0:
 * https://github.com/OpenZeppelin/openzeppelin-contracts/
 * Originally based on code by Enjin: https://github.com/enjin/erc-1155
 */
abstract contract ERC1155 is DiscountedBalances, Context, ERC165, IERC1155, IERC1155MetadataURI, IERC1155Errors {
    // Type declarations

    using Arrays for uint256[];
    using Arrays for address[];

    // State variables

    mapping(address account => mapping(address operator => bool)) private _operatorApprovals;

    // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
    string private _uri;

    // Constructor

    /**
     * @dev See {_setURI}.
     */
    constructor(string memory _newuri) {
        _setURI(_newuri);
    }

    // Public functions

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return _interfaceId == type(IERC1155).interfaceId || _interfaceId == type(IERC1155MetadataURI).interfaceId
            || super.supportsInterface(_interfaceId);
    }

    /**
     * @dev See {IERC1155MetadataURI-uri}.
     *
     * This implementation returns the same URI for *all* token types. It relies
     * on the token type ID substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * Clients calling this function must replace the `\{id\}` substring with the
     * actual token type ID.
     */
    function uri(uint256 /* id */ ) public view virtual returns (string memory) {
        return _uri;
    }

    /**
     * @dev See {IERC1155-balanceOf}.
     */
    function balanceOf(address _account, uint256 _id) public view returns (uint256) {
        (uint256 balance,) = balanceOfOnDay(_account, _id, day(block.timestamp));
        return balance;
    }

    /**
     * @dev See {IERC1155-balanceOfBatch}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] memory _accounts, uint256[] memory _ids) public view returns (uint256[] memory) {
        if (_accounts.length != _ids.length) {
            revert ERC1155InvalidArrayLength(_ids.length, _accounts.length);
        }

        uint64 today = day(block.timestamp);

        uint256[] memory batchBalances = new uint256[](_accounts.length);

        for (uint256 i = 0; i < _accounts.length; ++i) {
            (batchBalances[i],) = balanceOfOnDay(_accounts.unsafeMemoryAccess(i), _ids.unsafeMemoryAccess(i), today);
        }

        return batchBalances;
    }

    /**
     * @dev See {IERC1155-setApprovalForAll}.
     */
    function setApprovalForAll(address _operator, bool _approved) public {
        _setApprovalForAll(_msgSender(), _operator, _approved);
    }

    /**
     * @dev See {IERC1155-isApprovedForAll}.
     */
    function isApprovedForAll(address _account, address _operator) public view returns (bool) {
        return _operatorApprovals[_account][_operator];
    }

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes memory _data) public {
        address sender = _msgSender();
        if (_from != sender && !isApprovedForAll(_from, sender)) {
            revert ERC1155MissingApprovalForAll(sender, _from);
        }
        _safeTransferFrom(_from, _to, _id, _value, _data);
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address _from,
        address _to,
        uint256[] memory _ids,
        uint256[] memory _values,
        bytes memory _data
    ) public virtual {
        address sender = _msgSender();
        if (_from != sender && !isApprovedForAll(_from, sender)) {
            revert ERC1155MissingApprovalForAll(sender, _from);
        }
        _safeBatchTransferFrom(_from, _to, _ids, _values, _data);
    }

    // Internal functions

    /**
     * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from`
     * (or `to`) is the zero address.
     *
     * Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received}
     *   or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value.
     * - `ids` and `values` must have the same length.
     *
     * NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead.
     */
    function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual {
        if (ids.length != values.length) {
            revert ERC1155InvalidArrayLength(ids.length, values.length);
        }

        address operator = _msgSender();

        uint64 today = day(block.timestamp);

        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids.unsafeMemoryAccess(i);
            uint256 value = values.unsafeMemoryAccess(i);

            if (from != address(0)) {
                (uint256 fromBalance, uint256 discountCost) = balanceOfOnDay(from, id, today);
                if (fromBalance < value) {
                    revert ERC1155InsufficientBalance(from, fromBalance, value, id);
                }
                if (discountCost > 0) {
                    emit TransferSingle(operator, from, address(0), id, discountCost);
                    emit DiscountCost(from, id, discountCost);
                }
                unchecked {
                    // Overflow not possible: value <= fromBalance
                    _updateBalance(from, id, fromBalance - value, today);
                }
            }

            if (to != address(0)) {
                _discountAndAddToBalance(to, id, value, today);
            }
        }

        if (ids.length == 1) {
            uint256 id = ids.unsafeMemoryAccess(0);
            uint256 value = values.unsafeMemoryAccess(0);
            emit TransferSingle(operator, from, to, id, value);
        } else {
            emit TransferBatch(operator, from, to, ids, values);
        }
    }

    /**
     * @dev Version of {_update} that performs the token acceptance check by calling
     * {IERC1155Receiver-onERC1155Received} or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it
     * contains code (eg. is a smart contract at the moment of execution).
     *
     * IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any
     * update to the contract state after this function would break the check-effect-interaction pattern. Consider
     * overriding {_update} instead.
     */
    function _updateWithAcceptanceCheck(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) internal virtual {
        _update(from, to, ids, values);
        _acceptanceCheck(from, to, ids, values, data);
    }

    /**
     * @dev do the ERC1155 token acceptance check to the receiver
     */
    function _acceptanceCheck(
        address _from,
        address _to,
        uint256[] memory _ids,
        uint256[] memory _values,
        bytes memory _data
    ) internal {
        if (_to != address(0)) {
            address operator = _msgSender();
            if (_ids.length == 1) {
                uint256 id = _ids.unsafeMemoryAccess(0);
                uint256 value = _values.unsafeMemoryAccess(0);
                _doSafeTransferAcceptanceCheck(operator, _from, _to, id, value, _data);
            } else {
                _doSafeBatchTransferAcceptanceCheck(operator, _from, _to, _ids, _values, _data);
            }
        }
    }

    /**
     * @dev Transfers a `value` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `from` must have a balance of tokens of type `id` of at least `value` amount.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        _updateWithAcceptanceCheck(from, to, ids, values, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     * - `ids` and `values` must have the same length.
     */
    function _safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        _updateWithAcceptanceCheck(from, to, ids, values, data);
    }

    /**
     * @dev Sets a new URI for all token types, by relying on the token type ID
     * substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * By this mechanism, any occurrence of the `\{id\}` substring in either the
     * URI or any of the values in the JSON file at said URI will be replaced by
     * clients with the token type ID.
     *
     * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
     * interpreted by clients as
     * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
     * for token type ID 0x4cce0.
     *
     * See {uri}.
     *
     * Because these URIs cannot be meaningfully represented by the {URI} event,
     * this function emits no events.
     */
    function _setURI(string memory _newuri) internal virtual {
        _uri = _newuri;
    }

    /**
     * @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If `_doAcceptanceCheck` is true, it will perform ERC1155 acceptance check, otherwise only update
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _mint(address to, uint256 id, uint256 value, bytes memory data, bool _doAcceptanceCheck) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        if (_doAcceptanceCheck) {
            _updateWithAcceptanceCheck(address(0), to, ids, values, data);
        } else {
            _update(address(0), to, ids, values);
        }
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `values` must have the same length.
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    // function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
    //     if (to == address(0)) {
    //         revert ERC1155InvalidReceiver(address(0));
    //     }
    //     _updateWithAcceptanceCheck(address(0), to, ids, values, data);
    // }

    /**
     * @dev Destroys a `value` amount of tokens of type `id` from `from`
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `value` amount of tokens of type `id`.
     */
    function _burn(address from, uint256 id, uint256 value) internal {
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        _updateWithAcceptanceCheck(from, address(0), ids, values, "");
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `value` amount of tokens of type `id`.
     * - `ids` and `values` must have the same length.
     * //
     */
    // function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal {
    //     if (from == address(0)) {
    //         revert ERC1155InvalidSender(address(0));
    //     }
    //     _updateWithAcceptanceCheck(from, address(0), ids, values, "");
    // }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the zero address.
     */
    function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
        if (operator == address(0)) {
            revert ERC1155InvalidOperator(address(0));
        }
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Creates an array in memory with only one value for each of the elements provided.
     */
    function _asSingletonArrays(uint256 element1, uint256 element2)
        internal
        pure
        returns (uint256[] memory array1, uint256[] memory array2)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Load the free memory pointer
            array1 := mload(0x40)
            // Set array length to 1
            mstore(array1, 1)
            // Store the single element at the next word after the length (where content starts)
            mstore(add(array1, 0x20), element1)

            // Repeat for next array locating it right after the first array
            array2 := add(array1, 0x40)
            mstore(array2, 1)
            mstore(add(array2, 0x20), element2)

            // Update the free memory pointer by pointing after the second array
            mstore(0x40, add(array2, 0x40))
        }
    }

    // Private functions

    /**
     * @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address
     * if it contains code at the moment of execution.
     */
    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 value,
        bytes memory data
    ) private {
        if (to.code.length > 0) {
            try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) {
                if (response != IERC1155Receiver.onERC1155Received.selector) {
                    // Tokens rejected
                    revert ERC1155InvalidReceiver(to);
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    // non-ERC1155Receiver implementer
                    revert ERC1155InvalidReceiver(to);
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }

    /**
     * @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address
     * if it contains code at the moment of execution.
     */
    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) private {
        if (to.code.length > 0) {
            try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns (bytes4 response)
            {
                if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                    // Tokens rejected
                    revert ERC1155InvalidReceiver(to);
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    // non-ERC1155Receiver implementer
                    revert ERC1155InvalidReceiver(to);
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }
}

// src/circles/Circles.sol

contract Circles is ERC1155, ICirclesErrors {
    // Type declarations

    /**
     * @notice MintTime struct stores the last mint time,
     * and the status of a connected v1 Circles contract.
     * @dev This is used to store the last mint time for each avatar,
     * and the address is used as a status for the connected v1 Circles contract.
     * The address is kept at zero address if the avatar is not registered in Hub v1.
     * If the avatar is registered in Hub v1, but the associated Circles ERC20 contract
     * has not been stopped, then the address is set to that v1 Circles contract address.
     * Once the Circles v1 contract has been stopped, the address is set to 0x01.
     * At every observed transition of the status of the v1 Circles contract,
     * the lastMintTime will be updated to the current timestamp to avoid possible
     * overlap of the mint between Hub v1 and Hub v2.
     */
    struct MintTime {
        address mintV1Status;
        uint96 lastMintTime;
    }

    // Constants

    /**
     * @notice Upon claiming, the maximum claim is upto two weeks
     * of history. Unclaimed older Circles are unclaimable.
     */
    uint256 private constant MAX_CLAIM_DURATION = 2 weeks;

    /**
     * @dev Address used to indicate that the associated v1 Circles contract has been stopped.
     */
    address internal constant CIRCLES_STOPPED_V1 = address(0x1);

    /**
     * @notice Indefinite future, or approximated with uint96.max
     */
    uint96 internal constant INDEFINITE_FUTURE = type(uint96).max;

    // State variables

    /**
     * @notice The mapping of avatar addresses to the last mint time,
     * and the status of the v1 Circles minting.
     * @dev This is used to store the last mint time for each avatar.
     */
    mapping(address => MintTime) internal mintTimes;

    // Events

    event PersonalMint(address indexed human, uint256 amount, uint256 startPeriod, uint256 endPeriod);

    // Constructor

    /**
     * Constructor to create a Circles ERC1155 contract with demurrage.
     * @param _inflation_day_zero Inflation day zero stores the start of the global inflation curve
     * @param _uri uri for the Circles metadata
     */
    constructor(uint256 _inflation_day_zero, string memory _uri)
        ERC1155(_uri)
        DiscountedBalances(_inflation_day_zero)
    {}

    // Internal functions

    /**
     * @notice Calculate the demurraged issuance for a human's avatar.
     * @param _human Address of the human's avatar to calculate the issuance for.
     * @return issuance The issuance in attoCircles.
     * @return startPeriod The start of the claimable period.
     * @return endPeriod The end of the claimable period.
     */
    function _calculateIssuance(address _human) internal view returns (uint256, uint256, uint256) {
        MintTime memory mintTime = mintTimes[_human];
        if (mintTime.mintV1Status != address(0) && mintTime.mintV1Status != CIRCLES_STOPPED_V1) {
            // Circles v1 contract cannot be active.
            // revert CirclesERC1155MintBlocked(_human, mintTime.mintV1Status);
            revert CirclesErrorOneAddressArg(_human, 0xC0);
        }

        // Check if at least one new completed hour is mintable
        uint256 lastCompletedHour = mintTime.lastMintTime / 1 hours;
        uint256 currentCompletedHour = block.timestamp / 1 hours;

        if (lastCompletedHour >= currentCompletedHour || mintTime.lastMintTime == INDEFINITE_FUTURE) {
            // No new completed hour to mint, or stopped
            return (0, 0, 0);
        }

        // calculate the start of the claimable period
        uint256 startMint = _max(block.timestamp - MAX_CLAIM_DURATION, mintTime.lastMintTime);

        // day of start of mint, dA
        uint256 dA = uint256(day(startMint));

        // day of current block, dB
        uint256 dB = uint256(day(block.timestamp));

        // the difference of days between dB and dA used for the table lookups
        uint256 n = dB - dA;

        // calculate the number of completed hours in day A until `startMint`
        int128 k = ABDKMath64x64.fromUInt((startMint - (dA * 1 days + inflationDayZero)) / 1 hours);

        // Calculate the number of seconds remaining in the current day (dB)
        uint256 secondsRemainingInB = ((dB + 1) * 1 days + inflationDayZero - block.timestamp);
        // Calculate the number of complete hours remaining
        uint256 hoursRemainingInB = secondsRemainingInB / 1 hours;
        // Calculate l:
        // If there are any seconds beyond complete hours, add 1 to account for the incomplete hour
        // Convert the result to int128 using Math64x64.fromUInt
        int128 l = ABDKMath64x64.fromUInt(hoursRemainingInB + (secondsRemainingInB % 1 hours > 0 ? 1 : 0));

        // calculate the overcounted (demurraged) k (in day A) and l (in day B) hours
        // note that the hours l are not demurraged as it is current day by construction
        int128 overcount = ABDKMath64x64.add(ABDKMath64x64.mul(R[n], k), l);

        // subtract the overcount from the total issuance, and convert to attoCircles
        return (
            ABDKMath64x64.mulu(ABDKMath64x64.sub(T[n], overcount), EXA),
            // start of the claimable period
            inflationDayZero + dA * 1 days + ABDKMath64x64.mulu(k, 1 hours),
            // end of the claimable period
            inflationDayZero + dB * 1 days + 1 days - ABDKMath64x64.mulu(l, 1 hours)
        );
    }

    /**
     * @notice Claim issuance for a human's avatar and update the last mint time.
     * @param _human Address of the human's avatar to claim the issuance for.
     */
    function _claimIssuance(address _human) internal {
        (uint256 issuance, uint256 startPeriod, uint256 endPeriod) = _calculateIssuance(_human);
        if (issuance == 0) {
            // No issuance to claim, simply return without reverting
            return;
        }

        // update the last mint time, before minting as mint time determines the check (guard for reeentrancy attack)
        mintTimes[_human].lastMintTime = uint96(block.timestamp);

        // mint personal Circles to the human; ERC1155 mint will perform acceptance call
        _mintAndUpdateTotalSupply(_human, toTokenId(_human), issuance, "", true);

        emit PersonalMint(_human, issuance, startPeriod, endPeriod);
    }

    function _mintAndUpdateTotalSupply(
        address _account,
        uint256 _id,
        uint256 _value,
        bytes memory _data,
        bool _doAcceptanceCheck
    ) internal {
        _mint(_account, _id, _value, _data, _doAcceptanceCheck);

        uint64 today = day(block.timestamp);
        DiscountedBalance memory totalSupplyBalance = discountedTotalSupplies[_id];
        uint256 newTotalSupply =
            _calculateDiscountedBalance(totalSupplyBalance.balance, today - totalSupplyBalance.lastUpdatedDay) + _value;
        if (newTotalSupply > MAX_VALUE) {
            // DiscountedBalances: balance exceeds maximum value
            // revert CirclesDemurrageAmountExceedsMaxUint192(_account, _id, newTotalSupply, 2);
            revert CirclesErrorAddressUintArgs(_account, _id, 0x80);
        }
        totalSupplyBalance.balance = uint192(newTotalSupply);
        totalSupplyBalance.lastUpdatedDay = today;
        discountedTotalSupplies[_id] = totalSupplyBalance;
    }

    function _burnAndUpdateTotalSupply(address _account, uint256 _id, uint256 _value) internal {
        // _update will discount the balance before subtracting the value
        _burn(_account, _id, _value);

        uint64 today = day(block.timestamp);
        DiscountedBalance memory totalSupplyBalance = discountedTotalSupplies[_id];
        uint256 discountedTotalSupply =
            _calculateDiscountedBalance(totalSupplyBalance.balance, today - totalSupplyBalance.lastUpdatedDay);
        if (discountedTotalSupply < _value) {
            // Logically impossible to burn more than the total supply
            // however if the total supply nears dust, the discounting of the balance
            // and the total supply might differ on the least significant bits.
            // There is no good way to handle this, so user should burn a few attoCRC less,
            // or wait a day for the total supply to be discounted to zero automatically.
            // revert CirclesLogicAssertion(4);
            revert CirclesErrorNoArgs(0x84);
        }
        unchecked {
            totalSupplyBalance.balance = uint192(discountedTotalSupply - _value);
        }
        totalSupplyBalance.lastUpdatedDay = today;
        discountedTotalSupplies[_id] = totalSupplyBalance;
    }

    /**
     * @dev Max function to compare two values.
     * @param a Value a
     * @param b Value b
     */
    function _max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }
}

// src/hub/Hub.sol

/**
 * @title Hub v2 contract for Circles
 * @notice The Hub contract is the main contract for the Circles protocol.
 * It adopts the ERC1155 standard for multi-token contracts and governs
 * the personal and group Circles of people, organizations and groups.
 * Circle balances are demurraged in the Hub contract.
 * It registers the trust relations between people and groups and allows
 * to transfer Circles to be path fungible along trust relations.
 * It further allows to wrap any token into an inflationary or demurraged
 * ERC20 Circles contract.
 */
contract Hub is Circles, TypeDefinitions, IHubErrors {
    // Constants

    /**
     * @dev Welcome bonus for new avatars invited to Circles. Set to 48 Circles.
     */
    uint256 private constant WELCOME_BONUS = 48 * EXA;

    /**
     * @dev The cost of an invitation for a new avatar, paid in personal Circles burnt, set to 96 Circles.
     */
    uint256 private constant INVITATION_COST = 2 * WELCOME_BONUS;

    /**
     * @dev The address used as the first element of the linked list of avatars.
     */
    address private constant SENTINEL = address(0x1);

    /**
     * @dev advanced flag to indicate whether avatar enables consented flow
     */
    bytes32 private constant ADVANCED_FLAG_ENABLE_CONSENTEDFLOW = bytes32(uint256(1));

    // State variables

    /**
     * @notice The Hub v1 contract address.
     */
    IHubV1 internal immutable hubV1;

    /**
     * @notice The name registry contract address.
     */
    INameRegistry internal nameRegistry;

    /**
     * @notice The address of the migration contract for v1 Circles.
     */
    address internal migration;

    /**
     * @notice The address of the Lift ERC20 contract.
     */
    IERC20Lift internal liftERC20;

    /**
     * @notice The timestamp of the start of the invitation-only period.
     * @dev This is used to determine the start of the invitation-only period.
     * Prior to this time v1 avatars can register without an invitation, and
     * new avatars can be invited by registered avatars. After this time
     * only registered avatars can invite new avatars.
     */
    uint256 public immutable invitationOnlyTime;

    /**
     * @notice The standard treasury contract address used when
     * registering a (non-custom) group.
     */
    address internal standardTreasury;

    /**
     * @notice The mapping of registered avatar addresses to the next avatar address,
     * stored as a linked list.
     * @dev This is used to store the linked list of registered avatars.
     */
    mapping(address => address) public avatars;

    /**
     * @notice The mapping of group avatar addresses to the mint policy contract address.
     */
    mapping(address => address) public mintPolicies;

    /**
     * @notice The mapping of group avatar addresses to the treasury contract address.
     */
    mapping(address => address) public treasuries;

    /**
     * @notice The iterable mapping of directional trust relations between avatars and
     * their expiry times.
     */
    mapping(address => mapping(address => TrustMarker)) public trustMarkers;

    /**
     * @notice Advanced usage flags for avatar. Only the least significant bit is used
     * by the Circles protocol itself for consented flow behaviour, the remaining bits
     * are reserved for future community-proposed extensions.
     */
    mapping(address => bytes32) public advancedUsageFlags;

    // Events

    event RegisterHuman(address indexed avatar, address indexed inviter);
    event RegisterOrganization(address indexed organization, string name);
    event RegisterGroup(
        address indexed group, address indexed mint, address indexed treasury, string name, string symbol
    );

    event Trust(address indexed truster, address indexed trustee, uint256 expiryTime);

    event Stopped(address indexed avatar);

    event FlowEdgesScopeSingleStarted(uint256 indexed flowEdgeId, uint16 streamId);
    event FlowEdgesScopeLastEnded();
    event StreamCompleted(
        address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] amounts
    );

    event GroupMint(
        address indexed sender, address indexed receiver, address indexed group, uint256[] collateral, uint256[] amounts
    );

    event SetAdvancedUsageFlag(address indexed avatar, bytes32 flag);

    // Modifiers

    /**
     * Modifier to check if the caller is the migration contract.
     */
    modifier onlyMigration() {
        if (msg.sender != migration) {
            // revert CirclesInvalidFunctionCaller(msg.sender, migration, 0);
            revert CirclesErrorOneAddressArg(msg.sender, 0xE0);
        }
        _;
    }

    /**
     * @dev Reentrancy guard for nonReentrant functions.
     * see https://soliditylang.org/blog/2024/01/26/transient-storage/
     */
    modifier nonReentrant() {
        assembly {
            if tload(0) { revert(0, 0) }
            tstore(0, 1)
        }
        _;
        assembly {
            tstore(0, 0)
        }
    }

    // Constructor

    /**
     * @notice Constructor for the Hub contract.
     * @param _hubV1 address of the Hub v1 contract
     * @param _inflationDayZero timestamp of the start of the global inflation curve.
     * For deployment on Gnosis Chain this parameter should be set to midnight 15 October 2020,
     * or in unix time 1602786330 (deployment at 6:25:30 pm UTC) - 66330 (offset to midnight) = 1602720000.
     * @param _standardTreasury address of the standard treasury contract
     * @param _bootstrapTime duration of the bootstrap period (for v1 registration) in seconds
     * @param _gatewayUrl gateway URL string for the ERC1155 metadata mirroring IPFS metadata storage
     * (eg. "https://gateway.aboutcircles.com/v2/circles/{id}.json")
     */
    constructor(
        IHubV1 _hubV1,
        INameRegistry _nameRegistry,
        address _migration,
        IERC20Lift _liftERC20,
        address _standardTreasury,
        uint256 _inflationDayZero,
        uint256 _bootstrapTime,
        string memory _gatewayUrl
    ) Circles(_inflationDayZero, _gatewayUrl) {
        if (address(_hubV1) == address(0)) {
            // revert CirclesAddressCannotBeZero(0);
            revert CirclesErrorNoArgs(0x00);
        }
        if (_standardTreasury == address(0)) {
            // revert CirclesAddressCannotBeZero(1);
            revert CirclesErrorNoArgs(0x01);
        }

        // initialize linked list for avatars
        avatars[SENTINEL] = SENTINEL;

        // store the Hub v1 contract address
        hubV1 = _hubV1;

        // store the name registry contract address
        nameRegistry = _nameRegistry;

        // store the migration contract address
        migration = _migration;

        // store the lift ERC20 contract address
        liftERC20 = _liftERC20;

        // store the standard treasury contract address for registerGroup()
        standardTreasury = _standardTreasury;

        // invitation-only period starts after the bootstrap time has passed since deployment
        invitationOnlyTime = block.timestamp + _bootstrapTime;
    }

    // External functions

    /**
     * @notice Register human allows to register an avatar for a human,
     * if they have a stopped v1 Circles contract, that has been stopped
     * before the end of the invitation period.
     * Otherwise the caller must have been invited by an already registered human avatar.
     * Humans can invite someone by trusting their address ahead of this call.
     * After the invitation period, the inviter must burn the invitation cost, and the
     * newly registered human will receive the welcome bonus.
     * @param _inviter address of the inviter, who must have trusted the caller ahead of this call.
     * If the inviter is zero, the caller can self-register if they have a stopped v1 Circles contract
     * (stopped before the end of the invitation period).
     * @param _metadataDigest (optional) sha256 metadata digest for the avatar metadata
     * should follow ERC1155 metadata standard.
     */
    function registerHuman(address _inviter, bytes32 _metadataDigest) external {
        if (_inviter == address(0)) {
            // to self-register yourself if you are a stopped v1 user,
            // leave the inviter address as zero.

            // only available for v1 users with stopped v1 mint, for initial bootstrap period
            (address v1CirclesStatus, uint256 v1LastTouched) = _registerHuman(msg.sender, _inviter);
            // check if v1 Circles exists and has been stopped
            // and if it has been stopped, did it stop before the end of the invitation period?
            if (v1CirclesStatus != CIRCLES_STOPPED_V1 || v1LastTouched >= invitationOnlyTime) {
                // revert CirclesHubRegisterAvatarV1MustBeStoppedBeforeEndOfInvitationPeriod(msg.sender, 0);
                revert CirclesErrorOneAddressArg(msg.sender, 0x60);
            }
        } else {
            // if someone has invited you by trusting your address ahead of this call,
            // they must themselves be a registered human, and they must pay the invitation cost (after invitation period).

            if (!isHuman(_inviter) || !isTrusted(_inviter, msg.sender)) {
                // revert CirclesHubMustBeHuman(msg.sender, 0);
                // revert CirclesHubInvalidTrustReceiver(msg.sender, 0);
                revert CirclesErrorOneAddressArg(_inviter, 0xA0);
            }

            // register the invited human; reverts if they already exist
            // it checks the status of the avatar in v1, but regardless of the status
            // we can proceed to register the avatar in v2 (they might not be able to mint yet
            // if they have not stopped their v1 contract)
            _registerHuman(msg.sender, _inviter);

            if (block.timestamp > invitationOnlyTime) {
                // after the invitation period, the inviter must burn the invitation cost
                _burnAndUpdateTotalSupply(_inviter, toTokenId(_inviter), INVITATION_COST);

                // mint the welcome bonus to the newly registered human
                _mintAndUpdateTotalSupply(msg.sender, toTokenId(msg.sender), WELCOME_BONUS, "", true);
            }
        }

        // store the metadata digest for the avatar metadata
        if (_metadataDigest != bytes32(0)) {
            nameRegistry.setMetadataDigest(msg.sender, _metadataDigest);
        }
    }

    /**
     * @notice Register group allows to register a group avatar.
     * @param _mint mint address will be called before minting group circles
     * @param _name immutable name of the group Circles
     * @param _symbol immutable symbol of the group Circles
     * @param _metadataDigest sha256 digest for the group metadata
     */
    function registerGroup(address _mint, string calldata _name, string calldata _symbol, bytes32 _metadataDigest)
        external
    {
        _registerGroup(msg.sender, _mint, standardTreasury, _name, _symbol);

        // for groups register possible custom name and symbol
        nameRegistry.registerCustomName(msg.sender, _name);
        nameRegistry.registerCustomSymbol(msg.sender, _symbol);

        // store the IPFS CIDv0 digest for the group metadata
        nameRegistry.setMetadataDigest(msg.sender, _metadataDigest);

        emit RegisterGroup(msg.sender, _mint, standardTreasury, _name, _symbol);
    }

    /**
     * @notice Register custom group allows to register a group with a custom treasury contract.
     * @param _mint mint address will be called before minting group circles
     * @param _treasury treasury address for receiving collateral
     * @param _name immutable name of the group Circles
     * @param _symbol immutable symbol of the group Circles
     * @param _metadataDigest metadata digest for the group metadata
     */
    function registerCustomGroup(
        address _mint,
        address _treasury,
        string calldata _name,
        string calldata _symbol,
        bytes32 _metadataDigest
    ) external {
        _registerGroup(msg.sender, _mint, _treasury, _name, _symbol);

        // for groups register possible custom name and symbol
        nameRegistry.registerCustomName(msg.sender, _name);
        nameRegistry.registerCustomSymbol(msg.sender, _symbol);

        // store the metadata digest for the group metadata
        nameRegistry.setMetadataDigest(msg.sender, _metadataDigest);

        emit RegisterGroup(msg.sender, _mint, _treasury, _name, _symbol);
    }

    /**
     * @notice Register organization allows to register an organization avatar.
     * @param _name name of the organization
     * @param _metadataDigest Metadata digest for the organization metadata
     */
    function registerOrganization(string calldata _name, bytes32 _metadataDigest) external {
        _insertAvatar(msg.sender);

        // for organizations, only register possible custom name
        nameRegistry.registerCustomName(msg.sender, _name);

        // store the IPFS CIDv0 digest for the organization metadata
        nameRegistry.setMetadataDigest(msg.sender, _metadataDigest);

        emit RegisterOrganization(msg.sender, _name);
    }

    /**
     * @notice Trust allows to trust another address for a certain period of time.
     * Expiry times in the past are set to the current block timestamp.
     * @param _trustReceiver address that is trusted by the caller. The trust receiver
     * does not (yet) need to be registered as an avatar.
     * @param _expiry expiry time in seconds since unix epoch until when trust is valid
     * @dev Trust is directional and can be set by the caller to any address.
     * The trusted address does not (yet) have to be registered in the Hub contract.
     */
    function trust(address _trustReceiver, uint96 _expiry) external {
        if (
            avatars[msg.sender] == address(0) || _trustReceiver == address(0) || _trustReceiver == SENTINEL
                || _trustReceiver == msg.sender
        ) {
            // You cannot trust the zero address or the sentinel address.
            // Reserved addresses for logic.
            // You also cannot edit your own trust relation.
            // revert CirclesHubInvalidTrustReceiver(_trustReceiver, 1);
            revert CirclesErrorOneAddressArg(_trustReceiver, 0xA1);
        }

        // expiring trust cannot be set in the past
        if (_expiry < block.timestamp) _expiry = uint96(block.timestamp);
        _trust(msg.sender, _trustReceiver, _expiry);
    }

    /**
     * @notice Personal mint allows to mint personal Circles for a registered human avatar.
     */
    function personalMint() external {
        if (!isHuman(msg.sender)) {
            // Only avatars registered as human can call personal mint.
            // revert CirclesHubMustBeHuman(msg.sender, 1);
            revert CirclesErrorOneAddressArg(msg.sender, 0x01);
        }
        // check if v1 Circles is known to be stopped and update status
        _checkHumanV1CirclesStatus(msg.sender);

        // claim issuance if any is available
        _claimIssuance(msg.sender);
    }

    /**
     * @notice Calculate the demurraged issuance for a human's avatar.
     * @param _human Address of the human's avatar to calculate the issuance for.
     * @return issuance The issuance in attoCircles.
     * @return startPeriod The start of the claimable period.
     * @return endPeriod The end of the claimable period.
     */
    function calculateIssuance(address _human) external view returns (uint256, uint256, uint256) {
        if (!isHuman(_human)) {
            // Only avatars registered as human can calculate issuance.
            // If the avatar is not registered as human, return 0 issuance.
            return (0, 0, 0);
        }
        return _calculateIssuance(_human);
    }

    /**
     * @notice Calculate issuance allows to calculate the issuance for a human avatar with a check
     * to update the v1 mint status if updated.
     * @param _human address of the human avatar to calculate the issuance for
     * @return issuance amount of Circles that can be minted
     * @return startPeriod start of the claimable period
     * @return endPeriod end of the claimable period
     */
    function calculateIssuanceWithCheck(address _human) external returns (uint256, uint256, uint256) {
        // check if v1 Circles is known to be stopped and update status
        _checkHumanV1CirclesStatus(_human);
        // calculate issuance for the human avatar, but don't mint
        return _calculateIssuance(_human);
    }

    /**
     * @notice Group mint allows to mint group Circles by providing the required collateral.
     * @param _group address of the group avatar to mint Circles of
     * @param _collateralAvatars array of (personal or group) avatar addresses to be used as collateral
     * @param _amounts array of amounts of collateral to be used for minting
     * @param _data (optional) additional data to be passed to the mint policy, treasury and minter (caller)
     */
    function groupMint(
        address _group,
        address[] calldata _collateralAvatars,
        uint256[] calldata _amounts,
        bytes calldata _data
    ) external {
        uint256[] memory collateral = new uint256[](_collateralAvatars.length);
        for (uint256 i = 0; i < _collateralAvatars.length; i++) {
            collateral[i] = toTokenId(_collateralAvatars[i]);
        }
        _groupMint(msg.sender, msg.sender, _group, collateral, _amounts, _data, true);
    }

    /**
     * @notice Stop allows to stop future mints of personal Circles for this avatar.
     * Must be called by the avatar itself. This action is irreversible.
     */
    function stop() external {
        if (!isHuman(msg.sender)) {
            // Only human can call stop.
            // revert CirclesHubMustBeHuman(msg.sender, 2);
            revert CirclesErrorOneAddressArg(msg.sender, 0x02);
        }
        MintTime storage mintTime = mintTimes[msg.sender];
        // check if already stopped
        if (mintTime.lastMintTime == INDEFINITE_FUTURE) {
            return;
        }
        // stop future mints of personal Circles
        // by setting the last mint time to indefinite future.
        mintTime.lastMintTime = INDEFINITE_FUTURE;

        emit Stopped(msg.sender);
    }

    /**
     * Stopped checks whether the avatar has stopped future mints of personal Circles.
     * @param _human address of avatar of the human to check whether it is stopped
     */
    function stopped(address _human) external view returns (bool) {
        if (!isHuman(_human)) {
            // Only personal Circles can have a status of boolean stopped.
            // revert CirclesHubMustBeHuman(_human, 3);
            revert CirclesErrorOneAddressArg(_human, 0x03);
        }
        MintTime storage mintTime = mintTimes[msg.sender];
        return (mintTime.lastMintTime == INDEFINITE_FUTURE);
    }

    /**
     * @notice Migrate allows to migrate v1 Circles to v2 Circles. During bootstrap period,
     * no invitation cost needs to be paid for new humans to be registered. After the bootstrap
     * period the same invitation cost applies as for normal invitations, and this requires the
     * owner to be a human and to have enough personal Circles to pay the invitation cost.
     * Organizations and groups have to ensure all humans have been registered after the bootstrap period.
     * Can only be called by the migration contract.
     * @param _owner address of the owner of the v1 Circles and beneficiary of the v2 Circles
     * @param _avatars array of avatar addresses to migrate
     * @param _amounts array of amounts in inflationary v1 units to migrate
     */
    function migrate(address _owner, address[] calldata _avatars, uint256[] calldata _amounts) external onlyMigration {
        if (avatars[_owner] == address(0) || _avatars.length != _amounts.length) {
            // Only registered avatars can migrate v1 tokens.
            // Array length is already checked in the migration contract, so redundant check here,
            // can be collapsed under the more meaningful error.
            // revert CirclesAvatarMustBeRegistered(_owner, 1);
            revert CirclesErrorOneAddressArg(_owner, 0x21);
        }

        // register all unregistered avatars as humans, and check that registered avatars are humans
        // after the bootstrap period, the _owner needs to pay the equivalent invitation cost for all newly registered humans
        uint256 cost = INVITATION_COST * _ensureAvatarsRegistered(_owner, _avatars);

        // Invitation cost only applies after the bootstrap period
        if (block.timestamp > invitationOnlyTime && cost > 0) {
            // personal Circles are required to burn the invitation cost
            if (!isHuman(_owner)) {
                // Only humans can migrate v1 tokens after the bootstrap period.
                // revert CirclesHubMustBeHuman(_owner, 4);
                revert CirclesErrorOneAddressArg(_owner, 0x04);
            }
            _burnAndUpdateTotalSupply(_owner, toTokenId(_owner), cost);
        }

        for (uint256 i = 0; i < _avatars.length; i++) {
            // mint the migrated balances to _owner
            _mintAndUpdateTotalSupply(_owner, toTokenId(_avatars[i]), _amounts[i], "", true);
        }
    }

    /**
     * @notice Burn allows to burn Circles owned by the caller.
     * @param _id Circles identifier of the Circles to burn
     * @param _amount amount of Circles to burn
     * @param _data (optional) additional data to be passed to the burn policy if they are group Circles
     */
    function burn(uint256 _id, uint256 _amount, bytes calldata _data) external {
        // note: by construction we can not have an id with non-zero balance,
        // that was not converted from a group address.
        // Nonetheless assert that the id is identical an address
        address group = _validateAddressFromId(_id, 0);

        IMintPolicy policy = IMintPolicy(mintPolicies[group]);
        if (address(policy) != address(0) && treasuries[group] != msg.sender) {
            // if Circles are a group Circles and if the burner is not the associated treasury,
            // then the mint policy must approve the burn
            if (!policy.beforeBurnPolicy(msg.sender, group, _amount, _data)) {
                // Burn policy rejected burn.
                // revert CirclesHubGroupMintPolicyRejectedBurn(msg.sender, group, _amount, _data, 0);
                revert CirclesErrorAddressUintArgs(msg.sender, _id, 0x40);
            }
        }
        _burnAndUpdateTotalSupply(msg.sender, _id, _amount);
    }

    function wrap(address _avatar, uint256 _amount, CirclesType _type) external returns (address) {
        if (!isHuman(_avatar) && !isGroup(_avatar)) {
            // Avatar must be human or group.
            // revert CirclesAvatarMustBeRegistered(_avatar, 2);
            revert CirclesErrorOneAddressArg(_avatar, 0x22);
        }
        address erc20Wrapper = liftERC20.ensureERC20(_avatar, _type);
        safeTransferFrom(msg.sender, erc20Wrapper, toTokenId(_avatar), _amount, "");

        return erc20Wrapper;
    }

    function operateFlowMatrix(
        address[] calldata _flowVertices,
        FlowEdge[] calldata _flow,
        Stream[] calldata _streams,
        bytes calldata _packedCoordinates
    ) external nonReentrant {
        // first unpack the coordinates to array of uint16
        uint16[] memory coordinates = _unpackCoordinates(_packedCoordinates, _flow.length);

        // check all senders have the operator authorized
        for (uint256 i = 0; i < _streams.length; i++) {
            if (!isApprovedForAll(_flowVertices[_streams[i].sourceCoordinate], msg.sender)) {
                // Operator not approved for source.
                // revert CirclesHubOperatorNotApprovedForSource(
                //     msg.sender, _flowVertices[_streams[i].sourceCoordinate], i, 0
                // );
                revert CirclesErrorAddressUintArgs(_flowVertices[_streams[i].sourceCoordinate], i, 0x00);
            }
        }

        // if no streams are provided, the streams will nett to zero for all vertices
        // so to pass the acceptance checks, the flow matrix must also nett to zero
        // which can be true if for all vertices the sum of incoming and outgoing flow is zero

        // verify the correctness of the flow matrix describing the path itself,
        // ie. well-definedness of the flow matrix itself,
        // check all entities are registered, and the trust relations are respected.
        int256[] memory matrixNettedFlow = _verifyFlowMatrix(_flowVertices, _flow, coordinates);

        _effectPathTransfers(_flowVertices, _flow, _streams, coordinates);

        int256[] memory streamsNettedFlow = _callAcceptanceChecks(_flowVertices, _flow, _streams, coordinates);

        _matchNettedFlows(streamsNettedFlow, matrixNettedFlow);
    }

    /**
     * @notice Set the advanced usage flag for the caller's avatar.
     * @param _flag advanced usage flags combination to set
     */
    function setAdvancedUsageFlag(bytes32 _flag) external {
        if (avatars[msg.sender] == address(0)) {
            // Only registered avatars can set advanced usage flags.
            // revert CirclesAvatarMustBeRegistered(msg.sender, 3);
            revert CirclesErrorOneAddressArg(msg.sender, 0x23);
        }

        advancedUsageFlags[msg.sender] = _flag;

        // emit event for setting the advanced usage flag
        emit SetAdvancedUsageFlag(msg.sender, _flag);
    }

    function name() external view returns (string memory) {
        return nameRegistry.name(address(this));
    }

    function symbol() external view returns (string memory) {
        return nameRegistry.symbol(address(this));
    }

    // Public functions

    /**
     * Checks if an avatar is registered as a human.
     * @param _human address of the human to check
     */
    function isHuman(address _human) public view returns (bool) {
        return mintTimes[_human].lastMintTime > 0;
    }

    /**
     * Checks if an avatar is registered as a group.
     * @param _group address of the group to check
     */
    function isGroup(address _group) public view returns (bool) {
        return mintPolicies[_group] != address(0);
    }

    /**
     * @notice Checks if an avatar is registered as an organization.
     * @param _organization address of the organization to check
     */
    function isOrganization(address _organization) public view returns (bool) {
        return avatars[_organization] != address(0) && mintPolicies[_organization] == address(0)
            && mintTimes[_organization].lastMintTime == uint256(0);
    }

    /**
     * @notice Returns true if the truster trusts the trustee.
     * @param _truster Address of the trusting account
     * @param _trustee Address of the trusted account
     */
    function isTrusted(address _truster, address _trustee) public view returns (bool) {
        // trust up until expiry timestamp
        return uint256(trustMarkers[_truster][_trustee].expiry) >= block.timestamp;
    }

    /**
     * @notice Returns true if the flow to the receiver is permitted. By default avatars don't have
     * consented flow enabled, so then this function is equivalent to isTrusted(). This function is called
     * to check whether the flow edge is permitted (either along a path's flow edge, or upon groupMint).
     * If the sender avatar has enabled consented flow for the Circles balances they own,
     * then the receiver must trust the Circles being sent, and the sender must trust the receiver,
     * and to preserve the protection recursively the receiver themselves must have consented flow enabled.
     * @param _from Address of the sender
     * @param _to Address of the receiver
     * @param _circlesAvatar Address of the Circles avatar of the Circles being sent
     * @return permitted true if the flow is permitted, false otherwise
     */
    function isPermittedFlow(address _from, address _to, address _circlesAvatar) public view returns (bool) {
        // Check if receiver trusts the Circles being sent
        if (uint256(trustMarkers[_to][_circlesAvatar].expiry) < block.timestamp) return false;

        // Check if sender has enabled consented flow
        if (advancedUsageFlags[_from] & ADVANCED_FLAG_ENABLE_CONSENTEDFLOW == bytes32(0)) {
            return true; // If not enabled, standard trust is sufficient
        }
        // For consented flow, check sender trusts receiver,
        // and receiver has consented flow enabled too
        return (
            uint256(trustMarkers[_from][_to].expiry) >= block.timestamp
                && advancedUsageFlags[_to] & ADVANCED_FLAG_ENABLE_CONSENTEDFLOW != bytes32(0)
        );
    }

    // Internal functions

    /**
     * @notice Group mint allows to mint group Circles by providing the required collateral.
     * @param _sender address of the sender of the group mint
     * @param _receiver address of the receiver of minted group Circles
     * @param _group address of the group avatar to mint Circles of
     * @param _collateral array of (personal or group) avatar addresses to be used as collateral
     * @param _amounts array of amounts of collateral to be used for minting
     * @param _data (optional) additional data to be passed to the mint policy, treasury and minter
     * @param _explicitCall true if the call is made explicitly over groupMint(), or false if
     * it is called as part of a path transfer
     */
    function _groupMint(
        address _sender,
        address _receiver,
        address _group,
        uint256[] memory _collateral,
        uint256[] memory _amounts,
        bytes memory _data,
        bool _explicitCall
    ) internal {
        if (_collateral.length != _amounts.length || _collateral.length == 0) {
            // Collateral and amount arrays must have equal length.
            // At least one collateral must be provided.
            // revert CirclesArraysLengthMismatch(_collateral.length, _amounts.length, 1);
            revert CirclesErrorNoArgs(0xA1);
        }
        if (!isGroup(_group)) {
            // Group is not registered as an avatar.
            // revert CirclesHubGroupIsNotRegistered(_group, 0);
            revert CirclesErrorOneAddressArg(_group, 0x40);
        }

        // note: we don't need to check whether collateral circle ids are registered,
        // because only for registered collateral do non-zero balances exist to transfer,
        // so it suffices to check that all amounts are non-zero during summing.
        uint256 sumAmounts = 0;
        for (uint256 i = 0; i < _amounts.length; i++) {
            address collateralAvatar = _validateAddressFromId(_collateral[i], 1);

            // check the group trusts the collateral
            // and if the sender has opted into consented flow, the sender must also trust the the group
            bool isValidCollateral =
                _explicitCall ? isTrusted(_group, collateralAvatar) : isPermittedFlow(_sender, _group, collateralAvatar);

            if (!isValidCollateral || _amounts[i] == 0) {
                // Group does not trust collateral, or flow edge is not permitted
                // Non-zero collateral must be provided.
                // revert CirclesHubFlowEdgeIsNotPermitted(_group, _collateral[i], 0);
                revert CirclesErrorAddressUintArgs(_group, _collateral[i], 0x20);
            }

            sumAmounts += _amounts[i];
        }

        // Rely on the mint policy to determine whether the collateral is valid for minting
        if (!IMintPolicy(mintPolicies[_group]).beforeMintPolicy(_sender, _group, _collateral, _amounts, _data)) {
            // Mint policy rejected mint.
            // revert CirclesHubGroupMintPolicyRejectedMint(_sender, _group, _collateral, _amounts, _data, 0);
            revert CirclesErrorAddressUintArgs(_sender, toTokenId(_group), 0x60);
        }

        // abi encode the group address into the data to send onwards to the treasury
        bytes memory metadataGroup = abi.encode(GroupMintMetadata({group: _group}));
        bytes memory dataWithGroup = abi.encode(
            Metadata({metadataType: METADATATYPE_GROUPMINT, metadata: metadataGroup, erc1155UserData: _data})
        );

        // note: treasury.on1155Received must implement and unpack the GroupMintMetadata to know the group
        safeBatchTransferFrom(_sender, treasuries[_group], _collateral, _amounts, dataWithGroup);

        // mint group Circles to the receiver and send the original _data onwards.
        // Only if it is an explicit call perform the ERC1155 acceptance call; if not (ie via path),
        // suppress the normal acceptance call and only perform the final stream based acceptance calls
        _mintAndUpdateTotalSupply(_receiver, toTokenId(_group), sumAmounts, _data, _explicitCall);

        // emit the group mint event
        emit GroupMint(_sender, _receiver, _group, _collateral, _amounts);
    }

    /**
     * @dev Verify the correctness of the flow matrix describing the path transfer
     * @param _flowVertices an ordered list of avatar addresses as the vertices which the path touches
     * @param _flow array of flow edges, each edge is a struct with the amount (uint192)
     * and streamSinkId (reference to a stream, where for non-terminal flow edges this is 0, and for terminal flow edges
     * this must reference the index of the stream in the streams array, starting from 1)
     * @param _coordinates unpacked array of coordinates of the flow edges, with 3 coordinates per flow edge:
     * Circles identifier being transfered, sender, receiver, each a uint16 referencing the flow vertex.
     */
    function _verifyFlowMatrix(
        address[] calldata _flowVertices,
        FlowEdge[] calldata _flow,
        uint16[] memory _coordinates
    ) internal view returns (int256[] memory) {
        if (
            3 * _flow.length != _coordinates.length // Mismatch in flow and coordinates length.
                || _flowVertices.length > type(uint16).max // Too many vertices.
                || _flowVertices.length == 0 || _flow.length == 0 // Empty flow matrix
        ) {
            // revert CirclesArraysLengthMismatch(_flow.length, _coordinates.length, 2);
            revert CirclesErrorNoArgs(0xA2);
        }

        // initialize the netted flow array
        int256[] memory nettedFlow = new int256[](_flowVertices.length);

        {
            // check all vertices are valid avatars, groups or organizations
            for (uint256 i = 0; i < _flowVertices.length - 1; i++) {
                if (uint160(_flowVertices[i]) >= uint160(_flowVertices[i + 1])) {
                    // Flow vertices must be in ascending order.
                    // revert CirclesHubFlowVerticesMustBeSorted();
                    revert CirclesErrorNoArgs(0x60);
                }
                if (avatars[_flowVertices[i]] == address(0)) {
                    // Avatar must be registered.
                    // revert CirclesAvatarMustBeRegistered(_flowVertices[i], 4);
                    revert CirclesErrorOneAddressArg(_flowVertices[i], 0x24);
                }
            }

            address lastAvatar = _flowVertices[_flowVertices.length - 1];
            if (avatars[lastAvatar] == address(0)) {
                // Avatar must be registered.
                // revert CirclesAvatarMustBeRegistered(lastAvatar, 5);
                revert CirclesErrorOneAddressArg(lastAvatar, 0x25);
            }
        }

        {
            // iterate over the coordinate index
            uint16 index = uint16(0);

            for (uint256 i = 0; i < _flow.length; i++) {
                // index: coordinate of Circles identifier avatar address
                // index + 1: sender coordinate
                // index + 2: receiver coordinate
                address circlesId = _flowVertices[_coordinates[index]];
                address from = _flowVertices[_coordinates[index + 1]];
                address to = _flowVertices[_coordinates[index + 2]];
                int256 flow = int256(uint256(_flow[i].amount));

                // check the receiver trusts the Circles being sent
                // and if the sender has enabled consented flow, also check that the sender trusts the receiver
                if (!isPermittedFlow(from, to, circlesId)) {
                    // Flow edge is not permitted.
                    // revert CirclesHubFlowEdgeIsNotPermitted(to, toTokenId(circlesId), 1);
                    revert CirclesErrorAddressUintArgs(to, toTokenId(circlesId), 0x21);
                }

                // nett the flow, dividing out the different Circle identifiers
                nettedFlow[_coordinates[index + 1]] -= flow;
                nettedFlow[_coordinates[index + 2]] += flow;

                index = index + 3;
            }
        }

        return nettedFlow;
    }

    /**
     * @dev Effect the flow edges of the path transfer, this will revert if any balance is insufficient
     * @param _flowVertices an ordered list of avatar addresses as the vertices which the path touches
     * @param _flow array of flow edges, each edge is a struct with the amount and streamSinkId
     * @param _streams array of streams, each stream is a struct that references the source vertex coordinate,
     * the ids of the terminal flow edges of this stream, and the data that is passed to the ERC1155 acceptance check
     * @param _coordinates unpacked array of coordinates of the flow edges
     */
    function _effectPathTransfers(
        address[] calldata _flowVertices,
        FlowEdge[] calldata _flow,
        Stream[] calldata _streams,
        uint16[] memory _coordinates
    ) internal {
        // Create a counter to track the proper definition of the streams
        uint16[] memory streamBatchCounter = new uint16[](_streams.length);
        address[] memory streamReceivers = new address[](_streams.length);

        {
            // iterate over the coordinate index
            uint16 index = uint16(0);

            for (uint256 i = 0; i < _flow.length; i++) {
                // index: coordinate of Circles identifier avatar address
                // index + 1: sender coordinate
                // index + 2: receiver coordinate
                address to = _flowVertices[_coordinates[index + 2]];

                (uint256[] memory ids, uint256[] memory amounts) =
                    _asSingletonArrays(toTokenId(_flowVertices[_coordinates[index]]), uint256(_flow[i].amount));

                // Check that each stream has listed the actual terminal flow edges in the correct order.
                // Note, we can't do this check in _verifyFlowMatrix, because we run out of stack depth there.
                // streamSinkId starts counting from 1, so that 0 is reserved for non-terminal flow edges.
                if (_flow[i].streamSinkId > 0) {
                    uint16 streamSinkArrayId = _flow[i].streamSinkId - 1;
                    if (_streams[streamSinkArrayId].flowEdgeIds[streamBatchCounter[streamSinkArrayId]] != i) {
                        // Invalid stream sink
                        revert CirclesHubFlowEdgeStreamMismatch(i, _flow[i].streamSinkId, 0);
                    }
                    streamBatchCounter[streamSinkArrayId]++;
                    if (streamReceivers[streamSinkArrayId] == address(0)) {
                        streamReceivers[streamSinkArrayId] = to;
                    } else if (streamReceivers[streamSinkArrayId] != to) {
                        // Invalid stream receiver
                        revert CirclesHubFlowEdgeStreamMismatch(i, _flow[i].streamSinkId, 1);
                    }
                }

                emit FlowEdgesScopeSingleStarted(i, _flow[i].streamSinkId);

                // effect the flow edge
                if (!isGroup(to)) {
                    // do a erc1155 single transfer without acceptance check,
                    // as only nett receivers will get an acceptance call
                    _update(
                        _flowVertices[_coordinates[index + 1]], // sender, from coordinate
                        to,
                        ids,
                        amounts
                    );
                } else {
                    // do group mint, and the group itself receives the minted group Circles
                    _groupMint(
                        _flowVertices[_coordinates[index + 1]], // sender, from coordinate
                        to, // receiver, to coordinate
                        to, // group; for triggering group mint, to == the group to mint for
                        ids, // collateral
                        amounts, // amounts
                        "", // path-based group mints never send data to the mint policy
                        false
                    );
                }

                index = index + 3;
            }

            emit FlowEdgesScopeLastEnded();

            // check that all streams are properly defined
            for (uint256 i = 0; i < _streams.length; i++) {
                if (streamReceivers[i] == address(0) || streamBatchCounter[i] != _streams[i].flowEdgeIds.length) {
                    // Invalid stream receiver
                    revert CirclesHubStreamMismatch(i);
                }
            }
        }
    }

    /**
     * @dev Call the acceptance checks for the streams, and return the netted streams
     * @param _flowVertices sorted array of avatar addresses as the vertices which the path touches
     * @param _flow array of flow edges
     * @param _streams array of streams
     * @param _coordinates unpacked array of coordinates of the flow edges
     */
    function _callAcceptanceChecks(
        address[] calldata _flowVertices,
        FlowEdge[] calldata _flow,
        Stream[] calldata _streams,
        uint16[] memory _coordinates
    ) internal returns (int256[] memory) {
        // initialize netted flow to zero
        int256[] memory nettedFlow = new int256[](_flowVertices.length);

        // effect the stream transfers with acceptance calls
        for (uint256 i = 0; i < _streams.length; i++) {
            uint256[] memory ids = new uint256[](_streams[i].flowEdgeIds.length);
            uint256[] memory amounts = new uint256[](_streams[i].flowEdgeIds.length);
            uint256 streamTotal = uint256(0);
            for (uint256 j = 0; j < _streams[i].flowEdgeIds.length; j++) {
                // the Circles identifier coordinate is the first of three coordinates per flow edge
                ids[j] = toTokenId(_flowVertices[_coordinates[3 * _streams[i].flowEdgeIds[j]]]);
                amounts[j] = _flow[_streams[i].flowEdgeIds[j]].amount;
                streamTotal += amounts[j];
            }
            // use the first sink flow edge to recover the receiver coordinate
            uint16 receiverCoordinate = _coordinates[3 * _streams[i].flowEdgeIds[0] + 2];
            address receiver = _flowVertices[receiverCoordinate];
            _acceptanceCheck(
                _flowVertices[_streams[i].sourceCoordinate], // from
                receiver, // to
                ids, // batch of Circles identifiers terminating in receiver
                amounts, // batch of amounts terminating in receiver
                _streams[i].data // user-provided data for stream
            );
            // require(streamTotal <= uint256(type(int256).max));
            nettedFlow[_streams[i].sourceCoordinate] -= int256(streamTotal);
            // to recover the receiver coordinate, get the first sink
            nettedFlow[receiverCoordinate] += int256(streamTotal);

            // emit the stream completed event which expresses the effective "ERC1155:BatchTransfer" event
            // for the stream as part of a batch of path transfers.
            emit StreamCompleted(msg.sender, _flowVertices[_streams[i].sourceCoordinate], receiver, ids, amounts);
        }

        return nettedFlow;
    }

    function _matchNettedFlows(int256[] memory _streamsNettedFlow, int256[] memory _matrixNettedFlow) internal pure {
        if (_streamsNettedFlow.length != _matrixNettedFlow.length) {
            // Mismatch in netted flow length.
            // revert CirclesArraysLengthMismatch(_streamsNettedFlow.length, _matrixNettedFlow.length, 5);
            revert CirclesErrorNoArgs(0xA5);
        }
        for (uint256 i = 0; i < _streamsNettedFlow.length; i++) {
            if (_streamsNettedFlow[i] != _matrixNettedFlow[i]) {
                // Intended flow does not match verified flow.
                revert CirclesHubNettedFlowMismatch(i, _matrixNettedFlow[i], _streamsNettedFlow[i]);
            }
        }
    }

    /**
     * Register human allows to register an avatar for a human,
     * and returns the status of the associated v1 Circles contract.
     * Additionally set the trust to self indefinitely.
     * @param _human address of the human to be registered
     */
    function _registerHuman(address _human, address _inviter)
        internal
        returns (address v1CirclesStatus, uint256 v1LastTouched)
    {
        // insert avatar into linked list; reverts if it already exists
        _insertAvatar(_human);

        // set the last mint time to the current timestamp for invited human
        // and register the v1 Circles contract status
        (v1CirclesStatus, v1LastTouched) = _avatarV1CirclesStatus(_human);
        MintTime storage mintTime = mintTimes[_human];
        mintTime.mintV1Status = v1CirclesStatus;
        mintTime.lastMintTime = uint96(block.timestamp);

        // trust self indefinitely, cannot be altered later
        _trust(_human, _human, INDEFINITE_FUTURE);

        emit RegisterHuman(_human, _inviter);

        return (v1CirclesStatus, v1LastTouched);
    }

    /**
     * Register a group avatar.
     * @param _avatar address of the group registering
     * @param _mint address of the mint policy for the group
     * @param _treasury address of the treasury for the group
     * @param _name name of the group Circles
     * @param _symbol symbol of the group Circles
     */
    function _registerGroup(
        address _avatar,
        address _mint,
        address _treasury,
        string calldata _name,
        string calldata _symbol
    ) internal {
        if (_mint == address(0) || _treasury == address(0)) {
            // Mint address can not be zero.
            // Treasury address can not be zero.
            revert CirclesErrorNoArgs(0x02);
        }
        if (!nameRegistry.isValidName(_name) || !nameRegistry.isValidSymbol(_symbol)) {
            // Invalid group name or symbol
            // name must be ASCII alphanumeric and some special characters
            revert CirclesErrorNoArgs(0x03);
        }

        // insert avatar into linked list; reverts if it already exists
        _insertAvatar(_avatar);

        // store the mint policy for the group
        mintPolicies[_avatar] = _mint;

        // store the treasury for the group
        treasuries[_avatar] = _treasury;
    }

    function _trust(address _truster, address _trustee, uint96 _expiry) internal {
        _upsertTrustMarker(_truster, _trustee, _expiry);

        emit Trust(_truster, _trustee, _expiry);
    }

    function _ensureAvatarsRegistered(address _inviter, address[] calldata _avatars) internal returns (uint256) {
        uint256 registrationCount = 0;
        for (uint256 i = 0; i < _avatars.length; i++) {
            if (avatars[_avatars[i]] == address(0)) {
                registrationCount++;
                _registerHuman(_avatars[i], _inviter);
            } else {
                if (!isHuman(_avatars[i])) {
                    // Only humans can be registered.
                    // revert CirclesHubMustBeHuman(_avatars[i], 5);
                    revert CirclesErrorOneAddressArg(_avatars[i], 0x05);
                }
            }
        }

        return registrationCount;
    }

    /**
     * Check the status of an avatar's Circles in the Hub v1 contract,
     * and update the mint status of the avatar.
     * @param _human Address of the human avatar to check the v1 mint status of.
     */
    function _checkHumanV1CirclesStatus(address _human) internal {
        // check if v1 Circles is known to be stopped
        if (mintTimes[_human].mintV1Status != CIRCLES_STOPPED_V1) {
            // if v1 Circles is not known to be stopped, check the status
            (address v1MintStatus,) = _avatarV1CirclesStatus(_human);
            _updateMintV1Status(_human, v1MintStatus);
        }
    }

    /**
     * @dev Checks the status of an avatar's Circles in the Hub v1 contract,
     * and returns the address of the Circles if it exists and is not stopped.
     * Else, it returns the zero address if no Circles exist,
     * and it returns the address CIRCLES_STOPPED_V1 (0x1) if the Circles contract is stopped.
     * If a Circles contract exists, it also returns the last touched time of the Circles v1 token.
     * @param _avatar avatar address for which to check registration in Hub v1
     * @return address of the Circles contract if it exists and is not stopped, or zero address if no Circles exist
     * or CIRCLES_STOPPED_V1 if the Circles contract is stopped.
     * Additionally, return the last touched time of the Circles v1 token (ie. the last time it minted CRC),
     * if the token exists, or zero if it does not.
     */
    function _avatarV1CirclesStatus(address _avatar) internal view returns (address, uint256) {
        address circlesV1 = hubV1.userToToken(_avatar);
        // no token exists in Hub v1, so return status is zero address
        if (circlesV1 == address(0)) return (address(0), uint256(0));
        // get the last touched time of the Circles v1 token
        uint256 lastTouched = ITokenV1(circlesV1).lastTouched();
        // return the status of the token
        if (ITokenV1(circlesV1).stopped()) {
            // return the stopped status of the Circles contract, and the last touched time
            return (CIRCLES_STOPPED_V1, lastTouched);
        } else {
            // return the address of the Circles contract if it exists and is not stopped
            return (circlesV1, lastTouched);
        }
    }

    /**
     * Update the mint status of an avatar given the status of the v1 Circles contract.
     * @param _human Address of the human avatar to check the v1 mint status of.
     * @param _mintV1Status Mint status of the v1 Circles contract.
     */
    function _updateMintV1Status(address _human, address _mintV1Status) internal {
        MintTime storage mintTime = mintTimes[_human];
        // precautionary check to ensure that the last mint time is already set
        // as this marks whether an avatar is registered as human or not
        if (mintTime.lastMintTime == 0) {
            // Avatar must already be registered as human before we call update
            // revert CirclesLogicAssertion(0);
            revert CirclesErrorNoArgs(0x80);
        }
        // if the status has changed, update the last mint time
        // to avoid possible overlap of the mint between Hub v1 and Hub v2
        if (mintTime.mintV1Status != _mintV1Status) {
            mintTime.mintV1Status = _mintV1Status;
            // for last mint time take the maximum to avoid resetting "INDEFINITE_FUTURE"
            // which indicates stopped status of the human
            mintTime.lastMintTime = uint96(_max(mintTime.lastMintTime, uint96(block.timestamp)));
        }
    }

    /**
     * Insert an avatar into the linked list of avatars.
     * Reverts on inserting duplicates.
     * @param _avatar avatar address to insert
     */
    function _insertAvatar(address _avatar) internal {
        if (avatars[_avatar] != address(0)) {
            // Avatar already inserted
            // revert CirclesHubAvatarAlreadyRegistered(_avatar, 0);
            revert CirclesErrorOneAddressArg(_avatar, 0x80);
        }
        avatars[_avatar] = avatars[SENTINEL];
        avatars[SENTINEL] = _avatar;
    }

    function _validateAddressFromId(uint256 _id, uint8 _code) internal pure returns (address) {
        if (_id > type(uint160).max) {
            // Invalid Circles identifier, not derived from address
            revert CirclesIdMustBeDerivedFromAddress(_id, _code);
        }
        return address(uint160(_id));
    }

    /**
     * @dev abi.encodePacked of an array uint16[] would still pad each uint16 - I think;
     *      if abi packing does not add padding this function is redundant and should be thrown out
     *      Unpacks the packed coordinates from bytes.
     *      Each coordinate is 16 bits, and each triplet is thus 48 bits.
     * @param _packedData The packed data containing the coordinates.
     * @param _numberOfTriplets The number of coordinate triplets in the packed data.
     * @return unpackedCoordinates_ An array of unpacked coordinates (of length 3* numberOfTriplets)
     */
    function _unpackCoordinates(bytes calldata _packedData, uint256 _numberOfTriplets)
        internal
        pure
        returns (uint16[] memory unpackedCoordinates_)
    {
        if (_packedData.length != _numberOfTriplets * 6) {
            // Invalid packed data length
            // revert CirclesArraysLengthMismatch(_packedData.length, _numberOfTriplets, 6);
            revert CirclesErrorNoArgs(0xA6);
        }

        unpackedCoordinates_ = new uint16[](_numberOfTriplets * 3);
        uint256 index = 0;

        // per three coordinates, shift each upper byte left
        for (uint256 i = 0; i < _packedData.length; i += 6) {
            unpackedCoordinates_[index++] = uint16(uint8(_packedData[i])) << 8 | uint16(uint8(_packedData[i + 1]));
            unpackedCoordinates_[index++] = uint16(uint8(_packedData[i + 2])) << 8 | uint16(uint8(_packedData[i + 3]));
            unpackedCoordinates_[index++] = uint16(uint8(_packedData[i + 4])) << 8 | uint16(uint8(_packedData[i + 5]));
        }
    }

    // Private functions

    /**
     * @dev Internal function to upsert a trust marker for a truster and a trusted address.
     * It will initialize the linked list for the truster if it does not exist yet.
     * If the trustee is not yet trusted by the truster, it will insert the trust marker.
     * It will update the expiry time for the trusted address.
     */
    function _upsertTrustMarker(address _truster, address _trusted, uint96 _expiry) private {
        if (_truster == address(0) || _trusted == address(0) || _trusted == SENTINEL) {
            revert CirclesErrorNoArgs(0x81); // CirclesLogicAssertion(1);
        }

        TrustMarker storage sentinelMarker = trustMarkers[_truster][SENTINEL];
        if (sentinelMarker.previous == address(0)) {
            // initialize the linked list for truster
            sentinelMarker.previous = SENTINEL;
        }

        TrustMarker storage trustMarker = trustMarkers[_truster][_trusted];
        if (trustMarker.previous == address(0)) {
            // insert the trust marker
            trustMarker.previous = sentinelMarker.previous;
            sentinelMarker.previous = _trusted;
        }

        // update the expiry; checks must be done by caller
        trustMarker.expiry = _expiry;
    }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IHubV1","name":"_hubV1","type":"address"},{"internalType":"contract INameRegistry","name":"_nameRegistry","type":"address"},{"internalType":"address","name":"_migration","type":"address"},{"internalType":"contract IERC20Lift","name":"_liftERC20","type":"address"},{"internalType":"address","name":"_standardTreasury","type":"address"},{"internalType":"uint256","name":"_inflationDayZero","type":"uint256"},{"internalType":"uint256","name":"_bootstrapTime","type":"uint256"},{"internalType":"string","name":"_gatewayUrl","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"code","type":"uint8"}],"name":"CirclesAmountOverflow","type":"error"},{"inputs":[{"internalType":"uint8","name":"code","type":"uint8"}],"name":"CirclesERC1155CannotReceiveBatch","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint8","name":"","type":"uint8"}],"name":"CirclesErrorAddressUintArgs","type":"error"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"CirclesErrorNoArgs","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint8","name":"","type":"uint8"}],"name":"CirclesErrorOneAddressArg","type":"error"},{"inputs":[{"internalType":"uint256","name":"flowEdgeId","type":"uint256"},{"internalType":"uint256","name":"streamId","type":"uint256"},{"internalType":"uint8","name":"code","type":"uint8"}],"name":"CirclesHubFlowEdgeStreamMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"vertexPosition","type":"uint256"},{"internalType":"int256","name":"matrixNettedFlow","type":"int256"},{"internalType":"int256","name":"streamNettedFlow","type":"int256"}],"name":"CirclesHubNettedFlowMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"name":"CirclesHubStreamMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"providedId","type":"uint256"},{"internalType":"uint8","name":"code","type":"uint8"}],"name":"CirclesIdMustBeDerivedFromAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint8","name":"code","type":"uint8"}],"name":"CirclesInvalidCirclesId","type":"error"},{"inputs":[{"internalType":"uint256","name":"parameter","type":"uint256"},{"internalType":"uint8","name":"code","type":"uint8"}],"name":"CirclesInvalidParameter","type":"error"},{"inputs":[],"name":"CirclesProxyAlreadyInitialized","type":"error"},{"inputs":[{"internalType":"uint8","name":"code","type":"uint8"}],"name":"CirclesReentrancyGuard","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC1155InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC1155InvalidApprover","type":"error"},{"inputs":[{"internalType":"uint256","name":"idsLength","type":"uint256"},{"internalType":"uint256","name":"valuesLength","type":"uint256"}],"name":"ERC1155InvalidArrayLength","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC1155InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC1155InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC1155InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC1155MissingApprovalForAll","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"discountCost","type":"uint256"}],"name":"DiscountCost","type":"event"},{"anonymous":false,"inputs":[],"name":"FlowEdgesScopeLastEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"flowEdgeId","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"streamId","type":"uint16"}],"name":"FlowEdgesScopeSingleStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"group","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"collateral","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"GroupMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"human","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endPeriod","type":"uint256"}],"name":"PersonalMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"group","type":"address"},{"indexed":true,"internalType":"address","name":"mint","type":"address"},{"indexed":true,"internalType":"address","name":"treasury","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"}],"name":"RegisterGroup","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"avatar","type":"address"},{"indexed":true,"internalType":"address","name":"inviter","type":"address"}],"name":"RegisterHuman","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"organization","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"RegisterOrganization","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"avatar","type":"address"},{"indexed":false,"internalType":"bytes32","name":"flag","type":"bytes32"}],"name":"SetAdvancedUsageFlag","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"avatar","type":"address"}],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"StreamCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"truster","type":"address"},{"indexed":true,"internalType":"address","name":"trustee","type":"address"},{"indexed":false,"internalType":"uint256","name":"expiryTime","type":"uint256"}],"name":"Trust","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"advancedUsageFlags","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"avatars","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_accounts","type":"address[]"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint64","name":"_day","type":"uint64"}],"name":"balanceOfOnDay","outputs":[{"internalType":"uint256","name":"balanceOnDay_","type":"uint256"},{"internalType":"uint256","name":"discountCost_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_human","type":"address"}],"name":"calculateIssuance","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_human","type":"address"}],"name":"calculateIssuanceWithCheck","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_demurrageValue","type":"uint256"},{"internalType":"uint64","name":"_dayUpdated","type":"uint64"}],"name":"convertDemurrageToInflationaryValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_inflationaryValue","type":"uint256"},{"internalType":"uint64","name":"_day","type":"uint64"}],"name":"convertInflationaryToDemurrageValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"day","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_group","type":"address"},{"internalType":"address[]","name":"_collateralAvatars","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"groupMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"inflationDayZero","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"invitationOnlyTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_group","type":"address"}],"name":"isGroup","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_human","type":"address"}],"name":"isHuman","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_organization","type":"address"}],"name":"isOrganization","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"address","name":"_circlesAvatar","type":"address"}],"name":"isPermittedFlow","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_truster","type":"address"},{"internalType":"address","name":"_trustee","type":"address"}],"name":"isTrusted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address[]","name":"_avatars","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mintPolicies","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_flowVertices","type":"address[]"},{"components":[{"internalType":"uint16","name":"streamSinkId","type":"uint16"},{"internalType":"uint192","name":"amount","type":"uint192"}],"internalType":"struct TypeDefinitions.FlowEdge[]","name":"_flow","type":"tuple[]"},{"components":[{"internalType":"uint16","name":"sourceCoordinate","type":"uint16"},{"internalType":"uint16[]","name":"flowEdgeIds","type":"uint16[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct TypeDefinitions.Stream[]","name":"_streams","type":"tuple[]"},{"internalType":"bytes","name":"_packedCoordinates","type":"bytes"}],"name":"operateFlowMatrix","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"personalMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_mint","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"bytes32","name":"_metadataDigest","type":"bytes32"}],"name":"registerCustomGroup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_mint","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"bytes32","name":"_metadataDigest","type":"bytes32"}],"name":"registerGroup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_inviter","type":"address"},{"internalType":"bytes32","name":"_metadataDigest","type":"bytes32"}],"name":"registerHuman","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"bytes32","name":"_metadataDigest","type":"bytes32"}],"name":"registerOrganization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_flag","type":"bytes32"}],"name":"setAdvancedUsageFlag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_human","type":"address"}],"name":"stopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_avatar","type":"address"}],"name":"toTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"treasuries","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_trustReceiver","type":"address"},{"internalType":"uint96","name":"_expiry","type":"uint96"}],"name":"trust","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"trustMarkers","outputs":[{"internalType":"address","name":"previous","type":"address"},{"internalType":"uint96","name":"expiry","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_avatar","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"enum CirclesType","name":"_type","type":"uint8"}],"name":"wrap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"}]

Deployed Bytecode

0x608060405234801561000f575f80fd5b506004361061026a575f3560e01c80638ff12b6d1161014b578063bfde380d116100bf578063edeeb93c11610084578063edeeb93c14610660578063f179c71314610688578063f242432a1461069b578063f3177079146106ae578063f72c436f146106c1578063f796a4af146106d4575f80fd5b8063bfde380d146105d7578063da33e065146105ea578063e76cec5314610612578063e985e9c514610625578063eb8c276014610638575f80fd5b80639e0cc3c4116101105780639e0cc3c41461054b578063a22cb46514610578578063aabd69541461058b578063b1ce8eab1461059e578063bd85b039146105b1578063bda79c54146105c4575f80fd5b80638ff12b6d146104c457806395d89b41146104ef57806399342aa3146104f75780639bec57261461050a5780639cd023131461051d575f80fd5b80632f01b98b116101e25780636cb498e5116101a75780636cb498e5146103fd57806375dcebc7146104105780637c234d01146104235780637cd0cea61461042b5780637cf637cd1461049757806380a5a371146104b1575f80fd5b80632f01b98b1461037d57806347df87ab146103a45780634e1273f4146103b75780634f338925146103d75780636713e230146103ea575f80fd5b80630849b234116102335780630849b234146102e95780630d22d9b5146103295780630d873a791461033c5780630e89341c14610344578063253dd0b5146103575780632eb2c2d61461036a575f80fd5b8062fdd58e1461026e57806301ffc9a7146102945780630528f507146102b757806306fdde03146102cc57806307da68f5146102e1575b5f80fd5b61028161027c366004614e53565b6106f3565b6040519081526020015b60405180910390f35b6102a76102a2366004614e92565b61070e565b604051901515815260200161028b565b6102ca6102c5366004614eea565b61075d565b005b6102d46108f6565b60405161028b9190614fbb565b6102ca610968565b6103116102f7366004614fcd565b601c6020525f90815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161028b565b6102ca610337366004615028565b610a16565b6102ca610b74565b6102d4610352366004615110565b610bb2565b610281610365366004615142565b610c44565b6102ca6103783660046152b1565b610c76565b6102817f000000000000000000000000000000000000000000000000000000006737e08881565b6102a76103b2366004614fcd565b610cdd565b6103ca6103c5366004615357565b610d2f565b60405161028b919061544c565b6102a76103e536600461545e565b610dff565b6102a76103f83660046154a6565b610ed4565b6102ca61040b3660046154dd565b610f12565b6102ca61041e366004615581565b611030565b6102815f5481565b6104706104393660046154a6565b601d60209081525f92835260408084209091529082529020546001600160a01b03811690600160a01b90046001600160601b031682565b604080516001600160a01b0390931683526001600160601b0390911660208301520161028b565b6102816104a5366004614fcd565b6001600160a01b031690565b6102ca6104bf3660046155b8565b6110c7565b6104d76104d2366004615110565b6111be565b6040516001600160401b03909116815260200161028b565b6102d46111da565b610281610505366004615142565b61120b565b6102ca610518366004615606565b611228565b61053061052b366004614fcd565b6113bc565b6040805193845260208401929092529082015260600161028b565b6102a7610559366004614fcd565b6001600160a01b039081165f908152601b602052604090205416151590565b6102ca6105863660046156a9565b6113df565b6103116105993660046156d5565b6113ea565b6102a76105ac366004614fcd565b6114d2565b6102816105bf366004615110565b611546565b6102ca6105d2366004615110565b6115bc565b6102ca6105e536600461570c565b611643565b6103116105f8366004614fcd565b601b6020525f90815260409020546001600160a01b031681565b6102ca610620366004614e53565b611754565b6102a76106333660046154a6565b61190f565b61064b610646366004615753565b61193c565b6040805192835260208301919091520161028b565b61031161066e366004614fcd565b601a6020525f90815260409020546001600160a01b031681565b610530610696366004614fcd565b611a1a565b6102ca6106a936600461578e565b611a37565b6102ca6106bc3660046157f1565b611a96565b6102a76106cf366004614fcd565b611c1b565b6102816106e2366004614fcd565b601e6020525f908152604090205481565b5f806107038484610646426111be565b509150505b92915050565b5f6001600160e01b03198216636cdb3d1360e11b148061073e57506001600160e01b031982166303a24d0760e21b145b8061070857506301ffc9a760e01b6001600160e01b0319831614610708565b60195461077a90339088906001600160a01b031688888888611c47565b60165460405163d199889360e01b81526001600160a01b039091169063d1998893906107ae90339089908990600401615895565b5f604051808303815f87803b1580156107c5575f80fd5b505af11580156107d7573d5f803e3d5ffd5b505060165460405163e27871dd60e01b81526001600160a01b03909116925063e27871dd915061080f90339087908790600401615895565b5f604051808303815f87803b158015610826575f80fd5b505af1158015610838573d5f803e3d5ffd5b505060165460405163e44b8c3560e01b8152336004820152602481018590526001600160a01b03909116925063e44b8c3591506044015f604051808303815f87803b158015610885575f80fd5b505af1158015610897573d5f803e3d5ffd5b50506019546040516001600160a01b039182169350908916915033907f851510db3e53b795660f9ffba16469222d46d357be10c67f27f619ffe33b5874906108e6908a908a908a908a906158c2565b60405180910390a4505050505050565b60165460405162cc244960e11b81523060048201526060916001600160a01b0316906301984892906024015b5f60405180830381865afa15801561093c573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261096391908101906158f3565b905090565b61097133611c1b565b61099b5733600260405162c14c0760e81b815260040161099292919061595b565b60405180910390fd5b335f90815260156020526040902080546bfffffffffffffffffffffffe19600160a01b9091046001600160601b0316016109d25750565b80546001600160a01b03166001600160a01b031917815560405133907f55c4adf1f68f084b809304657594a92ba835ada8d3b5340955bf05746723c05b905f90a250565b5f5c15610a21575f80fd5b60015f5d5f610a31838388611de4565b90505f5b84811015610b2857610aa28a8a888885818110610a5457610a54615977565b9050602002810190610a66919061598b565b610a749060208101906159a9565b61ffff16818110610a8757610a87615977565b9050602002016020810190610a9c9190614fcd565b3361190f565b610b20578989878784818110610aba57610aba615977565b9050602002810190610acc919061598b565b610ada9060208101906159a9565b61ffff16818110610aed57610aed615977565b9050602002016020810190610b029190614fcd565b815f604051632f20c6dd60e11b8152600401610992939291906159ca565b600101610a35565b505f610b378a8a8a8a8661200c565b9050610b488a8a8a8a8a8a8861248c565b5f610b588b8b8b8b8b8b89612ae8565b9050610b6481836130c4565b5050505f805d5050505050505050565b610b7d33611c1b565b610b9e5733600160405162c14c0760e81b815260040161099292919061595b565b610ba73361319c565b610bb0336131d7565b565b606060148054610bc1906159ee565b80601f0160208091040260200160405190810160405280929190818152602001828054610bed906159ee565b8015610c385780601f10610c0f57610100808354040283529160200191610c38565b820191905f5260205f20905b815481529060010190602001808311610c1b57829003601f168201915b50505050509050919050565b5f80610c626801000d05c213d3f237846001600160401b0316613296565b9050610c6e81856134b3565b949350505050565b336001600160a01b0386168114801590610c975750610c95868261190f565b155b15610cc85760405163711bec9160e11b81526001600160a01b03808316600483015287166024820152604401610992565b610cd58686868686613517565b505050505050565b5f610ce782611c1b565b610d085781600360405162c14c0760e81b815260040161099292919061595b565b5050335f90815260156020526040902054600160a01b90046001600160601b039081161490565b60608151835114610d605781518351604051635b05999160e01b815260048101929092526024820152604401610992565b5f610d6a426111be565b90505f84516001600160401b03811115610d8657610d8661516c565b604051908082528060200260200182016040528015610daf578160200160208202803683370190505b5090505f5b855181101561070357602080820287010151610dd9906020808402880101518561193c565b50828281518110610dec57610dec615977565b6020908102919091010152600101610db4565b6001600160a01b038281165f908152601d6020908152604080832093851683529290529081205442600160a01b9091046001600160601b03161015610e4557505f610ecd565b6001600160a01b0384165f908152601e6020526040902054600116610e6c57506001610ecd565b6001600160a01b038481165f908152601d602090815260408083209387168352929052205442600160a01b9091046001600160601b031610801590610eca57506001600160a01b0383165f908152601e602052604090205460011615155b90505b9392505050565b6001600160a01b039182165f908152601d6020908152604080832093909416825291909152205442600160a01b9091046001600160601b0316101590565b5f856001600160401b03811115610f2b57610f2b61516c565b604051908082528060200260200182016040528015610f54578160200160208202803683370190505b5090505f5b86811015610fb057610f8b888883818110610f7657610f76615977565b90506020020160208101906104a59190614fcd565b828281518110610f9d57610f9d615977565b6020908102919091010152600101610f59565b5061102633338a848989808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a90819084018382808284375f920191909152506001925061357c915050565b5050505050505050565b335f908152601a60205260409020546001600160a01b0316158061105b57506001600160a01b038216155b8061106f57506001600160a01b0382166001145b8061108257506001600160a01b03821633145b156110a4578160a160405162c14c0760e81b815260040161099292919061595b565b42816001600160601b031610156110b85750425b6110c33383836138c3565b5050565b5f6110d2855f613920565b6001600160a01b038082165f908152601b602052604090205491925016801580159061111757506001600160a01b038281165f908152601c6020526040902054163314155b156111b3576040516343101c5f60e11b81526001600160a01b0382169063862038be9061115090339086908a908a908a90600401615a26565b6020604051808303815f875af115801561116c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111909190615a59565b6111b357338660408051632f20c6dd60e11b8152600401610992939291906159ca565b610cd533878761395c565b5f620151805f54836111d09190615a88565b6107089190615aaf565b6016546040516354371abb60e11b81523060048201526060916001600160a01b03169063a86e357690602401610922565b5f80610c6267fff2fae779633d1e846001600160401b0316613296565b61123733888888888888611c47565b60165460405163d199889360e01b81526001600160a01b039091169063d19988939061126b90339089908990600401615895565b5f604051808303815f87803b158015611282575f80fd5b505af1158015611294573d5f803e3d5ffd5b505060165460405163e27871dd60e01b81526001600160a01b03909116925063e27871dd91506112cc90339087908790600401615895565b5f604051808303815f87803b1580156112e3575f80fd5b505af11580156112f5573d5f803e3d5ffd5b505060165460405163e44b8c3560e01b8152336004820152602481018590526001600160a01b03909116925063e44b8c3591506044015f604051808303815f87803b158015611342575f80fd5b505af1158015611354573d5f803e3d5ffd5b50505050856001600160a01b0316876001600160a01b0316336001600160a01b03167f851510db3e53b795660f9ffba16469222d46d357be10c67f27f619ffe33b5874888888886040516113ab94939291906158c2565b60405180910390a450505050505050565b5f805f6113c88461319c565b6113d184613a2f565b9250925092505b9193909250565b6110c3338383613d2a565b5f6113f484611c1b565b15801561141857506001600160a01b038481165f908152601b602052604090205416155b1561143a5783602260405162c14c0760e81b815260040161099292919061595b565b6018546040516395b645b160e01b81525f916001600160a01b0316906395b645b19061146c9088908790600401615ac2565b6020604051808303815f875af1158015611488573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114ac9190615afb565b9050610eca33826001600160a01b0388168760405180602001604052805f815250611a37565b6001600160a01b038181165f908152601a60205260408120549091161580159061151357506001600160a01b038281165f908152601b602052604090205416155b80156107085750506001600160a01b03165f90815260156020526040902054600160a01b90046001600160601b03161590565b5f8181526012602090815260408083208151808301909252546001600160c01b0381168252600160c01b90046001600160401b0316918101919091528161158c426111be565b9050610c6e825f01516001600160c01b03168360200151836115ae9190615b16565b6001600160401b0316613db6565b335f908152601a60205260409020546001600160a01b03166115f55733602360405162c14c0760e81b815260040161099292919061595b565b335f818152601e602052604090819020839055517f97595e7ebea71ea0ce8653cbc96a4288b887500876f1e475c26e789506130fc6906116389084815260200190565b60405180910390a250565b61164c33613dcf565b60165460405163d199889360e01b81526001600160a01b039091169063d19988939061168090339087908790600401615895565b5f604051808303815f87803b158015611697575f80fd5b505af11580156116a9573d5f803e3d5ffd5b505060165460405163e44b8c3560e01b8152336004820152602481018590526001600160a01b03909116925063e44b8c3591506044015f604051808303815f87803b1580156116f6575f80fd5b505af1158015611708573d5f803e3d5ffd5b50505050336001600160a01b03167fe191edab93dcedd4a646317289fded1d9665862550b031a14bd3c5b0bc0e50078484604051611747929190615b3d565b60405180910390a2505050565b6001600160a01b0382166117d5575f8061176e3385613e6d565b90925090506001600160a01b03821660011415806117ac57507f000000000000000000000000000000000000000000000000000000006737e0888110155b156117ce5733606060405162c14c0760e81b815260040161099292919061595b565b50506118ae565b6117de82611c1b565b15806117f157506117ef8233610ed4565b155b15611813578160a060405162c14c0760e81b815260040161099292919061595b565b61181d3383613e6d565b50507f000000000000000000000000000000000000000000000000000000006737e0884211156118ae5761187c826001600160a01b0381166118616012600a615c30565b61186c906030615c3e565b611877906002615c3e565b61395c565b6118ae338061188d6012600a615c30565b611898906030615c3e565b60405180602001604052805f8152506001613f0f565b80156110c35760165460405163e44b8c3560e01b8152336004820152602481018390526001600160a01b039091169063e44b8c35906044015f604051808303815f87803b1580156118fd575f80fd5b505af1158015610cd5573d5f803e3d5ffd5b6001600160a01b039182165f90815260136020908152604080832093909416825291909152205460ff1690565b5f8281526011602090815260408083206001600160a01b038716845282528083208151808301909252546001600160c01b03811682526001600160401b03600160c01b9091048116928201839052839290851610156119d5576020810151604051632f20c6dd60e11b81526001600160a01b03881660048201526001600160401b03909116602482015260a06044820152606401610992565b5f816020015185036001600160401b031690506119fe825f01516001600160c01b031682613db6565b9151919350506001600160c01b03168290039050935093915050565b5f805f611a2684611c1b565b6113c857505f9150819050806113d8565b336001600160a01b0386168114801590611a585750611a56868261190f565b155b15611a895760405163711bec9160e11b81526001600160a01b03808316600483015287166024820152604401610992565b610cd58686868686613ffd565b6017546001600160a01b03163314611ac5573360e060405162c14c0760e81b815260040161099292919061595b565b6001600160a01b038581165f908152601a6020526040902054161580611aeb5750828114155b15611b0d5784602160405162c14c0760e81b815260040161099292919061595b565b5f611b19868686614080565b611b256012600a615c30565b611b30906030615c3e565b611b3b906002615c3e565b611b459190615c3e565b90507f000000000000000000000000000000000000000000000000000000006737e08842118015611b7557505f81115b15611bb857611b8386611c1b565b611ba45785600460405162c14c0760e81b815260040161099292919061595b565b611bb8866001600160a01b0381168361395c565b5f5b84811015611c1257611c0a87611bdb888885818110610f7657610f76615977565b868685818110611bed57611bed615977565b9050602002013560405180602001604052805f8152506001613f0f565b600101611bba565b50505050505050565b6001600160a01b03165f90815260156020526040902054600160a01b90046001600160601b0316151590565b6001600160a01b0386161580611c6457506001600160a01b038516155b15611c855760405163d82c8fc960e01b815260026004820152602401610992565b601654604051631e30397f60e01b81526001600160a01b0390911690631e30397f90611cb79087908790600401615b3d565b602060405180830381865afa158015611cd2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cf69190615a59565b1580611d7057506016546040516347ea7b8d60e11b81526001600160a01b0390911690638fd4f71a90611d2f9085908590600401615b3d565b602060405180830381865afa158015611d4a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d6e9190615a59565b155b15611d915760405163d82c8fc960e01b815260036004820152602401610992565b611d9a87613dcf565b5050506001600160a01b039384165f908152601b6020908152604080832080549688166001600160a01b0319978816179055601c9091529020805492909416919092161790915550565b6060611df1826006615c3e565b8314611e135760405163d82c8fc960e01b815260a66004820152602401610992565b611e1e826003615c3e565b6001600160401b03811115611e3557611e3561516c565b604051908082528060200260200182016040528015611e5e578160200160208202803683370190505b5090505f805b84811015612003578585611e79836001615c55565b818110611e8857611e88615977565b919091013560f81c90506008878784818110611ea657611ea6615977565b919091013560f81c90911b9190911790508383611ec281615c68565b945081518110611ed457611ed4615977565b61ffff909216602092830291909101909101528585611ef4836003615c55565b818110611f0357611f03615977565b919091013560f81c905060088787611f1c856002615c55565b818110611f2b57611f2b615977565b919091013560f81c90911b9190911790508383611f4781615c68565b945081518110611f5957611f59615977565b61ffff909216602092830291909101909101528585611f79836005615c55565b818110611f8857611f88615977565b919091013560f81c905060088787611fa1856004615c55565b818110611fb057611fb0615977565b919091013560f81c90911b9190911790508383611fcc81615c68565b945081518110611fde57611fde615977565b61ffff90921660209283029190910190910152611ffc600682615c55565b9050611e64565b50509392505050565b805160609061201c846003615c3e565b14158061202a575061ffff85115b80612033575084155b8061203c575082155b1561205d5760405163d82c8fc960e01b815260a26004820152602401610992565b5f856001600160401b038111156120765761207661516c565b60405190808252806020026020018201604052801561209f578160200160208202803683370190505b5090505f5b6120af600188615a88565b8110156121d85787876120c3836001615c55565b8181106120d2576120d2615977565b90506020020160208101906120e79190614fcd565b6001600160a01b031688888381811061210257612102615977565b90506020020160208101906121179190614fcd565b6001600160a01b0316106121415760405163d82c8fc960e01b815260606004820152602401610992565b5f601a818a8a8581811061215757612157615977565b905060200201602081019061216c9190614fcd565b6001600160a01b03908116825260208201929092526040015f205416036121d05787878281811061219f5761219f615977565b90506020020160208101906121b49190614fcd565b602460405162c14c0760e81b815260040161099292919061595b565b6001016120a4565b505f87876121e7600182615a88565b8181106121f6576121f6615977565b905060200201602081019061220b9190614fcd565b6001600160a01b038082165f908152601a6020526040902054919250166122495780602560405162c14c0760e81b815260040161099292919061595b565b505f805b8581101561247f575f8989878561ffff168151811061226e5761226e615977565b602002602001015161ffff1681811061228957612289615977565b905060200201602081019061229e9190614fcd565b90505f8a8a886122af876001615c80565b61ffff16815181106122c3576122c3615977565b602002602001015161ffff168181106122de576122de615977565b90506020020160208101906122f39190614fcd565b90505f8b8b89612304886002615c80565b61ffff168151811061231857612318615977565b602002602001015161ffff1681811061233357612333615977565b90506020020160208101906123489190614fcd565b90505f8a8a8681811061235d5761235d615977565b90506040020160200160208101906123759190615c9b565b6001600160c01b0316905061238b838386610dff565b6123b857816001600160a01b0385166021604051632f20c6dd60e11b8152600401610992939291906159ca565b80878a6123c6896001615c80565b61ffff16815181106123da576123da615977565b602002602001015161ffff16815181106123f6576123f6615977565b6020026020010181815161240a9190615cc1565b90525080878a61241b896002615c80565b61ffff168151811061242f5761242f615977565b602002602001015161ffff168151811061244b5761244b615977565b6020026020010181815161245f9190615ce0565b90525061246d866003615c80565b9550506001909301925061224d915050565b5090979650505050505050565b5f826001600160401b038111156124a5576124a561516c565b6040519080825280602002602001820160405280156124ce578160200160208202803683370190505b5090505f836001600160401b038111156124ea576124ea61516c565b604051908082528060200260200182016040528015612513578160200160208202803683370190505b5090505f805b878110156129f6575f8b8b87612530866002615c80565b61ffff168151811061254457612544615977565b602002602001015161ffff1681811061255f5761255f615977565b90506020020160208101906125749190614fcd565b90505f8061260c6125b18f8f8b8961ffff168151811061259657612596615977565b602002602001015161ffff16818110610f7657610f76615977565b8d8d878181106125c3576125c3615977565b90506040020160200160208101906125db9190615c9b565b6001600160c01b03166040805160018082526020820194909452808201938452606081019290925260808201905291565b915091505f8c8c8681811061262357612623615977565b61263992602060409092020190810191506159a9565b61ffff16111561288c575f60018d8d8781811061265857612658615977565b61266e92602060409092020190810191506159a9565b6126789190615d07565b9050848b8b8361ffff1681811061269157612691615977565b90506020028101906126a3919061598b565b6126b1906020810190615d22565b8a8461ffff16815181106126c7576126c7615977565b602002602001015161ffff168181106126e2576126e2615977565b90506020020160208101906126f791906159a9565b61ffff161461275557848d8d8781811061271357612713615977565b61272992602060409092020190810191506159a9565b60405163761741fd60e11b8152600481019290925261ffff1660248201525f6044820152606401610992565b878161ffff168151811061276b5761276b615977565b60200260200101805180919061278090615d67565b61ffff1661ffff16815250505f6001600160a01b0316878261ffff16815181106127ac576127ac615977565b60200260200101516001600160a01b0316036127fe5783878261ffff16815181106127d9576127d9615977565b60200260200101906001600160a01b031690816001600160a01b03168152505061288a565b836001600160a01b0316878261ffff168151811061281e5761281e615977565b60200260200101516001600160a01b03161461288a57848d8d8781811061284757612847615977565b61285d92602060409092020190810191506159a9565b60405163761741fd60e11b8152600481019290925261ffff16602482015260016044820152606401610992565b505b837fde794eafdd0c49cd90c138ccbba748d374dd07edadf8996ec6c4c17bb207f62f8d8d878181106128c0576128c0615977565b6128d692602060409092020190810191506159a9565b60405161ffff909116815260200160405180910390a26001600160a01b038084165f908152601b60205260409020541661296c576129678e8e8a61291b896001615c80565b61ffff168151811061292f5761292f615977565b602002602001015161ffff1681811061294a5761294a615977565b905060200201602081019061295f9190614fcd565b84848461419e565b6129da565b6129da8e8e8a61297d896001615c80565b61ffff168151811061299157612991615977565b602002602001015161ffff168181106129ac576129ac615977565b90506020020160208101906129c19190614fcd565b8485858560405180602001604052805f8152505f61357c565b6129e5856003615c80565b945050600190920191506125199050565b506040517f4a5d0e1f680ae81712d9c29b0ad1c00a19eb56be491a766959559fc0dd63ffa3905f90a15f5b85811015612adb575f6001600160a01b0316838281518110612a4557612a45615977565b60200260200101516001600160a01b03161480612ab25750868682818110612a6f57612a6f615977565b9050602002810190612a81919061598b565b612a8f906020810190615d22565b9050848281518110612aa357612aa3615977565b602002602001015161ffff1614155b15612ad3576040516376e7d5d160e11b815260048101829052602401610992565b600101612a21565b5050505050505050505050565b60605f876001600160401b03811115612b0357612b0361516c565b604051908082528060200260200182016040528015612b2c578160200160208202803683370190505b5090505f5b848110156130b7575f868683818110612b4c57612b4c615977565b9050602002810190612b5e919061598b565b612b6c906020810190615d22565b90506001600160401b03811115612b8557612b8561516c565b604051908082528060200260200182016040528015612bae578160200160208202803683370190505b5090505f878784818110612bc457612bc4615977565b9050602002810190612bd6919061598b565b612be4906020810190615d22565b90506001600160401b03811115612bfd57612bfd61516c565b604051908082528060200260200182016040528015612c26578160200160208202803683370190505b5090505f805b898986818110612c3e57612c3e615977565b9050602002810190612c50919061598b565b612c5e906020810190615d22565b9050811015612ddb57612ce38e8e8a8d8d8a818110612c7f57612c7f615977565b9050602002810190612c91919061598b565b612c9f906020810190615d22565b86818110612caf57612caf615977565b9050602002016020810190612cc491906159a9565b612ccf906003615d87565b61ffff168151811061259657612596615977565b848281518110612cf557612cf5615977565b6020026020010181815250508b8b8b8b88818110612d1557612d15615977565b9050602002810190612d27919061598b565b612d35906020810190615d22565b84818110612d4557612d45615977565b9050602002016020810190612d5a91906159a9565b61ffff16818110612d6d57612d6d615977565b9050604002016020016020810190612d859190615c9b565b6001600160c01b0316838281518110612da057612da0615977565b602002602001018181525050828181518110612dbe57612dbe615977565b602002602001015182612dd19190615c55565b9150600101612c2c565b505f878a8a87818110612df057612df0615977565b9050602002810190612e02919061598b565b612e10906020810190615d22565b5f818110612e2057612e20615977565b9050602002016020810190612e3591906159a9565b612e40906003615d87565b612e4b906002615c80565b61ffff1681518110612e5f57612e5f615977565b602002602001015190505f8e8e8361ffff16818110612e8057612e80615977565b9050602002016020810190612e959190614fcd565b9050612f648f8f8d8d8a818110612eae57612eae615977565b9050602002810190612ec0919061598b565b612ece9060208101906159a9565b61ffff16818110612ee157612ee1615977565b9050602002016020810190612ef69190614fcd565b8287878f8f8c818110612f0b57612f0b615977565b9050602002810190612f1d919061598b565b612f2b906040810190615da5565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506143f392505050565b82878c8c89818110612f7857612f78615977565b9050602002810190612f8a919061598b565b612f989060208101906159a9565b61ffff1681518110612fac57612fac615977565b60200260200101818151612fc09190615cc1565b90525086518390889061ffff8516908110612fdd57612fdd615977565b60200260200101818151612ff19190615ce0565b9052506001600160a01b0381168f8f8d8d8a81811061301257613012615977565b9050602002810190613024919061598b565b6130329060208101906159a9565b61ffff1681811061304557613045615977565b905060200201602081019061305a9190614fcd565b6001600160a01b0316336001600160a01b03167fcfe53a731d24ac31b725405f3dca8a4d23512d3e1ade2359fbbe7982bec0fd42888860405161309e929190615de7565b60405180910390a4505060019093019250612b31915050565b5098975050505050505050565b80518251146130e95760405163d82c8fc960e01b815260a56004820152602401610992565b5f5b82518110156131975781818151811061310657613106615977565b602002602001015183828151811061312057613120615977565b60200260200101511461318f578082828151811061314057613140615977565b602002602001015184838151811061315a5761315a615977565b6020026020010151604051635c61ac6f60e11b8152600401610992939291909283526020830191909152604082015260600190565b6001016130eb565b505050565b6001600160a01b038181165f90815260156020526040902054166001146131d4575f6131c78261443a565b5090506110c382826145c3565b50565b5f805f6131e384613a2f565b925092509250825f036131f65750505050565b6001600160a01b038481165f8181526015602052604090208054909216600160a01b426001600160601b031602179091556132449085908560405180602001604052805f8152506001613f0f565b60408051848152602081018490529081018290526001600160a01b038516907f5679cef078fbc961b2e34e49c1f56efe542401e2e59dff633b68ddea27812cc29060600160405180910390a250505050565b5f805f84600f0b1280156132ad5750826001166001145b90505f8085600f0b126132c057846132c4565b845f035b6001600160801b03169050600160801b68010000000000000000821161335e57603f82901b91505b8415613356576001851615613301578102607f1c5b908002607f1c906002851615613317578102607f1c5b908002607f1c90600485161561332d578102607f1c5b908002607f1c906008851615613343578102607f1c5b60049490941c93908002607f1c906132ec565b60401c613470565b603f600160601b8310156133785760209290921b91601f19015b600160701b8310156133905760109290921b91600f19015b600160781b8310156133a85760089290921b91600719015b6001607c1b8310156133c05760049290921b91600319015b6001607e1b8310156133d85760029290921b91600119015b6001607f1b8310156133ef5760019290921b915f19015b5f5b861561345a5760408210613403575f80fd5b600187161561342957918302607f1c918101600160801b83111561342957600192831c92015b928002607f1c9260019190911b90600160801b841061344e57600193841c9391909101905b600187901c96506133f1565b60408110613466575f80fd5b6040039190911c90505b5f8361347c5781613480565b815f035b905060016001607f1b031981128015906134a1575060016001607f1b038113155b6134a9575f80fd5b9695505050505050565b5f815f036134c257505f610708565b5f83600f0b12156134d1575f80fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b038111156134ff575f80fd5b60401b811981111561350f575f80fd5b019392505050565b6001600160a01b03841661354057604051632bfa23e760e11b81525f6004820152602401610992565b6001600160a01b03851661356857604051626a0d4560e21b81525f6004820152602401610992565b6135758585858585614684565b5050505050565b8251845114158061358c57508351155b156135ad5760405163d82c8fc960e01b815260a16004820152602401610992565b6001600160a01b038086165f908152601b6020526040902054166135e6576040805162c14c0760e81b815261099291879160040161595b565b5f805b84518110156136cf575f61361787838151811061360857613608615977565b60200260200101516001613920565b90505f8461362f5761362a8b8a84610dff565b613639565b6136398983610ed4565b9050801580613660575086838151811061365557613655615977565b60200260200101515f145b1561369e578888848151811061367857613678615977565b60200260200101516020604051632f20c6dd60e11b8152600401610992939291906159ca565b8683815181106136b0576136b0615977565b6020026020010151846136c39190615c55565b935050506001016135e9565b506001600160a01b038087165f908152601b60205260409081902054905163b703825960e01b815291169063b703825990613716908b908a908a908a908a90600401615e0b565b6020604051808303815f875af1158015613732573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137569190615a59565b61378357876001600160a01b0387166060604051632f20c6dd60e11b8152600401610992939291906159ca565b5f6040518060200160405280886001600160a01b03168152506040516020016137b891516001600160a01b0316815260200190565b60408051601f198184030181526060830182527f3846339d4d39a76fd554559ca1c53716bfb66f542f4b8c5b7517c56812d99c578352602083810182905283830188905291519093505f9261380f92909101615e68565b60408051601f198184030181529181526001600160a01b03808b165f908152601c602052919091205491925061384a918c9116898985610c76565b613860896001600160a01b038a16858888613f0f565b876001600160a01b0316896001600160a01b03168b6001600160a01b03167f3a5b9c28bd46059b05474dba7c89bea05288c635ea94ef13a7870d081c87a5288a8a6040516138af929190615de7565b60405180910390a450505050505050505050565b6138ce83838361469d565b6040516001600160601b03821681526001600160a01b0380841691908516907fe60c754dd8ab0b1b5fccba257d6ebcd7d09e360ab7dd7a6e58198ca1f57cdcec906020015b60405180910390a3505050565b5f6001600160a01b038311156139555760405163a127935960e01b81526004810184905260ff83166024820152604401610992565b5090919050565b6139678383836147ae565b5f613971426111be565b5f8481526012602090815260408083208151808301909252546001600160c01b038116808352600160c01b9091046001600160401b0316928201839052939450926139c0916115ae9086615b16565b9050838110156139e65760405163d82c8fc960e01b815260846004820152602401610992565b6001600160c01b03939003831681526001600160401b0391821660208083019182525f95865260129052604090942090519351909116600160c01b029290911691909117905550565b6001600160a01b038181165f908152601560209081526040808320815180830190925254938416808252600160a01b9094046001600160601b03169181019190915290918291829115801590613a90575080516001600160a01b0316600114155b15613ab2578460c060405162c14c0760e81b815260040161099292919061595b565b5f610e108260200151613ac59190615eaa565b6001600160601b031690505f613add610e1042615aaf565b90508082101580613afb575060208301516001600160601b03908116145b15613b11575f805f9550955095505050506113d8565b5f613b35613b226212750042615a88565b85602001516001600160601b0316614814565b90505f613b41826111be565b6001600160401b031690505f613b56426111be565b6001600160401b031690505f613b6c8383615a88565b90505f613ba9610e105f548662015180613b869190615c3e565b613b909190615c55565b613b9a9088615a88565b613ba49190615aaf565b614823565b90505f425f54856001613bbc9190615c55565b613bc99062015180615c3e565b613bd39190615c55565b613bdd9190615a88565b90505f613bec610e1083615aaf565b90505f613c1a81613bff610e1086615ecf565b11613c0a575f613c0d565b60015b613ba49060ff1684615c55565b90505f613c5b613c55600988600f8110613c3657613c36615977565b600291828204019190066010029054906101000a9004600f0b8761483f565b83614874565b9050613ca6613c95600188600f8110613c7657613c76615977565b600291828204019190066010029054906101000a9004600f0b836148a5565b613ca16012600a615c30565b6134b3565b613cb286610e106134b3565b613cbf8a62015180615c3e565b5f54613ccb9190615c55565b613cd59190615c55565b613ce184610e106134b3565b613cee8a62015180615c3e565b5f54613cfa9190615c55565b613d079062015180615c55565b613d119190615a88565b9e509e509e505050505050505050505050509193909250565b6001600160a01b038216613d525760405162ced3e160e81b81525f6004820152602401610992565b6001600160a01b038381165f81815260136020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319101613913565b5f815f03613dc5575081610708565b5f610c62836148d6565b6001600160a01b038181165f908152601a60205260409020541615613e0b5780608060405162c14c0760e81b815260040161099292919061595b565b601a6020527ff88cd8d612926ebb404e40725c01084b6e9b3ce0344cde068570342cbd448c6180546001600160a01b039283165f818152604081208054959093166001600160a01b031995861617909255600190915281549092169091179055565b5f80613e7884613dcf565b613e818461443a565b6001600160a01b038087165f9081526015602052604090206001600160601b03428116600160a01b02928516929092178155929450909250613ec690869081906138c3565b836001600160a01b0316856001600160a01b03167ffea7c1e1973c8be64c654eb06dc19ffbfc2e924d57544b9da0c0a27d3f893d7760405160405180910390a3505b9250929050565b613f1c858585858561492f565b5f613f26426111be565b5f8681526012602090815260408083208151808301909252546001600160c01b038116808352600160c01b9091046001600160401b0316928201839052939450928791613f7891906115ae9087615b16565b613f829190615c55565b90506001600160c01b03811115613fb35787876080604051632f20c6dd60e11b8152600401610992939291906159ca565b6001600160c01b0390811682526001600160401b0392831660208084019182525f988952601290526040909720915196519616600160c01b96909216959095021790935550505050565b6001600160a01b03841661402657604051632bfa23e760e11b81525f6004820152602401610992565b6001600160a01b03851661404e57604051626a0d4560e21b81525f6004820152602401610992565b60408051600180825260208201869052818301908152606082018590526080820190925290611c128787848487614684565b5f80805b83811015614195575f601a818787858181106140a2576140a2615977565b90506020020160208101906140b79190614fcd565b6001600160a01b03908116825260208201929092526040015f2054160361411c57816140e281615c68565b9250506141158585838181106140fa576140fa615977565b905060200201602081019061410f9190614fcd565b87613e6d565b505061418d565b61414685858381811061413157614131615977565b90506020020160208101906106cf9190614fcd565b61418d5784848281811061415c5761415c615977565b90506020020160208101906141719190614fcd565b600560405162c14c0760e81b815260040161099292919061595b565b600101614084565b50949350505050565b80518251146141cd5781518151604051635b05999160e01b815260048101929092526024820152604401610992565b335f6141d8426111be565b90505f5b8451811015614324576020818102868101820151908601909101516001600160a01b038916156142ff575f806142138b858861193c565b9150915082821015614258576040516303dee4c560e01b81526001600160a01b038c166004820152602481018390526044810184905260648101859052608401610992565b80156142ee5760408051858152602081018390525f916001600160a01b038e811692908b16917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4838b6001600160a01b03167f0133941907a52d9dac02e146444ded662cbf8cabf0cbb1f1aead9814cda91d61836040516142e591815260200190565b60405180910390a35b6142fc8b85858503896149a1565b50505b6001600160a01b0388161561431a5761431a88838387614a36565b50506001016141dc565b5083516001036143a45760208401515f906020850151909150866001600160a01b0316886001600160a01b0316856001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051614395929190918252602082015260400190565b60405180910390a45050610cd5565b846001600160a01b0316866001600160a01b0316836001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb87876040516108e6929190615de7565b6001600160a01b03841615613575578251339060010361442c5760208481015190840151614425838989858589614c37565b5050610cd5565b610cd5818787878787614d58565b60405163146924ff60e11b81526001600160a01b0382811660048301525f91829182917f00000000000000000000000029b9a7fbb8995b2423a71cc17cf9810798f6c543909116906328d249fe90602401602060405180830381865afa1580156144a6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906144ca9190615afb565b90506001600160a01b0381166144e557505f93849350915050565b5f816001600160a01b0316638b4eed816040518163ffffffff1660e01b8152600401602060405180830381865afa158015614522573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906145469190615ee2565b9050816001600160a01b03166375f12b216040518163ffffffff1660e01b8152600401602060405180830381865afa158015614584573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906145a89190615a59565b156145b95760019590945092505050565b9094909350915050565b6001600160a01b0382165f90815260156020526040812080549091600160a01b9091046001600160601b031690036146115760405163d82c8fc960e01b815260806004820152602401610992565b80546001600160a01b038381169116146131975780546001600160a01b0319166001600160a01b0383161780825561465d90600160a01b90046001600160601b03908116904216614814565b81546001600160601b0391909116600160a01b026001600160a01b03909116178155505050565b6146908585858561419e565b61357585858585856143f3565b6001600160a01b03831615806146ba57506001600160a01b038216155b806146ce57506001600160a01b0382166001145b156146ef5760405163d82c8fc960e01b815260816004820152602401610992565b6001600160a01b038084165f908152601d60209081526040808320600184529091529020805490911661472e5780546001600160a01b03191660011781555b6001600160a01b038085165f908152601d6020908152604080832087851684529091529020805490911661478457815481546001600160a01b039182166001600160a01b03199182161783558354169085161782555b80546001600160601b03909316600160a01b026001600160a01b0390931692909217909155505050565b6001600160a01b0383166147d657604051626a0d4560e21b81525f6004820152602401610992565b604080516001808252602082018590528183019081526060820184905260a082019092525f6080820181815291929161357591879185908590614684565b5f818310156139555750919050565b5f677fffffffffffffff821115614838575f80fd5b5060401b90565b5f600f83810b9083900b0260401d60016001607f1b0319811280159061486c575060016001607f1b038113155b610ecd575f80fd5b5f600f83810b9083900b0160016001607f1b0319811280159061486c575060016001607f1b03811315610ecd575f80fd5b5f600f82810b9084900b0360016001607f1b0319811280159061486c575060016001607f1b03811315610ecd575f80fd5b5f600e821161491d575f600983600f81106148f3576148f3615977565b60028104919091015460019091166010026101000a9004600f0b9050801561491b5792915050565b505b61070867fff2fae779633d1e83613296565b6001600160a01b03851661495857604051632bfa23e760e11b81525f6004820152602401610992565b604080516001808252602082018790528183019081526060820186905260808201909252908215614995576149905f88848488614684565b611c12565b611c125f88848461419e565b6001600160c01b038211156149d05783836081604051632f20c6dd60e11b8152600401610992939291906159ca565b5f9283526011602090815260408085206001600160a01b0390961680865286835281862082518084019093526001600160c01b0395861683526001600160401b03948516838501908152919096529590915251935116600160c01b029216919091179055565b5f8381526011602090815260408083206001600160a01b03881684528252918290208251808401909352546001600160c01b03811683526001600160401b03600160c01b909104811691830182905283161015614acd576020810151604051632f20c6dd60e11b81526001600160a01b03871660048201526001600160401b03909116602482015260a16044820152606401610992565b5f816020015183036001600160401b031690505f614af7835f01516001600160c01b031683613db6565b83519091506001600160c01b0316818103908214614b9c5760408051888152602081018390525f916001600160a01b038b169133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a486886001600160a01b03167f0133941907a52d9dac02e146444ded662cbf8cabf0cbb1f1aead9814cda91d6183604051614b9391815260200190565b60405180910390a35b505f614ba88683615c55565b90506001600160c01b03811115614bd95787876082604051632f20c6dd60e11b8152600401610992939291906159ca565b6001600160c01b0390811684526001600160401b0394851660208086019182525f988952601181526040808a206001600160a01b03909b168a529990529790962092519651909316600160c01b029590941694909417909355505050565b6001600160a01b0384163b15610cd55760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190614c7b9089908990889088908890600401615ef9565b6020604051808303815f875af1925050508015614cb5575060408051601f3d908101601f19168201909252614cb291810190615f32565b60015b614d1c573d808015614ce2576040519150601f19603f3d011682016040523d82523d5f602084013e614ce7565b606091505b5080515f03614d1457604051632bfa23e760e11b81526001600160a01b0386166004820152602401610992565b805181602001fd5b6001600160e01b0319811663f23a6e6160e01b14611c1257604051632bfa23e760e11b81526001600160a01b0386166004820152602401610992565b6001600160a01b0384163b15610cd55760405163bc197c8160e01b81526001600160a01b0385169063bc197c8190614d9c9089908990889088908890600401615e0b565b6020604051808303815f875af1925050508015614dd6575060408051601f3d908101601f19168201909252614dd391810190615f32565b60015b614e03573d808015614ce2576040519150601f19603f3d011682016040523d82523d5f602084013e614ce7565b6001600160e01b0319811663bc197c8160e01b14611c1257604051632bfa23e760e11b81526001600160a01b0386166004820152602401610992565b6001600160a01b03811681146131d4575f80fd5b5f8060408385031215614e64575f80fd5b8235614e6f81614e3f565b946020939093013593505050565b6001600160e01b0319811681146131d4575f80fd5b5f60208284031215614ea2575f80fd5b8135610ecd81614e7d565b5f8083601f840112614ebd575f80fd5b5081356001600160401b03811115614ed3575f80fd5b602083019150836020828501011115613f08575f80fd5b5f805f805f8060808789031215614eff575f80fd5b8635614f0a81614e3f565b955060208701356001600160401b0380821115614f25575f80fd5b614f318a838b01614ead565b90975095506040890135915080821115614f49575f80fd5b50614f5689828a01614ead565b979a9699509497949695606090950135949350505050565b5f5b83811015614f88578181015183820152602001614f70565b50505f910152565b5f8151808452614fa7816020860160208601614f6e565b601f01601f19169290920160200192915050565b602081525f610ecd6020830184614f90565b5f60208284031215614fdd575f80fd5b8135610ecd81614e3f565b5f8083601f840112614ff8575f80fd5b5081356001600160401b0381111561500e575f80fd5b6020830191508360208260051b8501011115613f08575f80fd5b5f805f805f805f806080898b03121561503f575f80fd5b88356001600160401b0380821115615055575f80fd5b6150618c838d01614fe8565b909a50985060208b0135915080821115615079575f80fd5b818b0191508b601f83011261508c575f80fd5b81358181111561509a575f80fd5b8c60208260061b85010111156150ae575f80fd5b6020830198508097505060408b01359150808211156150cb575f80fd5b6150d78c838d01614fe8565b909650945060608b01359150808211156150ef575f80fd5b506150fc8b828c01614ead565b999c989b5096995094979396929594505050565b5f60208284031215615120575f80fd5b5035919050565b80356001600160401b038116811461513d575f80fd5b919050565b5f8060408385031215615153575f80fd5b8235915061516360208401615127565b90509250929050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b03811182821017156151a8576151a861516c565b604052919050565b5f6001600160401b038211156151c8576151c861516c565b5060051b60200190565b5f82601f8301126151e1575f80fd5b813560206151f66151f1836151b0565b615180565b8083825260208201915060208460051b870101935086841115615217575f80fd5b602086015b84811015615233578035835291830191830161521c565b509695505050505050565b5f6001600160401b038211156152565761525661516c565b50601f01601f191660200190565b5f82601f830112615273575f80fd5b81356152816151f18261523e565b818152846020838601011115615295575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f805f60a086880312156152c5575f80fd5b85356152d081614e3f565b945060208601356152e081614e3f565b935060408601356001600160401b03808211156152fb575f80fd5b61530789838a016151d2565b9450606088013591508082111561531c575f80fd5b61532889838a016151d2565b9350608088013591508082111561533d575f80fd5b5061534a88828901615264565b9150509295509295909350565b5f8060408385031215615368575f80fd5b82356001600160401b038082111561537e575f80fd5b818501915085601f830112615391575f80fd5b813560206153a16151f1836151b0565b82815260059290921b840181019181810190898411156153bf575f80fd5b948201945b838610156153e65785356153d781614e3f565b825294820194908201906153c4565b965050860135925050808211156153fb575f80fd5b50615408858286016151d2565b9150509250929050565b5f815180845260208085019450602084015f5b8381101561544157815187529582019590820190600101615425565b509495945050505050565b602081525f610ecd6020830184615412565b5f805f60608486031215615470575f80fd5b833561547b81614e3f565b9250602084013561548b81614e3f565b9150604084013561549b81614e3f565b809150509250925092565b5f80604083850312156154b7575f80fd5b82356154c281614e3f565b915060208301356154d281614e3f565b809150509250929050565b5f805f805f805f6080888a0312156154f3575f80fd5b87356154fe81614e3f565b965060208801356001600160401b0380821115615519575f80fd5b6155258b838c01614fe8565b909850965060408a013591508082111561553d575f80fd5b6155498b838c01614fe8565b909650945060608a0135915080821115615561575f80fd5b5061556e8a828b01614ead565b989b979a50959850939692959293505050565b5f8060408385031215615592575f80fd5b823561559d81614e3f565b915060208301356001600160601b03811681146154d2575f80fd5b5f805f80606085870312156155cb575f80fd5b843593506020850135925060408501356001600160401b038111156155ee575f80fd5b6155fa87828801614ead565b95989497509550505050565b5f805f805f805f60a0888a03121561561c575f80fd5b873561562781614e3f565b9650602088013561563781614e3f565b955060408801356001600160401b0380821115615652575f80fd5b61565e8b838c01614ead565b909750955060608a0135915080821115615676575f80fd5b506156838a828b01614ead565b989b979a50959894979596608090950135949350505050565b80151581146131d4575f80fd5b5f80604083850312156156ba575f80fd5b82356156c581614e3f565b915060208301356154d28161569c565b5f805f606084860312156156e7575f80fd5b83356156f281614e3f565b92506020840135915060408401356002811061549b575f80fd5b5f805f6040848603121561571e575f80fd5b83356001600160401b03811115615733575f80fd5b61573f86828701614ead565b909790965060209590950135949350505050565b5f805f60608486031215615765575f80fd5b833561577081614e3f565b92506020840135915061578560408501615127565b90509250925092565b5f805f805f60a086880312156157a2575f80fd5b85356157ad81614e3f565b945060208601356157bd81614e3f565b9350604086013592506060860135915060808601356001600160401b038111156157e5575f80fd5b61534a88828901615264565b5f805f805f60608688031215615805575f80fd5b853561581081614e3f565b945060208601356001600160401b038082111561582b575f80fd5b61583789838a01614fe8565b9096509450604088013591508082111561584f575f80fd5b5061585c88828901614fe8565b969995985093965092949392505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b03841681526040602082018190525f906158b9908301848661586d565b95945050505050565b604081525f6158d560408301868861586d565b82810360208401526158e881858761586d565b979650505050505050565b5f60208284031215615903575f80fd5b81516001600160401b03811115615918575f80fd5b8201601f81018413615928575f80fd5b80516159366151f18261523e565b81815285602083850101111561594a575f80fd5b6158b9826020830160208601614f6e565b6001600160a01b0392909216825260ff16602082015260400190565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e1983360301811261599f575f80fd5b9190910192915050565b5f602082840312156159b9575f80fd5b813561ffff81168114610ecd575f80fd5b6001600160a01b03939093168352602083019190915260ff16604082015260600190565b600181811c90821680615a0257607f821691505b602082108103615a2057634e487b7160e01b5f52602260045260245ffd5b50919050565b6001600160a01b03868116825285166020820152604081018490526080606082018190525f906158e8908301848661586d565b5f60208284031215615a69575f80fd5b8151610ecd8161569c565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561070857610708615a74565b634e487b7160e01b5f52601260045260245ffd5b5f82615abd57615abd615a9b565b500490565b6001600160a01b03831681526040810160028310615aee57634e487b7160e01b5f52602160045260245ffd5b8260208301529392505050565b5f60208284031215615b0b575f80fd5b8151610ecd81614e3f565b6001600160401b03828116828216039080821115615b3657615b36615a74565b5092915050565b602081525f610eca60208301848661586d565b600181815b80851115615b8a57815f1904821115615b7057615b70615a74565b80851615615b7d57918102915b93841c9390800290615b55565b509250929050565b5f82615ba057506001610708565b81615bac57505f610708565b8160018114615bc25760028114615bcc57615be8565b6001915050610708565b60ff841115615bdd57615bdd615a74565b50506001821b610708565b5060208310610133831016604e8410600b8410161715615c0b575081810a610708565b615c158383615b50565b805f1904821115615c2857615c28615a74565b029392505050565b5f610ecd60ff841683615b92565b808202811582820484141761070857610708615a74565b8082018082111561070857610708615a74565b5f60018201615c7957615c79615a74565b5060010190565b61ffff818116838216019080821115615b3657615b36615a74565b5f60208284031215615cab575f80fd5b81356001600160c01b0381168114610ecd575f80fd5b8181035f831280158383131683831282161715615b3657615b36615a74565b8082018281125f831280158216821582161715615cff57615cff615a74565b505092915050565b61ffff828116828216039080821115615b3657615b36615a74565b5f808335601e19843603018112615d37575f80fd5b8301803591506001600160401b03821115615d50575f80fd5b6020019150600581901b3603821315613f08575f80fd5b5f61ffff808316818103615d7d57615d7d615a74565b6001019392505050565b61ffff818116838216028082169190828114615cff57615cff615a74565b5f808335601e19843603018112615dba575f80fd5b8301803591506001600160401b03821115615dd3575f80fd5b602001915036819003821315613f08575f80fd5b604081525f615df96040830185615412565b82810360208401526158b98185615412565b6001600160a01b0386811682528516602082015260a0604082018190525f90615e3690830186615412565b8281036060840152615e488186615412565b90508281036080840152615e5c8185614f90565b98975050505050505050565b60208152815160208201525f602083015160606040840152615e8d6080840182614f90565b90506040840151601f198483030160608501526158b98282614f90565b5f6001600160601b0380841680615ec357615ec3615a9b565b92169190910492915050565b5f82615edd57615edd615a9b565b500690565b5f60208284031215615ef2575f80fd5b5051919050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190525f906158e890830184614f90565b5f60208284031215615f42575f80fd5b8151610ecd81614e7d56fea26469706673582212201a21a84b8e06838b9338ef71688f78e2c726b159dc94efb25f6fb50045d7337464736f6c63430008180033

Deployed Bytecode Sourcemap

130670:56173:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;104724:196;;;;;;:::i;:::-;;:::i;:::-;;;616:25:1;;;604:2;589:18;104724:196:0;;;;;;;;103854:288;;;;;;:::i;:::-;;:::i;:::-;;;1203:14:1;;1196:22;1178:41;;1166:2;1151:18;103854:288:0;1038:187:1;141203:631:0;;;;;;:::i;:::-;;:::i;:::-;;156382:112;;;:::i;:::-;;;;;;;:::i;148289:640::-;;;:::i;133056:45::-;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;133056:45:0;;;;;;-1:-1:-1;;;;;3685:32:1;;;3667:51;;3655:2;3640:18;133056:45:0;3521:203:1;153913:1811:0;;;;;;:::i;:::-;;:::i;145139:496::-;;;:::i;104553:106::-;;;;;;:::i;:::-;;:::i;93414:546::-;;;;;;:::i;:::-;;:::i;106646:454::-;;;;;;:::i;:::-;;:::i;132303:43::-;;;;;149127:430;;;;;;:::i;:::-;;:::i;105086:607::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;158867:819::-;;;;;;:::i;:::-;;:::i;157761:219::-;;;;;;:::i;:::-;;:::i;147608:495::-;;;;;;:::i;:::-;;:::i;144242:778::-;;;;;;:::i;:::-;;:::i;88423:31::-;;;;;;133244:71;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;133244:71:0;;;-1:-1:-1;;;133244:71:0;;-1:-1:-1;;;;;133244:71:0;;;;;;;-1:-1:-1;;;;;14008:32:1;;;13990:51;;-1:-1:-1;;;;;14077:39:1;;;14072:2;14057:18;;14050:67;13963:18;133244:71:0;13818:305:1;91959:117:0;;;;;;:::i;:::-;-1:-1:-1;;;;;92043:25:0;;91959:117;152324:1041;;;;;;:::i;:::-;;:::i;91523:288::-;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;14841:31:1;;;14823:50;;14811:2;14796:18;91523:288:0;14679:200:1;156502:116:0;;;:::i;92401:700::-;;;;;;:::i;:::-;;:::i;142291:678::-;;;;;;:::i;:::-;;:::i;146791:335::-;;;;;;:::i;:::-;;:::i;:::-;;;;16158:25:1;;;16214:2;16199:18;;16192:34;;;;16242:18;;;16235:34;16146:2;16131:18;146791:335:0;15956:319:1;157029:120:0;;;;;;:::i;:::-;-1:-1:-1;;;;;157107:20:0;;;157083:4;157107:20;;;:12;:20;;;;;;;:34;;;157029:120;105766:142;;;;;;:::i;:::-;;:::i;153373:532::-;;;;;;:::i;:::-;;:::i;157311:249::-;;;;;;:::i;:::-;;:::i;99135:319::-;;;;;;:::i;:::-;;:::i;155880:494::-;;;;;;:::i;:::-;;:::i;143199:459::-;;;;;;:::i;:::-;;:::i;132894:47::-;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;132894:47:0;;;138410:2437;;;;;;:::i;:::-;;:::i;105980:155::-;;;;;;:::i;:::-;;:::i;97841:1136::-;;;;;;:::i;:::-;;:::i;:::-;;;;18831:25:1;;;18887:2;18872:18;;18865:34;;;;18804:18;97841:1136:0;18657:248:1;132734:42:0;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;132734:42:0;;;145992:370;;;;;;:::i;:::-;;:::i;106207:362::-;;;;;;:::i;:::-;;:::i;150357:1660::-;;;;;;:::i;:::-;;:::i;156777:120::-;;;;;;:::i;:::-;;:::i;133581:53::-;;;;;;:::i;:::-;;;;;;;;;;;;;;104724:196;104795:7;104816:15;104836:51;104851:8;104861:3;104866:20;104870:15;104866:3;:20::i;104836:51::-;-1:-1:-1;104815:72:0;-1:-1:-1;;104724:196:0;;;;;:::o;103854:288::-;103957:4;-1:-1:-1;;;;;;103981:42:0;;-1:-1:-1;;;103981:42:0;;:99;;-1:-1:-1;;;;;;;104027:53:0;;-1:-1:-1;;;104027:53:0;103981:99;:153;;;-1:-1:-1;;;;;;;;;;78779:40:0;;;104097:37;78679:148;141203:631;141382:16;;141348:67;;141363:10;;141375:5;;-1:-1:-1;;;;;141382:16:0;141400:5;;141407:7;;141348:14;:67::i;:::-;141492:12;;:50;;-1:-1:-1;;;141492:50:0;;-1:-1:-1;;;;;141492:12:0;;;;:31;;:50;;141524:10;;141536:5;;;;141492:50;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;141553:12:0;;:54;;-1:-1:-1;;;141553:54:0;;-1:-1:-1;;;;;141553:12:0;;;;-1:-1:-1;141553:33:0;;-1:-1:-1;141553:54:0;;141587:10;;141599:7;;;;141553:54;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;141683:12:0;;:59;;-1:-1:-1;;;141683:59:0;;141714:10;141683:59;;;21539:51:1;21606:18;;;21599:34;;;-1:-1:-1;;;;;141683:12:0;;;;-1:-1:-1;141683:30:0;;-1:-1:-1;21512:18:1;;141683:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;141793:16:0;;141760:66;;-1:-1:-1;;;;;141793:16:0;;;;-1:-1:-1;141760:66:0;;;;-1:-1:-1;141774:10:0;;141760:66;;;;141811:5;;;;141818:7;;;;141760:66;:::i;:::-;;;;;;;;141203:631;;;;;;:::o;156382:112::-;156454:12;;:32;;-1:-1:-1;;;156454:32:0;;156480:4;156454:32;;;3667:51:1;156421:13:0;;-1:-1:-1;;;;;156454:12:0;;:17;;3640:18:1;;156454:32:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;156454:32:0;;;;;;;;;;;;:::i;:::-;156447:39;;156382:112;:::o;148289:640::-;148330:19;148338:10;148330:7;:19::i;:::-;148325:206;;148502:10;148514:4;148476:43;;-1:-1:-1;;;148476:43:0;;;;;;;;;:::i;:::-;;;;;;;;148325:206;148579:10;148541:25;148569:21;;;:9;:21;;;;;148642;;-1:-1:-1;;;;;148642:21:0;;;-1:-1:-1;;;;;148642:21:0;:42;148638:81;;148701:7;148289:640::o;148638:81::-;148843:41;;-1:-1:-1;;;;;148843:41:0;-1:-1:-1;;;;;;148843:41:0;;;148902:19;;148910:10;;148902:19;;148843:21;;148902:19;148314:615;148289:640::o;153913:1811::-;135157:1;135151:8;135148:28;;;135157:1;;135162:12;135148:28;135200:1;135157;135190:12;154200:27:::1;154230:52;154249:18:::0;;154269:5;154230:18:::1;:52::i;:::-;154200:82;;154359:9;154354:505;154374:19:::0;;::::1;154354:505;;;154420:73;154437:13;;154451:8;;154460:1;154451:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:28;::::0;::::1;::::0;::::1;::::0;::::1;:::i;:::-;154437:43;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;154482:10;154420:16;:73::i;:::-;154415:433;;154779:13;;154793:8;;154802:1;154793:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:28;::::0;::::1;::::0;::::1;::::0;::::1;:::i;:::-;154779:43;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;154824:1;154827:4;154751:81;;-1:-1:-1::0;;;154751:81:0::1;;;;;;;;;;:::i;154415:433::-;154395:3;;154354:505;;;;155369:32;155404:52;155422:13;;155437:5;;155444:11;155404:17;:52::i;:::-;155369:87;;155469:65;155490:13;;155505:5;;155512:8;;155522:11;155469:20;:65::i;:::-;155547:33;155583:66;155605:13;;155620:5;;155627:8;;155637:11;155583:21;:66::i;:::-;155547:102;;155662:54;155680:17;155699:16;155662:17;:54::i;:::-;154129:1595;;;135269:1:::0;;135259:12;153913:1811;;;;;;;;:::o;145139:496::-;145188:19;145196:10;145188:7;:19::i;:::-;145183:237;;145391:10;145403:4;145365:43;;-1:-1:-1;;;145365:43:0;;;;;;;;;:::i;145183:237::-;145503:38;145530:10;145503:26;:38::i;:::-;145601:26;145616:10;145601:14;:26::i;:::-;145139:496::o;104553:106::-;104614:13;104647:4;104640:11;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;104553:106;;;:::o;93414:546::-;93552:7;93834:8;93845:51;87483:20;93883:11;-1:-1:-1;;;;;93875:20:0;93845:17;:51::i;:::-;93834:62;;93914:38;93933:1;93936:15;93914:18;:38::i;:::-;93907:45;93414:546;-1:-1:-1;;;;93414:546:0:o;106646:454::-;36688:10;-1:-1:-1;;;;;106896:15:0;;;;;;;:51;;;106916:31;106933:5;106940:6;106916:16;:31::i;:::-;106915:32;106896:51;106892:134;;;106971:43;;-1:-1:-1;;;106971:43:0;;-1:-1:-1;;;;;25050:15:1;;;106971:43:0;;;25032:34:1;25102:15;;25082:18;;;25075:43;24967:18;;106971:43:0;24820:304:1;106892:134:0;107036:56;107059:5;107066:3;107071:4;107077:7;107086:5;107036:22;:56::i;:::-;106841:259;106646:454;;;;;:::o;149127:430::-;149183:4;149205:15;149213:6;149205:7;:15::i;:::-;149200:228;;149403:6;149411:4;149377:39;;-1:-1:-1;;;149377:39:0;;;;;;;;;:::i;149200:228::-;-1:-1:-1;;149476:10:0;149438:25;149466:21;;;:9;:21;;;;;149506;-1:-1:-1;;;149506:21:0;;-1:-1:-1;;;;;149506:21:0;;;:42;;149127:430::o;105086:607::-;105182:16;105235:4;:11;105215:9;:16;:31;105211:127;;105296:11;;105309:16;;105270:56;;-1:-1:-1;;;105270:56:0;;;;;18831:25:1;;;;18872:18;;;18865:34;18804:18;;105270:56:0;18657:248:1;105211:127:0;105350:12;105365:20;105369:15;105365:3;:20::i;:::-;105350:35;;105398:30;105445:9;:16;-1:-1:-1;;;;;105431:31:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;105431:31:0;;105398:64;;105480:9;105475:178;105499:9;:16;105495:1;:20;105475:178;;;84751:4;84742:14;;;84722:35;;;84716:42;105559:82;;84751:4;84742:14;;;84722:35;;;84716:42;105635:5;105559:14;:82::i;:::-;105537:104;105538:13;105552:1;105538:16;;;;;;;;:::i;:::-;;;;;;;;;;105537:104;105517:3;;105475:178;;158867:819;-1:-1:-1;;;;;159054:17:0;;;158965:4;159054:17;;;:12;:17;;;;;;;;:33;;;;;;;;;;;:40;159098:15;-1:-1:-1;;;159054:40:0;;;-1:-1:-1;;;;;159054:40:0;159046:67;159042:85;;;-1:-1:-1;159122:5:0;159115:12;;159042:85;-1:-1:-1;;;;;159199:25:0;;159273:1;159199:25;;;:18;:25;;;;;;131433:1;159199:62;159195:168;;-1:-1:-1;159299:4:0;159292:11;;159195:168;-1:-1:-1;;;;;159521:19:0;;;;;;;:12;:19;;;;;;;;:24;;;;;;;;;:31;159557:15;-1:-1:-1;;;159521:31:0;;;-1:-1:-1;;;;;159521:31:0;159513:59;;;;:154;;-1:-1:-1;;;;;;159593:23:0;;159665:1;159593:23;;;:18;:23;;;;;;131433:1;159593:60;:74;;159513:154;159491:187;;158867:819;;;;;;:::o;157761:219::-;-1:-1:-1;;;;;157913:22:0;;;157837:4;157913:22;;;:12;:22;;;;;;;;:32;;;;;;;;;;;:39;157957:15;-1:-1:-1;;;157913:39:0;;;-1:-1:-1;;;;;157913:39:0;157905:67;;;157761:219::o;147608:495::-;147796:27;147840:18;-1:-1:-1;;;;;147826:40:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;147826:40:0;;147796:70;;147882:9;147877:131;147897:29;;;147877:131;;;147964:32;147974:18;;147993:1;147974:21;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;147964:32::-;147948:10;147959:1;147948:13;;;;;;;;:::i;:::-;;;;;;;;;;:48;147928:3;;147877:131;;;;148018:77;148029:10;148041;148053:6;148061:10;148073:8;;148018:77;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;148018:77:0;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;148083:5:0;;-1:-1:-1;148083:5:0;;;;148018:77;;148083:5;;;;148018:77;;;;;;;;;-1:-1:-1;148090:4:0;;-1:-1:-1;148018:10:0;;-1:-1:-1;;148018:77:0:i;:::-;147785:318;147608:495;;;;;;;:::o;144242:778::-;144343:10;144366:1;144335:19;;;:7;:19;;;;;;-1:-1:-1;;;;;144335:19:0;:33;;:65;;-1:-1:-1;;;;;;144372:28:0;;;144335:65;:95;;;-1:-1:-1;;;;;;144404:26:0;;131247:3;144404:26;144335:95;:144;;;-1:-1:-1;;;;;;144451:28:0;;144469:10;144451:28;144335:144;144317:512;;;144796:14;144812:4;144770:47;;-1:-1:-1;;;144770:47:0;;;;;;;;;:::i;144317:512::-;144908:15;144898:7;-1:-1:-1;;;;;144898:25:0;;144894:64;;;-1:-1:-1;144942:15:0;144894:64;144969:43;144976:10;144988:14;145004:7;144969:6;:43::i;:::-;144242:778;;:::o;152324:1041::-;152613:13;152629:30;152652:3;152657:1;152629:22;:30::i;:::-;-1:-1:-1;;;;;152705:19:0;;;152672:18;152705:19;;;:12;:19;;;;;;152613:46;;-1:-1:-1;152705:19:0;152740:29;;;;;:64;;-1:-1:-1;;;;;;152773:17:0;;;;;;;:10;:17;;;;;;;152794:10;152773:31;;152740:64;152736:560;;;152982:58;;-1:-1:-1;;;152982:58:0;;-1:-1:-1;;;;;152982:23:0;;;;;:58;;153006:10;;153018:5;;153025:7;;153034:5;;;;152982:58;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;152977:308;;153247:10;153259:3;153264:4;153219:50;;-1:-1:-1;;;153219:50:0;;;;;;;;;;:::i;152977:308::-;153306:51;153332:10;153344:3;153349:7;153306:25;:51::i;91523:288::-;91577:6;85975;91766:16;;91753:10;:29;;;;:::i;:::-;91752:50;;;;:::i;156502:116::-;156576:12;;:34;;-1:-1:-1;;;156576:34:0;;156604:4;156576:34;;;3667:51:1;156543:13:0;;-1:-1:-1;;;;;156576:12:0;;:19;;3640:18:1;;156576:34:0;3521:203:1;92401:700:0;92535:7;92978:8;92989:45;86916:20;93028:4;-1:-1:-1;;;;;93020:13:0;92989:17;:45::i;142291:678::-;142499:60;142514:10;142526:5;142533:9;142544:5;;142551:7;;142499:14;:60::i;:::-;142636:12;;:50;;-1:-1:-1;;;142636:50:0;;-1:-1:-1;;;;;142636:12:0;;;;:31;;:50;;142668:10;;142680:5;;;;142636:50;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;142697:12:0;;:54;;-1:-1:-1;;;142697:54:0;;-1:-1:-1;;;;;142697:12:0;;;;-1:-1:-1;142697:33:0;;-1:-1:-1;142697:54:0;;142731:10;;142743:7;;;;142697:54;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;142825:12:0;;:59;;-1:-1:-1;;;142825:59:0;;142856:10;142825:59;;;21539:51:1;21606:18;;;21599:34;;;-1:-1:-1;;;;;142825:12:0;;;;-1:-1:-1;142825:30:0;;-1:-1:-1;21512:18:1;;142825:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;142935:9;-1:-1:-1;;;;;142902:59:0;142928:5;-1:-1:-1;;;;;142902:59:0;142916:10;-1:-1:-1;;;;;142902:59:0;;142946:5;;142953:7;;142902:59;;;;;;;;;:::i;:::-;;;;;;;;142291:678;;;;;;;:::o;146791:335::-;146861:7;146870;146879;146972:34;146999:6;146972:26;:34::i;:::-;147092:26;147111:6;147092:18;:26::i;:::-;147085:33;;;;;;146791:335;;;;;;:::o;105766:142::-;105846:54;36688:10;105879:9;105890;105846:18;:54::i;153373:532::-;153458:7;153483:16;153491:7;153483;:16::i;:::-;153482:17;:38;;;;-1:-1:-1;;;;;;157107:20:0;;;157083:4;157107:20;;;:12;:20;;;;;;;:34;153482:38;153478:231;;;153683:7;153692:4;153657:40;;-1:-1:-1;;;153657:40:0;;;;;;;;;:::i;153478:231::-;153742:9;;:37;;-1:-1:-1;;;153742:37:0;;153719:20;;-1:-1:-1;;;;;153742:9:0;;:21;;:37;;153764:7;;153773:5;;153742:37;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;153719:60;-1:-1:-1;153790:75:0;153807:10;153719:60;-1:-1:-1;;;;;92043:25:0;;153853:7;153790:75;;;;;;;;;;;;:16;:75::i;157311:249::-;-1:-1:-1;;;;;157403:22:0;;;157379:4;157403:22;;;:7;:22;;;;;;157379:4;;157403:22;:36;;;;:81;;-1:-1:-1;;;;;;157443:27:0;;;157482:1;157443:27;;;:12;:27;;;;;;;:41;157403:81;:149;;;;-1:-1:-1;;;;;;;157501:24:0;157550:1;157501:24;;;:9;:24;;;;;:37;-1:-1:-1;;;157501:37:0;;-1:-1:-1;;;;;157501:37:0;:51;;157311:249::o;99135:319::-;99190:7;99256:28;;;:23;:28;;;;;;;;99210:74;;;;;;;;;-1:-1:-1;;;;;99210:74:0;;;;-1:-1:-1;;;99210:74:0;;-1:-1:-1;;;;;99210:74:0;;;;;;;;99190:7;99310:20;99314:15;99310:3;:20::i;:::-;99295:35;;99348:98;99376:18;:26;;;-1:-1:-1;;;;;99348:98:0;99412:18;:33;;;99404:5;:41;;;;:::i;:::-;-1:-1:-1;;;;;99348:98:0;:27;:98::i;155880:494::-;155957:10;155980:1;155949:19;;;:7;:19;;;;;;-1:-1:-1;;;;;155949:19:0;155945:255;;156171:10;156183:4;156145:43;;-1:-1:-1;;;156145:43:0;;;;;;;;;:::i;155945:255::-;156231:10;156212:30;;;;:18;:30;;;;;;;:38;;;156327:39;;;;;156245:5;616:25:1;;604:2;589:18;;470:177;156327:39:0;;;;;;;;155880:494;:::o;143199:459::-;143297:25;143311:10;143297:13;:25::i;:::-;143401:12;;:50;;-1:-1:-1;;;143401:50:0;;-1:-1:-1;;;;;143401:12:0;;;;:31;;:50;;143433:10;;143445:5;;;;143401:50;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;143534:12:0;;:59;;-1:-1:-1;;;143534:59:0;;143565:10;143534:59;;;21539:51:1;21606:18;;;21599:34;;;-1:-1:-1;;;;;143534:12:0;;;;-1:-1:-1;143534:30:0;;-1:-1:-1;21512:18:1;;143534:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;143632:10;-1:-1:-1;;;;;143611:39:0;;143644:5;;143611:39;;;;;;;:::i;:::-;;;;;;;;143199:459;;;:::o;138410:2437::-;-1:-1:-1;;;;;138500:22:0;;138496:2149;;138760:23;138785:21;138810:36;138825:10;138837:8;138810:14;:36::i;:::-;138759:87;;-1:-1:-1;138759:87:0;-1:-1:-1;;;;;;139026:37:0;;122411:3;139026:37;;;:76;;;139084:18;139067:13;:35;;139026:76;139022:277;;;139266:10;139278:4;139240:43;;-1:-1:-1;;;139240:43:0;;;;;;;;;:::i;139022:277::-;138524:786;;138496:2149;;;139551:17;139559:8;139551:7;:17::i;:::-;139550:18;:54;;;;139573:31;139583:8;139593:10;139573:9;:31::i;:::-;139572:32;139550:54;139546:282;;;139797:8;139807:4;139771:41;;-1:-1:-1;;;139771:41:0;;;;;;;;;:::i;139546:282::-;140161:36;140176:10;140188:8;140161:14;:36::i;:::-;;;140236:18;140218:15;:36;140214:420;;;140366:73;140392:8;-1:-1:-1;;;;;92043:25:0;;87724:14;87621:2;87724;:14;:::i;:::-;130891:8;;:2;:8;:::i;:::-;131077:17;;:1;:17;:::i;:::-;140366:25;:73::i;:::-;140533:85;140559:10;;87724:14;87621:2;87724;:14;:::i;:::-;130891:8;;:2;:8;:::i;:::-;140533:85;;;;;;;;;;;;140613:4;140533:25;:85::i;:::-;140723:29;;140719:121;;140769:12;;:59;;-1:-1:-1;;;140769:59:0;;140800:10;140769:59;;;21539:51:1;21606:18;;;21599:34;;;-1:-1:-1;;;;;140769:12:0;;;;:30;;21512:18:1;;140769:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;105980:155;-1:-1:-1;;;;;106088:28:0;;;106064:4;106088:28;;;:18;:28;;;;;;;;:39;;;;;;;;;;;;;;;105980:155::o;97841:1136::-;97957:21;98064:23;;;:18;:23;;;;;;;;-1:-1:-1;;;;;98064:33:0;;;;;;;;;98019:78;;;;;;;;;-1:-1:-1;;;;;98019:78:0;;;;-1:-1:-1;;;;;;;;98019:78:0;;;;;;;;;;;97957:21;;98112:39;;;;98108:345;;;98402:32;;;;98364:77;;-1:-1:-1;;;98364:77:0;;-1:-1:-1;;;;;31492:32:1;;98364:77:0;;;31474:51:1;-1:-1:-1;;;;;31561:31:1;;;31541:18;;;31534:59;98436:4:0;31609:18:1;;;31602:45;31447:18;;98364:77:0;31265:388:1;98108:345:0;98463:21;98543:17;:32;;;98536:4;:39;-1:-1:-1;;;;;98520:55:0;;;98658:69;98686:17;:25;;;-1:-1:-1;;;;;98658:69:0;98713:13;98658:27;:69::i;:::-;98869:25;;98642:85;;-1:-1:-1;;;;;;;98869:41:0;;;;;-1:-1:-1;97841:1136:0;;;;;;:::o;145992:370::-;146058:7;146067;146076;146101:15;146109:6;146101:7;:15::i;:::-;146096:215;;-1:-1:-1;146291:1:0;;-1:-1:-1;146291:1:0;;-1:-1:-1;146291:1:0;146283:16;;106207:362;36688:10;-1:-1:-1;;;;;106372:15:0;;;;;;;:51;;;106392:31;106409:5;106416:6;106392:16;:31::i;:::-;106391:32;106372:51;106368:134;;;106447:43;;-1:-1:-1;;;106447:43:0;;-1:-1:-1;;;;;25050:15:1;;;106447:43:0;;;25032:34:1;25102:15;;25082:18;;;25075:43;24967:18;;106447:43:0;24820:304:1;106368:134:0;106512:49;106530:5;106537:3;106542;106547:6;106555:5;106512:17;:49::i;150357:1660::-;134747:9;;-1:-1:-1;;;;;134747:9:0;134733:10;:23;134729:185;;134885:10;134897:4;134859:43;;-1:-1:-1;;;134859:43:0;;;;;;;;;:::i;134729:185::-;-1:-1:-1;;;;;150486:15:0;;::::1;150513:1;150486:15:::0;;;:7:::1;:15;::::0;;;;;::::1;:29:::0;;:67:::1;;-1:-1:-1::0;150519:34:0;;::::1;;150486:67;150482:440;;;150897:6;150905:4;150871:39;;-1:-1:-1::0;;;150871:39:0::1;;;;;;;;;:::i;150482:440::-;151163:12;151196:42;151221:6;151229:8;;151196:24;:42::i;:::-;87724:14;87621:2;87724;:14;:::i;:::-;130891:8;::::0;:2:::1;:8;:::i;:::-;131077:17;::::0;:1:::1;:17;:::i;:::-;151178:60;;;;:::i;:::-;151163:75;;151341:18;151323:15;:36;:48;;;;;151370:1;151363:4;:8;151323:48;151319:473;;;151467:15;151475:6;151467:7;:15::i;:::-;151462:246;;151679:6;151687:4;151653:39;;-1:-1:-1::0;;;151653:39:0::1;;;;;;;;;:::i;151462:246::-;151722:58;151748:6:::0;-1:-1:-1;;;;;92043:25:0;;151775:4:::1;151722:25;:58::i;:::-;151809:9;151804:206;151824:19:::0;;::::1;151804:206;;;151918:80;151944:6;151952:22;151962:8;;151971:1;151962:11;;;;;;;:::i;151952:22::-;151976:8;;151985:1;151976:11;;;;;;;:::i;:::-;;;;;;;151918:80;;;;;;;;;;;::::0;151993:4:::1;151918:25;:80::i;:::-;151845:3;;151804:206;;;;150471:1546;150357:1660:::0;;;;;:::o;156777:120::-;-1:-1:-1;;;;;156855:17:0;156831:4;156855:17;;;:9;:17;;;;;:30;-1:-1:-1;;;156855:30:0;;-1:-1:-1;;;;;156855:30:0;:34;;;156777:120::o;177499:962::-;-1:-1:-1;;;;;177698:19:0;;;;:46;;-1:-1:-1;;;;;;177721:23:0;;;177698:46;177694:206;;;177864:24;;-1:-1:-1;;;177864:24:0;;177883:4;177864:24;;;32701:36:1;32674:18;;177864:24:0;32549:194:1;177694:206:0;177915:12;;:31;;-1:-1:-1;;;177915:31:0;;-1:-1:-1;;;;;177915:12:0;;;;:24;;:31;;177940:5;;;;177915:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;177914:32;:72;;;-1:-1:-1;177951:12:0;;:35;;-1:-1:-1;;;177951:35:0;;-1:-1:-1;;;;;177951:12:0;;;;:26;;:35;;177978:7;;;;177951:35;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;177950:36;177914:72;177910:257;;;178131:24;;-1:-1:-1;;;178131:24:0;;178150:4;178131:24;;;32701:36:1;32674:18;;178131:24:0;32549:194:1;177910:257:0;178252:22;178266:7;178252:13;:22::i;:::-;-1:-1:-1;;;;;;;;178335:21:0;;;;;;;:12;:21;;;;;;;;:29;;;;;-1:-1:-1;;;;;;178335:29:0;;;;;;178422:10;:19;;;;;:31;;;;;;;;;;;;;;-1:-1:-1;177499:962:0:o;184504:1034::-;184637:36;184717:21;:17;184737:1;184717:21;:::i;:::-;184695:43;;184691:244;;184899:24;;-1:-1:-1;;;184899:24:0;;184918:4;184899:24;;;32701:36:1;32674:18;;184899:24:0;32549:194:1;184691:244:0;184983:21;:17;185003:1;184983:21;:::i;:::-;-1:-1:-1;;;;;184970:35:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;184970:35:0;;184947:58;;185016:13;185113:9;185108:423;185128:22;;;185108:423;;;185257:11;;185269:5;:1;185273;185269:5;:::i;:::-;185257:18;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;185240:1:0;185220:11;;185232:1;185220:14;;;;;;;:::i;:::-;;;;;;;;185207:34;;;:70;;;;;-1:-1:-1;185175:20:0;185196:7;;;;:::i;:::-;;;185175:29;;;;;;;;:::i;:::-;:102;;;;:29;;;;;;;;;;;:102;185378:11;;185390:5;:1;185394;185390:5;:::i;:::-;185378:18;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;185361:1:0;185337:11;;185349:5;:1;185353;185349:5;:::i;:::-;185337:18;;;;;;;:::i;:::-;;;;;;;;185324:38;;;:74;;;;;-1:-1:-1;185292:20:0;185313:7;;;;:::i;:::-;;;185292:29;;;;;;;;:::i;:::-;:106;;;;:29;;;;;;;;;;;:106;185499:11;;185511:5;:1;185515;185511:5;:::i;:::-;185499:18;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;185482:1:0;185458:11;;185470:5;:1;185474;185470:5;:::i;:::-;185458:18;;;;;;;:::i;:::-;;;;;;;;185445:38;;;:74;;;;;-1:-1:-1;185413:20:0;185434:7;;;;:::i;:::-;;;185413:29;;;;;;;;:::i;:::-;:106;;;;:29;;;;;;;;;;;:106;185152:6;185157:1;185152:6;;:::i;:::-;;;185108:423;;;;184680:858;184504:1034;;;;;:::o;164756:3289::-;164997:19;;164931:15;;164977:16;164981:5;164977:1;:16;:::i;:::-;:39;;:143;;;-1:-1:-1;165104:16:0;165081:39;;164977:143;:211;;;-1:-1:-1;165163:25:0;;164977:211;:232;;;-1:-1:-1;165192:17:0;;164977:232;164959:431;;;165354:24;;-1:-1:-1;;;165354:24:0;;165373:4;165354:24;;;32701:36:1;32674:18;;165354:24:0;32549:194:1;164959:431:0;165447:26;165489:13;-1:-1:-1;;;;;165476:34:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;165476:34:0;;165447:63;;165621:9;165616:658;165640:24;165663:1;165640:13;:24;:::i;:::-;165636:1;:28;165616:658;;;165731:13;;165745:5;:1;165749;165745:5;:::i;:::-;165731:20;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;165694:58:0;165702:13;;165716:1;165702:16;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;165694:58:0;;165690:273;;165919:24;;-1:-1:-1;;;165919:24:0;;165938:4;165919:24;;;32701:36:1;32674:18;;165919:24:0;32549:194:1;165690:273:0;166022:1;165985:7;166022:1;165993:13;;166007:1;165993:16;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;165985:25:0;;;;;;;;;;;;;;-1:-1:-1;165985:25:0;;;:39;165981:278;;166216:13;;166230:1;166216:16;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;166234:4;166190:49;;-1:-1:-1;;;166190:49:0;;;;;;;;;:::i;165981:278::-;165666:3;;165616:658;;;-1:-1:-1;166290:18:0;166311:13;;166325:24;166348:1;166311:13;166325:24;:::i;:::-;166311:39;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;166369:19:0;;;166400:1;166369:19;;;:7;:19;;;;;;166290:60;;-1:-1:-1;166369:19:0;166365:244;;166576:10;166588:4;166550:43;;-1:-1:-1;;;166550:43:0;;;;;;;;;:::i;166365:244::-;165523:1097;166697:12;166743:9;166738:1259;166758:16;;;166738:1259;;;166975:17;166995:13;;167009:12;167022:5;167009:19;;;;;;;;;;:::i;:::-;;;;;;;166995:34;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;166975:54;-1:-1:-1;167048:12:0;167063:13;;167077:12;167090:9;:5;167098:1;167090:9;:::i;:::-;167077:23;;;;;;;;;;:::i;:::-;;;;;;;167063:38;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;167048:53;-1:-1:-1;167120:10:0;167133:13;;167147:12;167160:9;:5;167168:1;167160:9;:::i;:::-;167147:23;;;;;;;;;;:::i;:::-;;;;;;;167133:38;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;167120:51;;167190:11;167219:5;;167225:1;167219:8;;;;;;;:::i;:::-;;;;;;:15;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;167211:24:0;167190:46;;167444:36;167460:4;167466:2;167470:9;167444:15;:36::i;:::-;167439:298;;167686:2;-1:-1:-1;;;;;92043:25:0;;167712:4;167658:59;;-1:-1:-1;;;167658:59:0;;;;;;;;;;:::i;167439:298::-;167877:4;167838:10;167849:12;167862:9;:5;167870:1;167862:9;:::i;:::-;167849:23;;;;;;;;;;:::i;:::-;;;;;;;167838:35;;;;;;;;;;:::i;:::-;;;;;;:43;;;;;;;:::i;:::-;;;-1:-1:-1;167939:4:0;167900:10;167911:12;167924:9;:5;167932:1;167924:9;:::i;:::-;167911:23;;;;;;;;;;:::i;:::-;;;;;;;167900:35;;;;;;;;;;:::i;:::-;;;;;;:43;;;;;;;:::i;:::-;;;-1:-1:-1;167972:9:0;:5;167980:1;167972:9;:::i;:::-;167964:17;-1:-1:-1;;166776:3:0;;;;;-1:-1:-1;166738:1259:0;;-1:-1:-1;;166738:1259:0;;-1:-1:-1;168027:10:0;;164756:3289;-1:-1:-1;;;;;;;164756:3289:0:o;168684:3918::-;168971:34;169021:8;-1:-1:-1;;;;;169008:29:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;169008:29:0;-1:-1:-1;168971:66:0;-1:-1:-1;169048:32:0;169097:8;-1:-1:-1;;;;;169083:30:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;169083:30:0;;169048:65;;169191:12;169237:9;169232:2927;169252:16;;;169232:2927;;;169469:10;169482:13;;169496:12;169509:9;:5;169517:1;169509:9;:::i;:::-;169496:23;;;;;;;;;;:::i;:::-;;;;;;;169482:38;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;169469:51;;169542:20;169564:24;169613:91;169632:45;169642:13;;169656:12;169669:5;169656:19;;;;;;;;;;:::i;:::-;;;;;;;169642:34;;;;;;;;;:::i;169632:45::-;169687:5;;169693:1;169687:8;;;;;;;:::i;:::-;;;;;;:15;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;169679:24:0;117922:4;117916:11;;117994:1;117979:17;;;118127:4;118115:17;;118108:35;;;;118247:17;;;118278;;;117727:23;118316:17;;118309:35;;;;118455:17;;;118442:31;;117916:11;117613:878;169613:91;169541:163;;;;170080:1;170056:5;;170062:1;170056:8;;;;;;;:::i;:::-;:21;;;:8;;;;;:21;;;;-1:-1:-1;170056:21:0;:::i;:::-;:25;;;170052:855;;;170106:24;170157:1;170133:5;;170139:1;170133:8;;;;;;;:::i;:::-;:21;;;:8;;;;;:21;;;;-1:-1:-1;170133:21:0;:::i;:::-;:25;;;;:::i;:::-;170106:52;;170267:1;170185:8;;170194:17;170185:27;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:39;;;;;;;:::i;:::-;170225:18;170244:17;170225:37;;;;;;;;;;:::i;:::-;;;;;;;170185:78;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;:83;;;170181:256;;170385:1;170388:5;;170394:1;170388:8;;;;;;;:::i;:::-;:21;;;:8;;;;;:21;;;;-1:-1:-1;170388:21:0;:::i;:::-;170352:61;;-1:-1:-1;;;170352:61:0;;;;;36603:25:1;;;;36676:6;36664:19;36644:18;;;36637:47;170411:1:0;36700:18:1;;;36693:45;36576:18;;170352:61:0;36396:348:1;170181:256:0;170459:18;170478:17;170459:37;;;;;;;;;;:::i;:::-;;;;;;:39;;;;;;;;:::i;:::-;;;;;;;;;170571:1;-1:-1:-1;;;;;170525:48:0;:15;170541:17;170525:34;;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;170525:48:0;;170521:367;;170639:2;170602:15;170618:17;170602:34;;;;;;;;;;:::i;:::-;;;;;;:39;-1:-1:-1;;;;;170602:39:0;;;-1:-1:-1;;;;;170602:39:0;;;;;170521:367;;;170713:2;-1:-1:-1;;;;;170675:40:0;:15;170691:17;170675:34;;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;170675:40:0;;170671:217;;170836:1;170839:5;;170845:1;170839:8;;;;;;;:::i;:::-;:21;;;:8;;;;;:21;;;;-1:-1:-1;170839:21:0;:::i;:::-;170803:61;;-1:-1:-1;;;170803:61:0;;;;;36603:25:1;;;;36676:6;36664:19;36644:18;;;36637:47;170862:1:0;36700:18:1;;;36693:45;36576:18;;170803:61:0;36396:348:1;170671:217:0;170083:824;170052:855;170960:1;170932:53;170963:5;;170969:1;170963:8;;;;;;;:::i;:::-;:21;;;:8;;;;;:21;;;;-1:-1:-1;170963:21:0;:::i;:::-;170932:53;;37478:6:1;37466:19;;;37448:38;;37436:2;37421:18;170932:53:0;;;;;;;-1:-1:-1;;;;;157107:20:0;;;157083:4;157107:20;;;:12;:20;;;;;;;171047:1059;;171242:215;171276:13;;171290:12;171303:9;:5;171311:1;171303:9;:::i;:::-;171290:23;;;;;;;;;;:::i;:::-;;;;;;;171276:38;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;171368:2;171397:3;171427:7;171242;:215::i;:::-;171047:1059;;;171600:486;171637:13;;171651:12;171664:9;:5;171672:1;171664:9;:::i;:::-;171651:23;;;;;;;;;;:::i;:::-;;;;;;;171637:38;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;171729:2;171785;171879:3;171923:7;171600:486;;;;;;;;;;;;172058:5;171600:10;:486::i;:::-;172134:9;:5;172142:1;172134:9;:::i;:::-;172126:17;-1:-1:-1;;169270:3:0;;;;;-1:-1:-1;169232:2927:0;;-1:-1:-1;169232:2927:0;;-1:-1:-1;172180:25:0;;;;;;;172287:9;172282:302;172302:19;;;172282:302;;;172381:1;-1:-1:-1;;;;;172351:32:0;:15;172367:1;172351:18;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;172351:32:0;;:91;;;;172412:8;;172421:1;172412:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:23;;;;;;;:::i;:::-;:30;;172387:18;172406:1;172387:21;;;;;;;;:::i;:::-;;;;;;;:55;;;;172351:91;172347:222;;;172522:27;;-1:-1:-1;;;172522:27:0;;;;;616:25:1;;;589:18;;172522:27:0;470:177:1;172347:222:0;172323:3;;172282:302;;;;169126:3469;168885:3717;;168684:3918;;;;;;;:::o;172974:2321::-;173185:15;173256:26;173298:13;-1:-1:-1;;;;;173285:34:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;173285:34:0;;173256:63;;173399:9;173394:1864;173414:19;;;173394:1864;;;173455:20;173492:8;;173501:1;173492:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:23;;;;;;;:::i;:::-;:30;;-1:-1:-1;;;;;173478:45:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;173478:45:0;;173455:68;;173538:24;173579:8;;173588:1;173579:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:23;;;;;;;:::i;:::-;:30;;-1:-1:-1;;;;;173565:45:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;173565:45:0;;173538:72;;173625:19;173677:9;173672:393;173696:8;;173705:1;173696:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:23;;;;;;;:::i;:::-;:30;;173692:1;:34;173672:393;;;173863:70;173873:13;;173887:12;173904:8;;173913:1;173904:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:23;;;;;;;:::i;:::-;173928:1;173904:26;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;173900:30;;:1;:30;:::i;:::-;173887:44;;;;;;;;;;:::i;173863:70::-;173854:3;173858:1;173854:6;;;;;;;;:::i;:::-;;;;;;:79;;;;;173965:5;;173971:8;;173980:1;173971:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:23;;;;;;;:::i;:::-;173995:1;173971:26;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;173965:33;;;;;;;;;:::i;:::-;;;;;;:40;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;173952:53:0;:7;173960:1;173952:10;;;;;;;;:::i;:::-;;;;;;:53;;;;;174039:7;174047:1;174039:10;;;;;;;;:::i;:::-;;;;;;;174024:25;;;;;:::i;:::-;;-1:-1:-1;173728:3:0;;173672:393;;;;174159:25;174187:12;174204:8;;174213:1;174204:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:23;;;;;;;:::i;:::-;174228:1;174204:26;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;174200:30;;:1;:30;:::i;:::-;:34;;174233:1;174200:34;:::i;:::-;174187:48;;;;;;;;;;:::i;:::-;;;;;;;174159:76;;174250:16;174269:13;;174283:18;174269:33;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;174250:52;;174317:350;174352:13;;174366:8;;174375:1;174366:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:28;;;;;;;:::i;:::-;174352:43;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;174422:8;174455:3;174533:7;174603:8;;174612:1;174603:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:16;;;;;;;:::i;:::-;174317:350;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;174317:16:0;;-1:-1:-1;;;174317:350:0:i;:::-;174800:11;174749:10;174760:8;;174769:1;174760:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:28;;;;;;;:::i;:::-;174749:40;;;;;;;;;;:::i;:::-;;;;;;:63;;;;;;;:::i;:::-;;;-1:-1:-1;174898:30:0;;174939:11;;174898:10;;:30;;;;;;;;;;:::i;:::-;;;;;;:53;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;;175150:96:0;;175178:13;;175192:8;;175201:1;175192:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:28;;;;;;;:::i;:::-;175178:43;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;175150:96:0;175166:10;-1:-1:-1;;;;;175150:96:0;;175233:3;175238:7;175150:96;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;173435:3:0;;;;;-1:-1:-1;173394:1864:0;;-1:-1:-1;;173394:1864:0;;-1:-1:-1;175277:10:0;172974:2321;-1:-1:-1;;;;;;;;172974:2321:0:o;175303:728::-;175459:17;:24;175430:18;:25;:53;175426:273;;175663:24;;-1:-1:-1;;;175663:24:0;;175682:4;175663:24;;;32701:36:1;32674:18;;175663:24:0;32549:194:1;175426:273:0;175714:9;175709:315;175733:18;:25;175729:1;:29;175709:315;;;175809:17;175827:1;175809:20;;;;;;;;:::i;:::-;;;;;;;175784:18;175803:1;175784:21;;;;;;;;:::i;:::-;;;;;;;:45;175780:233;;175950:1;175953:17;175971:1;175953:20;;;;;;;;:::i;:::-;;;;;;;175975:18;175994:1;175975:21;;;;;;;;:::i;:::-;;;;;;;175921:76;;-1:-1:-1;;;175921:76:0;;;;;;;;;16158:25:1;;;16214:2;16199:18;;16192:34;;;;16257:2;16242:18;;16235:34;16146:2;16131:18;;15956:319;175780:233:0;175760:3;;175709:315;;;;175303:728;;:::o;179613:406::-;-1:-1:-1;;;;;179744:17:0;;;;;;;:9;:17;;;;;:30;;122411:3;179744:52;179740:272;;179889:20;179914:30;179937:6;179914:22;:30::i;:::-;179888:56;;;179959:41;179979:6;179987:12;179959:19;:41::i;179740:272::-;179613:406;:::o;126782:722::-;126843:16;126861:19;126882:17;126903:26;126922:6;126903:18;:26::i;:::-;126842:87;;;;;;126944:8;126956:1;126944:13;126940:122;;127044:7;;;126782:722;:::o;126940:122::-;-1:-1:-1;;;;;127193:17:0;;;;;;;:9;:17;;;;;:56;;;;;-1:-1:-1;;;127233:15:0;-1:-1:-1;;;;;127193:56:0;;;;;;127352:72;;127193:17;;127405:8;127352:72;;;;;;;;;;;;127419:4;127352:25;:72::i;:::-;127442:54;;;16158:25:1;;;16214:2;16199:18;;16192:34;;;16242:18;;;16235:34;;;-1:-1:-1;;;;;127442:54:0;;;;;16146:2:1;16131:18;127442:54:0;;;;;;;126831:673;;;126782:722;:::o;11724:2401::-;11782:6;11816:13;11836:1;11832;:5;;;:19;;;;;11841:1;11845;11841:5;11850:1;11841:10;11832:19;11816:35;;11862:12;11890:1;11886;:5;;;:14;;11899:1;11886:14;;;11895:1;11894:2;;11886:14;-1:-1:-1;;;;;11862:39:0;;-1:-1:-1;;;;12006:19:0;11998:27;;11994:1951;;12047:2;12038:11;;;;;12060:583;12067:6;;12060:583;;12096:3;12092:7;;:12;12088:82;;12133:16;;12153:3;12133:23;12088:82;12189:11;;;12204:3;12189:18;;12230:3;12226:7;;:12;12222:82;;12267:16;;12287:3;12267:23;12222:82;12323:11;;;12338:3;12323:18;;12364:3;12360:7;;:12;12356:82;;12401:16;;12421:3;12401:23;12356:82;12457:11;;;12472:3;12457:18;;12498:3;12494:7;;:12;12490:82;;12535:16;;12555:3;12535:23;12490:82;12630:1;12624:7;;;;;12591:11;;;12606:3;12591:18;;12060:583;;;12669:2;12655:16;11994:1951;;;12718:2;-1:-1:-1;;;12735:34:0;;12731:73;;;12782:2;12773:11;;;;;-1:-1:-1;;12786:15:0;12731:73;-1:-1:-1;;;12818:4:0;:38;12814:77;;;12869:2;12860:11;;;;;-1:-1:-1;;12873:15:0;12814:77;-1:-1:-1;;;12905:4:0;:40;12901:77;;;12958:1;12949:10;;;;;-1:-1:-1;;12961:14:0;12901:77;-1:-1:-1;;;12992:4:0;:41;12988:78;;;13046:1;13037:10;;;;;-1:-1:-1;;13049:14:0;12988:78;-1:-1:-1;;;13080:4:0;:41;13076:78;;;13134:1;13125:10;;;;;-1:-1:-1;;13137:14:0;13076:78;-1:-1:-1;;;13168:4:0;:41;13164:78;;;13222:1;13213:10;;;;;-1:-1:-1;;13225:14:0;13164:78;13254:19;13288:568;13295:6;;13288:568;;13337:2;13325:9;:14;13316:24;;;;;;13363:3;13359:7;;:12;13355:269;;13400:16;;;13420:3;13400:23;;13438:24;;-1:-1:-1;;;13481:47:0;;13477:134;;;13561:1;13547:15;;;;13579:16;13477:134;13643:11;;;13658:3;13643:18;;13688:1;13674:15;;;;;-1:-1:-1;;;13706:43:0;;13702:121;;13777:1;13768:10;;;;13795:14;;;;;13702:121;13843:1;13837:7;;;;;13288:568;;;13891:2;13877:11;:16;13868:26;;;;;;13919:2;:16;13905:30;;;;;-1:-1:-1;11994:1951:0;13953:13;13969:8;:51;;14010:9;13969:51;;;13989:9;13980:19;;13969:51;13953:67;-1:-1:-1;;;;;;;14038:19:0;;;;;:42;;-1:-1:-1;;;;;;14061:19:0;;;14038:42;14029:52;;;;;;14105:6;11724:2401;-1:-1:-1;;;;;;11724:2401:0:o;6539:529::-;6598:7;6637:1;6642;6637:6;6633:20;;-1:-1:-1;6652:1:0;6645:8;;6633:20;6678:1;6673;:6;;;;6664:16;;;;;;6714:10;;;;-1:-1:-1;;;;;6729:38:0;;6705:63;;6773:2;6704:71;;6826:3;6821:8;;;6797:33;-1:-1:-1;;;;;6850:56:0;;;6841:66;;;;;;6923:2;6916:9;6960:71;;6945:86;;;6936:96;;;;;;7048:7;;6539:529;-1:-1:-1;;;6539:529:0:o;112496:459::-;-1:-1:-1;;;;;112696:16:0;;112692:90;;112736:34;;-1:-1:-1;;;112736:34:0;;112767:1;112736:34;;;3667:51:1;3640:18;;112736:34:0;3521:203:1;112692:90:0;-1:-1:-1;;;;;112796:18:0;;112792:90;;112838:32;;-1:-1:-1;;;112838:32:0;;112867:1;112838:32;;;3667:51:1;3640:18;;112838:32:0;3521:203:1;112792:90:0;112892:55;112919:4;112925:2;112929:3;112934:6;112942:4;112892:26;:55::i;:::-;112496:459;;;;;:::o;160460:3562::-;160745:8;:15;160723:11;:18;:37;;:64;;;-1:-1:-1;160764:18:0;;:23;160723:64;160719:347;;;161030:24;;-1:-1:-1;;;161030:24:0;;161049:4;161030:24;;;32701:36:1;32674:18;;161030:24:0;32549:194:1;160719:347:0;-1:-1:-1;;;;;157107:20:0;;;157083:4;157107:20;;;:12;:20;;;;;;;161076:215;;161274:4;161240:39;;-1:-1:-1;;;161240:39:0;;;;161266:6;;161240:39;;;:::i;161076:215::-;161563:18;161601:9;161596:894;161620:8;:15;161616:1;:19;161596:894;;;161657:24;161684:41;161707:11;161719:1;161707:14;;;;;;;;:::i;:::-;;;;;;;161723:1;161684:22;:41::i;:::-;161657:68;;161902:22;161944:13;:104;;161998:50;162014:7;162023:6;162031:16;161998:15;:50::i;:::-;161944:104;;;161960:35;161970:6;161978:16;161960:9;:35::i;:::-;161902:146;;162070:17;162069:18;:38;;;;162091:8;162100:1;162091:11;;;;;;;;:::i;:::-;;;;;;;162106:1;162091:16;162069:38;162065:372;;;162392:6;162400:11;162412:1;162400:14;;;;;;;;:::i;:::-;;;;;;;162416:4;162364:57;;-1:-1:-1;;;162364:57:0;;;;;;;;;;:::i;162065:372::-;162467:8;162476:1;162467:11;;;;;;;;:::i;:::-;;;;;;;162453:25;;;;;:::i;:::-;;-1:-1:-1;;;161637:3:0;;161596:894;;;-1:-1:-1;;;;;;162612:20:0;;;;;;;:12;:20;;;;;;;;162600:97;;-1:-1:-1;;;162600:97:0;;162612:20;;;162600:50;;:97;;162651:7;;162625:6;;162668:11;;162681:8;;162691:5;;162600:97;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;162595:354;;162904:7;-1:-1:-1;;;;;92043:25:0;;162932:4;162876:61;;-1:-1:-1;;;162876:61:0;;;;;;;;;;:::i;162595:354::-;163048:26;163088:34;;;;;;;;163114:6;-1:-1:-1;;;;;163088:34:0;;;;163077:46;;;;;;41568:13:1;-1:-1:-1;;;;;41564:39:1;41546:58;;41534:2;41519:18;;41330:280;163077:46:0;;;;-1:-1:-1;;163077:46:0;;;;;;163188:97;;;;;67997:53;163188:97;;163077:46;163188:97;;;;;;;;;;;;163163:133;;163077:46;;-1:-1:-1;163134:26:0;;163163:133;;163077:46;;163163:133;;:::i;:::-;;;;-1:-1:-1;;163163:133:0;;;;;;;;;-1:-1:-1;;;;;163448:18:0;;;;;;;:10;163163:133;163448:18;;;;;;163163:133;;-1:-1:-1;163417:88:0;;163439:7;;163448:18;163468:11;163481:8;163163:133;163417:21;:88::i;:::-;163809:89;163835:9;-1:-1:-1;;;;;92043:25:0;;163865:10;163877:5;163884:13;163809:25;:89::i;:::-;163984:6;-1:-1:-1;;;;;163954:60:0;163973:9;-1:-1:-1;;;;;163954:60:0;163964:7;-1:-1:-1;;;;;163954:60:0;;163992:11;164005:8;163954:60;;;;;;;:::i;:::-;;;;;;;;160708:3314;;;160460:3562;;;;;;;:::o;178469:195::-;178557:47;178576:8;178586;178596:7;178557:18;:47::i;:::-;178622:34;;-1:-1:-1;;;;;42376:39:1;;42358:58;;-1:-1:-1;;;;;178622:34:0;;;;;;;;;;42346:2:1;42331:18;178622:34:0;;;;;;;;178469:195;;;:::o;183572:324::-;183653:7;-1:-1:-1;;;;;183677:23:0;;183673:177;;;183793:45;;-1:-1:-1;;;183793:45:0;;;;;42597:25:1;;;42670:4;42658:17;;42638:18;;;42631:45;42570:18;;183793:45:0;42427:255:1;183673:177:0;-1:-1:-1;183883:3:0;;183572:324;-1:-1:-1;183572:324:0:o;128534:1304::-;128711:28;128717:8;128727:3;128732:6;128711:5;:28::i;:::-;128752:12;128767:20;128771:15;128767:3;:20::i;:::-;128798:43;128844:28;;;:23;:28;;;;;;;;128798:74;;;;;;;;;-1:-1:-1;;;;;128798:74:0;;;;;-1:-1:-1;;;128798:74:0;;;-1:-1:-1;;;;;128798:74:0;;;;;;;128752:35;;-1:-1:-1;128798:74:0;128928:98;;128984:41;;128752:35;128984:41;:::i;128928:98::-;128883:143;;129065:6;129041:21;:30;129037:567;;;129568:24;;-1:-1:-1;;;129568:24:0;;129587:4;129568:24;;;32701:36:1;32674:18;;129568:24:0;32549:194:1;129037:567:0;-1:-1:-1;;;;;129676:30:0;;;129639:68;;;;-1:-1:-1;;;;;129729:41:0;;;:33;;;;:41;;;129639:26;129781:28;;;:23;:28;;;;;;:49;;;;;;;-1:-1:-1;;;129781:49:0;;;;;;;;;;;-1:-1:-1;128534:1304:0:o;123783:2811::-;-1:-1:-1;;;;;123915:17:0;;;123850:7;123915:17;;;:9;:17;;;;;;;;123888:44;;;;;;;;;;;;;;;-1:-1:-1;;;123888:44:0;;;-1:-1:-1;;;;;123888:44:0;;;;;;;;123850:7;;;;;;123947:35;;;;:82;;-1:-1:-1;123986:21:0;;-1:-1:-1;;;;;123986:43:0;122411:3;123986:43;;123947:82;123943:296;;;124214:6;124222:4;124188:39;;-1:-1:-1;;;124188:39:0;;;;;;;;;:::i;123943:296::-;124316:25;124368:7;124344:8;:21;;;:31;;;;:::i;:::-;-1:-1:-1;;;;;124316:59:0;;-1:-1:-1;124386:28:0;124417:25;124435:7;124417:15;:25;:::i;:::-;124386:56;;124480:20;124459:17;:41;;:87;;;-1:-1:-1;124504:21:0;;;;-1:-1:-1;;;;;124504:42:0;;;;124459:87;124455:194;;;124629:1;124632;124635;124621:16;;;;;;;;;;;124455:194;124717:17;124737:65;124742:36;122226:7;124742:15;:36;:::i;:::-;124780:8;:21;;;-1:-1:-1;;;;;124737:65:0;:4;:65::i;:::-;124717:85;;124852:10;124873:14;124877:9;124873:3;:14::i;:::-;-1:-1:-1;;;;;124865:23:0;124852:36;;124938:10;124959:20;124963:15;124959:3;:20::i;:::-;-1:-1:-1;;;;;124951:29:0;;-1:-1:-1;125073:9:0;125085:7;125090:2;124951:29;125085:7;:::i;:::-;125073:19;;125184:8;125195:80;125267:7;125246:16;;125232:2;125237:6;125232:11;;;;:::i;:::-;:30;;;;:::i;:::-;125219:44;;:9;:44;:::i;:::-;125218:56;;;;:::i;:::-;125195:22;:80::i;:::-;125184:91;;125366:27;125436:15;125417:16;;125398:2;125403:1;125398:6;;;;:::i;:::-;125397:17;;125408:6;125397:17;:::i;:::-;:36;;;;:::i;:::-;:54;;;;:::i;:::-;125366:86;-1:-1:-1;125524:25:0;125552:29;125574:7;125366:86;125552:29;:::i;:::-;125524:57;-1:-1:-1;125784:8:0;125795:87;125784:8;125839:29;125861:7;125839:19;:29;:::i;:::-;:33;:41;;125879:1;125839:41;;;125875:1;125839:41;125818:63;;;;:17;:63;:::i;125795:87::-;125784:98;;126072:16;126091:48;126109:26;126127:1;126129;126127:4;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;126133:1;126109:17;:26::i;:::-;126137:1;126091:17;:48::i;:::-;126072:67;;126261:59;126280:34;126298:1;126300;126298:4;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;126304:9;126280:17;:34::i;:::-;87724:14;87621:2;87724;:14;:::i;:::-;126261:18;:59::i;:::-;126414:30;126433:1;126436:7;126414:18;:30::i;:::-;126400:11;:2;126405:6;126400:11;:::i;:::-;126381:16;;:30;;;;:::i;:::-;:63;;;;:::i;:::-;126545:30;126564:1;126567:7;126545:18;:30::i;:::-;126522:11;:2;126527:6;126522:11;:::i;:::-;126503:16;;:30;;;;:::i;:::-;:39;;126536:6;126503:39;:::i;:::-;:72;;;;:::i;:::-;126239:347;;;;;;;;;;;;;;;;;;123783:2811;;;;;:::o;117171:321::-;-1:-1:-1;;;;;117279:22:0;;117275:96;;117325:34;;-1:-1:-1;;;117325:34:0;;117356:1;117325:34;;;3667:51:1;3640:18;;117325:34:0;3521:203:1;117275:96:0;-1:-1:-1;;;;;117381:25:0;;;;;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;:46;;-1:-1:-1;;117381:46:0;;;;;;;;;;117443:41;;1178::1;;;117443::0;;1151:18:1;117443:41:0;1038:187:1;94271:311:0;94374:7;94398:15;94417:1;94398:20;94394:68;;-1:-1:-1;94442:8:0;94435:15;;94394:68;94472:8;94483:42;94509:15;94483:25;:42::i;183192:372::-;-1:-1:-1;;;;;183256:16:0;;;183284:1;183256:16;;;:7;:16;;;;;;;:30;183252:220;;183446:7;183455:4;183420:40;;-1:-1:-1;;;183420:40:0;;;;;;;;;:::i;183252:220::-;183501:7;:17;;;;;-1:-1:-1;;;;;183482:16:0;;;183501:17;183482:16;;;183501:17;183482:16;;:36;;183501:17;;;;-1:-1:-1;;;;;;183482:36:0;;;;;;;-1:-1:-1;183529:17:0;;;:27;;;;;;;;;;183192:372::o;176309:852::-;176403:23;176428:21;176540;176554:6;176540:13;:21::i;:::-;176743:30;176766:6;176743:22;:30::i;:::-;-1:-1:-1;;;;;176812:17:0;;;176784:25;176812:17;;;:9;:17;;;;;-1:-1:-1;;;;;176921:15:0;176890:47;;-1:-1:-1;;;176890:47:0;176840:39;;;176890:47;;;;;;176708:65;;-1:-1:-1;176708:65:0;;-1:-1:-1;177011:41:0;;176822:6;;;;177011;:41::i;:::-;177092:8;-1:-1:-1;;;;;177070:31:0;177084:6;-1:-1:-1;;;;;177070:31:0;;;;;;;;;;;177114:39;176309:852;;;;;;:::o;127512:1014::-;127711:55;127717:8;127727:3;127732:6;127740:5;127747:18;127711:5;:55::i;:::-;127779:12;127794:20;127798:15;127794:3;:20::i;:::-;127825:43;127871:28;;;:23;:28;;;;;;;;127825:74;;;;;;;;;-1:-1:-1;;;;;127825:74:0;;;;;-1:-1:-1;;;127825:74:0;;;-1:-1:-1;;;;;127825:74:0;;;;;;;127779:35;;-1:-1:-1;127825:74:0;128049:6;;127948:98;;127825:74;128004:41;;127779:35;128004:41;:::i;127948:98::-;:107;;;;:::i;:::-;127910:145;-1:-1:-1;;;;;;128070:26:0;;128066:278;;;128312:8;128322:3;128327:4;128284:48;;-1:-1:-1;;;128284:48:0;;;;;;;;;;:::i;128066:278::-;-1:-1:-1;;;;;128354:52:0;;;;;-1:-1:-1;;;;;128417:41:0;;;:33;;;;:41;;;-1:-1:-1;128469:28:0;;;:23;:28;;;;;;:49;;;;;;-1:-1:-1;;;128469:49:0;;;;;;;;;;;;-1:-1:-1;;;;127512:1014:0:o;111610:472::-;-1:-1:-1;;;;;111733:16:0;;111729:90;;111773:34;;-1:-1:-1;;;111773:34:0;;111804:1;111773:34;;;3667:51:1;3640:18;;111773:34:0;3521:203:1;111729:90:0;-1:-1:-1;;;;;111833:18:0;;111829:90;;111875:32;;-1:-1:-1;;;111875:32:0;;111904:1;111875:32;;;3667:51:1;3640:18;;111875:32:0;3521:203:1;111829:90:0;117922:4;117916:11;;117994:1;117979:17;;;118127:4;118115:17;;118108:35;;;118247:17;;;118278;;;117727:23;118316:17;;118309:35;;;118455:17;;;118442:31;;;117916:11;112019:55;112046:4;112052:2;117916:11;118247:17;112069:4;112019:26;:55::i;178672:711::-;178771:7;;;178831:508;178851:19;;;178831:508;;;178928:1;178896:7;178928:1;178904:8;;178913:1;178904:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;178896:20:0;;;;;;;;;;;;;;-1:-1:-1;178896:20:0;;;:34;178892:436;;178951:19;;;;:::i;:::-;;;;178989:37;179004:8;;179013:1;179004:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;179017:8;178989:14;:37::i;:::-;;;178892:436;;;179072:20;179080:8;;179089:1;179080:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;179072:20::-;179067:246;;179275:8;;179284:1;179275:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;179288:4;179249:44;;-1:-1:-1;;;179249:44:0;;;;;;;;;:::i;179067:246::-;178872:3;;178831:508;;;-1:-1:-1;179358:17:0;178672:711;-1:-1:-1;;;;178672:711:0:o;107846:1642::-;107982:6;:13;107968:3;:10;:27;107964:119;;108045:10;;108057:13;;108019:52;;-1:-1:-1;;;108019:52:0;;;;;18831:25:1;;;;18872:18;;;18865:34;18804:18;;108019:52:0;18657:248:1;107964:119:0;36688:10;108095:16;108154:20;108158:15;108154:3;:20::i;:::-;108139:35;;108192:9;108187:988;108211:3;:10;108207:1;:14;108187:988;;;84751:4;84742:14;;;84722:35;;;;;84716:42;84722:35;;;;;;84716:42;-1:-1:-1;;;;;108361:18:0;;;108357:688;;108401:19;108422:20;108446:31;108461:4;108467:2;108471:5;108446:14;:31::i;:::-;108400:77;;;;108514:5;108500:11;:19;108496:131;;;108551:56;;-1:-1:-1;;;108551:56:0;;-1:-1:-1;;;;;44727:32:1;;108551:56:0;;;44709:51:1;44776:18;;;44769:34;;;44819:18;;;44812:34;;;44862:18;;;44855:34;;;44681:19;;108551:56:0;44478:417:1;108496:131:0;108649:16;;108645:194;;108695:60;;;18831:25:1;;;18887:2;18872:18;;18865:34;;;108734:1:0;;-1:-1:-1;;;;;108695:60:0;;;;;;;;;;18804:18:1;108695:60:0;;;;;;;108802:2;108796:4;-1:-1:-1;;;;;108783:36:0;;108806:12;108783:36;;;;616:25:1;;604:2;589:18;;470:177;108783:36:0;;;;;;;;108645:194;108958:52;108973:4;108979:2;108997:5;108983:11;:19;109004:5;108958:14;:52::i;:::-;108381:664;;108357:688;-1:-1:-1;;;;;109065:16:0;;;109061:103;;109102:46;109127:2;109131;109135:5;109142;109102:24;:46::i;:::-;-1:-1:-1;;108223:3:0;;108187:988;;;;109191:3;:10;109205:1;109191:15;109187:294;;84751:4;84722:35;;84716:42;109223:10;;84751:4;84722:35;;84716:42;109223:38;;-1:-1:-1;109371:2:0;-1:-1:-1;;;;;109340:45:0;109365:4;-1:-1:-1;;;;;109340:45:0;109355:8;-1:-1:-1;;;;;109340:45:0;;109375:2;109379:5;109340:45;;;;;;18831:25:1;;;18887:2;18872:18;;18865:34;18819:2;18804:18;;18657:248;109340:45:0;;;;;;;;109208:189;;109187:294;;;109453:2;-1:-1:-1;;;;;109423:46:0;109447:4;-1:-1:-1;;;;;109423:46:0;109437:8;-1:-1:-1;;;;;109423:46:0;;109457:3;109462:6;109423:46;;;;;;;:::i;110473:666::-;-1:-1:-1;;;;;110672:17:0;;;110668:464;;110756:11;;36688:10;;110771:1;110756:16;110752:369;;84751:4;84722:35;;;84716:42;84722:35;;;84716:42;110915:70;110946:8;110956:5;110963:3;84716:42;;110979:5;110915:30;:70::i;:::-;110774:227;;110752:369;;;111026:79;111062:8;111072:5;111079:3;111084:4;111090:7;111099:5;111026:35;:79::i;180889:829::-;181010:26;;-1:-1:-1;;;181010:26:0;;-1:-1:-1;;;;;3685:32:1;;;181010:26:0;;;3667:51:1;-1:-1:-1;;;;;;181010:5:0;:17;;;;;;3640:18:1;;181010:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;180990:46;-1:-1:-1;;;;;;181123:23:0;;181119:60;;-1:-1:-1;181164:1:0;;;;-1:-1:-1;180889:829:0;-1:-1:-1;;180889:829:0:o;181119:60::-;181252:19;181283:9;-1:-1:-1;;;;;181274:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;181252:55;;181374:9;-1:-1:-1;;;;;181365:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;181361:350;;;122411:3;;181532:11;;-1:-1:-1;180889:829:0;-1:-1:-1;;;180889:829:0:o;181361:350::-;181676:9;;181687:11;;-1:-1:-1;180889:829:0;-1:-1:-1;;180889:829:0:o;181984:1035::-;-1:-1:-1;;;;;182100:17:0;;182072:25;182100:17;;;:9;:17;;;;;182287:21;;182100:17;;-1:-1:-1;;;182287:21:0;;;-1:-1:-1;;;;;182287:21:0;:26;;182283:220;;182467:24;;-1:-1:-1;;;182467:24:0;;182486:4;182467:24;;;32701:36:1;32674:18;;182467:24:0;32549:194:1;182283:220:0;182658:21;;-1:-1:-1;;;;;182658:38:0;;;:21;;:38;182654:358;;182713:37;;-1:-1:-1;;;;;;182713:37:0;-1:-1:-1;;;;;182713:37:0;;;;;;182947:52;;-1:-1:-1;;;182952:21:0;;-1:-1:-1;;;;;182952:21:0;;;;182982:15;182947:52;:4;:52::i;:::-;182916:84;;-1:-1:-1;;;;;182916:84:0;;;;-1:-1:-1;;;182916:84:0;-1:-1:-1;;;;;182916:84:0;;;;;;182061:958;181984:1035;;:::o;110078:302::-;110286:30;110294:4;110300:2;110304:3;110309:6;110286:7;:30::i;:::-;110327:45;110344:4;110350:2;110354:3;110359:6;110367:4;110327:16;:45::i;185925:915::-;-1:-1:-1;;;;;186028:22:0;;;;:48;;-1:-1:-1;;;;;;186054:22:0;;;186028:48;:72;;;-1:-1:-1;;;;;;186080:20:0;;131247:3;186080:20;186028:72;186024:165;;;186124:24;;-1:-1:-1;;;186124:24:0;;186143:4;186124:24;;;32701:36:1;32674:18;;186124:24:0;32549:194:1;186024:165:0;-1:-1:-1;;;;;186238:22:0;;;186201:34;186238:22;;;:12;:22;;;;;;;;131247:3;186238:32;;;;;;;186285:23;;186238:32;;186285:23;186281:159;;186394:34;;-1:-1:-1;;;;;;186394:34:0;131247:3;186394:34;;;186281:159;-1:-1:-1;;;;;186486:22:0;;;186452:31;186486:22;;;:12;:22;;;;;;;;:32;;;;;;;;;;186533:20;;186486:32;;186533:20;186529:202;;186647:23;;186624:46;;-1:-1:-1;;;;;186647:23:0;;;-1:-1:-1;;;;;;186624:46:0;;;;;;186685:34;;;;;;;;;186529:202;186804:28;;-1:-1:-1;;;;;186804:28:0;;;-1:-1:-1;;;186804:28:0;-1:-1:-1;;;;;186804:28:0;;;;;;;;;;-1:-1:-1;;;185925:915:0:o;115938:335::-;-1:-1:-1;;;;;116018:18:0;;116014:90;;116060:32;;-1:-1:-1;;;116060:32:0;;116089:1;116060:32;;;3667:51:1;3640:18;;116060:32:0;3521:203:1;116014:90:0;117922:4;117916:11;;117994:1;117979:17;;;118127:4;118115:17;;118108:35;;;118247:17;;;118278;;;117727:23;118316:17;;118309:35;;;116204:61;;;;;;-1:-1:-1;118455:17:0;;;116204:61;;;117916:11;;118247:17;116204:61;;116231:4;;117916:11;;118247:17;;116204:26;:61::i;129963:108::-;130022:7;130054:1;130049;:6;;:14;;-1:-1:-1;130062:1:0;130042:21;-1:-1:-1;129963:108:0:o;2090:174::-;2143:6;2191:18;2186:1;:23;;2177:33;;;;;;-1:-1:-1;2247:2:0;2242:7;;2090:174::o;4613:231::-;4670:6;4720:13;:9;;;:13;;;;;4737:2;4720:19;-1:-1:-1;;;;;;4757:19:0;;;;;:42;;-1:-1:-1;;;;;;4780:19:0;;;4757:42;4748:52;;;;;3705:225;3762:6;3812:13;:9;;;:13;;;;;-1:-1:-1;;;;;;3843:19:0;;;;;:42;;-1:-1:-1;;;;;;3866:19:0;;;3834:52;;;;;4152:225;4209:6;4259:13;;;;:9;;;;:13;-1:-1:-1;;;;;;4290:19:0;;;;;:42;;-1:-1:-1;;;;;;4313:19:0;;;4281:52;;;;;94943:552;95025:6;87952:2;95048:32;;95044:298;;95191:22;95216:1;95218:14;95216:17;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;95252:20:0;;95248:83;;95300:15;94943:552;-1:-1:-1;;94943:552:0:o;95248:83::-;95082:260;95044:298;95441:46;86916:20;95472:14;95441:17;:46::i;114386:496::-;-1:-1:-1;;;;;114508:16:0;;114504:90;;114548:34;;-1:-1:-1;;;114548:34:0;;114579:1;114548:34;;;3667:51:1;3640:18;;114548:34:0;3521:203:1;114504:90:0;117922:4;117916:11;;117994:1;117979:17;;;118127:4;118115:17;;118108:35;;;118247:17;;;118278;;;117727:23;118316:17;;118309:35;;;118455:17;;;118442:31;;;117916:11;114694:181;;;;114733:61;114768:1;114772:2;114776:3;114781:6;114789:4;114733:26;:61::i;:::-;114694:181;;;114827:36;114843:1;114847:2;114851:3;114856:6;114827:7;:36::i;99847:638::-;-1:-1:-1;;;;;99957:20:0;;99953:266;;;100187:8;100197:3;100202:4;100159:48;;-1:-1:-1;;;100159:48:0;;;;;;;;;;:::i;99953:266::-;100229:42;100274:23;;;:18;:23;;;;;;;;-1:-1:-1;;;;;100274:33:0;;;;;;;;;;;;100229:78;;;;;;;;-1:-1:-1;;;;;100318:45:0;;;;;-1:-1:-1;;;;;100374:39:0;;;100229:78;;;100374:39;;;100424:33;;;;;;;;:53;;;;-1:-1:-1;;;100424:53:0;;;;;;;;;99847:638::o;100897:1760::-;101011:42;101056:23;;;:18;:23;;;;;;;;-1:-1:-1;;;;;101056:33:0;;;;;;;;;;101011:78;;;;;;;;;-1:-1:-1;;;;;101011:78:0;;;;-1:-1:-1;;;;;;;;101011:78:0;;;;;;;;;;;101104:39;;;101100:345;;;101394:32;;;;101356:77;;-1:-1:-1;;;101356:77:0;;-1:-1:-1;;;;;31492:32:1;;101356:77:0;;;31474:51:1;-1:-1:-1;;;;;31561:31:1;;;31541:18;;;31534:59;101428:4:0;31609:18:1;;;31602:45;31447:18;;101356:77:0;31265:388:1;101100:345:0;101455:21;101535:17;:32;;;101528:4;:39;-1:-1:-1;;;;;101512:55:0;;;101589:30;101622:69;101650:17;:25;;;-1:-1:-1;;;;;101622:69:0;101677:13;101622:27;:69::i;:::-;101840:25;;101589:102;;-1:-1:-1;;;;;;101840:50:0;;;;;101909:16;;101905:203;;101951:76;;;18831:25:1;;;18887:2;18872:18;;18865:34;;;102005:1:0;;-1:-1:-1;;;;;101951:76:0;;;101975:10;;101951:76;;18804:18:1;101951:76:0;;;;;;;102074:3;102064:8;-1:-1:-1;;;;;102051:41:0;;102079:12;102051:41;;;;616:25:1;;604:2;589:18;;470:177;102051:41:0;;;;;;;;101905:203;-1:-1:-1;102129:22:0;102154:31;102179:6;102154:22;:31;:::i;:::-;102129:56;-1:-1:-1;;;;;;102200:26:0;;102196:278;;;102442:8;102452:3;102457:4;102414:48;;-1:-1:-1;;;102414:48:0;;;;;;;;;;:::i;102196:278::-;-1:-1:-1;;;;;102484:51:0;;;;;-1:-1:-1;;;;;102546:39:0;;;:32;;;;:39;;;102484:25;102596:23;;;:18;:23;;;;;;-1:-1:-1;;;;;102596:33:0;;;;;;;;;;;;:53;;;;;;;-1:-1:-1;;;102596:53:0;;;;;;;;;;;;-1:-1:-1;;;100897:1760:0:o;118703:1000::-;-1:-1:-1;;;;;118917:14:0;;;:18;118913:783;;118956:71;;-1:-1:-1;;;118956:71:0;;-1:-1:-1;;;;;118956:38:0;;;;;:71;;118995:8;;119005:4;;119011:2;;119015:5;;119022:4;;118956:71;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;118956:71:0;;;;;;;;-1:-1:-1;;118956:71:0;;;;;;;;;;;;:::i;:::-;;;118952:733;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;119317:6;:13;119334:1;119317:18;119313:357;;119423:26;;-1:-1:-1;;;119423:26:0;;-1:-1:-1;;;;;3685:32:1;;119423:26:0;;;3667:51:1;3640:18;;119423:26:0;3521:203:1;119313:357:0;119620:6;119614:13;119605:6;119601:2;119597:15;119590:38;118952:733;-1:-1:-1;;;;;;119077:55:0;;-1:-1:-1;;;119077:55:0;119073:177;;119204:26;;-1:-1:-1;;;119204:26:0;;-1:-1:-1;;;;;3685:32:1;;119204:26:0;;;3667:51:1;3640:18;;119204:26:0;3521:203:1;119897:1050:0;-1:-1:-1;;;;;120136:14:0;;;:18;120132:808;;120175:78;;-1:-1:-1;;;120175:78:0;;-1:-1:-1;;;;;120175:43:0;;;;;:78;;120219:8;;120229:4;;120235:3;;120240:6;;120248:4;;120175:78;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;120175:78:0;;;;;;;;-1:-1:-1;;120175:78:0;;;;;;;;;;;;:::i;:::-;;;120171:758;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;120316:60:0;;-1:-1:-1;;;120316:60:0;120312:182;;120448:26;;-1:-1:-1;;;120448:26:0;;-1:-1:-1;;;;;3685:32:1;;120448:26:0;;;3667:51:1;3640:18;;120448:26:0;3521:203:1;14:131;-1:-1:-1;;;;;89:31:1;;79:42;;69:70;;135:1;132;125:12;150:315;218:6;226;279:2;267:9;258:7;254:23;250:32;247:52;;;295:1;292;285:12;247:52;334:9;321:23;353:31;378:5;353:31;:::i;:::-;403:5;455:2;440:18;;;;427:32;;-1:-1:-1;;;150:315:1:o;652:131::-;-1:-1:-1;;;;;;726:32:1;;716:43;;706:71;;773:1;770;763:12;788:245;846:6;899:2;887:9;878:7;874:23;870:32;867:52;;;915:1;912;905:12;867:52;954:9;941:23;973:30;997:5;973:30;:::i;1230:348::-;1282:8;1292:6;1346:3;1339:4;1331:6;1327:17;1323:27;1313:55;;1364:1;1361;1354:12;1313:55;-1:-1:-1;1387:20:1;;-1:-1:-1;;;;;1419:30:1;;1416:50;;;1462:1;1459;1452:12;1416:50;1499:4;1491:6;1487:17;1475:29;;1551:3;1544:4;1535:6;1527;1523:19;1519:30;1516:39;1513:59;;;1568:1;1565;1558:12;1583:925;1693:6;1701;1709;1717;1725;1733;1786:3;1774:9;1765:7;1761:23;1757:33;1754:53;;;1803:1;1800;1793:12;1754:53;1842:9;1829:23;1861:31;1886:5;1861:31;:::i;:::-;1911:5;-1:-1:-1;1967:2:1;1952:18;;1939:32;-1:-1:-1;;;;;2020:14:1;;;2017:34;;;2047:1;2044;2037:12;2017:34;2086:59;2137:7;2128:6;2117:9;2113:22;2086:59;:::i;:::-;2164:8;;-1:-1:-1;2060:85:1;-1:-1:-1;2252:2:1;2237:18;;2224:32;;-1:-1:-1;2268:16:1;;;2265:36;;;2297:1;2294;2287:12;2265:36;;2336:61;2389:7;2378:8;2367:9;2363:24;2336:61;:::i;:::-;1583:925;;;;-1:-1:-1;1583:925:1;;;;;2498:2;2483:18;;;2470:32;;1583:925;-1:-1:-1;;;;1583:925:1:o;2513:250::-;2598:1;2608:113;2622:6;2619:1;2616:13;2608:113;;;2698:11;;;2692:18;2679:11;;;2672:39;2644:2;2637:10;2608:113;;;-1:-1:-1;;2755:1:1;2737:16;;2730:27;2513:250::o;2768:271::-;2810:3;2848:5;2842:12;2875:6;2870:3;2863:19;2891:76;2960:6;2953:4;2948:3;2944:14;2937:4;2930:5;2926:16;2891:76;:::i;:::-;3021:2;3000:15;-1:-1:-1;;2996:29:1;2987:39;;;;3028:4;2983:50;;2768:271;-1:-1:-1;;2768:271:1:o;3044:220::-;3193:2;3182:9;3175:21;3156:4;3213:45;3254:2;3243:9;3239:18;3231:6;3213:45;:::i;3269:247::-;3328:6;3381:2;3369:9;3360:7;3356:23;3352:32;3349:52;;;3397:1;3394;3387:12;3349:52;3436:9;3423:23;3455:31;3480:5;3455:31;:::i;3729:367::-;3792:8;3802:6;3856:3;3849:4;3841:6;3837:17;3833:27;3823:55;;3874:1;3871;3864:12;3823:55;-1:-1:-1;3897:20:1;;-1:-1:-1;;;;;3929:30:1;;3926:50;;;3972:1;3969;3962:12;3926:50;4009:4;4001:6;3997:17;3985:29;;4069:3;4062:4;4052:6;4049:1;4045:14;4037:6;4033:27;4029:38;4026:47;4023:67;;;4086:1;4083;4076:12;4101:1588;4333:6;4341;4349;4357;4365;4373;4381;4389;4442:3;4430:9;4421:7;4417:23;4413:33;4410:53;;;4459:1;4456;4449:12;4410:53;4499:9;4486:23;-1:-1:-1;;;;;4569:2:1;4561:6;4558:14;4555:34;;;4585:1;4582;4575:12;4555:34;4624:70;4686:7;4677:6;4666:9;4662:22;4624:70;:::i;:::-;4713:8;;-1:-1:-1;4598:96:1;-1:-1:-1;4801:2:1;4786:18;;4773:32;;-1:-1:-1;4817:16:1;;;4814:36;;;4846:1;4843;4836:12;4814:36;4884:8;4873:9;4869:24;4859:34;;4931:7;4924:4;4920:2;4916:13;4912:27;4902:55;;4953:1;4950;4943:12;4902:55;4993:2;4980:16;5019:2;5011:6;5008:14;5005:34;;;5035:1;5032;5025:12;5005:34;5088:7;5083:2;5073:6;5070:1;5066:14;5062:2;5058:23;5054:32;5051:45;5048:65;;;5109:1;5106;5099:12;5048:65;5140:2;5136;5132:11;5122:21;;5162:6;5152:16;;;5221:2;5210:9;5206:18;5193:32;5177:48;;5250:2;5240:8;5237:16;5234:36;;;5266:1;5263;5256:12;5234:36;5305:72;5369:7;5358:8;5347:9;5343:24;5305:72;:::i;:::-;5396:8;;-1:-1:-1;5279:98:1;-1:-1:-1;5484:2:1;5469:18;;5456:32;;-1:-1:-1;5500:16:1;;;5497:36;;;5529:1;5526;5519:12;5497:36;;5568:61;5621:7;5610:8;5599:9;5595:24;5568:61;:::i;:::-;4101:1588;;;;-1:-1:-1;4101:1588:1;;-1:-1:-1;4101:1588:1;;;;;;5648:8;-1:-1:-1;;;4101:1588:1:o;5694:180::-;5753:6;5806:2;5794:9;5785:7;5781:23;5777:32;5774:52;;;5822:1;5819;5812:12;5774:52;-1:-1:-1;5845:23:1;;5694:180;-1:-1:-1;5694:180:1:o;5879:171::-;5946:20;;-1:-1:-1;;;;;5995:30:1;;5985:41;;5975:69;;6040:1;6037;6030:12;5975:69;5879:171;;;:::o;6055:252::-;6122:6;6130;6183:2;6171:9;6162:7;6158:23;6154:32;6151:52;;;6199:1;6196;6189:12;6151:52;6235:9;6222:23;6212:33;;6264:37;6297:2;6286:9;6282:18;6264:37;:::i;:::-;6254:47;;6055:252;;;;;:::o;6312:127::-;6373:10;6368:3;6364:20;6361:1;6354:31;6404:4;6401:1;6394:15;6428:4;6425:1;6418:15;6444:275;6515:2;6509:9;6580:2;6561:13;;-1:-1:-1;;6557:27:1;6545:40;;-1:-1:-1;;;;;6600:34:1;;6636:22;;;6597:62;6594:88;;;6662:18;;:::i;:::-;6698:2;6691:22;6444:275;;-1:-1:-1;6444:275:1:o;6724:183::-;6784:4;-1:-1:-1;;;;;6809:6:1;6806:30;6803:56;;;6839:18;;:::i;:::-;-1:-1:-1;6884:1:1;6880:14;6896:4;6876:25;;6724:183::o;6912:668::-;6966:5;7019:3;7012:4;7004:6;7000:17;6996:27;6986:55;;7037:1;7034;7027:12;6986:55;7073:6;7060:20;7099:4;7123:60;7139:43;7179:2;7139:43;:::i;:::-;7123:60;:::i;:::-;7205:3;7229:2;7224:3;7217:15;7257:4;7252:3;7248:14;7241:21;;7314:4;7308:2;7305:1;7301:10;7293:6;7289:23;7285:34;7271:48;;7342:3;7334:6;7331:15;7328:35;;;7359:1;7356;7349:12;7328:35;7395:4;7387:6;7383:17;7409:142;7425:6;7420:3;7417:15;7409:142;;;7491:17;;7479:30;;7529:12;;;;7442;;7409:142;;;-1:-1:-1;7569:5:1;6912:668;-1:-1:-1;;;;;;6912:668:1:o;7585:186::-;7633:4;-1:-1:-1;;;;;7658:6:1;7655:30;7652:56;;;7688:18;;:::i;:::-;-1:-1:-1;7754:2:1;7733:15;-1:-1:-1;;7729:29:1;7760:4;7725:40;;7585:186::o;7776:462::-;7818:5;7871:3;7864:4;7856:6;7852:17;7848:27;7838:55;;7889:1;7886;7879:12;7838:55;7925:6;7912:20;7956:48;7972:31;8000:2;7972:31;:::i;7956:48::-;8029:2;8020:7;8013:19;8075:3;8068:4;8063:2;8055:6;8051:15;8047:26;8044:35;8041:55;;;8092:1;8089;8082:12;8041:55;8157:2;8150:4;8142:6;8138:17;8131:4;8122:7;8118:18;8105:55;8205:1;8180:16;;;8198:4;8176:27;8169:38;;;;8184:7;7776:462;-1:-1:-1;;;7776:462:1:o;8243:1071::-;8397:6;8405;8413;8421;8429;8482:3;8470:9;8461:7;8457:23;8453:33;8450:53;;;8499:1;8496;8489:12;8450:53;8538:9;8525:23;8557:31;8582:5;8557:31;:::i;:::-;8607:5;-1:-1:-1;8664:2:1;8649:18;;8636:32;8677:33;8636:32;8677:33;:::i;:::-;8729:7;-1:-1:-1;8787:2:1;8772:18;;8759:32;-1:-1:-1;;;;;8840:14:1;;;8837:34;;;8867:1;8864;8857:12;8837:34;8890:61;8943:7;8934:6;8923:9;8919:22;8890:61;:::i;:::-;8880:71;;9004:2;8993:9;8989:18;8976:32;8960:48;;9033:2;9023:8;9020:16;9017:36;;;9049:1;9046;9039:12;9017:36;9072:63;9127:7;9116:8;9105:9;9101:24;9072:63;:::i;:::-;9062:73;;9188:3;9177:9;9173:19;9160:33;9144:49;;9218:2;9208:8;9205:16;9202:36;;;9234:1;9231;9224:12;9202:36;;9257:51;9300:7;9289:8;9278:9;9274:24;9257:51;:::i;:::-;9247:61;;;8243:1071;;;;;;;;:::o;9319:1215::-;9437:6;9445;9498:2;9486:9;9477:7;9473:23;9469:32;9466:52;;;9514:1;9511;9504:12;9466:52;9554:9;9541:23;-1:-1:-1;;;;;9624:2:1;9616:6;9613:14;9610:34;;;9640:1;9637;9630:12;9610:34;9678:6;9667:9;9663:22;9653:32;;9723:7;9716:4;9712:2;9708:13;9704:27;9694:55;;9745:1;9742;9735:12;9694:55;9781:2;9768:16;9803:4;9827:60;9843:43;9883:2;9843:43;:::i;9827:60::-;9921:15;;;10003:1;9999:10;;;;9991:19;;9987:28;;;9952:12;;;;10027:19;;;10024:39;;;10059:1;10056;10049:12;10024:39;10083:11;;;;10103:217;10119:6;10114:3;10111:15;10103:217;;;10199:3;10186:17;10216:31;10241:5;10216:31;:::i;:::-;10260:18;;10136:12;;;;10298;;;;10103:217;;;10339:5;-1:-1:-1;;10382:18:1;;10369:32;;-1:-1:-1;;10413:16:1;;;10410:36;;;10442:1;10439;10432:12;10410:36;;10465:63;10520:7;10509:8;10498:9;10494:24;10465:63;:::i;:::-;10455:73;;;9319:1215;;;;;:::o;10539:439::-;10592:3;10630:5;10624:12;10657:6;10652:3;10645:19;10683:4;10712;10707:3;10703:14;10696:21;;10751:4;10744:5;10740:16;10774:1;10784:169;10798:6;10795:1;10792:13;10784:169;;;10859:13;;10847:26;;10893:12;;;;10928:15;;;;10820:1;10813:9;10784:169;;;-1:-1:-1;10969:3:1;;10539:439;-1:-1:-1;;;;;10539:439:1:o;10983:261::-;11162:2;11151:9;11144:21;11125:4;11182:56;11234:2;11223:9;11219:18;11211:6;11182:56;:::i;11249:529::-;11326:6;11334;11342;11395:2;11383:9;11374:7;11370:23;11366:32;11363:52;;;11411:1;11408;11401:12;11363:52;11450:9;11437:23;11469:31;11494:5;11469:31;:::i;:::-;11519:5;-1:-1:-1;11576:2:1;11561:18;;11548:32;11589:33;11548:32;11589:33;:::i;:::-;11641:7;-1:-1:-1;11700:2:1;11685:18;;11672:32;11713:33;11672:32;11713:33;:::i;:::-;11765:7;11755:17;;;11249:529;;;;;:::o;11783:388::-;11851:6;11859;11912:2;11900:9;11891:7;11887:23;11883:32;11880:52;;;11928:1;11925;11918:12;11880:52;11967:9;11954:23;11986:31;12011:5;11986:31;:::i;:::-;12036:5;-1:-1:-1;12093:2:1;12078:18;;12065:32;12106:33;12065:32;12106:33;:::i;:::-;12158:7;12148:17;;;11783:388;;;;;:::o;12176:1197::-;12327:6;12335;12343;12351;12359;12367;12375;12428:3;12416:9;12407:7;12403:23;12399:33;12396:53;;;12445:1;12442;12435:12;12396:53;12484:9;12471:23;12503:31;12528:5;12503:31;:::i;:::-;12553:5;-1:-1:-1;12609:2:1;12594:18;;12581:32;-1:-1:-1;;;;;12662:14:1;;;12659:34;;;12689:1;12686;12679:12;12659:34;12728:70;12790:7;12781:6;12770:9;12766:22;12728:70;:::i;:::-;12817:8;;-1:-1:-1;12702:96:1;-1:-1:-1;12905:2:1;12890:18;;12877:32;;-1:-1:-1;12921:16:1;;;12918:36;;;12950:1;12947;12940:12;12918:36;12989:72;13053:7;13042:8;13031:9;13027:24;12989:72;:::i;:::-;13080:8;;-1:-1:-1;12963:98:1;-1:-1:-1;13168:2:1;13153:18;;13140:32;;-1:-1:-1;13184:16:1;;;13181:36;;;13213:1;13210;13203:12;13181:36;;13252:61;13305:7;13294:8;13283:9;13279:24;13252:61;:::i;:::-;12176:1197;;;;-1:-1:-1;12176:1197:1;;-1:-1:-1;12176:1197:1;;;;13226:87;;-1:-1:-1;;;12176:1197:1:o;13378:435::-;13445:6;13453;13506:2;13494:9;13485:7;13481:23;13477:32;13474:52;;;13522:1;13519;13512:12;13474:52;13561:9;13548:23;13580:31;13605:5;13580:31;:::i;:::-;13630:5;-1:-1:-1;13687:2:1;13672:18;;13659:32;-1:-1:-1;;;;;13722:40:1;;13710:53;;13700:81;;13777:1;13774;13767:12;14128:546;14216:6;14224;14232;14240;14293:2;14281:9;14272:7;14268:23;14264:32;14261:52;;;14309:1;14306;14299:12;14261:52;14345:9;14332:23;14322:33;;14402:2;14391:9;14387:18;14374:32;14364:42;;14457:2;14446:9;14442:18;14429:32;-1:-1:-1;;;;;14476:6:1;14473:30;14470:50;;;14516:1;14513;14506:12;14470:50;14555:59;14606:7;14597:6;14586:9;14582:22;14555:59;:::i;:::-;14128:546;;;;-1:-1:-1;14633:8:1;-1:-1:-1;;;;14128:546:1:o;14884:1067::-;15003:6;15011;15019;15027;15035;15043;15051;15104:3;15092:9;15083:7;15079:23;15075:33;15072:53;;;15121:1;15118;15111:12;15072:53;15160:9;15147:23;15179:31;15204:5;15179:31;:::i;:::-;15229:5;-1:-1:-1;15286:2:1;15271:18;;15258:32;15299:33;15258:32;15299:33;:::i;:::-;15351:7;-1:-1:-1;15409:2:1;15394:18;;15381:32;-1:-1:-1;;;;;15462:14:1;;;15459:34;;;15489:1;15486;15479:12;15459:34;15528:59;15579:7;15570:6;15559:9;15555:22;15528:59;:::i;:::-;15606:8;;-1:-1:-1;15502:85:1;-1:-1:-1;15694:2:1;15679:18;;15666:32;;-1:-1:-1;15710:16:1;;;15707:36;;;15739:1;15736;15729:12;15707:36;;15778:61;15831:7;15820:8;15809:9;15805:24;15778:61;:::i;:::-;14884:1067;;;;-1:-1:-1;14884:1067:1;;;;;;15940:3;15925:19;;;15912:33;;14884:1067;-1:-1:-1;;;;14884:1067:1:o;16280:118::-;16366:5;16359:13;16352:21;16345:5;16342:32;16332:60;;16388:1;16385;16378:12;16403:382;16468:6;16476;16529:2;16517:9;16508:7;16504:23;16500:32;16497:52;;;16545:1;16542;16535:12;16497:52;16584:9;16571:23;16603:31;16628:5;16603:31;:::i;:::-;16653:5;-1:-1:-1;16710:2:1;16695:18;;16682:32;16723:30;16682:32;16723:30;:::i;16790:481::-;16883:6;16891;16899;16952:2;16940:9;16931:7;16927:23;16923:32;16920:52;;;16968:1;16965;16958:12;16920:52;17007:9;16994:23;17026:31;17051:5;17026:31;:::i;:::-;17076:5;-1:-1:-1;17128:2:1;17113:18;;17100:32;;-1:-1:-1;17184:2:1;17169:18;;17156:32;17219:1;17207:14;;17197:42;;17235:1;17232;17225:12;17461:479;17541:6;17549;17557;17610:2;17598:9;17589:7;17585:23;17581:32;17578:52;;;17626:1;17623;17616:12;17578:52;17666:9;17653:23;-1:-1:-1;;;;;17691:6:1;17688:30;17685:50;;;17731:1;17728;17721:12;17685:50;17770:59;17821:7;17812:6;17801:9;17797:22;17770:59;:::i;:::-;17848:8;;17744:85;;-1:-1:-1;17930:2:1;17915:18;;;;17902:32;;17461:479;-1:-1:-1;;;;17461:479:1:o;18265:387::-;18341:6;18349;18357;18410:2;18398:9;18389:7;18385:23;18381:32;18378:52;;;18426:1;18423;18416:12;18378:52;18465:9;18452:23;18484:31;18509:5;18484:31;:::i;:::-;18534:5;-1:-1:-1;18586:2:1;18571:18;;18558:32;;-1:-1:-1;18609:37:1;18642:2;18627:18;;18609:37;:::i;:::-;18599:47;;18265:387;;;;;:::o;18910:734::-;19014:6;19022;19030;19038;19046;19099:3;19087:9;19078:7;19074:23;19070:33;19067:53;;;19116:1;19113;19106:12;19067:53;19155:9;19142:23;19174:31;19199:5;19174:31;:::i;:::-;19224:5;-1:-1:-1;19281:2:1;19266:18;;19253:32;19294:33;19253:32;19294:33;:::i;:::-;19346:7;-1:-1:-1;19400:2:1;19385:18;;19372:32;;-1:-1:-1;19451:2:1;19436:18;;19423:32;;-1:-1:-1;19506:3:1;19491:19;;19478:33;-1:-1:-1;;;;;19523:30:1;;19520:50;;;19566:1;19563;19556:12;19520:50;19589:49;19630:7;19621:6;19610:9;19606:22;19589:49;:::i;19649:908::-;19780:6;19788;19796;19804;19812;19865:2;19853:9;19844:7;19840:23;19836:32;19833:52;;;19881:1;19878;19871:12;19833:52;19920:9;19907:23;19939:31;19964:5;19939:31;:::i;:::-;19989:5;-1:-1:-1;20045:2:1;20030:18;;20017:32;-1:-1:-1;;;;;20098:14:1;;;20095:34;;;20125:1;20122;20115:12;20095:34;20164:70;20226:7;20217:6;20206:9;20202:22;20164:70;:::i;:::-;20253:8;;-1:-1:-1;20138:96:1;-1:-1:-1;20341:2:1;20326:18;;20313:32;;-1:-1:-1;20357:16:1;;;20354:36;;;20386:1;20383;20376:12;20354:36;;20425:72;20489:7;20478:8;20467:9;20463:24;20425:72;:::i;:::-;19649:908;;;;-1:-1:-1;19649:908:1;;-1:-1:-1;20516:8:1;;20399:98;19649:908;-1:-1:-1;;;19649:908:1:o;20744:267::-;20833:6;20828:3;20821:19;20885:6;20878:5;20871:4;20866:3;20862:14;20849:43;-1:-1:-1;20937:1:1;20912:16;;;20930:4;20908:27;;;20901:38;;;;20993:2;20972:15;;;-1:-1:-1;;20968:29:1;20959:39;;;20955:50;;20744:267::o;21016:344::-;-1:-1:-1;;;;;21203:32:1;;21185:51;;21272:2;21267;21252:18;;21245:30;;;-1:-1:-1;;21292:62:1;;21335:18;;21327:6;21319;21292:62;:::i;:::-;21284:70;21016:344;-1:-1:-1;;;;;21016:344:1:o;21644:437::-;21861:2;21850:9;21843:21;21824:4;21887:62;21945:2;21934:9;21930:18;21922:6;21914;21887:62;:::i;:::-;21997:9;21989:6;21985:22;21980:2;21969:9;21965:18;21958:50;22025;22068:6;22060;22052;22025:50;:::i;:::-;22017:58;21644:437;-1:-1:-1;;;;;;;21644:437:1:o;22086:648::-;22166:6;22219:2;22207:9;22198:7;22194:23;22190:32;22187:52;;;22235:1;22232;22225:12;22187:52;22268:9;22262:16;-1:-1:-1;;;;;22293:6:1;22290:30;22287:50;;;22333:1;22330;22323:12;22287:50;22356:22;;22409:4;22401:13;;22397:27;-1:-1:-1;22387:55:1;;22438:1;22435;22428:12;22387:55;22467:2;22461:9;22492:48;22508:31;22536:2;22508:31;:::i;22492:48::-;22563:2;22556:5;22549:17;22603:7;22598:2;22593;22589;22585:11;22581:20;22578:33;22575:53;;;22624:1;22621;22614:12;22575:53;22637:67;22701:2;22696;22689:5;22685:14;22680:2;22676;22672:11;22637:67;:::i;22739:291::-;-1:-1:-1;;;;;22937:32:1;;;;22919:51;;23018:4;23006:17;23001:2;22986:18;;22979:45;22907:2;22892:18;;22739:291::o;23035:127::-;23096:10;23091:3;23087:20;23084:1;23077:31;23127:4;23124:1;23117:15;23151:4;23148:1;23141:15;23167:323;23259:4;23317:11;23304:25;23411:2;23407:7;23396:8;23380:14;23376:29;23372:43;23352:18;23348:68;23338:96;;23430:1;23427;23420:12;23338:96;23451:33;;;;;23167:323;-1:-1:-1;;23167:323:1:o;23495:272::-;23553:6;23606:2;23594:9;23585:7;23581:23;23577:32;23574:52;;;23622:1;23619;23612:12;23574:52;23661:9;23648:23;23711:6;23704:5;23700:18;23693:5;23690:29;23680:57;;23733:1;23730;23723:12;23772:362;-1:-1:-1;;;;;23998:32:1;;;;23980:51;;24062:2;24047:18;;24040:34;;;;24122:4;24110:17;24105:2;24090:18;;24083:45;23968:2;23953:18;;23772:362::o;24435:380::-;24514:1;24510:12;;;;24557;;;24578:61;;24632:4;24624:6;24620:17;24610:27;;24578:61;24685:2;24677:6;24674:14;24654:18;24651:38;24648:161;;24731:10;24726:3;24722:20;24719:1;24712:31;24766:4;24763:1;24756:15;24794:4;24791:1;24784:15;24648:161;;24435:380;;;:::o;25723:516::-;-1:-1:-1;;;;;26002:15:1;;;25984:34;;26054:15;;26049:2;26034:18;;26027:43;26101:2;26086:18;;26079:34;;;26149:3;26144:2;26129:18;;26122:31;;;25927:4;;26170:63;;26213:19;;26205:6;26197;26170:63;:::i;26244:245::-;26311:6;26364:2;26352:9;26343:7;26339:23;26335:32;26332:52;;;26380:1;26377;26370:12;26332:52;26412:9;26406:16;26431:28;26453:5;26431:28;:::i;26862:127::-;26923:10;26918:3;26914:20;26911:1;26904:31;26954:4;26951:1;26944:15;26978:4;26975:1;26968:15;26994:128;27061:9;;;27082:11;;;27079:37;;;27096:18;;:::i;27127:127::-;27188:10;27183:3;27179:20;27176:1;27169:31;27219:4;27216:1;27209:15;27243:4;27240:1;27233:15;27259:120;27299:1;27325;27315:35;;27330:18;;:::i;:::-;-1:-1:-1;27364:9:1;;27259:120::o;27681:441::-;-1:-1:-1;;;;;27887:32:1;;27869:51;;27857:2;27842:18;;27950:1;27939:13;;27929:144;;27995:10;27990:3;27986:20;27983:1;27976:31;28030:4;28027:1;28020:15;28058:4;28055:1;28048:15;27929:144;28109:6;28104:2;28093:9;28089:18;28082:34;27681:441;;;;;:::o;28127:251::-;28197:6;28250:2;28238:9;28229:7;28225:23;28221:32;28218:52;;;28266:1;28263;28256:12;28218:52;28298:9;28292:16;28317:31;28342:5;28317:31;:::i;28383:183::-;-1:-1:-1;;;;;28502:10:1;;;28490;;;28486:27;;28525:12;;;28522:38;;;28540:18;;:::i;:::-;28522:38;28383:183;;;;:::o;28868:247::-;29027:2;29016:9;29009:21;28990:4;29047:62;29105:2;29094:9;29090:18;29082:6;29074;29047:62;:::i;29715:416::-;29804:1;29841:5;29804:1;29855:270;29876:7;29866:8;29863:21;29855:270;;;29935:4;29931:1;29927:6;29923:17;29917:4;29914:27;29911:53;;;29944:18;;:::i;:::-;29994:7;29984:8;29980:22;29977:55;;;30014:16;;;;29977:55;30093:22;;;;30053:15;;;;29855:270;;;29859:3;29715:416;;;;;:::o;30136:806::-;30185:5;30215:8;30205:80;;-1:-1:-1;30256:1:1;30270:5;;30205:80;30304:4;30294:76;;-1:-1:-1;30341:1:1;30355:5;;30294:76;30386:4;30404:1;30399:59;;;;30472:1;30467:130;;;;30379:218;;30399:59;30429:1;30420:10;;30443:5;;;30467:130;30504:3;30494:8;30491:17;30488:43;;;30511:18;;:::i;:::-;-1:-1:-1;;30567:1:1;30553:16;;30582:5;;30379:218;;30681:2;30671:8;30668:16;30662:3;30656:4;30653:13;30649:36;30643:2;30633:8;30630:16;30625:2;30619:4;30616:12;30612:35;30609:77;30606:159;;;-1:-1:-1;30718:19:1;;;30750:5;;30606:159;30797:34;30822:8;30816:4;30797:34;:::i;:::-;30867:6;30863:1;30859:6;30855:19;30846:7;30843:32;30840:58;;;30878:18;;:::i;:::-;30916:20;;30136:806;-1:-1:-1;;;30136:806:1:o;30947:140::-;31005:5;31034:47;31075:4;31065:8;31061:19;31055:4;31034:47;:::i;31092:168::-;31165:9;;;31196;;31213:15;;;31207:22;;31193:37;31183:71;;31234:18;;:::i;33148:125::-;33213:9;;;33234:10;;;33231:36;;;33247:18;;:::i;33278:135::-;33317:3;33338:17;;;33335:43;;33358:18;;:::i;:::-;-1:-1:-1;33405:1:1;33394:13;;33278:135::o;34413:168::-;34480:6;34506:10;;;34518;;;34502:27;;34541:11;;;34538:37;;;34555:18;;:::i;34586:286::-;34645:6;34698:2;34686:9;34677:7;34673:23;34669:32;34666:52;;;34714:1;34711;34704:12;34666:52;34740:23;;-1:-1:-1;;;;;34792:31:1;;34782:42;;34772:70;;34838:1;34835;34828:12;35245:200;35311:9;;;35284:4;35339:9;;35367:10;;35379:12;;;35363:29;35402:12;;;35394:21;;35360:56;35357:82;;;35419:18;;:::i;35450:216::-;35514:9;;;35542:11;;;35489:3;35572:9;;35600:10;;35596:19;;35625:10;;35617:19;;35593:44;35590:70;;;35640:18;;:::i;:::-;35590:70;;35450:216;;;;:::o;35671:171::-;35739:6;35778:10;;;35766;;;35762:27;;35801:12;;;35798:38;;;35816:18;;:::i;35847:544::-;35939:4;35945:6;36005:11;35992:25;36099:2;36095:7;36084:8;36068:14;36064:29;36060:43;36040:18;36036:68;36026:96;;36118:1;36115;36108:12;36026:96;36145:33;;36197:20;;;-1:-1:-1;;;;;;36229:30:1;;36226:50;;;36272:1;36269;36262:12;36226:50;36305:4;36293:17;;-1:-1:-1;36356:1:1;36352:14;;;36336;36332:35;36322:46;;36319:66;;;36381:1;36378;36371:12;36749:197;36787:3;36815:6;36856:2;36849:5;36845:14;36883:2;36874:7;36871:15;36868:41;;36889:18;;:::i;:::-;36938:1;36925:15;;36749:197;-1:-1:-1;;;36749:197:1:o;37497:245::-;37568:6;37606:10;;;37618;;;37602:27;37649:20;;;;37568:6;37688:24;;;37678:58;;37716:18;;:::i;37747:521::-;37824:4;37830:6;37890:11;37877:25;37984:2;37980:7;37969:8;37953:14;37949:29;37945:43;37925:18;37921:68;37911:96;;38003:1;38000;37993:12;37911:96;38030:33;;38082:20;;;-1:-1:-1;;;;;;38114:30:1;;38111:50;;;38157:1;38154;38147:12;38111:50;38190:4;38178:17;;-1:-1:-1;38221:14:1;38217:27;;;38207:38;;38204:58;;;38258:1;38255;38248:12;38273:465;38530:2;38519:9;38512:21;38493:4;38556:56;38608:2;38597:9;38593:18;38585:6;38556:56;:::i;:::-;38660:9;38652:6;38648:22;38643:2;38632:9;38628:18;38621:50;38688:44;38725:6;38717;38688:44;:::i;40130:827::-;-1:-1:-1;;;;;40527:15:1;;;40509:34;;40579:15;;40574:2;40559:18;;40552:43;40489:3;40626:2;40611:18;;40604:31;;;40452:4;;40658:57;;40695:19;;40687:6;40658:57;:::i;:::-;40763:9;40755:6;40751:22;40746:2;40735:9;40731:18;40724:50;40797:44;40834:6;40826;40797:44;:::i;:::-;40783:58;;40890:9;40882:6;40878:22;40872:3;40861:9;40857:19;40850:51;40918:33;40944:6;40936;40918:33;:::i;:::-;40910:41;40130:827;-1:-1:-1;;;;;;;;40130:827:1:o;41615:593::-;41796:2;41785:9;41778:21;41841:6;41835:13;41830:2;41819:9;41815:18;41808:41;41759:4;41896:2;41888:6;41884:15;41878:22;41936:4;41931:2;41920:9;41916:18;41909:32;41964:52;42011:3;42000:9;41996:19;41982:12;41964:52;:::i;:::-;41950:66;;42065:2;42057:6;42053:15;42047:22;42139:2;42135:7;42123:9;42115:6;42111:22;42107:36;42100:4;42089:9;42085:20;42078:66;42161:41;42195:6;42179:14;42161:41;:::i;43186:207::-;43225:1;-1:-1:-1;;;;;43304:2:1;43301:1;43297:10;43326:3;43316:37;;43333:18;;:::i;:::-;43371:10;;43367:20;;;;;43186:207;-1:-1:-1;;43186:207:1:o;43398:112::-;43430:1;43456;43446:35;;43461:18;;:::i;:::-;-1:-1:-1;43495:9:1;;43398:112::o;44900:184::-;44970:6;45023:2;45011:9;45002:7;44998:23;44994:32;44991:52;;;45039:1;45036;45029:12;44991:52;-1:-1:-1;45062:16:1;;44900:184;-1:-1:-1;44900:184:1:o;46622:561::-;-1:-1:-1;;;;;46919:15:1;;;46901:34;;46971:15;;46966:2;46951:18;;46944:43;47018:2;47003:18;;46996:34;;;47061:2;47046:18;;47039:34;;;46881:3;47104;47089:19;;47082:32;;;46844:4;;47131:46;;47157:19;;47149:6;47131:46;:::i;47188:249::-;47257:6;47310:2;47298:9;47289:7;47285:23;47281:32;47278:52;;;47326:1;47323;47316:12;47278:52;47358:9;47352:16;47377:30;47401:5;47377:30;:::i

Swarm Source

ipfs://1a21a84b8e06838b9338ef71688f78e2c726b159dc94efb25f6fb50045d73374

Block Transaction Gas Used Reward
view all blocks validated

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

Validator Index Block Amount
View All Withdrawals

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

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