false
false
0

Contract Address Details

0x951D1F73f30716fE0d3E9f9998486fd1F48b68A1

Contract Name
TwoBearsOrders
Creator
0xebe894–7a24f6 at 0x5135ad–ad32f7
Balance
0 CLO
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
16288471
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
TwoBearsOrders




Optimization enabled
false
Compiler version
v0.8.16+commit.07a7930e




EVM Version
default




Verified at
2024-09-26T15:35:22.515028Z

Contract source code

// All rights reserved.
// SPDX-License-Identifier: No License (None)

pragma solidity ^0.8.16;

interface IContractDeposits {
    function withdraw(address _token, address _owner, uint _value) external;
    function withdrawFee(address _token, uint _value) external;
}

contract TwoBearsOrders {

    struct Orders {
        uint256 time; // время обновляется при изменении статуса ордер
        uint256 commission; // комиссия биржи за исполнение данного ордера, выплачивается в момент исполнения ордера получаемым токеном
        uint256 value_in; // количество которое отдает владелец ордера (остаток обмена) (когда это значение дойдет до 0, ордер будет закрыт)
        uint256 price; // цена исполнения ордера
        uint256 value_out; // количество которое должен получить владелец ордера (остаток к получению) (когда это значение дойдет до 0, ордер будет закрыт)
        uint256 exec_in; // количество уже обменено
        uint256 exec_out; // количество уже получено
        address token_in; // адрес токена который отдает владелец ордера
        address token_out; // адрес токена который получает владелец ордера
        address owner; // адрес владельца ордера
        uint8 order_type; // тип ордера. 1 - продажа, 2 - покупка
        uint8 order_status; // стутус ордера. 1 - ордер создан. 4 - ордер отменен. 6 - ордер частично выполнен. 7 - ордер закрыт (полное выполнение). 8 - помечен пользователем для удаления из системы. 9 - ордер закрыт (полное выполнение), закрыт по причине достижения лимита исполняемых ордеров, остаток меняемого токена владельцу разблокирован.
    }

    struct OwnerListID{
        uint256 next; // указатель на следующий id ордера
        uint256 prev; // указатель на предыдущий id ордера
    }

    struct OrderBook{
        uint256 price; // цена ордера
        uint256 next; // указатель на следующий id ордера
        uint256 prev; // указатель на предыдущий id ордера
    }

    struct Variables { // структура переменных для исполнения ордера (обходим ошибку глубину стека)
        uint _hash_pair;
        uint _opposite_id;
        uint _opposite_price;
        uint _opposite_value_out;
        uint _val_in_diff;
        uint _temp;
        uint _commission;
        uint _value_add;
        uint _fee_in;
        uint _fee_out;
        address _recipient;
    }

    uint256 public id; // уникальный идентификатор ордера

    mapping(uint256 => mapping(uint256 => OrderBook)) private order_book; // упорядоченный список ордеров по ценам (первый параметр это хэш двух токенов без сортировки)
    mapping(address => mapping(uint256 => OwnerListID)) private all_open_order; // список всех открытых ордеров владельца
    mapping(uint256 => mapping(uint256 => OwnerListID)) private open_order; // открытые ордера трейдера по парам
    mapping(uint256 => mapping(uint256 => OwnerListID)) private close_order; // закрытые ордера трейдера по парам
    mapping(uint256 => uint256[51]) private exec_order_book; // выполненые/частично выполненые ордера на бирже. Цикличный буфер через массив, 0 - элемент указывает на текущую позицию. (первый параметр это хэш двух токенов с сортировкой)
    mapping(uint256 => Orders) private orders; // все ордера на бирже

    address public owner = 0xeBE894814554c8382EA6a24CcDdf1527407A24f6; // Владелец
    address public constant contractDeposits = 0x5cec09F125f4839656164A5109BC076DAAbD6Ed6; // Контракт с депозитами
    
    event CreateOrder(uint indexed ID);
    event CancelOrder(uint indexed ID);
    event DeleteOrder(uint indexed ID);
    event ExecutableOrder(uint indexed ID);

    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can call this.");
        _;
    }



    // ФУНКЦИИ ХЭШИРОВАНИЯ АДРЕСОВ
    function hash2Address(address _a1, address _a2, bool _sort) private pure returns (uint256) // Возвращаем хэш по 2-м адресам, при неодходимости первоначально сортируем их
    {
        if(_sort){
            (_a1, _a2) = _a1 < _a2 ? (_a1, _a2) : (_a2, _a1); // сортируем токены
        }
        return (uint256(keccak256(abi.encodePacked(_a1, _a2))));
    }

    function hash3Address(address _a1, address _a2, address _a3) private pure returns (uint256) // Возвращаем хэш по 3-м адресам
    {
        uint256 _hash = hash2Address(_a1, _a2, true); // получаем хэш первых 2-х токенов с их обязательной сортировкой
        return (uint256(keccak256(abi.encodePacked(_hash, _a3))));
    }
    // ***************************


    // ФУНКЦИИ ДЛЯ РАБОТЫ С ОРДЕРАМИ

    function createOrder(address _owner, address _token_in, uint _value_in, address _token_out, uint _value_out, uint8 _order_type, uint _price, uint _order_position, uint _dex_fee, uint _dex_num_exec_ord) external returns (uint256) // создание ордера (возвращаем ID ордера)
    {    
        require(msg.sender == contractDeposits); // Только контракт депозитов имеет право на создание ордеров

        Orders memory _ord;
        _ord.time = block.timestamp;
        //_ord.commission = _value_in * commission / (100 * 1e18); // комиссия биржи во входящем токене
        _ord.value_in = _value_in;
        _ord.value_out = _value_out;
        //_ord.exec_in = 0;
        //_ord.exec_out = 0;
        _ord.order_type = _order_type;
        _ord.price = _price;
        _ord.token_in = _token_in;
        _ord.token_out = _token_out;
        _ord.owner = _owner;
        _ord.order_status = 1;

        ++id; // ID нового ордера
        uint _id = id;

        // Найдем позицию нового ордера в стакане, а также определим является ли новый ордер вершиной стакана
        bool top;
        (_order_position, top) = searchPositionInOrderBook(hash2Address(_token_in, _token_out, false), _order_position, _price, _order_type);

        if(top){ // новый ордер размещается на вершине стакана, надо проверить возможность его исполнения
            Variables memory variable;
            variable._hash_pair = hash2Address(_token_out, _token_in, false); // получаем хэш по выходящему и входящему токену
            variable._opposite_id = order_book[variable._hash_pair][0].prev; // вершина противоположного стакана
            while(variable._opposite_id > 0){ // перебираем подходящие встречные ордера с вершины стакана в глубину
                variable._opposite_price = order_book[variable._hash_pair][variable._opposite_id].price; // получаем цену ордера
                if(_order_type == 1){ // новый ордер продажи
                    if(_price > variable._opposite_price) break; // если нет пересекающийся цены ордеров, то выполнять нечего
                }
                else{ // новый ордер покупки
                    if(_price < variable._opposite_price) break; // если нет пересекающийся цены ордеров, то выполнять нечего
                }

                // Контролируем лимит исполняемых ордеров
                if(_dex_num_exec_ord == 0){ // если было исполнено максимальное количество ордеров установленное биржей
                    _ord.order_status = 9;
                    IContractDeposits(contractDeposits).withdraw(_token_in, _ord.owner, _ord.value_in); // не исполненый остаток от ордера возвращаем владельцу
                    break;
                }
                --_dex_num_exec_ord;

                // выполняем ордера
                variable._opposite_value_out = orders[variable._opposite_id].value_out; // получаем значение выходящего токена из книги ордеров
                variable._val_in_diff = _ord.value_in < variable._opposite_value_out ? _ord.value_in : variable._opposite_value_out; // найдем объем входящего токена, у создающегося ордере, который надо исполнить

                _ord.value_out = (_ord.value_in - variable._val_in_diff) * _ord.value_out / _ord.value_in; // остаток получения в создаваемом ордере
                variable._temp = _ord.value_out == 0 ? _ord.value_in : variable._val_in_diff; // если остаток получения = 0, тогда отдаем весь вход с пылью (фактически отдает трейдер, создающий ордер)
                _ord.value_in -= variable._temp; // осталось на обмен в создаваемом ордере
                _ord.exec_in += variable._temp; // фактически обменяно от всего ордера
                variable._commission = variable._temp * _dex_fee / (100 * 1e18); // фактически отдает ордер из книги, комиссию бирже
                variable._fee_in += variable._commission; // накапливаем выплату комиссии биржи

                variable._recipient = orders[variable._opposite_id].owner; // владелец чей ордер исполняется (из книги ордеров)
                IContractDeposits(contractDeposits).withdraw(_token_in, variable._recipient, variable._temp - variable._commission);

                orders[variable._opposite_id].exec_out += (variable._temp - variable._commission);
                orders[variable._opposite_id].commission += variable._commission;

                
                variable._temp = variable._val_in_diff * orders[variable._opposite_id].value_in / variable._opposite_value_out; // фактически отдает трейдер из книги ордеров
                variable._commission = variable._temp * _dex_fee / (100 * 1e18); // фактически отдает трейдер комиссию бирже
                orders[variable._opposite_id].value_in -= variable._temp; // осталось на обмен в ордере
                orders[variable._opposite_id].value_out = variable._opposite_value_out - variable._val_in_diff; // осталось на обмен в ордере
                orders[variable._opposite_id].exec_in += variable._temp; // фактически обменяно от всего ордера
                variable._fee_out += variable._commission; // накапливаем выплату комиссии биржи

                variable._value_add += (variable._temp - variable._commission);
                _ord.exec_out += (variable._temp - variable._commission);
                _ord.commission += variable._commission;


                orders[variable._opposite_id].time = block.timestamp; // обновляем время последнего исполнения

                // перекрестные ордера отработали
                emit ExecutableOrder(variable._opposite_id);

                if(orders[variable._opposite_id].value_in == 0){ // ордер из книги ордеров полностью отработал
                    orders[variable._opposite_id].order_status = 7; // статус закрытого ордера (полностью отработал)
                    del_ID_order_book(variable._hash_pair, variable._opposite_id); // удаляем ордер из книги ордеров
                    del_ID_open_order(_token_out, _token_in, variable._recipient, variable._opposite_id); // удаляем ордер в открытых ордерах
                    add_ID_close_order(_token_out, _token_in, variable._recipient, variable._opposite_id); // Добавить ордер в закрытые ордера
                    add_ID_exec_order_book(_token_out, _token_in, variable._opposite_id); // Добавляем в исполненые
                    variable._opposite_id = order_book[variable._hash_pair][0].prev;
                }
                else{ // ордер отработал частично
                    orders[variable._opposite_id].order_status = 6; // ордер выполнен частично
                }

                if(_ord.value_in == 0){ // создаваемый ордер полностью отработал
                    _ord.order_status = 7;
                    break;
                }
                else{
                    _ord.order_status = 6; // создаваемый ордер отработал частично
                }
            }

            // Переводы создателю ордера
            if(variable._value_add > 0) IContractDeposits(contractDeposits).withdraw(_token_out, _ord.owner, variable._value_add); // создатель ордера должен получить второй токен
            // переводим всю собранную комиссию (комиссия копится в контракте комиссий)
            if(variable._fee_in > 0) IContractDeposits(contractDeposits).withdrawFee(_token_in, variable._fee_in);
            if(variable._fee_out > 0) IContractDeposits(contractDeposits).withdrawFee(_token_out, variable._fee_out);
        }

        orders[_id] = _ord; // сохраняем ордер целиком под уникальным номером

        if ((_ord.order_status == 1) || (_ord.order_status == 6)) { // создание ордера или частичное исполнение
            add_ID_order_book(hash2Address(_token_in, _token_out, false), _order_position, _id, _price); // Добавляем новый ордер в книгу ордеров
            add_ID_open_order(_token_in, _token_out, _ord.owner, _id); // добавление нового ордера в открытые ордера трейдера
        } else { // 7 - ордер полностью исполнен или 9 - ордер полностью исполнен (с разблокировкой оставщейся необменяной суммой)
            add_ID_close_order(_token_in, _token_out, _ord.owner, _id); // добавление нового ордера в закрытые ордера трейдера
            add_ID_exec_order_book(_token_in, _token_out, _id);
        }

        emit CreateOrder(_id);
        return _id;
    }



    function add_ID_order_book(uint256 _hash_pair, uint _id_prev, uint _id_new, uint _price) private { // добавление нового ордера в книгу ордеров
        uint _id_next = order_book[_hash_pair][_id_prev].next; // _id_new будет расположен между _id_prev и _id_next
        order_book[_hash_pair][_id_prev].next = _id_new;
        order_book[_hash_pair][_id_next].prev = _id_new;
        order_book[_hash_pair][_id_new] = OrderBook(_price, _id_next, _id_prev);
    }

    function add_ID_open_order(address _token1, address _token2, address _owner, uint _id_new) private { // добавление нового ордера в открытые ордера трейдера
        uint _id_last = all_open_order[_owner][0].prev; // получаем последний открытый ордер трейдера
        all_open_order[_owner][_id_last].next = _id_new;
        all_open_order[_owner][0].prev = _id_new;
        all_open_order[_owner][_id_new].prev = _id_last; // более оптимальная запись, так как next последнего элемента всегда указывает на 0

        uint256 _hash_pair_owner = hash3Address(_token1, _token2, _owner); // _hash_pair_owner - при получении хэша пары, токены были отсортированы
        _id_last = open_order[_hash_pair_owner][0].prev; // получаем последний открытый ордер трейдера
        open_order[_hash_pair_owner][_id_last].next = _id_new;
        open_order[_hash_pair_owner][0].prev = _id_new;
        open_order[_hash_pair_owner][_id_new].prev = _id_last; // более оптимальная запись, так как next последнего элемента всегда указывает на 0
    }

    function add_ID_close_order(address _token1, address _token2, address _owner, uint _id_new) private { // добавление нового ордера в закрытые ордера трейдера
        uint256 _hash_pair_owner = hash3Address(_token1, _token2, _owner); // _hash_pair_owner - при получении хэша пары, токены были отсортированы
        uint _id_last = close_order[_hash_pair_owner][0].prev; // получаем последний закрытый ордер трейдера
        close_order[_hash_pair_owner][_id_last].next = _id_new;
        close_order[_hash_pair_owner][0].prev = _id_new;
        close_order[_hash_pair_owner][_id_new].prev = _id_last; // более оптимальная запись, так как next последнего элемента всегда указывает на 0
    }

    function add_ID_exec_order_book(address _token1, address _token2, uint _id_new) private { // добавление ордера в список исполненых ордеров
        uint256 _hash_pair = hash2Address(_token1, _token2, true); // _hash_pair - при получении хэша пары, токены были отсортированы
        uint _index = exec_order_book[_hash_pair][0]; // получаем последний элемент цикличного буфера
        if(_index == 50) _index = 0; // если текущий элемент это последний элемент списка
        ++_index;
        exec_order_book[_hash_pair][_index] = _id_new; // добавляем выполненый ордер
        exec_order_book[_hash_pair][0] = _index; // запоминаем индекс последнего добавленного ордера
    }

    function del_ID_order_book(uint256 _hash_pair, uint _id_del) private { // удаление ордера из книги ордеров
        uint _id_next = order_book[_hash_pair][_id_del].next;
        uint _id_prev = order_book[_hash_pair][_id_del].prev;
        order_book[_hash_pair][_id_prev].next = _id_next;
        order_book[_hash_pair][_id_next].prev = _id_prev;
        delete order_book[_hash_pair][_id_del];
    }

    function del_ID_open_order(address _token1, address _token2, address _owner, uint _id_del) private { // удаление ордера из открытых ордеров трейдера
        uint _id_next = all_open_order[_owner][_id_del].next;
        uint _id_prev = all_open_order[_owner][_id_del].prev;
        all_open_order[_owner][_id_prev].next = _id_next;
        all_open_order[_owner][_id_next].prev = _id_prev;
        delete all_open_order[_owner][_id_del];

        uint256 _hash_pair_owner = hash3Address(_token1, _token2, _owner); // _hash_pair_owner - при получении хэша пары, токены были отсортированы
        _id_next = open_order[_hash_pair_owner][_id_del].next;
        _id_prev = open_order[_hash_pair_owner][_id_del].prev;
        open_order[_hash_pair_owner][_id_prev].next = _id_next;
        open_order[_hash_pair_owner][_id_next].prev = _id_prev;
        delete open_order[_hash_pair_owner][_id_del];
    }

    function del_ID_close_order(uint256 _hash_pair_owner, uint _id_del) private { // удаление ордера из закрытых ордеров трейдера
        // сортировка токенов была выполнена в функции deleteCloseOrders
        uint _id_next = close_order[_hash_pair_owner][_id_del].next;
        uint _id_prev = close_order[_hash_pair_owner][_id_del].prev;
        close_order[_hash_pair_owner][_id_prev].next = _id_next;
        close_order[_hash_pair_owner][_id_next].prev = _id_prev;
        delete close_order[_hash_pair_owner][_id_del];
    }


    function cancelOrders(uint[] memory _id_arr) external returns (uint [] memory) { // отмена ордеров, возвращаем массив с отмененными ордерами (если ордер не был отменен, то вместо его ID в массив записывается 0)
        uint8 _status; // текущий статус ордера из массива
        uint256 _id; // ID текущего ордера
        uint _pay; // Вернуть владельцу оставшиеся токены
        address _token_in;
        address _token_out;
        for(uint i; i < _id_arr.length; i++){ // перебираем весь массив с ордерами на отмену
            _id = _id_arr[i];
            _status = orders[_id].order_status;
            if((orders[_id].owner == msg.sender) && ((_status == 1) || (_status == 6))){
                _pay = orders[_id].value_in; // Вернуть владельцу оставшиеся токены
                _token_in = orders[_id].token_in;
                _token_out = orders[_id].token_out;
                IContractDeposits(contractDeposits).withdraw(_token_in, msg.sender, _pay);
                orders[_id].time = block.timestamp;
                orders[_id].value_in = 0;
                orders[_id].value_out = 0;
                orders[_id].order_status = 4;

                del_ID_order_book(hash2Address(_token_in, _token_out, false), _id); // удаляем ордер из книги ордеров
                del_ID_open_order(_token_in, _token_out, msg.sender, _id); // удаляем ордер в открытых ордерах
                add_ID_close_order(_token_in, _token_out, msg.sender, _id); // Добавить ордер в закрытые ордера
                emit CancelOrder(_id);
            }
            else{ // ордер не может быть отменен (другой владелец или не подходящий статус ордера)
                _id_arr[i] = 0; // убираем ID ордера из массива отменяемых ордеров
            }
        }
        return (_id_arr);
    }


    function deleteCloseOrders(uint[] memory _id_arr) external returns (uint [] memory) { // удаление закрытых пользовательских ордеров, возвращаем массив с удаленными ордерами (если ордер не был удален, то вместо его ID в массив записывается 0)
        uint8 _status; // текущий статус ордера из массива
        uint256 _id; // ID текущего ордера
        for(uint i; i < _id_arr.length; i++){ // перебираем весь массив с ордерами на удаление
            _id = _id_arr[i];
            _status = orders[_id].order_status;
            if((orders[_id].owner == msg.sender) && ((_status == 4) || (_status == 7) || (_status == 9))){
                del_ID_close_order(hash3Address(orders[_id].token_in, orders[_id].token_out, msg.sender), _id); // удаляем ордер из списка закрытых ордеров пользователя
                orders[_id].order_status = 8; // глобально помечаем ордер для удаления из системы
                emit DeleteOrder(_id);
            }
            else{ // ордер не может быть удален (другой владелец или не подходящий статус ордера)
                _id_arr[i] = 0; // убираем ID ордера из массива удаляемых ордеров
            }
        }
        return (_id_arr);
    }


    function deleteGlobalOrders(uint[] calldata _id_arr) external onlyOwner // Удаление списка ордеров из системы. Только тех ордеров, что пользователи пометили как удаляемые
    {
        for(uint i; i < _id_arr.length; i++){ // перебираем весь массив с ордерами на удаление
            if(orders[_id_arr[i]].order_status == 8){ // можно удалять только если пользователь отметил данный ордер как удаляемый
                delete orders[_id_arr[i]];
            }
        }
    }



    function searchPositionInOrderBook(uint256 _hash_pair, uint _startID, uint _price, uint8 _order_type) private view returns (uint256, bool) // вернуть ID ордера после которого будет размещен новый ордер, а также вернуть true если новый ордер это вершина стакана
    {
        uint256 tek_price;
        uint256 next_id;

        _startID = order_book[_hash_pair][_startID].price > 0 ? _startID : order_book[_hash_pair][0].prev; // определяем стартовую позицию ордера, если такого ордера нет в книге, то стартавая позиция это последний ордер в книге

        tek_price = order_book[_hash_pair][_startID].price;

        if(tek_price == 0){ // если книга ордеров пуста
            return (0, true);
        }
        else{ // надо искать позицию
            if(_order_type == 1){ // новый ордер продажи
                if(_price < tek_price){ // поиск к вершине стакана
                    next_id = order_book[_hash_pair][_startID].next;
                    while(_price < tek_price){
                        if(next_id == 0) return (_startID, true);
                        _startID = next_id;
                        tek_price = order_book[_hash_pair][_startID].price;
                        next_id = order_book[_hash_pair][_startID].next;
                    }
                    return (order_book[_hash_pair][_startID].prev, false);
                }
                else{ // поиск в глубь стакана
                    next_id = order_book[_hash_pair][_startID].prev;
                    while(_price >= tek_price){
                        if(next_id == 0) return (0, false);
                        _startID = next_id;
                        tek_price = order_book[_hash_pair][_startID].price;
                        next_id = order_book[_hash_pair][_startID].prev;
                    }
                    return (_startID, false);
                }
            }
            else{ // новый ордер покупки
                if(_price > tek_price){ // поиск к вершине стакана
                    next_id = order_book[_hash_pair][_startID].next;
                    while(_price > tek_price){
                        if(next_id == 0) return (_startID, true);
                        _startID = next_id;
                        tek_price = order_book[_hash_pair][_startID].price;
                        next_id = order_book[_hash_pair][_startID].next;
                    }
                    return (order_book[_hash_pair][_startID].prev, false);
                }
                else{ // поиск в глубь стакана
                    next_id = order_book[_hash_pair][_startID].prev;
                    while(_price <= tek_price){
                        if(next_id == 0) return (0, false);
                        _startID = next_id;
                        tek_price = order_book[_hash_pair][_startID].price;
                        next_id = order_book[_hash_pair][_startID].prev;
                    }
                    return (_startID, false);
                }
            }
        }
    }


    function get_ID_and_Prices_from_OrderBook(address _token_in, address _token_out, uint _id_start, uint _amount) public view returns (uint [] memory) // Возвращает ID и цены из книги ордеров (для фронта). Фронт учавствует в поиске позиции для ордера
    {   
        uint256 _hash_pair = hash2Address(_token_in, _token_out, false); // получаем хэш пары по входящему и выходящему токену
        _id_start = order_book[_hash_pair][_id_start].price > 0 ? _id_start : order_book[_hash_pair][0].prev; // определяем стартовую позицию ордера, если такого ордера нет в книге, то стартавая позиция это последний ордер в книге
        uint _index;
        uint[] memory result = new uint[](_amount * 2); // [ID, цена...]

        for(uint i; i < _amount; i++){
            if(_id_start == 0) break;
            result[_index++] = _id_start;
            result[_index++] = order_book[_hash_pair][_id_start].price;
            _id_start = order_book[_hash_pair][_id_start].prev;
        }

        return (result);
    }

    function getOrderByID(uint _id) public view returns (Orders memory) // Возвращаем ордер по ID
    {   
        return (orders[_id]);
    }

    function getOrderBook(address _token_in, address _token_out, uint _amount) public view returns (uint [] memory) // Возвращаем ордера стакана от вершины стакана в глубину
    {   
        uint256 _hash_pair = hash2Address(_token_in, _token_out, false); // получаем хэш пары по входящему и выходящему токену
        uint _index;
        uint _id = order_book[_hash_pair][0].prev;
        uint[] memory result = new uint[](_amount * 3); // [цена, отдаю, получаю...]

        for(uint i; i < _amount; i++){
            if(_id == 0) break;
            result[_index++] = orders[_id].price;
            result[_index++] = orders[_id].value_in;
            result[_index++] = orders[_id].value_out;
            _id = order_book[_hash_pair][_id].prev;
        }
        return (result);
    }

    function getExecOrderBook(address _token1, address _token2) public view returns (uint [] memory) // Возвращаем выполненые ордера в данной торговой паре
    {   
        uint256 _hash_pair = hash2Address(_token1, _token2, true); // _hash_pair - при получении хэша пары, токены были отсортированы
        uint _index_top = exec_order_book[_hash_pair][0];
        if(_index_top == 0) return (new uint[](1)); // если исполненых ордеров еще не существует, вернем [0]

        uint _index;
        uint _id;
        uint[] memory result = new uint[](50 * 6); // [id, тип_ордера, время, цена, отдал, получил...]        

        for(uint i = 0; i < 50; i++){
            _id = exec_order_book[_hash_pair][_index_top];
            result[_index++] = _id;
            result[_index++] = orders[_id].order_type;
            result[_index++] = orders[_id].time;
            result[_index++] = orders[_id].price;
            result[_index++] = orders[_id].exec_in;
            result[_index++] = orders[_id].exec_out;
            if(--_index_top == 0){
                _index_top = 50;
                if(exec_order_book[_hash_pair][_index_top] == 0) break; // обрываем цикл если исполнено менее 50 ордеров
            } 
        }

        return (result);
    }

    function getAllOpenOrders(address _owner, uint _id, uint _amount) public view returns (uint [] memory) // Возвращаем указанное количество открытых ордеров пользователя, со сдедующего ордера от стартового ID
    {   // если _id = 0, тогда открытые ордера формируются с самого последнего ордера
        _id = all_open_order[_owner][_id].prev;

        if(_id == 0) return (new uint[](1)); // если открытых ордеров еще не существует, либо если это первый ордер в списке, который уже был обработан, вернем [0]

        uint _index;
        uint[] memory result = new uint[](_amount * 9); // [id, время, цена, осталось_отдать, адрес_токена_IN, осталось_получить, адрес_токена_OUT, тип_ордера, статус...]

        for(uint i; i < _amount; i++){
            if(_id == 0) break;
            result[_index++] = _id;
            result[_index++] = orders[_id].time;
            result[_index++] = orders[_id].price;
            result[_index++] = orders[_id].value_in;
            result[_index++] = uint256(uint160(orders[_id].token_in));
            result[_index++] = orders[_id].value_out;
            result[_index++] = uint256(uint160(orders[_id].token_out));
            result[_index++] = orders[_id].order_type;
            result[_index++] = orders[_id].order_status;
            _id = all_open_order[_owner][_id].prev;
        }
        return (result);
    }

    function getOpenOrders(address _token1, address _token2, address _owner, uint _id, uint _amount) public view returns (uint [] memory) // Возвращаем указанное количество открытых ордеров пользователя, со сдедующего ордера от стартового ID, в данной торговой паре
    {   // если _id = 0, тогда открытые ордера формируются с самого последнего ордера
        uint256 _hash_pair_owner = hash3Address(_token1, _token2, _owner); // _hash_pair_owner - при получении хэша пары, токены были отсортированы
        _id = open_order[_hash_pair_owner][_id].prev;

        if(_id == 0) return (new uint[](1)); // если открытых ордеров еще не существует, либо если это первый ордер в списке, который уже был обработан, вернем [0]

        uint _index;
        uint[] memory result = new uint[](_amount * 6); // [id, тип_ордера, время, цена, осталось_отдать, осталось_получить...]

        for(uint i; i < _amount; i++){
            if(_id == 0) break;
            result[_index++] = _id;
            result[_index++] = orders[_id].order_type;
            result[_index++] = orders[_id].time;
            result[_index++] = orders[_id].price;
            result[_index++] = orders[_id].value_in;
            result[_index++] = orders[_id].value_out;
            _id = open_order[_hash_pair_owner][_id].prev;
        }
        return (result);
    }

    function getCloseOrders(address _token1, address _token2, address _owner, uint _id, uint _amount) public view returns (uint [] memory) // Возвращаем указанное количество закрытых ордеров пользователя, со следующего ордера от стартового ID, в данной торговой паре
    {   // если _id = 0, тогда закрытые ордера формируются с самого последнего ордера
        uint256 _hash_pair_owner = hash3Address(_token1, _token2, _owner); // _hash_pair_owner - при получении хэша пары, токены были отсортированы
        _id = close_order[_hash_pair_owner][_id].prev;

        if(_id == 0) return (new uint[](1)); // если закрытых ордеров еще не существует, либо если это первый ордер в списке, который уже был обработан, вернем [0]

        uint _index;
        uint[] memory result = new uint[](_amount * 6); // [id, тип_ордера, время, цена, отдал, получил...]

        for(uint i; i < _amount; i++){
            if(_id == 0) break;
            result[_index++] = _id;
            result[_index++] = orders[_id].order_type;
            result[_index++] = orders[_id].time;
            result[_index++] = orders[_id].price;
            result[_index++] = orders[_id].exec_in;
            result[_index++] = orders[_id].exec_out;
            _id = close_order[_hash_pair_owner][_id].prev;
        }
        return (result);
    }


    // Функции для работы с ботами

    function getLockedTokensForOracle(uint _id1, uint _id2) public view returns (uint [] memory) // функция возвращает заблокированные в контракте токены у 2-х запрашиваемых ордеров в одной торговой паре
    {   // возвращает массив [токен1, количество1, токен2, количество2]
        uint[] memory result = new uint[](4);
        address _token1;
        uint _value1;
        address _token2;
        uint _value2;
        uint8 _status1 = orders[_id1].order_status; // статус первого ордера
        uint8 _status2 = orders[_id2].order_status; // статус второго ордера
        
        if(_status1 > 0){ // если ордер существует или существовал ранее. Тогда возьмем адреса токенов из него
            (_token1, _token2) = (orders[_id1].token_in, orders[_id1].token_out);
        }
        else{ // Адреса токенов берем из второго ордера
            (_token1, _token2) = (orders[_id2].token_in, orders[_id2].token_out);
        }

        if((_status1 == 1) || (_status1 == 6) || (_status1 == 7) || (_status1 == 9)){ // считаем количество токенов которое удерживает контракт
            if(_token1 == orders[_id1].token_in){
                _value1 += orders[_id1].value_in;
                _value2 += orders[_id1].exec_out;
            }
            else{
                _value2 += orders[_id1].value_in;
                _value1 += orders[_id1].exec_out;
            }
        }

        if((_status2 == 1) || (_status2 == 6) || (_status2 == 7) || (_status2 == 9)){ // считаем количество токенов которое удерживает контракт
            if(_token1 == orders[_id2].token_in){
                _value1 += orders[_id2].value_in;
                _value2 += orders[_id2].exec_out;
            }
            else{
                _value2 += orders[_id2].value_in;
                _value1 += orders[_id2].exec_out;
            }
        }

        result[0] = uint256(uint160(_token1));
        result[1] = _value1;
        result[2] = uint256(uint160(_token2));
        result[3] = _value2;        
        return (result);
    }

    function getOrderDataForOracle(uint _id) public view returns (uint [] memory) // Возвращаем данные по ордеру необходимые оракулу
    {
        uint[] memory result = new uint[](6); // [статус, тип_ордера, осталось_отдать, осталось_получить, отдал, получил]
        result[0] = orders[_id].order_status;
        result[1] = orders[_id].order_type;
        result[2] = orders[_id].value_in;
        result[3] = orders[_id].value_out;
        result[4] = orders[_id].exec_in;
        result[5] = orders[_id].exec_out;
        return (result);
    }

    function getCloseOrdersOracle(address _token1, address _token2, address _owner, uint _id, uint _amount) public view returns (uint [] memory) // Возвращаем указанное количество ID закрытых ордеров пользователя, со следующего ордера от стартового ID, в данной торговой паре
    {   // если _id = 0, тогда закрытые ордера формируются с самого последнего ордера
        uint256 _hash_pair_owner = hash3Address(_token1, _token2, _owner); // _hash_pair_owner - при получении хэша пары, токены были отсортированы
        _id = close_order[_hash_pair_owner][_id].prev;

        if(_id == 0) return (new uint[](1)); // если закрытых ордеров еще не существует, либо если это первый ордер в списке, который уже был обработан, вернем [0]

        uint _index;
        uint[] memory result = new uint[](_amount); // [id,...]

        for(uint i; i < _amount; i++){
            if(_id == 0) break;
            result[_index++] = _id;
            _id = close_order[_hash_pair_owner][_id].prev;
        }
        return (result);
    }
}
        

Contract ABI

[{"type":"event","name":"CancelOrder","inputs":[{"type":"uint256","name":"ID","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"CreateOrder","inputs":[{"type":"uint256","name":"ID","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"DeleteOrder","inputs":[{"type":"uint256","name":"ID","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"ExecutableOrder","inputs":[{"type":"uint256","name":"ID","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"cancelOrders","inputs":[{"type":"uint256[]","name":"_id_arr","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"contractDeposits","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"createOrder","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"address","name":"_token_in","internalType":"address"},{"type":"uint256","name":"_value_in","internalType":"uint256"},{"type":"address","name":"_token_out","internalType":"address"},{"type":"uint256","name":"_value_out","internalType":"uint256"},{"type":"uint8","name":"_order_type","internalType":"uint8"},{"type":"uint256","name":"_price","internalType":"uint256"},{"type":"uint256","name":"_order_position","internalType":"uint256"},{"type":"uint256","name":"_dex_fee","internalType":"uint256"},{"type":"uint256","name":"_dex_num_exec_ord","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"deleteCloseOrders","inputs":[{"type":"uint256[]","name":"_id_arr","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deleteGlobalOrders","inputs":[{"type":"uint256[]","name":"_id_arr","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getAllOpenOrders","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"uint256","name":"_id","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getCloseOrders","inputs":[{"type":"address","name":"_token1","internalType":"address"},{"type":"address","name":"_token2","internalType":"address"},{"type":"address","name":"_owner","internalType":"address"},{"type":"uint256","name":"_id","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getCloseOrdersOracle","inputs":[{"type":"address","name":"_token1","internalType":"address"},{"type":"address","name":"_token2","internalType":"address"},{"type":"address","name":"_owner","internalType":"address"},{"type":"uint256","name":"_id","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getExecOrderBook","inputs":[{"type":"address","name":"_token1","internalType":"address"},{"type":"address","name":"_token2","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getLockedTokensForOracle","inputs":[{"type":"uint256","name":"_id1","internalType":"uint256"},{"type":"uint256","name":"_id2","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getOpenOrders","inputs":[{"type":"address","name":"_token1","internalType":"address"},{"type":"address","name":"_token2","internalType":"address"},{"type":"address","name":"_owner","internalType":"address"},{"type":"uint256","name":"_id","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getOrderBook","inputs":[{"type":"address","name":"_token_in","internalType":"address"},{"type":"address","name":"_token_out","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct TwoBearsOrders.Orders","components":[{"type":"uint256","name":"time","internalType":"uint256"},{"type":"uint256","name":"commission","internalType":"uint256"},{"type":"uint256","name":"value_in","internalType":"uint256"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"value_out","internalType":"uint256"},{"type":"uint256","name":"exec_in","internalType":"uint256"},{"type":"uint256","name":"exec_out","internalType":"uint256"},{"type":"address","name":"token_in","internalType":"address"},{"type":"address","name":"token_out","internalType":"address"},{"type":"address","name":"owner","internalType":"address"},{"type":"uint8","name":"order_type","internalType":"uint8"},{"type":"uint8","name":"order_status","internalType":"uint8"}]}],"name":"getOrderByID","inputs":[{"type":"uint256","name":"_id","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getOrderDataForOracle","inputs":[{"type":"uint256","name":"_id","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"get_ID_and_Prices_from_OrderBook","inputs":[{"type":"address","name":"_token_in","internalType":"address"},{"type":"address","name":"_token_out","internalType":"address"},{"type":"uint256","name":"_id_start","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"id","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]}]
              

Contract Creation Code

Verify & Publish
0x608060405273ebe894814554c8382ea6a24ccddf1527407a24f6600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561006557600080fd5b50614dd1806100756000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c80636da42a15116100a25780638da5cb5b116100715780638da5cb5b1461032a5780639435298b14610348578063af640d0f14610378578063b55fb57414610396578063e0a31339146103c65761010b565b80636da42a151461026a57806375b024051461029a5780637e9da7a2146102ca578063809741ed146102fa5761010b565b8063334503bf116100de578063334503bf146101aa57806336511013146101da57806347402bea1461020a5780635eb2088e1461023a5761010b565b80630e0578f514610110578063127e11971461014057806318df23881461015e578063299821f61461018e575b600080fd5b61012a600480360381019061012591906141b3565b6103f6565b6040516101379190614342565b60405180910390f35b6101486105a6565b604051610155919061436d565b60405180910390f35b610178600480360381019061017391906143b4565b6105be565b60405161018591906144ca565b60405180910390f35b6101a860048036038101906101a39190614551565b610769565b005b6101c460048036038101906101bf919061459e565b61096b565b6040516101d191906144ca565b60405180910390f35b6101f460048036038101906101ef9190614619565b610c42565b60405161020191906144ca565b60405180910390f35b610224600480360381019061021f9190614685565b611112565b6040516102319190614773565b60405180910390f35b610254600480360381019061024f919061478e565b611dfc565b60405161026191906144ca565b60405180910390f35b610284600480360381019061027f91906141b3565b61225a565b60405161029191906144ca565b60405180910390f35b6102b460048036038101906102af9190614930565b61241d565b6040516102c191906144ca565b60405180910390f35b6102e460048036038101906102df919061459e565b612628565b6040516102f191906144ca565b60405180910390f35b610314600480360381019061030f9190614979565b6128ff565b60405161032191906144ca565b60405180910390f35b610332612c10565b60405161033f919061436d565b60405180910390f35b610362600480360381019061035d91906149b9565b612c36565b60405161036f91906144ca565b60405180910390f35b610380612df4565b60405161038d9190614773565b60405180910390f35b6103b060048036038101906103ab9190614930565b612dfa565b6040516103bd91906144ca565b60405180910390f35b6103e060048036038101906103db919061459e565b61310c565b6040516103ed91906144ca565b60405180910390f35b6103fe614050565b6006600083815260200190815260200160002060405180610180016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016008820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016009820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016009820160149054906101000a900460ff1660ff1660ff1681526020016009820160159054906101000a900460ff1660ff1660ff16815250509050919050565b735cec09f125f4839656164a5109bc076daabd6ed681565b606060006105ce8686600061327d565b90506000600160008381526020019081526020016000206000868152602001908152602001600020600001541161062c576001600082815260200190815260200160002060008081526020019081526020016000206002015461062e565b835b93506000806002856106409190614a3b565b67ffffffffffffffff811115610659576106586147f2565b5b6040519080825280602002602001820160405280156106875781602001602082028036833780820191505090505b50905060005b8581101561075a57600087031561075a57868284806106ab90614a95565b9550815181106106be576106bd614add565b5b602002602001018181525050600160008581526020019081526020016000206000888152602001908152602001600020600001548284806106fe90614a95565b95508151811061071157610710614add565b5b602002602001018181525050600160008581526020019081526020016000206000888152602001908152602001600020600201549650808061075290614a95565b91505061068d565b50809350505050949350505050565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146107f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107f090614b69565b60405180910390fd5b60005b82829050811015610966576008600660008585858181106108205761081f614add565b5b90506020020135815260200190815260200160002060090160159054906101000a900460ff1660ff1603610953576006600084848481811061086557610864614add565b5b9050602002013581526020019081526020016000206000808201600090556001820160009055600282016000905560038201600090556004820160009055600582016000905560068201600090556007820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556008820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556009820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556009820160146101000a81549060ff02191690556009820160156101000a81549060ff021916905550505b808061095e90614a95565b9150506107fc565b505050565b6060600061097a878787613300565b905060036000828152602001908152602001600020600085815260200190815260200160002060010154935060008403610a0057600167ffffffffffffffff8111156109c9576109c86147f2565b5b6040519080825280602002602001820160405280156109f75781602001602082028036833780820191505090505b50915050610c39565b600080600685610a109190614a3b565b67ffffffffffffffff811115610a2957610a286147f2565b5b604051908082528060200260200182016040528015610a575781602001602082028036833780820191505090505b50905060005b85811015610c31576000870315610c315786828480610a7b90614a95565b955081518110610a8e57610a8d614add565b5b6020026020010181815250506006600088815260200190815260200160002060090160149054906101000a900460ff1660ff16828480610acd90614a95565b955081518110610ae057610adf614add565b5b6020026020010181815250506006600088815260200190815260200160002060000154828480610b0f90614a95565b955081518110610b2257610b21614add565b5b6020026020010181815250506006600088815260200190815260200160002060030154828480610b5190614a95565b955081518110610b6457610b63614add565b5b6020026020010181815250506006600088815260200190815260200160002060020154828480610b9390614a95565b955081518110610ba657610ba5614add565b5b6020026020010181815250506006600088815260200190815260200160002060040154828480610bd590614a95565b955081518110610be857610be7614add565b5b6020026020010181815250506003600085815260200190815260200160002060008881526020019081526020016000206001015496508080610c2990614a95565b915050610a5d565b508093505050505b95945050505050565b60606000600467ffffffffffffffff811115610c6157610c606147f2565b5b604051908082528060200260200182016040528015610c8f5781602001602082028036833780820191505090505b5090506000806000806000600660008a815260200190815260200160002060090160159054906101000a900460ff1690506000600660008a815260200190815260200160002060090160159054906101000a900460ff16905060008260ff161115610d6f57600660008b815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600660008c815260200190815260200160002060080160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168095508197505050610de6565b600660008a815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600660008b815260200190815260200160002060080160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1680955081975050505b60018260ff161480610dfb575060068260ff16145b80610e09575060078260ff16145b80610e17575060098260ff16145b15610f1c57600660008b815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603610ed257600660008b81526020019081526020016000206002015485610ea79190614b89565b9450600660008b81526020019081526020016000206006015483610ecb9190614b89565b9250610f1b565b600660008b81526020019081526020016000206002015483610ef49190614b89565b9250600660008b81526020019081526020016000206006015485610f189190614b89565b94505b5b60018160ff161480610f31575060068160ff16145b80610f3f575060078160ff16145b80610f4d575060098160ff16145b1561105257600660008a815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff160361100857600660008a81526020019081526020016000206002015485610fdd9190614b89565b9450600660008a815260200190815260200160002060060154836110019190614b89565b9250611051565b600660008a8152602001908152602001600020600201548361102a9190614b89565b9250600660008a8152602001908152602001600020600601548561104e9190614b89565b94505b5b8573ffffffffffffffffffffffffffffffffffffffff168760008151811061107d5761107c614add565b5b602002602001018181525050848760018151811061109e5761109d614add565b5b6020026020010181815250508373ffffffffffffffffffffffffffffffffffffffff16876002815181106110d5576110d4614add565b5b60200260200101818152505082876003815181106110f6576110f5614add565b5b6020026020010181815250508697505050505050505092915050565b6000735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461116057600080fd5b611168614050565b4281600001818152505089816040018181525050878160800181815250508681610140019060ff16908160ff1681525050858160600181815250508a8160e0019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508881610100019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508b81610120019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600181610160019060ff16908160ff1681525050600080815461126f90614a95565b91905081905550600080549050600061129561128d8e8d600061327d565b888a8c613347565b80925081985050508015611bd5576112ab6140f9565b6112b78c8f600061327d565b81600001818152505060016000826000015181526020019081526020016000206000808152602001908152602001600020600201548160200181815250505b600081602001511115611a0f5760016000826000015181526020019081526020016000206000826020015181526020019081526020016000206000015481604001818152505060018a60ff16036113575780604001518911611a0f57611363565b80604001518910611a0f575b6000860361141057600984610160019060ff16908160ff1681525050735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663d9caed128f86610120015187604001516040518463ffffffff1660e01b81526004016113d993929190614bbd565b600060405180830381600087803b1580156113f357600080fd5b505af1158015611407573d6000803e3d6000fd5b50505050611a0f565b8561141a90614bf4565b9550600660008260200151815260200190815260200160002060040154816060018181525050806060015184604001511061145957806060015161145f565b83604001515b81608001818152505083604001518460800151826080015186604001516114869190614c1d565b6114909190614a3b565b61149a9190614c80565b84608001818152505060008460800151146114b95780608001516114bf565b83604001515b8160a00181815250508060a00151846040018181516114de9190614c1d565b915081815250508060a001518460a0018181516114fb9190614b89565b9150818152505068056bc75e2d63100000878260a0015161151c9190614a3b565b6115269190614c80565b8160c00181815250508060c0015181610100018181516115469190614b89565b91508181525050600660008260200151815260200190815260200160002060090160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681610140019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663d9caed128f8361014001518460c001518560a0015161160b9190614c1d565b6040518463ffffffff1660e01b815260040161162993929190614bbd565b600060405180830381600087803b15801561164357600080fd5b505af1158015611657573d6000803e3d6000fd5b505050508060c001518160a0015161166f9190614c1d565b600660008360200151815260200190815260200160002060060160008282546116989190614b89565b925050819055508060c00151600660008360200151815260200190815260200160002060010160008282546116cd9190614b89565b92505081905550806060015160066000836020015181526020019081526020016000206002015482608001516117039190614a3b565b61170d9190614c80565b8160a001818152505068056bc75e2d63100000878260a001516117309190614a3b565b61173a9190614c80565b8160c00181815250508060a00151600660008360200151815260200190815260200160002060020160008282546117719190614c1d565b925050819055508060800151816060015161178c9190614c1d565b6006600083602001518152602001908152602001600020600401819055508060a00151600660008360200151815260200190815260200160002060050160008282546117d89190614b89565b925050819055508060c0015181610120018181516117f69190614b89565b915081815250508060c001518160a001516118119190614c1d565b8160e0018181516118229190614b89565b915081815250508060c001518160a0015161183d9190614c1d565b8460c00181815161184e9190614b89565b915081815250508060c001518460200181815161186b9190614b89565b915081815250504260066000836020015181526020019081526020016000206000018190555080602001517f271adf7ca5026da9466c7e2ee50294432b6518106821bb0baa27adfbe5203bad60405160405180910390a260006006600083602001518152602001908152602001600020600201540361199d576007600660008360200151815260200190815260200160002060090160156101000a81548160ff021916908360ff16021790555061192a81600001518260200151613726565b61193f8c8f836101400151846020015161381b565b6119548c8f8361014001518460200151613ad9565b6119638c8f8360200151613ba0565b60016000826000015181526020019081526020016000206000808152602001908152602001600020600201548160200181815250506119d1565b60068060008360200151815260200190815260200160002060090160156101000a81548160ff021916908360ff1602179055505b60008460400151036119f657600784610160019060ff16908160ff1681525050611a0f565b600684610160019060ff16908160ff16815250506112f6565b60008160e001511115611aa957735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663d9caed128d8661012001518460e001516040518463ffffffff1660e01b8152600401611a7693929190614bbd565b600060405180830381600087803b158015611a9057600080fd5b505af1158015611aa4573d6000803e3d6000fd5b505050505b60008161010001511115611b3e57735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663fd9be5228f8361010001516040518363ffffffff1660e01b8152600401611b0b929190614cb1565b600060405180830381600087803b158015611b2557600080fd5b505af1158015611b39573d6000803e3d6000fd5b505050505b60008161012001511115611bd357735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663fd9be5228d8361012001516040518363ffffffff1660e01b8152600401611ba0929190614cb1565b600060405180830381600087803b158015611bba57600080fd5b505af1158015611bce573d6000803e3d6000fd5b505050505b505b8260066000848152602001908152602001600020600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c0820151816006015560e08201518160070160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101008201518160080160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160090160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101408201518160090160146101000a81548160ff021916908360ff1602179055506101608201518160090160156101000a81548160ff021916908360ff160217905550905050600183610160015160ff161480611d6c5750600683610160015160ff16145b15611d9e57611d88611d808e8d600061327d565b88848b613c53565b611d998d8c85610120015185613d3e565b611dbb565b611daf8d8c85610120015185613ad9565b611dba8d8c84613ba0565b5b817f2f539bcf68b0eef24f9fef1ae5ad7dd5a37f80a2fab34f406ad2b92c779d606460405160405180910390a28193505050509a9950505050505050505050565b6060600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002060010154925060008303611ead57600167ffffffffffffffff811115611e7757611e766147f2565b5b604051908082528060200260200182016040528015611ea55781602001602082028036833780820191505090505b509050612253565b600080600984611ebd9190614a3b565b67ffffffffffffffff811115611ed657611ed56147f2565b5b604051908082528060200260200182016040528015611f045781602001602082028036833780820191505090505b50905060005b8481101561224c57600086031561224c5785828480611f2890614a95565b955081518110611f3b57611f3a614add565b5b6020026020010181815250506006600087815260200190815260200160002060000154828480611f6a90614a95565b955081518110611f7d57611f7c614add565b5b6020026020010181815250506006600087815260200190815260200160002060030154828480611fac90614a95565b955081518110611fbf57611fbe614add565b5b6020026020010181815250506006600087815260200190815260200160002060020154828480611fee90614a95565b95508151811061200157612000614add565b5b6020026020010181815250506006600087815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1682848061206690614a95565b95508151811061207957612078614add565b5b60200260200101818152505060066000878152602001908152602001600020600401548284806120a890614a95565b9550815181106120bb576120ba614add565b5b6020026020010181815250506006600087815260200190815260200160002060080160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1682848061212090614a95565b95508151811061213357612132614add565b5b6020026020010181815250506006600087815260200190815260200160002060090160149054906101000a900460ff1660ff1682848061217290614a95565b95508151811061218557612184614add565b5b6020026020010181815250506006600087815260200190815260200160002060090160159054906101000a900460ff1660ff168284806121c490614a95565b9550815181106121d7576121d6614add565b5b602002602001018181525050600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000878152602001908152602001600020600101549550808061224490614a95565b915050611f0a565b5080925050505b9392505050565b60606000600667ffffffffffffffff811115612279576122786147f2565b5b6040519080825280602002602001820160405280156122a75781602001602082028036833780820191505090505b5090506006600084815260200190815260200160002060090160159054906101000a900460ff1660ff16816000815181106122e5576122e4614add565b5b6020026020010181815250506006600084815260200190815260200160002060090160149054906101000a900460ff1660ff168160018151811061232c5761232b614add565b5b60200260200101818152505060066000848152602001908152602001600020600201548160028151811061236357612362614add565b5b60200260200101818152505060066000848152602001908152602001600020600401548160038151811061239a57612399614add565b5b6020026020010181815250506006600084815260200190815260200160002060050154816004815181106123d1576123d0614add565b5b60200260200101818152505060066000848152602001908152602001600020600601548160058151811061240857612407614add565b5b60200260200101818152505080915050919050565b606060008060005b845181101561261d5784818151811061244157612440614add565b5b602002602001015191506006600083815260200190815260200160002060090160159054906101000a900460ff1692503373ffffffffffffffffffffffffffffffffffffffff166006600084815260200190815260200160002060090160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148015612501575060048360ff1614806124f2575060078360ff16145b80612500575060098360ff16145b5b156125e8576125866125806006600085815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166006600086815260200190815260200160002060080160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633613300565b83613f63565b60086006600084815260200190815260200160002060090160156101000a81548160ff021916908360ff160217905550817fbd000546857b596b03c884060c13e7d8c7a7ce52366d2f116f76688e6f000f6660405160405180910390a261260a565b60008582815181106125fd576125fc614add565b5b6020026020010181815250505b808061261590614a95565b915050612425565b508392505050919050565b60606000612637878787613300565b9050600460008281526020019081526020016000206000858152602001908152602001600020600101549350600084036126bd57600167ffffffffffffffff811115612686576126856147f2565b5b6040519080825280602002602001820160405280156126b45781602001602082028036833780820191505090505b509150506128f6565b6000806006856126cd9190614a3b565b67ffffffffffffffff8111156126e6576126e56147f2565b5b6040519080825280602002602001820160405280156127145781602001602082028036833780820191505090505b50905060005b858110156128ee5760008703156128ee578682848061273890614a95565b95508151811061274b5761274a614add565b5b6020026020010181815250506006600088815260200190815260200160002060090160149054906101000a900460ff1660ff1682848061278a90614a95565b95508151811061279d5761279c614add565b5b60200260200101818152505060066000888152602001908152602001600020600001548284806127cc90614a95565b9550815181106127df576127de614add565b5b602002602001018181525050600660008881526020019081526020016000206003015482848061280e90614a95565b95508151811061282157612820614add565b5b602002602001018181525050600660008881526020019081526020016000206005015482848061285090614a95565b95508151811061286357612862614add565b5b602002602001018181525050600660008881526020019081526020016000206006015482848061289290614a95565b9550815181106128a5576128a4614add565b5b60200260200101818152505060046000858152602001908152602001600020600088815260200190815260200160002060010154965080806128e690614a95565b91505061271a565b508093505050505b95945050505050565b6060600061290f8484600161327d565b905060006005600083815260200190815260200160002060006033811061293957612938614add565b5b015490506000810361299857600167ffffffffffffffff8111156129605761295f6147f2565b5b60405190808252806020026020018201604052801561298e5781602001602082028036833780820191505090505b5092505050612c0a565b600080600061012c67ffffffffffffffff8111156129b9576129b86147f2565b5b6040519080825280602002602001820160405280156129e75781602001602082028036833780820191505090505b50905060005b6032811015612c0057600560008781526020019081526020016000208560338110612a1b57612a1a614add565b5b0154925082828580612a2c90614a95565b965081518110612a3f57612a3e614add565b5b6020026020010181815250506006600084815260200190815260200160002060090160149054906101000a900460ff1660ff16828580612a7e90614a95565b965081518110612a9157612a90614add565b5b6020026020010181815250506006600084815260200190815260200160002060000154828580612ac090614a95565b965081518110612ad357612ad2614add565b5b6020026020010181815250506006600084815260200190815260200160002060030154828580612b0290614a95565b965081518110612b1557612b14614add565b5b6020026020010181815250506006600084815260200190815260200160002060050154828580612b4490614a95565b965081518110612b5757612b56614add565b5b6020026020010181815250506006600084815260200190815260200160002060060154828580612b8690614a95565b965081518110612b9957612b98614add565b5b602002602001018181525050600085612bb190614bf4565b95508503612bed57603294506000600560008881526020019081526020016000208660338110612be457612be3614add565b5b01540315612c00575b8080612bf890614a95565b9150506129ed565b5080955050505050505b92915050565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60606000612c468585600061327d565b90506000806001600084815260200190815260200160002060008081526020019081526020016000206002015490506000600386612c849190614a3b565b67ffffffffffffffff811115612c9d57612c9c6147f2565b5b604051908082528060200260200182016040528015612ccb5781602001602082028036833780820191505090505b50905060005b86811015612de5576000830315612de5576006600084815260200190815260200160002060030154828580612d0590614a95565b965081518110612d1857612d17614add565b5b6020026020010181815250506006600084815260200190815260200160002060020154828580612d4790614a95565b965081518110612d5a57612d59614add565b5b6020026020010181815250506006600084815260200190815260200160002060040154828580612d8990614a95565b965081518110612d9c57612d9b614add565b5b6020026020010181815250506001600086815260200190815260200160002060008481526020019081526020016000206002015492508080612ddd90614a95565b915050612cd1565b50809450505050509392505050565b60005481565b60606000806000806000805b87518110156130fe57878181518110612e2257612e21614add565b5b602002602001015194506006600086815260200190815260200160002060090160159054906101000a900460ff1695503373ffffffffffffffffffffffffffffffffffffffff166006600087815260200190815260200160002060090160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148015612ed4575060018660ff161480612ed3575060068660ff16145b5b156130c957600660008681526020019081526020016000206002015493506006600086815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1692506006600086815260200190815260200160002060080160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663d9caed128433876040518463ffffffff1660e01b8152600401612fb593929190614bbd565b600060405180830381600087803b158015612fcf57600080fd5b505af1158015612fe3573d6000803e3d6000fd5b50505050426006600087815260200190815260200160002060000181905550600060066000878152602001908152602001600020600201819055506000600660008781526020019081526020016000206004018190555060046006600087815260200190815260200160002060090160156101000a81548160ff021916908360ff16021790555061307f6130798484600061327d565b86613726565b61308b8383338861381b565b61309783833388613ad9565b847f935c9ad2f1fda9d7eae0d2a512f1521cb7190ee06165414e722366a65975fb6b60405160405180910390a26130eb565b60008882815181106130de576130dd614add565b5b6020026020010181815250505b80806130f690614a95565b915050612e06565b508695505050505050919050565b6060600061311b878787613300565b9050600460008281526020019081526020016000206000858152602001908152602001600020600101549350600084036131a157600167ffffffffffffffff81111561316a576131696147f2565b5b6040519080825280602002602001820160405280156131985781602001602082028036833780820191505090505b50915050613274565b6000808467ffffffffffffffff8111156131be576131bd6147f2565b5b6040519080825280602002602001820160405280156131ec5781602001602082028036833780820191505090505b50905060005b8581101561326c57600087031561326c578682848061321090614a95565b95508151811061322357613222614add565b5b602002602001018181525050600460008581526020019081526020016000206000888152602001908152602001600020600101549650808061326490614a95565b9150506131f2565b508093505050505b95945050505050565b600081156132cb578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16106132bf5782846132c2565b83835b80945081955050505b83836040516020016132de929190614d22565b6040516020818303038152906040528051906020012060001c90509392505050565b60008061330f8585600161327d565b90508083604051602001613324929190614d6f565b6040516020818303038152906040528051906020012060001c9150509392505050565b6000806000806000600160008a8152602001908152602001600020600089815260200190815260200160002060000154116133a957600160008981526020019081526020016000206000808152602001908152602001600020600201546133ab565b865b9650600160008981526020019081526020016000206000888152602001908152602001600020600001549150600082036133ee576000600193509350505061371d565b60018560ff160361358d57818610156134db576001600089815260200190815260200160002060008881526020019081526020016000206001015490505b818610156134a6576000810361344a5786600193509350505061371d565b80965060016000898152602001908152602001600020600088815260200190815260200160002060000154915060016000898152602001908152602001600020600088815260200190815260200160002060010154905061342c565b60016000898152602001908152602001600020600088815260200190815260200160002060020154600093509350505061371d565b6001600089815260200190815260200160002060008881526020019081526020016000206002015490505b81861061357f57600081036135235760008093509350505061371d565b809650600160008981526020019081526020016000206000888152602001908152602001600020600001549150600160008981526020019081526020016000206000888152602001908152602001600020600201549050613506565b86600093509350505061371d565b8186111561366f576001600089815260200190815260200160002060008881526020019081526020016000206001015490505b8186111561363a57600081036135de5786600193509350505061371d565b8096506001600089815260200190815260200160002060008881526020019081526020016000206000015491506001600089815260200190815260200160002060008881526020019081526020016000206001015490506135c0565b60016000898152602001908152602001600020600088815260200190815260200160002060020154600093509350505061371d565b6001600089815260200190815260200160002060008881526020019081526020016000206002015490505b81861161371357600081036136b75760008093509350505061371d565b80965060016000898152602001908152602001600020600088815260200190815260200160002060000154915060016000898152602001908152602001600020600088815260200190815260200160002060020154905061369a565b8660009350935050505b94509492505050565b600060016000848152602001908152602001600020600083815260200190815260200160002060010154905060006001600085815260200190815260200160002060008481526020019081526020016000206002015490508160016000868152602001908152602001600020600083815260200190815260200160002060010181905550806001600086815260200190815260200160002060008481526020019081526020016000206002018190555060016000858152602001908152602001600020600084815260200190815260200160002060008082016000905560018201600090556002820160009055505050505050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000206000015490506000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002060010154905081600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000206000018190555080600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002060010181905550600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008481526020019081526020016000206000808201600090556001820160009055505060006139eb878787613300565b9050600360008281526020019081526020016000206000858152602001908152602001600020600001549250600360008281526020019081526020016000206000858152602001908152602001600020600101549150826003600083815260200190815260200160002060008481526020019081526020016000206000018190555081600360008381526020019081526020016000206000858152602001908152602001600020600101819055506003600082815260200190815260200160002060008581526020019081526020016000206000808201600090556001820160009055505050505050505050565b6000613ae6858585613300565b90506000600460008381526020019081526020016000206000808152602001908152602001600020600101549050826004600084815260200190815260200160002060008381526020019081526020016000206000018190555082600460008481526020019081526020016000206000808152602001908152602001600020600101819055508060046000848152602001908152602001600020600085815260200190815260200160002060010181905550505050505050565b6000613bae8484600161327d565b9050600060056000838152602001908152602001600020600060338110613bd857613bd7614add565b5b0154905060328103613be957600090505b80613bf390614a95565b905082600560008481526020019081526020016000208260338110613c1b57613c1a614add565b5b01819055508060056000848152602001908152602001600020600060338110613c4757613c46614add565b5b01819055505050505050565b6000600160008681526020019081526020016000206000858152602001908152602001600020600101549050826001600087815260200190815260200160002060008681526020019081526020016000206001018190555082600160008781526020019081526020016000206000838152602001908152602001600020600201819055506040518060600160405280838152602001828152602001858152506001600087815260200190815260200160002060008581526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050505050505050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080815260200190815260200160002060010154905081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000206000018190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008081526020019081526020016000206001018190555080600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000848152602001908152602001600020600101819055506000613eab868686613300565b9050600360008281526020019081526020016000206000808152602001908152602001600020600101549150826003600083815260200190815260200160002060008481526020019081526020016000206000018190555082600360008381526020019081526020016000206000808152602001908152602001600020600101819055508160036000838152602001908152602001600020600085815260200190815260200160002060010181905550505050505050565b60006004600084815260200190815260200160002060008381526020019081526020016000206000015490506000600460008581526020019081526020016000206000848152602001908152602001600020600101549050816004600086815260200190815260200160002060008381526020019081526020016000206000018190555080600460008681526020019081526020016000206000848152602001908152602001600020600101819055506004600085815260200190815260200160002060008481526020019081526020016000206000808201600090556001820160009055505050505050565b60405180610180016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600060ff168152602001600060ff1681525090565b60405180610160016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6141908161417d565b811461419b57600080fd5b50565b6000813590506141ad81614187565b92915050565b6000602082840312156141c9576141c8614173565b5b60006141d78482850161419e565b91505092915050565b6141e98161417d565b82525050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061421a826141ef565b9050919050565b61422a8161420f565b82525050565b600060ff82169050919050565b61424681614230565b82525050565b6101808201600082015161426360008501826141e0565b50602082015161427660208501826141e0565b50604082015161428960408501826141e0565b50606082015161429c60608501826141e0565b5060808201516142af60808501826141e0565b5060a08201516142c260a08501826141e0565b5060c08201516142d560c08501826141e0565b5060e08201516142e860e0850182614221565b506101008201516142fd610100850182614221565b50610120820151614312610120850182614221565b5061014082015161432761014085018261423d565b5061016082015161433c61016085018261423d565b50505050565b600061018082019050614358600083018461424c565b92915050565b6143678161420f565b82525050565b6000602082019050614382600083018461435e565b92915050565b6143918161420f565b811461439c57600080fd5b50565b6000813590506143ae81614388565b92915050565b600080600080608085870312156143ce576143cd614173565b5b60006143dc8782880161439f565b94505060206143ed8782880161439f565b93505060406143fe8782880161419e565b925050606061440f8782880161419e565b91505092959194509250565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600061445383836141e0565b60208301905092915050565b6000602082019050919050565b60006144778261441b565b6144818185614426565b935061448c83614437565b8060005b838110156144bd5781516144a48882614447565b97506144af8361445f565b925050600181019050614490565b5085935050505092915050565b600060208201905081810360008301526144e4818461446c565b905092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112614511576145106144ec565b5b8235905067ffffffffffffffff81111561452e5761452d6144f1565b5b60208301915083602082028301111561454a576145496144f6565b5b9250929050565b6000806020838503121561456857614567614173565b5b600083013567ffffffffffffffff81111561458657614585614178565b5b614592858286016144fb565b92509250509250929050565b600080600080600060a086880312156145ba576145b9614173565b5b60006145c88882890161439f565b95505060206145d98882890161439f565b94505060406145ea8882890161439f565b93505060606145fb8882890161419e565b925050608061460c8882890161419e565b9150509295509295909350565b600080604083850312156146305761462f614173565b5b600061463e8582860161419e565b925050602061464f8582860161419e565b9150509250929050565b61466281614230565b811461466d57600080fd5b50565b60008135905061467f81614659565b92915050565b6000806000806000806000806000806101408b8d0312156146a9576146a8614173565b5b60006146b78d828e0161439f565b9a505060206146c88d828e0161439f565b99505060406146d98d828e0161419e565b98505060606146ea8d828e0161439f565b97505060806146fb8d828e0161419e565b96505060a061470c8d828e01614670565b95505060c061471d8d828e0161419e565b94505060e061472e8d828e0161419e565b9350506101006147408d828e0161419e565b9250506101206147528d828e0161419e565b9150509295989b9194979a5092959850565b61476d8161417d565b82525050565b60006020820190506147886000830184614764565b92915050565b6000806000606084860312156147a7576147a6614173565b5b60006147b58682870161439f565b93505060206147c68682870161419e565b92505060406147d78682870161419e565b9150509250925092565b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61482a826147e1565b810181811067ffffffffffffffff82111715614849576148486147f2565b5b80604052505050565b600061485c614169565b90506148688282614821565b919050565b600067ffffffffffffffff821115614888576148876147f2565b5b602082029050602081019050919050565b60006148ac6148a78461486d565b614852565b905080838252602082019050602084028301858111156148cf576148ce6144f6565b5b835b818110156148f857806148e4888261419e565b8452602084019350506020810190506148d1565b5050509392505050565b600082601f830112614917576149166144ec565b5b8135614927848260208601614899565b91505092915050565b60006020828403121561494657614945614173565b5b600082013567ffffffffffffffff81111561496457614963614178565b5b61497084828501614902565b91505092915050565b600080604083850312156149905761498f614173565b5b600061499e8582860161439f565b92505060206149af8582860161439f565b9150509250929050565b6000806000606084860312156149d2576149d1614173565b5b60006149e08682870161439f565b93505060206149f18682870161439f565b9250506040614a028682870161419e565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614a468261417d565b9150614a518361417d565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614a8a57614a89614a0c565b5b828202905092915050565b6000614aa08261417d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614ad257614ad1614a0c565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082825260208201905092915050565b7f4f6e6c79206f776e65722063616e2063616c6c20746869732e00000000000000600082015250565b6000614b53601983614b0c565b9150614b5e82614b1d565b602082019050919050565b60006020820190508181036000830152614b8281614b46565b9050919050565b6000614b948261417d565b9150614b9f8361417d565b9250828201905080821115614bb757614bb6614a0c565b5b92915050565b6000606082019050614bd2600083018661435e565b614bdf602083018561435e565b614bec6040830184614764565b949350505050565b6000614bff8261417d565b915060008203614c1257614c11614a0c565b5b600182039050919050565b6000614c288261417d565b9150614c338361417d565b9250828203905081811115614c4b57614c4a614a0c565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000614c8b8261417d565b9150614c968361417d565b925082614ca657614ca5614c51565b5b828204905092915050565b6000604082019050614cc6600083018561435e565b614cd36020830184614764565b9392505050565b60008160601b9050919050565b6000614cf282614cda565b9050919050565b6000614d0482614ce7565b9050919050565b614d1c614d178261420f565b614cf9565b82525050565b6000614d2e8285614d0b565b601482019150614d3e8284614d0b565b6014820191508190509392505050565b6000819050919050565b614d69614d648261417d565b614d4e565b82525050565b6000614d7b8285614d58565b602082019150614d8b8284614d0b565b601482019150819050939250505056fea264697066735822122057d230393a932febfaacac97af53a0cc27e1b2eb184f5d892afb95c4114f2f0264736f6c63430008100033

Deployed ByteCode

0x608060405234801561001057600080fd5b506004361061010b5760003560e01c80636da42a15116100a25780638da5cb5b116100715780638da5cb5b1461032a5780639435298b14610348578063af640d0f14610378578063b55fb57414610396578063e0a31339146103c65761010b565b80636da42a151461026a57806375b024051461029a5780637e9da7a2146102ca578063809741ed146102fa5761010b565b8063334503bf116100de578063334503bf146101aa57806336511013146101da57806347402bea1461020a5780635eb2088e1461023a5761010b565b80630e0578f514610110578063127e11971461014057806318df23881461015e578063299821f61461018e575b600080fd5b61012a600480360381019061012591906141b3565b6103f6565b6040516101379190614342565b60405180910390f35b6101486105a6565b604051610155919061436d565b60405180910390f35b610178600480360381019061017391906143b4565b6105be565b60405161018591906144ca565b60405180910390f35b6101a860048036038101906101a39190614551565b610769565b005b6101c460048036038101906101bf919061459e565b61096b565b6040516101d191906144ca565b60405180910390f35b6101f460048036038101906101ef9190614619565b610c42565b60405161020191906144ca565b60405180910390f35b610224600480360381019061021f9190614685565b611112565b6040516102319190614773565b60405180910390f35b610254600480360381019061024f919061478e565b611dfc565b60405161026191906144ca565b60405180910390f35b610284600480360381019061027f91906141b3565b61225a565b60405161029191906144ca565b60405180910390f35b6102b460048036038101906102af9190614930565b61241d565b6040516102c191906144ca565b60405180910390f35b6102e460048036038101906102df919061459e565b612628565b6040516102f191906144ca565b60405180910390f35b610314600480360381019061030f9190614979565b6128ff565b60405161032191906144ca565b60405180910390f35b610332612c10565b60405161033f919061436d565b60405180910390f35b610362600480360381019061035d91906149b9565b612c36565b60405161036f91906144ca565b60405180910390f35b610380612df4565b60405161038d9190614773565b60405180910390f35b6103b060048036038101906103ab9190614930565b612dfa565b6040516103bd91906144ca565b60405180910390f35b6103e060048036038101906103db919061459e565b61310c565b6040516103ed91906144ca565b60405180910390f35b6103fe614050565b6006600083815260200190815260200160002060405180610180016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016008820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016009820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016009820160149054906101000a900460ff1660ff1660ff1681526020016009820160159054906101000a900460ff1660ff1660ff16815250509050919050565b735cec09f125f4839656164a5109bc076daabd6ed681565b606060006105ce8686600061327d565b90506000600160008381526020019081526020016000206000868152602001908152602001600020600001541161062c576001600082815260200190815260200160002060008081526020019081526020016000206002015461062e565b835b93506000806002856106409190614a3b565b67ffffffffffffffff811115610659576106586147f2565b5b6040519080825280602002602001820160405280156106875781602001602082028036833780820191505090505b50905060005b8581101561075a57600087031561075a57868284806106ab90614a95565b9550815181106106be576106bd614add565b5b602002602001018181525050600160008581526020019081526020016000206000888152602001908152602001600020600001548284806106fe90614a95565b95508151811061071157610710614add565b5b602002602001018181525050600160008581526020019081526020016000206000888152602001908152602001600020600201549650808061075290614a95565b91505061068d565b50809350505050949350505050565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146107f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107f090614b69565b60405180910390fd5b60005b82829050811015610966576008600660008585858181106108205761081f614add565b5b90506020020135815260200190815260200160002060090160159054906101000a900460ff1660ff1603610953576006600084848481811061086557610864614add565b5b9050602002013581526020019081526020016000206000808201600090556001820160009055600282016000905560038201600090556004820160009055600582016000905560068201600090556007820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556008820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556009820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556009820160146101000a81549060ff02191690556009820160156101000a81549060ff021916905550505b808061095e90614a95565b9150506107fc565b505050565b6060600061097a878787613300565b905060036000828152602001908152602001600020600085815260200190815260200160002060010154935060008403610a0057600167ffffffffffffffff8111156109c9576109c86147f2565b5b6040519080825280602002602001820160405280156109f75781602001602082028036833780820191505090505b50915050610c39565b600080600685610a109190614a3b565b67ffffffffffffffff811115610a2957610a286147f2565b5b604051908082528060200260200182016040528015610a575781602001602082028036833780820191505090505b50905060005b85811015610c31576000870315610c315786828480610a7b90614a95565b955081518110610a8e57610a8d614add565b5b6020026020010181815250506006600088815260200190815260200160002060090160149054906101000a900460ff1660ff16828480610acd90614a95565b955081518110610ae057610adf614add565b5b6020026020010181815250506006600088815260200190815260200160002060000154828480610b0f90614a95565b955081518110610b2257610b21614add565b5b6020026020010181815250506006600088815260200190815260200160002060030154828480610b5190614a95565b955081518110610b6457610b63614add565b5b6020026020010181815250506006600088815260200190815260200160002060020154828480610b9390614a95565b955081518110610ba657610ba5614add565b5b6020026020010181815250506006600088815260200190815260200160002060040154828480610bd590614a95565b955081518110610be857610be7614add565b5b6020026020010181815250506003600085815260200190815260200160002060008881526020019081526020016000206001015496508080610c2990614a95565b915050610a5d565b508093505050505b95945050505050565b60606000600467ffffffffffffffff811115610c6157610c606147f2565b5b604051908082528060200260200182016040528015610c8f5781602001602082028036833780820191505090505b5090506000806000806000600660008a815260200190815260200160002060090160159054906101000a900460ff1690506000600660008a815260200190815260200160002060090160159054906101000a900460ff16905060008260ff161115610d6f57600660008b815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600660008c815260200190815260200160002060080160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168095508197505050610de6565b600660008a815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600660008b815260200190815260200160002060080160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1680955081975050505b60018260ff161480610dfb575060068260ff16145b80610e09575060078260ff16145b80610e17575060098260ff16145b15610f1c57600660008b815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603610ed257600660008b81526020019081526020016000206002015485610ea79190614b89565b9450600660008b81526020019081526020016000206006015483610ecb9190614b89565b9250610f1b565b600660008b81526020019081526020016000206002015483610ef49190614b89565b9250600660008b81526020019081526020016000206006015485610f189190614b89565b94505b5b60018160ff161480610f31575060068160ff16145b80610f3f575060078160ff16145b80610f4d575060098160ff16145b1561105257600660008a815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff160361100857600660008a81526020019081526020016000206002015485610fdd9190614b89565b9450600660008a815260200190815260200160002060060154836110019190614b89565b9250611051565b600660008a8152602001908152602001600020600201548361102a9190614b89565b9250600660008a8152602001908152602001600020600601548561104e9190614b89565b94505b5b8573ffffffffffffffffffffffffffffffffffffffff168760008151811061107d5761107c614add565b5b602002602001018181525050848760018151811061109e5761109d614add565b5b6020026020010181815250508373ffffffffffffffffffffffffffffffffffffffff16876002815181106110d5576110d4614add565b5b60200260200101818152505082876003815181106110f6576110f5614add565b5b6020026020010181815250508697505050505050505092915050565b6000735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461116057600080fd5b611168614050565b4281600001818152505089816040018181525050878160800181815250508681610140019060ff16908160ff1681525050858160600181815250508a8160e0019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508881610100019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508b81610120019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600181610160019060ff16908160ff1681525050600080815461126f90614a95565b91905081905550600080549050600061129561128d8e8d600061327d565b888a8c613347565b80925081985050508015611bd5576112ab6140f9565b6112b78c8f600061327d565b81600001818152505060016000826000015181526020019081526020016000206000808152602001908152602001600020600201548160200181815250505b600081602001511115611a0f5760016000826000015181526020019081526020016000206000826020015181526020019081526020016000206000015481604001818152505060018a60ff16036113575780604001518911611a0f57611363565b80604001518910611a0f575b6000860361141057600984610160019060ff16908160ff1681525050735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663d9caed128f86610120015187604001516040518463ffffffff1660e01b81526004016113d993929190614bbd565b600060405180830381600087803b1580156113f357600080fd5b505af1158015611407573d6000803e3d6000fd5b50505050611a0f565b8561141a90614bf4565b9550600660008260200151815260200190815260200160002060040154816060018181525050806060015184604001511061145957806060015161145f565b83604001515b81608001818152505083604001518460800151826080015186604001516114869190614c1d565b6114909190614a3b565b61149a9190614c80565b84608001818152505060008460800151146114b95780608001516114bf565b83604001515b8160a00181815250508060a00151846040018181516114de9190614c1d565b915081815250508060a001518460a0018181516114fb9190614b89565b9150818152505068056bc75e2d63100000878260a0015161151c9190614a3b565b6115269190614c80565b8160c00181815250508060c0015181610100018181516115469190614b89565b91508181525050600660008260200151815260200190815260200160002060090160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681610140019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663d9caed128f8361014001518460c001518560a0015161160b9190614c1d565b6040518463ffffffff1660e01b815260040161162993929190614bbd565b600060405180830381600087803b15801561164357600080fd5b505af1158015611657573d6000803e3d6000fd5b505050508060c001518160a0015161166f9190614c1d565b600660008360200151815260200190815260200160002060060160008282546116989190614b89565b925050819055508060c00151600660008360200151815260200190815260200160002060010160008282546116cd9190614b89565b92505081905550806060015160066000836020015181526020019081526020016000206002015482608001516117039190614a3b565b61170d9190614c80565b8160a001818152505068056bc75e2d63100000878260a001516117309190614a3b565b61173a9190614c80565b8160c00181815250508060a00151600660008360200151815260200190815260200160002060020160008282546117719190614c1d565b925050819055508060800151816060015161178c9190614c1d565b6006600083602001518152602001908152602001600020600401819055508060a00151600660008360200151815260200190815260200160002060050160008282546117d89190614b89565b925050819055508060c0015181610120018181516117f69190614b89565b915081815250508060c001518160a001516118119190614c1d565b8160e0018181516118229190614b89565b915081815250508060c001518160a0015161183d9190614c1d565b8460c00181815161184e9190614b89565b915081815250508060c001518460200181815161186b9190614b89565b915081815250504260066000836020015181526020019081526020016000206000018190555080602001517f271adf7ca5026da9466c7e2ee50294432b6518106821bb0baa27adfbe5203bad60405160405180910390a260006006600083602001518152602001908152602001600020600201540361199d576007600660008360200151815260200190815260200160002060090160156101000a81548160ff021916908360ff16021790555061192a81600001518260200151613726565b61193f8c8f836101400151846020015161381b565b6119548c8f8361014001518460200151613ad9565b6119638c8f8360200151613ba0565b60016000826000015181526020019081526020016000206000808152602001908152602001600020600201548160200181815250506119d1565b60068060008360200151815260200190815260200160002060090160156101000a81548160ff021916908360ff1602179055505b60008460400151036119f657600784610160019060ff16908160ff1681525050611a0f565b600684610160019060ff16908160ff16815250506112f6565b60008160e001511115611aa957735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663d9caed128d8661012001518460e001516040518463ffffffff1660e01b8152600401611a7693929190614bbd565b600060405180830381600087803b158015611a9057600080fd5b505af1158015611aa4573d6000803e3d6000fd5b505050505b60008161010001511115611b3e57735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663fd9be5228f8361010001516040518363ffffffff1660e01b8152600401611b0b929190614cb1565b600060405180830381600087803b158015611b2557600080fd5b505af1158015611b39573d6000803e3d6000fd5b505050505b60008161012001511115611bd357735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663fd9be5228d8361012001516040518363ffffffff1660e01b8152600401611ba0929190614cb1565b600060405180830381600087803b158015611bba57600080fd5b505af1158015611bce573d6000803e3d6000fd5b505050505b505b8260066000848152602001908152602001600020600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c0820151816006015560e08201518160070160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101008201518160080160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160090160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101408201518160090160146101000a81548160ff021916908360ff1602179055506101608201518160090160156101000a81548160ff021916908360ff160217905550905050600183610160015160ff161480611d6c5750600683610160015160ff16145b15611d9e57611d88611d808e8d600061327d565b88848b613c53565b611d998d8c85610120015185613d3e565b611dbb565b611daf8d8c85610120015185613ad9565b611dba8d8c84613ba0565b5b817f2f539bcf68b0eef24f9fef1ae5ad7dd5a37f80a2fab34f406ad2b92c779d606460405160405180910390a28193505050509a9950505050505050505050565b6060600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002060010154925060008303611ead57600167ffffffffffffffff811115611e7757611e766147f2565b5b604051908082528060200260200182016040528015611ea55781602001602082028036833780820191505090505b509050612253565b600080600984611ebd9190614a3b565b67ffffffffffffffff811115611ed657611ed56147f2565b5b604051908082528060200260200182016040528015611f045781602001602082028036833780820191505090505b50905060005b8481101561224c57600086031561224c5785828480611f2890614a95565b955081518110611f3b57611f3a614add565b5b6020026020010181815250506006600087815260200190815260200160002060000154828480611f6a90614a95565b955081518110611f7d57611f7c614add565b5b6020026020010181815250506006600087815260200190815260200160002060030154828480611fac90614a95565b955081518110611fbf57611fbe614add565b5b6020026020010181815250506006600087815260200190815260200160002060020154828480611fee90614a95565b95508151811061200157612000614add565b5b6020026020010181815250506006600087815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1682848061206690614a95565b95508151811061207957612078614add565b5b60200260200101818152505060066000878152602001908152602001600020600401548284806120a890614a95565b9550815181106120bb576120ba614add565b5b6020026020010181815250506006600087815260200190815260200160002060080160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1682848061212090614a95565b95508151811061213357612132614add565b5b6020026020010181815250506006600087815260200190815260200160002060090160149054906101000a900460ff1660ff1682848061217290614a95565b95508151811061218557612184614add565b5b6020026020010181815250506006600087815260200190815260200160002060090160159054906101000a900460ff1660ff168284806121c490614a95565b9550815181106121d7576121d6614add565b5b602002602001018181525050600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000878152602001908152602001600020600101549550808061224490614a95565b915050611f0a565b5080925050505b9392505050565b60606000600667ffffffffffffffff811115612279576122786147f2565b5b6040519080825280602002602001820160405280156122a75781602001602082028036833780820191505090505b5090506006600084815260200190815260200160002060090160159054906101000a900460ff1660ff16816000815181106122e5576122e4614add565b5b6020026020010181815250506006600084815260200190815260200160002060090160149054906101000a900460ff1660ff168160018151811061232c5761232b614add565b5b60200260200101818152505060066000848152602001908152602001600020600201548160028151811061236357612362614add565b5b60200260200101818152505060066000848152602001908152602001600020600401548160038151811061239a57612399614add565b5b6020026020010181815250506006600084815260200190815260200160002060050154816004815181106123d1576123d0614add565b5b60200260200101818152505060066000848152602001908152602001600020600601548160058151811061240857612407614add565b5b60200260200101818152505080915050919050565b606060008060005b845181101561261d5784818151811061244157612440614add565b5b602002602001015191506006600083815260200190815260200160002060090160159054906101000a900460ff1692503373ffffffffffffffffffffffffffffffffffffffff166006600084815260200190815260200160002060090160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148015612501575060048360ff1614806124f2575060078360ff16145b80612500575060098360ff16145b5b156125e8576125866125806006600085815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166006600086815260200190815260200160002060080160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633613300565b83613f63565b60086006600084815260200190815260200160002060090160156101000a81548160ff021916908360ff160217905550817fbd000546857b596b03c884060c13e7d8c7a7ce52366d2f116f76688e6f000f6660405160405180910390a261260a565b60008582815181106125fd576125fc614add565b5b6020026020010181815250505b808061261590614a95565b915050612425565b508392505050919050565b60606000612637878787613300565b9050600460008281526020019081526020016000206000858152602001908152602001600020600101549350600084036126bd57600167ffffffffffffffff811115612686576126856147f2565b5b6040519080825280602002602001820160405280156126b45781602001602082028036833780820191505090505b509150506128f6565b6000806006856126cd9190614a3b565b67ffffffffffffffff8111156126e6576126e56147f2565b5b6040519080825280602002602001820160405280156127145781602001602082028036833780820191505090505b50905060005b858110156128ee5760008703156128ee578682848061273890614a95565b95508151811061274b5761274a614add565b5b6020026020010181815250506006600088815260200190815260200160002060090160149054906101000a900460ff1660ff1682848061278a90614a95565b95508151811061279d5761279c614add565b5b60200260200101818152505060066000888152602001908152602001600020600001548284806127cc90614a95565b9550815181106127df576127de614add565b5b602002602001018181525050600660008881526020019081526020016000206003015482848061280e90614a95565b95508151811061282157612820614add565b5b602002602001018181525050600660008881526020019081526020016000206005015482848061285090614a95565b95508151811061286357612862614add565b5b602002602001018181525050600660008881526020019081526020016000206006015482848061289290614a95565b9550815181106128a5576128a4614add565b5b60200260200101818152505060046000858152602001908152602001600020600088815260200190815260200160002060010154965080806128e690614a95565b91505061271a565b508093505050505b95945050505050565b6060600061290f8484600161327d565b905060006005600083815260200190815260200160002060006033811061293957612938614add565b5b015490506000810361299857600167ffffffffffffffff8111156129605761295f6147f2565b5b60405190808252806020026020018201604052801561298e5781602001602082028036833780820191505090505b5092505050612c0a565b600080600061012c67ffffffffffffffff8111156129b9576129b86147f2565b5b6040519080825280602002602001820160405280156129e75781602001602082028036833780820191505090505b50905060005b6032811015612c0057600560008781526020019081526020016000208560338110612a1b57612a1a614add565b5b0154925082828580612a2c90614a95565b965081518110612a3f57612a3e614add565b5b6020026020010181815250506006600084815260200190815260200160002060090160149054906101000a900460ff1660ff16828580612a7e90614a95565b965081518110612a9157612a90614add565b5b6020026020010181815250506006600084815260200190815260200160002060000154828580612ac090614a95565b965081518110612ad357612ad2614add565b5b6020026020010181815250506006600084815260200190815260200160002060030154828580612b0290614a95565b965081518110612b1557612b14614add565b5b6020026020010181815250506006600084815260200190815260200160002060050154828580612b4490614a95565b965081518110612b5757612b56614add565b5b6020026020010181815250506006600084815260200190815260200160002060060154828580612b8690614a95565b965081518110612b9957612b98614add565b5b602002602001018181525050600085612bb190614bf4565b95508503612bed57603294506000600560008881526020019081526020016000208660338110612be457612be3614add565b5b01540315612c00575b8080612bf890614a95565b9150506129ed565b5080955050505050505b92915050565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60606000612c468585600061327d565b90506000806001600084815260200190815260200160002060008081526020019081526020016000206002015490506000600386612c849190614a3b565b67ffffffffffffffff811115612c9d57612c9c6147f2565b5b604051908082528060200260200182016040528015612ccb5781602001602082028036833780820191505090505b50905060005b86811015612de5576000830315612de5576006600084815260200190815260200160002060030154828580612d0590614a95565b965081518110612d1857612d17614add565b5b6020026020010181815250506006600084815260200190815260200160002060020154828580612d4790614a95565b965081518110612d5a57612d59614add565b5b6020026020010181815250506006600084815260200190815260200160002060040154828580612d8990614a95565b965081518110612d9c57612d9b614add565b5b6020026020010181815250506001600086815260200190815260200160002060008481526020019081526020016000206002015492508080612ddd90614a95565b915050612cd1565b50809450505050509392505050565b60005481565b60606000806000806000805b87518110156130fe57878181518110612e2257612e21614add565b5b602002602001015194506006600086815260200190815260200160002060090160159054906101000a900460ff1695503373ffffffffffffffffffffffffffffffffffffffff166006600087815260200190815260200160002060090160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148015612ed4575060018660ff161480612ed3575060068660ff16145b5b156130c957600660008681526020019081526020016000206002015493506006600086815260200190815260200160002060070160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1692506006600086815260200190815260200160002060080160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150735cec09f125f4839656164a5109bc076daabd6ed673ffffffffffffffffffffffffffffffffffffffff1663d9caed128433876040518463ffffffff1660e01b8152600401612fb593929190614bbd565b600060405180830381600087803b158015612fcf57600080fd5b505af1158015612fe3573d6000803e3d6000fd5b50505050426006600087815260200190815260200160002060000181905550600060066000878152602001908152602001600020600201819055506000600660008781526020019081526020016000206004018190555060046006600087815260200190815260200160002060090160156101000a81548160ff021916908360ff16021790555061307f6130798484600061327d565b86613726565b61308b8383338861381b565b61309783833388613ad9565b847f935c9ad2f1fda9d7eae0d2a512f1521cb7190ee06165414e722366a65975fb6b60405160405180910390a26130eb565b60008882815181106130de576130dd614add565b5b6020026020010181815250505b80806130f690614a95565b915050612e06565b508695505050505050919050565b6060600061311b878787613300565b9050600460008281526020019081526020016000206000858152602001908152602001600020600101549350600084036131a157600167ffffffffffffffff81111561316a576131696147f2565b5b6040519080825280602002602001820160405280156131985781602001602082028036833780820191505090505b50915050613274565b6000808467ffffffffffffffff8111156131be576131bd6147f2565b5b6040519080825280602002602001820160405280156131ec5781602001602082028036833780820191505090505b50905060005b8581101561326c57600087031561326c578682848061321090614a95565b95508151811061322357613222614add565b5b602002602001018181525050600460008581526020019081526020016000206000888152602001908152602001600020600101549650808061326490614a95565b9150506131f2565b508093505050505b95945050505050565b600081156132cb578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16106132bf5782846132c2565b83835b80945081955050505b83836040516020016132de929190614d22565b6040516020818303038152906040528051906020012060001c90509392505050565b60008061330f8585600161327d565b90508083604051602001613324929190614d6f565b6040516020818303038152906040528051906020012060001c9150509392505050565b6000806000806000600160008a8152602001908152602001600020600089815260200190815260200160002060000154116133a957600160008981526020019081526020016000206000808152602001908152602001600020600201546133ab565b865b9650600160008981526020019081526020016000206000888152602001908152602001600020600001549150600082036133ee576000600193509350505061371d565b60018560ff160361358d57818610156134db576001600089815260200190815260200160002060008881526020019081526020016000206001015490505b818610156134a6576000810361344a5786600193509350505061371d565b80965060016000898152602001908152602001600020600088815260200190815260200160002060000154915060016000898152602001908152602001600020600088815260200190815260200160002060010154905061342c565b60016000898152602001908152602001600020600088815260200190815260200160002060020154600093509350505061371d565b6001600089815260200190815260200160002060008881526020019081526020016000206002015490505b81861061357f57600081036135235760008093509350505061371d565b809650600160008981526020019081526020016000206000888152602001908152602001600020600001549150600160008981526020019081526020016000206000888152602001908152602001600020600201549050613506565b86600093509350505061371d565b8186111561366f576001600089815260200190815260200160002060008881526020019081526020016000206001015490505b8186111561363a57600081036135de5786600193509350505061371d565b8096506001600089815260200190815260200160002060008881526020019081526020016000206000015491506001600089815260200190815260200160002060008881526020019081526020016000206001015490506135c0565b60016000898152602001908152602001600020600088815260200190815260200160002060020154600093509350505061371d565b6001600089815260200190815260200160002060008881526020019081526020016000206002015490505b81861161371357600081036136b75760008093509350505061371d565b80965060016000898152602001908152602001600020600088815260200190815260200160002060000154915060016000898152602001908152602001600020600088815260200190815260200160002060020154905061369a565b8660009350935050505b94509492505050565b600060016000848152602001908152602001600020600083815260200190815260200160002060010154905060006001600085815260200190815260200160002060008481526020019081526020016000206002015490508160016000868152602001908152602001600020600083815260200190815260200160002060010181905550806001600086815260200190815260200160002060008481526020019081526020016000206002018190555060016000858152602001908152602001600020600084815260200190815260200160002060008082016000905560018201600090556002820160009055505050505050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000206000015490506000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002060010154905081600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000206000018190555080600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002060010181905550600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008481526020019081526020016000206000808201600090556001820160009055505060006139eb878787613300565b9050600360008281526020019081526020016000206000858152602001908152602001600020600001549250600360008281526020019081526020016000206000858152602001908152602001600020600101549150826003600083815260200190815260200160002060008481526020019081526020016000206000018190555081600360008381526020019081526020016000206000858152602001908152602001600020600101819055506003600082815260200190815260200160002060008581526020019081526020016000206000808201600090556001820160009055505050505050505050565b6000613ae6858585613300565b90506000600460008381526020019081526020016000206000808152602001908152602001600020600101549050826004600084815260200190815260200160002060008381526020019081526020016000206000018190555082600460008481526020019081526020016000206000808152602001908152602001600020600101819055508060046000848152602001908152602001600020600085815260200190815260200160002060010181905550505050505050565b6000613bae8484600161327d565b9050600060056000838152602001908152602001600020600060338110613bd857613bd7614add565b5b0154905060328103613be957600090505b80613bf390614a95565b905082600560008481526020019081526020016000208260338110613c1b57613c1a614add565b5b01819055508060056000848152602001908152602001600020600060338110613c4757613c46614add565b5b01819055505050505050565b6000600160008681526020019081526020016000206000858152602001908152602001600020600101549050826001600087815260200190815260200160002060008681526020019081526020016000206001018190555082600160008781526020019081526020016000206000838152602001908152602001600020600201819055506040518060600160405280838152602001828152602001858152506001600087815260200190815260200160002060008581526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050505050505050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600080815260200190815260200160002060010154905081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000206000018190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008081526020019081526020016000206001018190555080600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000848152602001908152602001600020600101819055506000613eab868686613300565b9050600360008281526020019081526020016000206000808152602001908152602001600020600101549150826003600083815260200190815260200160002060008481526020019081526020016000206000018190555082600360008381526020019081526020016000206000808152602001908152602001600020600101819055508160036000838152602001908152602001600020600085815260200190815260200160002060010181905550505050505050565b60006004600084815260200190815260200160002060008381526020019081526020016000206000015490506000600460008581526020019081526020016000206000848152602001908152602001600020600101549050816004600086815260200190815260200160002060008381526020019081526020016000206000018190555080600460008681526020019081526020016000206000848152602001908152602001600020600101819055506004600085815260200190815260200160002060008481526020019081526020016000206000808201600090556001820160009055505050505050565b60405180610180016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600060ff168152602001600060ff1681525090565b60405180610160016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6141908161417d565b811461419b57600080fd5b50565b6000813590506141ad81614187565b92915050565b6000602082840312156141c9576141c8614173565b5b60006141d78482850161419e565b91505092915050565b6141e98161417d565b82525050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061421a826141ef565b9050919050565b61422a8161420f565b82525050565b600060ff82169050919050565b61424681614230565b82525050565b6101808201600082015161426360008501826141e0565b50602082015161427660208501826141e0565b50604082015161428960408501826141e0565b50606082015161429c60608501826141e0565b5060808201516142af60808501826141e0565b5060a08201516142c260a08501826141e0565b5060c08201516142d560c08501826141e0565b5060e08201516142e860e0850182614221565b506101008201516142fd610100850182614221565b50610120820151614312610120850182614221565b5061014082015161432761014085018261423d565b5061016082015161433c61016085018261423d565b50505050565b600061018082019050614358600083018461424c565b92915050565b6143678161420f565b82525050565b6000602082019050614382600083018461435e565b92915050565b6143918161420f565b811461439c57600080fd5b50565b6000813590506143ae81614388565b92915050565b600080600080608085870312156143ce576143cd614173565b5b60006143dc8782880161439f565b94505060206143ed8782880161439f565b93505060406143fe8782880161419e565b925050606061440f8782880161419e565b91505092959194509250565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600061445383836141e0565b60208301905092915050565b6000602082019050919050565b60006144778261441b565b6144818185614426565b935061448c83614437565b8060005b838110156144bd5781516144a48882614447565b97506144af8361445f565b925050600181019050614490565b5085935050505092915050565b600060208201905081810360008301526144e4818461446c565b905092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112614511576145106144ec565b5b8235905067ffffffffffffffff81111561452e5761452d6144f1565b5b60208301915083602082028301111561454a576145496144f6565b5b9250929050565b6000806020838503121561456857614567614173565b5b600083013567ffffffffffffffff81111561458657614585614178565b5b614592858286016144fb565b92509250509250929050565b600080600080600060a086880312156145ba576145b9614173565b5b60006145c88882890161439f565b95505060206145d98882890161439f565b94505060406145ea8882890161439f565b93505060606145fb8882890161419e565b925050608061460c8882890161419e565b9150509295509295909350565b600080604083850312156146305761462f614173565b5b600061463e8582860161419e565b925050602061464f8582860161419e565b9150509250929050565b61466281614230565b811461466d57600080fd5b50565b60008135905061467f81614659565b92915050565b6000806000806000806000806000806101408b8d0312156146a9576146a8614173565b5b60006146b78d828e0161439f565b9a505060206146c88d828e0161439f565b99505060406146d98d828e0161419e565b98505060606146ea8d828e0161439f565b97505060806146fb8d828e0161419e565b96505060a061470c8d828e01614670565b95505060c061471d8d828e0161419e565b94505060e061472e8d828e0161419e565b9350506101006147408d828e0161419e565b9250506101206147528d828e0161419e565b9150509295989b9194979a5092959850565b61476d8161417d565b82525050565b60006020820190506147886000830184614764565b92915050565b6000806000606084860312156147a7576147a6614173565b5b60006147b58682870161439f565b93505060206147c68682870161419e565b92505060406147d78682870161419e565b9150509250925092565b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61482a826147e1565b810181811067ffffffffffffffff82111715614849576148486147f2565b5b80604052505050565b600061485c614169565b90506148688282614821565b919050565b600067ffffffffffffffff821115614888576148876147f2565b5b602082029050602081019050919050565b60006148ac6148a78461486d565b614852565b905080838252602082019050602084028301858111156148cf576148ce6144f6565b5b835b818110156148f857806148e4888261419e565b8452602084019350506020810190506148d1565b5050509392505050565b600082601f830112614917576149166144ec565b5b8135614927848260208601614899565b91505092915050565b60006020828403121561494657614945614173565b5b600082013567ffffffffffffffff81111561496457614963614178565b5b61497084828501614902565b91505092915050565b600080604083850312156149905761498f614173565b5b600061499e8582860161439f565b92505060206149af8582860161439f565b9150509250929050565b6000806000606084860312156149d2576149d1614173565b5b60006149e08682870161439f565b93505060206149f18682870161439f565b9250506040614a028682870161419e565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614a468261417d565b9150614a518361417d565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614a8a57614a89614a0c565b5b828202905092915050565b6000614aa08261417d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614ad257614ad1614a0c565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082825260208201905092915050565b7f4f6e6c79206f776e65722063616e2063616c6c20746869732e00000000000000600082015250565b6000614b53601983614b0c565b9150614b5e82614b1d565b602082019050919050565b60006020820190508181036000830152614b8281614b46565b9050919050565b6000614b948261417d565b9150614b9f8361417d565b9250828201905080821115614bb757614bb6614a0c565b5b92915050565b6000606082019050614bd2600083018661435e565b614bdf602083018561435e565b614bec6040830184614764565b949350505050565b6000614bff8261417d565b915060008203614c1257614c11614a0c565b5b600182039050919050565b6000614c288261417d565b9150614c338361417d565b9250828203905081811115614c4b57614c4a614a0c565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000614c8b8261417d565b9150614c968361417d565b925082614ca657614ca5614c51565b5b828204905092915050565b6000604082019050614cc6600083018561435e565b614cd36020830184614764565b9392505050565b60008160601b9050919050565b6000614cf282614cda565b9050919050565b6000614d0482614ce7565b9050919050565b614d1c614d178261420f565b614cf9565b82525050565b6000614d2e8285614d0b565b601482019150614d3e8284614d0b565b6014820191508190509392505050565b6000819050919050565b614d69614d648261417d565b614d4e565b82525050565b6000614d7b8285614d58565b602082019150614d8b8284614d0b565b601482019150819050939250505056fea264697066735822122057d230393a932febfaacac97af53a0cc27e1b2eb184f5d892afb95c4114f2f0264736f6c63430008100033