ETH Price: $1,956.12 (+7.75%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Token Escape71717002019-02-04 4:37:482578 days ago1549255068IN
0xeC7d564E...3A76D78B3
0 ETH0.0012669841
Token Escape71716912019-02-04 4:35:362578 days ago1549254936IN
0xeC7d564E...3A76D78B3
0 ETH0.0022736141
__callback71695992019-02-03 18:28:282578 days ago1549218508IN
0xeC7d564E...3A76D78B3
0 ETH0.00096528
__callback71690392019-02-03 15:36:542578 days ago1549208214IN
0xeC7d564E...3A76D78B3
0 ETH0.00108528
Change Gas71689682019-02-03 15:14:402578 days ago1549206880IN
0xeC7d564E...3A76D78B3
0 ETH0.00031238
__callback71681572019-02-03 11:07:122579 days ago1549192032IN
0xeC7d564E...3A76D78B3
0 ETH0.00081396
__callback71670662019-02-03 5:33:082579 days ago1549171988IN
0xeC7d564E...3A76D78B3
0 ETH0.001165666
__callback71670652019-02-03 5:32:582579 days ago1549171978IN
0xeC7d564E...3A76D78B3
0 ETH0.000627886
__callback71668562019-02-03 4:30:532579 days ago1549168253IN
0xeC7d564E...3A76D78B3
0 ETH0.00073596
Change Gas71667162019-02-03 3:54:452579 days ago1549166085IN
0xeC7d564E...3A76D78B3
0 ETH0.000234226
Change Gas71666402019-02-03 3:35:032579 days ago1549164903IN
0xeC7d564E...3A76D78B3
0 ETH0.0004684512
__callback71658822019-02-02 23:47:422579 days ago1549151262IN
0xeC7d564E...3A76D78B3
0 ETH0.001079738
__callback71639852019-02-02 14:42:552579 days ago1549118575IN
0xeC7d564E...3A76D78B3
0 ETH0.000787378
Change Gas71611482019-02-02 0:54:362580 days ago1549068876IN
0xeC7d564E...3A76D78B3
0 ETH0.00031238
Change Gas71596312019-02-01 17:23:142580 days ago1549041794IN
0xeC7d564E...3A76D78B3
0 ETH0.000234226
Change Gas71594932019-02-01 16:43:592580 days ago1549039439IN
0xeC7d564E...3A76D78B3
0 ETH0.0004301211.0002
Change Gas71594442019-02-01 16:26:042580 days ago1549038364IN
0xeC7d564E...3A76D78B3
0 ETH0.0006432216.45
Change Gas71593992019-02-01 16:13:262580 days ago1549037606IN
0xeC7d564E...3A76D78B3
0 ETH0.0005074913
Change Gas71593742019-02-01 16:03:372580 days ago1549037017IN
0xeC7d564E...3A76D78B3
0 ETH0.000288887.4
Change Gas71592742019-02-01 15:33:572580 days ago1549035237IN
0xeC7d564E...3A76D78B3
0 ETH0.0005074913
Change Gas71592432019-02-01 15:23:212580 days ago1549034601IN
0xeC7d564E...3A76D78B3
0 ETH0.0004223110.800396
Change Gas71592122019-02-01 15:13:262580 days ago1549034006IN
0xeC7d564E...3A76D78B3
0 ETH0.000329988.4390546
Change Gas71591772019-02-01 15:03:072580 days ago1549033387IN
0xeC7d564E...3A76D78B3
0 ETH0.000273267
Change Gas71579732019-02-01 9:05:232581 days ago1549011923IN
0xeC7d564E...3A76D78B3
0 ETH0.00031238
Change Gas71579342019-02-01 8:55:532581 days ago1549011353IN
0xeC7d564E...3A76D78B3
0 ETH0.000234226
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
-71717002019-02-04 4:37:482578 days ago1549255068
0xeC7d564E...3A76D78B3
1.80400715 ETH
-71716912019-02-04 4:35:362578 days ago1549254936
0xeC7d564E...3A76D78B3
1 wei
-71695962019-02-03 18:27:342578 days ago1549218454
0xeC7d564E...3A76D78B3
0.00198257 ETH
-71690352019-02-03 15:36:072578 days ago1549208167
0xeC7d564E...3A76D78B3
0.00198257 ETH
-71681522019-02-03 11:04:542579 days ago1549191894
0xeC7d564E...3A76D78B3
0.00160257 ETH
-71670642019-02-03 5:32:522579 days ago1549171972
0xeC7d564E...3A76D78B3
0.00208257 ETH
-71670622019-02-03 5:32:032579 days ago1549171923
0xeC7d564E...3A76D78B3
0.00160257 ETH
-71668532019-02-03 4:30:212579 days ago1549168221
0xeC7d564E...3A76D78B3
0.00184257 ETH
-71658372019-02-02 23:35:482579 days ago1549150548
0xeC7d564E...3A76D78B3
0.00198257 ETH
-71639822019-02-02 14:41:382579 days ago1549118498
0xeC7d564E...3A76D78B3
0.00227327 ETH
-71550832019-01-31 18:58:422581 days ago1548961122
0xeC7d564E...3A76D78B3
0.00233327 ETH
-71219332019-01-25 2:41:222588 days ago1548384082
0xeC7d564E...3A76D78B3
0.00227327 ETH
-71218922019-01-25 2:27:052588 days ago1548383225
0xeC7d564E...3A76D78B3
0.00195327 ETH
-71194772019-01-24 15:10:252588 days ago1548342625
0xeC7d564E...3A76D78B3
0.00195327 ETH
-71156172019-01-23 21:01:382589 days ago1548277298
0xeC7d564E...3A76D78B3
0.00216037 ETH
-71154432019-01-23 20:12:242589 days ago1548274344
0xeC7d564E...3A76D78B3
0.00216037 ETH
-71151132019-01-23 18:31:542589 days ago1548268314
0xeC7d564E...3A76D78B3
0.00216037 ETH
-71150572019-01-23 18:18:252589 days ago1548267505
0xeC7d564E...3A76D78B3
0.00216037 ETH
-71137552019-01-23 12:12:112590 days ago1548245531
0xeC7d564E...3A76D78B3
0.00195327 ETH
-71137382019-01-23 12:08:322590 days ago1548245312
0xeC7d564E...3A76D78B3
0.00195327 ETH
-71137092019-01-23 12:01:472590 days ago1548244907
0xeC7d564E...3A76D78B3
0.00227327 ETH
-71136942019-01-23 11:58:232590 days ago1548244703
0xeC7d564E...3A76D78B3
0.00227327 ETH
-71136692019-01-23 11:50:172590 days ago1548244217
0xeC7d564E...3A76D78B3
0.00157327 ETH
-71136622019-01-23 11:46:192590 days ago1548243979
0xeC7d564E...3A76D78B3
0.00181327 ETH
-71136602019-01-23 11:45:422590 days ago1548243942
0xeC7d564E...3A76D78B3
0.00157327 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Investment

Compiler Version
v0.4.25+commit.59dbf8f1

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
/**
 *Submitted for verification at Etherscan.io on 2019-01-17
*/

pragma solidity 0.4.25;

/*
 * @title String & slice utility library for Solidity contracts.
 * @author Nick Johnson <arachnid@notdot.net>
 *
 * @dev Functionality in this library is largely implemented using an
 *      abstraction called a 'slice'. A slice represents a part of a string -
 *      anything from the entire string to a single character, or even no
 *      characters at all (a 0-length slice). Since a slice only has to specify
 *      an offset and a length, copying and manipulating slices is a lot less
 *      expensive than copying and manipulating the strings they reference.
 *
 *      To further reduce gas costs, most functions on slice that need to return
 *      a slice modify the original one instead of allocating a new one; for
 *      instance, `s.split(".")` will return the text up to the first '.',
 *      modifying s to only contain the remainder of the string after the '.'.
 *      In situations where you do not want to modify the original slice, you
 *      can make a copy first with `.copy()`, for example:
 *      `s.copy().split(".")`. Try and avoid using this idiom in loops; since
 *      Solidity has no memory management, it will result in allocating many
 *      short-lived slices that are later discarded.
 *
 *      Functions that return two slices come in two versions: a non-allocating
 *      version that takes the second slice as an argument, modifying it in
 *      place, and an allocating version that allocates and returns the second
 *      slice; see `nextRune` for example.
 *
 *      Functions that have to copy string data will return strings rather than
 *      slices; these can be cast back to slices for further processing if
 *      required.
 *
 *      For convenience, some functions are provided with non-modifying
 *      variants that create a new slice and return both; for instance,
 *      `s.splitNew('.')` leaves s unmodified, and returns two values
 *      corresponding to the left and right parts of the string.
 */

pragma solidity 0.4.25;

library strings {
    struct slice {
        uint _len;
        uint _ptr;
    }

    function memcpy(uint dest, uint src, uint len) private pure {
        // Copy word-length chunks while possible
        for(; len >= 32; len -= 32) {
            assembly {
                mstore(dest, mload(src))
            }
            dest += 32;
            src += 32;
        }

        // Copy remaining bytes
        uint mask = 256 ** (32 - len) - 1;
        assembly {
            let srcpart := and(mload(src), not(mask))
            let destpart := and(mload(dest), mask)
            mstore(dest, or(destpart, srcpart))
        }
    }

    /*
     * @dev Returns a slice containing the entire string.
     * @param self The string to make a slice from.
     * @return A newly allocated slice containing the entire string.
     */
    function toSlice(string self) internal pure returns (slice) {
        uint ptr;
        assembly {
            ptr := add(self, 0x20)
        }
        return slice(bytes(self).length, ptr);
    }

    /*
     * @dev Returns the length of a null-terminated bytes32 string.
     * @param self The value to find the length of.
     * @return The length of the string, from 0 to 32.
     */
    function len(bytes32 self) internal pure returns (uint) {
        uint ret;
        if (self == 0)
            return 0;
        if (self & 0xffffffffffffffffffffffffffffffff == 0) {
            ret += 16;
            self = bytes32(uint(self) / 0x100000000000000000000000000000000);
        }
        if (self & 0xffffffffffffffff == 0) {
            ret += 8;
            self = bytes32(uint(self) / 0x10000000000000000);
        }
        if (self & 0xffffffff == 0) {
            ret += 4;
            self = bytes32(uint(self) / 0x100000000);
        }
        if (self & 0xffff == 0) {
            ret += 2;
            self = bytes32(uint(self) / 0x10000);
        }
        if (self & 0xff == 0) {
            ret += 1;
        }
        return 32 - ret;
    }

    /*
     * @dev Returns a slice containing the entire bytes32, interpreted as a
     *      null-terminated utf-8 string.
     * @param self The bytes32 value to convert to a slice.
     * @return A new slice containing the value of the input argument up to the
     *         first null.
     */
    function toSliceB32(bytes32 self) internal pure returns (slice ret) {
        // Allocate space for `self` in memory, copy it there, and point ret at it
        assembly {
            let ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x20))
            mstore(ptr, self)
            mstore(add(ret, 0x20), ptr)
        }
        ret._len = len(self);
    }

    /*
     * @dev Returns a new slice containing the same data as the current slice.
     * @param self The slice to copy.
     * @return A new slice containing the same data as `self`.
     */
    function copy(slice self) internal pure returns (slice) {
        return slice(self._len, self._ptr);
    }

    /*
     * @dev Copies a slice to a new string.
     * @param self The slice to copy.
     * @return A newly allocated string containing the slice's text.
     */
    function toString(slice self) internal pure returns (string) {
        string memory ret = new string(self._len);
        uint retptr;
        assembly { retptr := add(ret, 32) }

        memcpy(retptr, self._ptr, self._len);
        return ret;
    }

    /*
     * @dev Returns the length in runes of the slice. Note that this operation
     *      takes time proportional to the length of the slice; avoid using it
     *      in loops, and call `slice.empty()` if you only need to know whether
     *      the slice is empty or not.
     * @param self The slice to operate on.
     * @return The length of the slice in runes.
     */
    function len(slice self) internal pure returns (uint l) {
        // Starting at ptr-31 means the LSB will be the byte we care about
        uint ptr = self._ptr - 31;
        uint end = ptr + self._len;
        for (l = 0; ptr < end; l++) {
            uint8 b;
            assembly { b := and(mload(ptr), 0xFF) }
            if (b < 0x80) {
                ptr += 1;
            } else if(b < 0xE0) {
                ptr += 2;
            } else if(b < 0xF0) {
                ptr += 3;
            } else if(b < 0xF8) {
                ptr += 4;
            } else if(b < 0xFC) {
                ptr += 5;
            } else {
                ptr += 6;
            }
        }
    }

    /*
     * @dev Returns true if the slice is empty (has a length of 0).
     * @param self The slice to operate on.
     * @return True if the slice is empty, False otherwise.
     */
    function empty(slice self) internal pure returns (bool) {
        return self._len == 0;
    }

    /*
     * @dev Returns a positive number if `other` comes lexicographically after
     *      `self`, a negative number if it comes before, or zero if the
     *      contents of the two slices are equal. Comparison is done per-rune,
     *      on unicode codepoints.
     * @param self The first slice to compare.
     * @param other The second slice to compare.
     * @return The result of the comparison.
     */
    function compare(slice self, slice other) internal pure returns (int) {
        uint shortest = self._len;
        if (other._len < self._len)
            shortest = other._len;

        uint selfptr = self._ptr;
        uint otherptr = other._ptr;
        for (uint idx = 0; idx < shortest; idx += 32) {
            uint a;
            uint b;
            assembly {
                a := mload(selfptr)
                b := mload(otherptr)
            }
            if (a != b) {
                // Mask out irrelevant bytes and check again
                uint256 mask = uint256(-1); // 0xffff...
                if(shortest < 32) {
                  mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);
                }
                uint256 diff = (a & mask) - (b & mask);
                if (diff != 0)
                    return int(diff);
            }
            selfptr += 32;
            otherptr += 32;
        }
        return int(self._len) - int(other._len);
    }

    /*
     * @dev Returns true if the two slices contain the same text.
     * @param self The first slice to compare.
     * @param self The second slice to compare.
     * @return True if the slices are equal, false otherwise.
     */
    function equals(slice self, slice other) internal pure returns (bool) {
        return compare(self, other) == 0;
    }

    /*
     * @dev Extracts the first rune in the slice into `rune`, advancing the
     *      slice to point to the next rune and returning `self`.
     * @param self The slice to operate on.
     * @param rune The slice that will contain the first rune.
     * @return `rune`.
     */
    function nextRune(slice self, slice rune) internal pure returns (slice) {
        rune._ptr = self._ptr;

        if (self._len == 0) {
            rune._len = 0;
            return rune;
        }

        uint l;
        uint b;
        // Load the first byte of the rune into the LSBs of b
        assembly { b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF) }
        if (b < 0x80) {
            l = 1;
        } else if(b < 0xE0) {
            l = 2;
        } else if(b < 0xF0) {
            l = 3;
        } else {
            l = 4;
        }

        // Check for truncated codepoints
        if (l > self._len) {
            rune._len = self._len;
            self._ptr += self._len;
            self._len = 0;
            return rune;
        }

        self._ptr += l;
        self._len -= l;
        rune._len = l;
        return rune;
    }

    /*
     * @dev Returns the first rune in the slice, advancing the slice to point
     *      to the next rune.
     * @param self The slice to operate on.
     * @return A slice containing only the first rune from `self`.
     */
    function nextRune(slice self) internal pure returns (slice ret) {
        nextRune(self, ret);
    }

    /*
     * @dev Returns the number of the first codepoint in the slice.
     * @param self The slice to operate on.
     * @return The number of the first codepoint in the slice.
     */
    function ord(slice self) internal pure returns (uint ret) {
        if (self._len == 0) {
            return 0;
        }

        uint word;
        uint length;
        uint divisor = 2 ** 248;

        // Load the rune into the MSBs of b
        assembly { word:= mload(mload(add(self, 32))) }
        uint b = word / divisor;
        if (b < 0x80) {
            ret = b;
            length = 1;
        } else if(b < 0xE0) {
            ret = b & 0x1F;
            length = 2;
        } else if(b < 0xF0) {
            ret = b & 0x0F;
            length = 3;
        } else {
            ret = b & 0x07;
            length = 4;
        }

        // Check for truncated codepoints
        if (length > self._len) {
            return 0;
        }

        for (uint i = 1; i < length; i++) {
            divisor = divisor / 256;
            b = (word / divisor) & 0xFF;
            if (b & 0xC0 != 0x80) {
                // Invalid UTF-8 sequence
                return 0;
            }
            ret = (ret * 64) | (b & 0x3F);
        }

        return ret;
    }

    /*
     * @dev Returns the keccak-256 hash of the slice.
     * @param self The slice to hash.
     * @return The hash of the slice.
     */
    function keccak(slice self) internal pure returns (bytes32 ret) {
        assembly {
            ret := keccak256(mload(add(self, 32)), mload(self))
        }
    }

    /*
     * @dev Returns true if `self` starts with `needle`.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return True if the slice starts with the provided text, false otherwise.
     */
    function startsWith(slice self, slice needle) internal pure returns (bool) {
        if (self._len < needle._len) {
            return false;
        }

        if (self._ptr == needle._ptr) {
            return true;
        }

        bool equal;
        assembly {
            let length := mload(needle)
            let selfptr := mload(add(self, 0x20))
            let needleptr := mload(add(needle, 0x20))
            equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
        }
        return equal;
    }

    /*
     * @dev If `self` starts with `needle`, `needle` is removed from the
     *      beginning of `self`. Otherwise, `self` is unmodified.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return `self`
     */
    function beyond(slice self, slice needle) internal pure returns (slice) {
        if (self._len < needle._len) {
            return self;
        }

        bool equal = true;
        if (self._ptr != needle._ptr) {
            assembly {
                let length := mload(needle)
                let selfptr := mload(add(self, 0x20))
                let needleptr := mload(add(needle, 0x20))
                equal := eq(sha3(selfptr, length), sha3(needleptr, length))
            }
        }

        if (equal) {
            self._len -= needle._len;
            self._ptr += needle._len;
        }

        return self;
    }

    /*
     * @dev Returns true if the slice ends with `needle`.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return True if the slice starts with the provided text, false otherwise.
     */
    function endsWith(slice self, slice needle) internal pure returns (bool) {
        if (self._len < needle._len) {
            return false;
        }

        uint selfptr = self._ptr + self._len - needle._len;

        if (selfptr == needle._ptr) {
            return true;
        }

        bool equal;
        assembly {
            let length := mload(needle)
            let needleptr := mload(add(needle, 0x20))
            equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
        }

        return equal;
    }

    /*
     * @dev If `self` ends with `needle`, `needle` is removed from the
     *      end of `self`. Otherwise, `self` is unmodified.
     * @param self The slice to operate on.
     * @param needle The slice to search for.
     * @return `self`
     */
    function until(slice self, slice needle) internal pure returns (slice) {
        if (self._len < needle._len) {
            return self;
        }

        uint selfptr = self._ptr + self._len - needle._len;
        bool equal = true;
        if (selfptr != needle._ptr) {
            assembly {
                let length := mload(needle)
                let needleptr := mload(add(needle, 0x20))
                equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
            }
        }

        if (equal) {
            self._len -= needle._len;
        }

        return self;
    }

    event log_bytemask(bytes32 mask);

    // Returns the memory address of the first byte of the first occurrence of
    // `needle` in `self`, or the first byte after `self` if not found.
    function findPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) {
        uint ptr = selfptr;
        uint idx;

        if (needlelen <= selflen) {
            if (needlelen <= 32) {
                bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1));

                bytes32 needledata;
                assembly { needledata := and(mload(needleptr), mask) }

                uint end = selfptr + selflen - needlelen;
                bytes32 ptrdata;
                assembly { ptrdata := and(mload(ptr), mask) }

                while (ptrdata != needledata) {
                    if (ptr >= end)
                        return selfptr + selflen;
                    ptr++;
                    assembly { ptrdata := and(mload(ptr), mask) }
                }
                return ptr;
            } else {
                // For long needles, use hashing
                bytes32 hash;
                assembly { hash := sha3(needleptr, needlelen) }

                for (idx = 0; idx <= selflen - needlelen; idx++) {
                    bytes32 testHash;
                    assembly { testHash := sha3(ptr, needlelen) }
                    if (hash == testHash)
                        return ptr;
                    ptr += 1;
                }
            }
        }
        return selfptr + selflen;
    }

    // Returns the memory address of the first byte after the last occurrence of
    // `needle` in `self`, or the address of `self` if not found.
    function rfindPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) {
        uint ptr;

        if (needlelen <= selflen) {
            if (needlelen <= 32) {
                bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1));

                bytes32 needledata;
                assembly { needledata := and(mload(needleptr), mask) }

                ptr = selfptr + selflen - needlelen;
                bytes32 ptrdata;
                assembly { ptrdata := and(mload(ptr), mask) }

                while (ptrdata != needledata) {
                    if (ptr <= selfptr)
                        return selfptr;
                    ptr--;
                    assembly { ptrdata := and(mload(ptr), mask) }
                }
                return ptr + needlelen;
            } else {
                // For long needles, use hashing
                bytes32 hash;
                assembly { hash := sha3(needleptr, needlelen) }
                ptr = selfptr + (selflen - needlelen);
                while (ptr >= selfptr) {
                    bytes32 testHash;
                    assembly { testHash := sha3(ptr, needlelen) }
                    if (hash == testHash)
                        return ptr + needlelen;
                    ptr -= 1;
                }
            }
        }
        return selfptr;
    }

    /*
     * @dev Modifies `self` to contain everything from the first occurrence of
     *      `needle` to the end of the slice. `self` is set to the empty slice
     *      if `needle` is not found.
     * @param self The slice to search and modify.
     * @param needle The text to search for.
     * @return `self`.
     */
    function find(slice self, slice needle) internal pure returns (slice) {
        uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
        self._len -= ptr - self._ptr;
        self._ptr = ptr;
        return self;
    }

    /*
     * @dev Modifies `self` to contain the part of the string from the start of
     *      `self` to the end of the first occurrence of `needle`. If `needle`
     *      is not found, `self` is set to the empty slice.
     * @param self The slice to search and modify.
     * @param needle The text to search for.
     * @return `self`.
     */
    function rfind(slice self, slice needle) internal pure returns (slice) {
        uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
        self._len = ptr - self._ptr;
        return self;
    }

    /*
     * @dev Splits the slice, setting `self` to everything after the first
     *      occurrence of `needle`, and `token` to everything before it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and `token` is set to the entirety of `self`.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @param token An output parameter to which the first token is written.
     * @return `token`.
     */
    function split(slice self, slice needle, slice token) internal pure returns (slice) {
        uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
        token._ptr = self._ptr;
        token._len = ptr - self._ptr;
        if (ptr == self._ptr + self._len) {
            // Not found
            self._len = 0;
        } else {
            self._len -= token._len + needle._len;
            self._ptr = ptr + needle._len;
        }
        return token;
    }

    /*
     * @dev Splits the slice, setting `self` to everything after the first
     *      occurrence of `needle`, and returning everything before it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and the entirety of `self` is returned.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @return The part of `self` up to the first occurrence of `delim`.
     */
    function split(slice self, slice needle) internal pure returns (slice token) {
        split(self, needle, token);
    }

    /*
     * @dev Splits the slice, setting `self` to everything before the last
     *      occurrence of `needle`, and `token` to everything after it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and `token` is set to the entirety of `self`.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @param token An output parameter to which the first token is written.
     * @return `token`.
     */
    function rsplit(slice self, slice needle, slice token) internal pure returns (slice) {
        uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
        token._ptr = ptr;
        token._len = self._len - (ptr - self._ptr);
        if (ptr == self._ptr) {
            // Not found
            self._len = 0;
        } else {
            self._len -= token._len + needle._len;
        }
        return token;
    }

    /*
     * @dev Splits the slice, setting `self` to everything before the last
     *      occurrence of `needle`, and returning everything after it. If
     *      `needle` does not occur in `self`, `self` is set to the empty slice,
     *      and the entirety of `self` is returned.
     * @param self The slice to split.
     * @param needle The text to search for in `self`.
     * @return The part of `self` after the last occurrence of `delim`.
     */
    function rsplit(slice self, slice needle) internal pure returns (slice token) {
        rsplit(self, needle, token);
    }

    /*
     * @dev Counts the number of nonoverlapping occurrences of `needle` in `self`.
     * @param self The slice to search.
     * @param needle The text to search for in `self`.
     * @return The number of occurrences of `needle` found in `self`.
     */
    function count(slice self, slice needle) internal pure returns (uint cnt) {
        uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr) + needle._len;
        while (ptr <= self._ptr + self._len) {
            cnt++;
            ptr = findPtr(self._len - (ptr - self._ptr), ptr, needle._len, needle._ptr) + needle._len;
        }
    }

    /*
     * @dev Returns True if `self` contains `needle`.
     * @param self The slice to search.
     * @param needle The text to search for in `self`.
     * @return True if `needle` is found in `self`, false otherwise.
     */
    function contains(slice self, slice needle) internal pure returns (bool) {
        return rfindPtr(self._len, self._ptr, needle._len, needle._ptr) != self._ptr;
    }

    /*
     * @dev Returns a newly allocated string containing the concatenation of
     *      `self` and `other`.
     * @param self The first slice to concatenate.
     * @param other The second slice to concatenate.
     * @return The concatenation of the two strings.
     */
    function concat(slice self, slice other) internal pure returns (string) {
        string memory ret = new string(self._len + other._len);
        uint retptr;
        assembly { retptr := add(ret, 32) }
        memcpy(retptr, self._ptr, self._len);
        memcpy(retptr + self._len, other._ptr, other._len);
        return ret;
    }

    /*
     * @dev Joins an array of slices, using `self` as a delimiter, returning a
     *      newly allocated string.
     * @param self The delimiter to use.
     * @param parts A list of slices to join.
     * @return A newly allocated string containing all the slices in `parts`,
     *         joined with `self`.
     */
    function join(slice self, slice[] parts) internal pure returns (string) {
        if (parts.length == 0)
            return "";

        uint length = self._len * (parts.length - 1);
        for(uint i = 0; i < parts.length; i++)
            length += parts[i]._len;

        string memory ret = new string(length);
        uint retptr;
        assembly { retptr := add(ret, 32) }

        for(i = 0; i < parts.length; i++) {
            memcpy(retptr, parts[i]._ptr, parts[i]._len);
            retptr += parts[i]._len;
            if (i < parts.length - 1) {
                memcpy(retptr, self._ptr, self._len);
                retptr += self._len;
            }
        }

        return ret;
    }
}

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
  address public owner;
  address public coinvest;
  mapping (address => bool) public admins;

  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  constructor() public {
    owner = msg.sender;
    coinvest = msg.sender;
    admins[owner] = true;
    admins[coinvest] = true;
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

  modifier coinvestOrOwner() {
      require(msg.sender == coinvest || msg.sender == owner);
      _;
  }

  modifier onlyAdmin() {
      require(admins[msg.sender]);
      _;
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) onlyOwner public {
    require(newOwner != address(0));
    emit OwnershipTransferred(owner, newOwner);
    owner = newOwner;
  }
  
  /**
   * @dev Changes the Coinvest wallet that will receive funds from investment contract.
   * @param _newCoinvest The address of the new wallet.
  **/
  function transferCoinvest(address _newCoinvest) 
    external
    onlyOwner
  {
    require(_newCoinvest != address(0));
    coinvest = _newCoinvest;
  }

  /**
   * @dev Used to add admins who are allowed to add funds to the investment contract and change gas price.
   * @param _user The address of the admin to add or remove.
   * @param _status True to add the user, False to remove the user.
  **/
  function alterAdmin(address _user, bool _status)
    external
    onlyOwner
  {
    require(_user != address(0));
    require(_user != coinvest);
    admins[_user] = _status;
  }

}

// <ORACLIZE_API>
/*
Copyright (c) 2015-2016 Oraclize SRL
Copyright (c) 2016 Oraclize LTD



Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:



The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.



THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

pragma solidity >= 0.4.1 < 0.5;// Incompatible compiler version... please select one stated within pragma solidity or use different oraclizeAPI version

contract OraclizeI {
    address public cbAddress;
    function query(uint _timestamp, string _datasource, string _arg) payable returns (bytes32 _id);
    function query_withGasLimit(uint _timestamp, string _datasource, string _arg, uint _gaslimit) payable returns (bytes32 _id);
    function query2(uint _timestamp, string _datasource, string _arg1, string _arg2) payable returns (bytes32 _id);
    function query2_withGasLimit(uint _timestamp, string _datasource, string _arg1, string _arg2, uint _gaslimit) payable returns (bytes32 _id);
    function queryN(uint _timestamp, string _datasource, bytes _argN) payable returns (bytes32 _id);
    function queryN_withGasLimit(uint _timestamp, string _datasource, bytes _argN, uint _gaslimit) payable returns (bytes32 _id);
    function getPrice(string _datasource) returns (uint _dsprice);
    function getPrice(string _datasource, uint gaslimit) returns (uint _dsprice);
    function useCoupon(string _coupon);
    function setProofType(byte _proofType);
    function setConfig(bytes32 _config);
    function setCustomGasPrice(uint _gasPrice);
    function randomDS_getSessionPubKeyHash() returns(bytes32);
}

contract OraclizeAddrResolverI {
    function getAddress() returns (address _addr);
}

/*
Begin solidity-cborutils

https://github.com/smartcontractkit/solidity-cborutils

MIT License

Copyright (c) 2018 SmartContract ChainLink, Ltd.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
 */

library Buffer {
    struct buffer {
        bytes buf;
        uint capacity;
    }

    function init(buffer memory buf, uint _capacity) internal constant {
        uint capacity = _capacity;
        if(capacity % 32 != 0) capacity += 32 - (capacity % 32);
        // Allocate space for the buffer data
        buf.capacity = capacity;
        assembly {
            let ptr := mload(0x40)
            mstore(buf, ptr)
            mstore(ptr, 0)
            mstore(0x40, add(ptr, capacity))
        }
    }

    function resize(buffer memory buf, uint capacity) private constant {
        bytes memory oldbuf = buf.buf;
        init(buf, capacity);
        append(buf, oldbuf);
    }

    function max(uint a, uint b) private constant returns(uint) {
        if(a > b) {
            return a;
        }
        return b;
    }

    /**
     * @dev Appends a byte array to the end of the buffer. Resizes if doing so
     *      would exceed the capacity of the buffer.
     * @param buf The buffer to append to.
     * @param data The data to append.
     * @return The original buffer.
     */
    function append(buffer memory buf, bytes data) internal constant returns(buffer memory) {
        if(data.length + buf.buf.length > buf.capacity) {
            resize(buf, max(buf.capacity, data.length) * 2);
        }

        uint dest;
        uint src;
        uint len = data.length;
        assembly {
            // Memory address of the buffer data
            let bufptr := mload(buf)
            // Length of existing buffer data
            let buflen := mload(bufptr)
            // Start address = buffer address + buffer length + sizeof(buffer length)
            dest := add(add(bufptr, buflen), 32)
            // Update buffer length
            mstore(bufptr, add(buflen, mload(data)))
            src := add(data, 32)
        }

        // Copy word-length chunks while possible
        for(; len >= 32; len -= 32) {
            assembly {
                mstore(dest, mload(src))
            }
            dest += 32;
            src += 32;
        }

        // Copy remaining bytes
        uint mask = 256 ** (32 - len) - 1;
        assembly {
            let srcpart := and(mload(src), not(mask))
            let destpart := and(mload(dest), mask)
            mstore(dest, or(destpart, srcpart))
        }

        return buf;
    }

    /**
     * @dev Appends a byte to the end of the buffer. Resizes if doing so would
     * exceed the capacity of the buffer.
     * @param buf The buffer to append to.
     * @param data The data to append.
     * @return The original buffer.
     */
    function append(buffer memory buf, uint8 data) internal constant {
        if(buf.buf.length + 1 > buf.capacity) {
            resize(buf, buf.capacity * 2);
        }

        assembly {
            // Memory address of the buffer data
            let bufptr := mload(buf)
            // Length of existing buffer data
            let buflen := mload(bufptr)
            // Address = buffer address + buffer length + sizeof(buffer length)
            let dest := add(add(bufptr, buflen), 32)
            mstore8(dest, data)
            // Update buffer length
            mstore(bufptr, add(buflen, 1))
        }
    }

    /**
     * @dev Appends a byte to the end of the buffer. Resizes if doing so would
     * exceed the capacity of the buffer.
     * @param buf The buffer to append to.
     * @param data The data to append.
     * @return The original buffer.
     */
    function appendInt(buffer memory buf, uint data, uint len) internal constant returns(buffer memory) {
        if(len + buf.buf.length > buf.capacity) {
            resize(buf, max(buf.capacity, len) * 2);
        }

        uint mask = 256 ** len - 1;
        assembly {
            // Memory address of the buffer data
            let bufptr := mload(buf)
            // Length of existing buffer data
            let buflen := mload(bufptr)
            // Address = buffer address + buffer length + sizeof(buffer length) + len
            let dest := add(add(bufptr, buflen), len)
            mstore(dest, or(and(mload(dest), not(mask)), data))
            // Update buffer length
            mstore(bufptr, add(buflen, len))
        }
        return buf;
    }
}

library CBOR {
    using Buffer for Buffer.buffer;

    uint8 private constant MAJOR_TYPE_INT = 0;
    uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1;
    uint8 private constant MAJOR_TYPE_BYTES = 2;
    uint8 private constant MAJOR_TYPE_STRING = 3;
    uint8 private constant MAJOR_TYPE_ARRAY = 4;
    uint8 private constant MAJOR_TYPE_MAP = 5;
    uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7;

    function shl8(uint8 x, uint8 y) private constant returns (uint8) {
        return x * (2 ** y);
    }

    function encodeType(Buffer.buffer memory buf, uint8 major, uint value) private constant {
        if(value <= 23) {
            buf.append(uint8(shl8(major, 5) | value));
        } else if(value <= 0xFF) {
            buf.append(uint8(shl8(major, 5) | 24));
            buf.appendInt(value, 1);
        } else if(value <= 0xFFFF) {
            buf.append(uint8(shl8(major, 5) | 25));
            buf.appendInt(value, 2);
        } else if(value <= 0xFFFFFFFF) {
            buf.append(uint8(shl8(major, 5) | 26));
            buf.appendInt(value, 4);
        } else if(value <= 0xFFFFFFFFFFFFFFFF) {
            buf.append(uint8(shl8(major, 5) | 27));
            buf.appendInt(value, 8);
        }
    }

    function encodeIndefiniteLengthType(Buffer.buffer memory buf, uint8 major) private constant {
        buf.append(uint8(shl8(major, 5) | 31));
    }

    function encodeUInt(Buffer.buffer memory buf, uint value) internal constant {
        encodeType(buf, MAJOR_TYPE_INT, value);
    }

    function encodeInt(Buffer.buffer memory buf, int value) internal constant {
        if(value >= 0) {
            encodeType(buf, MAJOR_TYPE_INT, uint(value));
        } else {
            encodeType(buf, MAJOR_TYPE_NEGATIVE_INT, uint(-1 - value));
        }
    }

    function encodeBytes(Buffer.buffer memory buf, bytes value) internal constant {
        encodeType(buf, MAJOR_TYPE_BYTES, value.length);
        buf.append(value);
    }

    function encodeString(Buffer.buffer memory buf, string value) internal constant {
        encodeType(buf, MAJOR_TYPE_STRING, bytes(value).length);
        buf.append(bytes(value));
    }

    function startArray(Buffer.buffer memory buf) internal constant {
        encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY);
    }

    function startMap(Buffer.buffer memory buf) internal constant {
        encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP);
    }

    function endSequence(Buffer.buffer memory buf) internal constant {
        encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE);
    }
}

/*
End solidity-cborutils
 */

contract usingOraclize {
    uint constant day = 60*60*24;
    uint constant week = 60*60*24*7;
    uint constant month = 60*60*24*30;
    byte constant proofType_NONE = 0x00;
    byte constant proofType_TLSNotary = 0x10;
    byte constant proofType_Ledger = 0x30;
    byte constant proofType_Android = 0x40;
    byte constant proofType_Native = 0xF0;
    byte constant proofStorage_IPFS = 0x01;
    uint8 constant networkID_auto = 0;
    uint8 constant networkID_mainnet = 1;
    uint8 constant networkID_testnet = 2;
    uint8 constant networkID_morden = 2;
    uint8 constant networkID_consensys = 161;

    OraclizeAddrResolverI OAR;

    OraclizeI oraclize;
    modifier oraclizeAPI {
        if((address(OAR)==0)||(getCodeSize(address(OAR))==0))
            oraclize_setNetwork(networkID_auto);

        if(address(oraclize) != OAR.getAddress())
            oraclize = OraclizeI(OAR.getAddress());

        _;
    }
    modifier coupon(string code){
        oraclize = OraclizeI(OAR.getAddress());
        oraclize.useCoupon(code);
        _;
    }

    function oraclize_setNetwork(uint8 networkID) internal returns(bool){
        if (getCodeSize(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed)>0){ //mainnet
            OAR = OraclizeAddrResolverI(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed);
            oraclize_setNetworkName("eth_mainnet");
            return true;
        }
        if (getCodeSize(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1)>0){ //ropsten testnet
            OAR = OraclizeAddrResolverI(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1);
            oraclize_setNetworkName("eth_ropsten3");
            return true;
        }
        if (getCodeSize(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e)>0){ //kovan testnet
            OAR = OraclizeAddrResolverI(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e);
            oraclize_setNetworkName("eth_kovan");
            return true;
        }
        if (getCodeSize(0x146500cfd35B22E4A392Fe0aDc06De1a1368Ed48)>0){ //rinkeby testnet
            OAR = OraclizeAddrResolverI(0x146500cfd35B22E4A392Fe0aDc06De1a1368Ed48);
            oraclize_setNetworkName("eth_rinkeby");
            return true;
        }
        if (getCodeSize(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475)>0){ //ethereum-bridge
            OAR = OraclizeAddrResolverI(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475);
            return true;
        }
        if (getCodeSize(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF)>0){ //ether.camp ide
            OAR = OraclizeAddrResolverI(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF);
            return true;
        }
        if (getCodeSize(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA)>0){ //browser-solidity
            OAR = OraclizeAddrResolverI(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA);
            return true;
        }
        return false;
    }

    function __callback(bytes32 myid, string result) {
        __callback(myid, result, new bytes(0));
    }
    function __callback(bytes32 myid, string result, bytes proof) {
    }

    function oraclize_useCoupon(string code) oraclizeAPI internal {
        oraclize.useCoupon(code);
    }

    function oraclize_getPrice(string datasource) oraclizeAPI internal returns (uint){
        return oraclize.getPrice(datasource);
    }

    function oraclize_getPrice(string datasource, uint gaslimit) oraclizeAPI internal returns (uint){
        return oraclize.getPrice(datasource, gaslimit);
    }

    function oraclize_query(string datasource, string arg) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource);
        if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
        return oraclize.query.value(price)(0, datasource, arg);
    }
    function oraclize_query(uint timestamp, string datasource, string arg) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource);
        if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
        return oraclize.query.value(price)(timestamp, datasource, arg);
    }
    function oraclize_query(uint timestamp, string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource, gaslimit);
        if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
        return oraclize.query_withGasLimit.value(price)(timestamp, datasource, arg, gaslimit);
    }
    function oraclize_query(string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource, gaslimit);
        if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
        return oraclize.query_withGasLimit.value(price)(0, datasource, arg, gaslimit);
    }
    function oraclize_query(string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource);
        if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
        return oraclize.query2.value(price)(0, datasource, arg1, arg2);
    }
    function oraclize_query(uint timestamp, string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource);
        if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
        return oraclize.query2.value(price)(timestamp, datasource, arg1, arg2);
    }
    function oraclize_query(uint timestamp, string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource, gaslimit);
        if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
        return oraclize.query2_withGasLimit.value(price)(timestamp, datasource, arg1, arg2, gaslimit);
    }
    function oraclize_query(string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource, gaslimit);
        if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
        return oraclize.query2_withGasLimit.value(price)(0, datasource, arg1, arg2, gaslimit);
    }
    function oraclize_query(string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource);
        if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
        bytes memory args = stra2cbor(argN);
        return oraclize.queryN.value(price)(0, datasource, args);
    }
    function oraclize_query(uint timestamp, string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource);
        if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
        bytes memory args = stra2cbor(argN);
        return oraclize.queryN.value(price)(timestamp, datasource, args);
    }
    function oraclize_query(uint timestamp, string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource, gaslimit);
        if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
        bytes memory args = stra2cbor(argN);
        return oraclize.queryN_withGasLimit.value(price)(timestamp, datasource, args, gaslimit);
    }
    function oraclize_query(string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource, gaslimit);
        if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
        bytes memory args = stra2cbor(argN);
        return oraclize.queryN_withGasLimit.value(price)(0, datasource, args, gaslimit);
    }
    function oraclize_query(string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](1);
        dynargs[0] = args[0];
        return oraclize_query(datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](1);
        dynargs[0] = args[0];
        return oraclize_query(timestamp, datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](1);
        dynargs[0] = args[0];
        return oraclize_query(timestamp, datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](1);
        dynargs[0] = args[0];
        return oraclize_query(datasource, dynargs, gaslimit);
    }

    function oraclize_query(string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](2);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        return oraclize_query(datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](2);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        return oraclize_query(timestamp, datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](2);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        return oraclize_query(timestamp, datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](2);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        return oraclize_query(datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](3);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        return oraclize_query(datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](3);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        return oraclize_query(timestamp, datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](3);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        return oraclize_query(timestamp, datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](3);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        return oraclize_query(datasource, dynargs, gaslimit);
    }

    function oraclize_query(string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](4);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        return oraclize_query(datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](4);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        return oraclize_query(timestamp, datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](4);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        return oraclize_query(timestamp, datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](4);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        return oraclize_query(datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](5);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        dynargs[4] = args[4];
        return oraclize_query(datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](5);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        dynargs[4] = args[4];
        return oraclize_query(timestamp, datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](5);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        dynargs[4] = args[4];
        return oraclize_query(timestamp, datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        string[] memory dynargs = new string[](5);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        dynargs[4] = args[4];
        return oraclize_query(datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, bytes[] argN) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource);
        if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
        bytes memory args = ba2cbor(argN);
        return oraclize.queryN.value(price)(0, datasource, args);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[] argN) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource);
        if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
        bytes memory args = ba2cbor(argN);
        return oraclize.queryN.value(price)(timestamp, datasource, args);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource, gaslimit);
        if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
        bytes memory args = ba2cbor(argN);
        return oraclize.queryN_withGasLimit.value(price)(timestamp, datasource, args, gaslimit);
    }
    function oraclize_query(string datasource, bytes[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
        uint price = oraclize.getPrice(datasource, gaslimit);
        if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
        bytes memory args = ba2cbor(argN);
        return oraclize.queryN_withGasLimit.value(price)(0, datasource, args, gaslimit);
    }
    function oraclize_query(string datasource, bytes[1] args) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](1);
        dynargs[0] = args[0];
        return oraclize_query(datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[1] args) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](1);
        dynargs[0] = args[0];
        return oraclize_query(timestamp, datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](1);
        dynargs[0] = args[0];
        return oraclize_query(timestamp, datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, bytes[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](1);
        dynargs[0] = args[0];
        return oraclize_query(datasource, dynargs, gaslimit);
    }

    function oraclize_query(string datasource, bytes[2] args) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](2);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        return oraclize_query(datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[2] args) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](2);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        return oraclize_query(timestamp, datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](2);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        return oraclize_query(timestamp, datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, bytes[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](2);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        return oraclize_query(datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, bytes[3] args) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](3);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        return oraclize_query(datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[3] args) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](3);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        return oraclize_query(timestamp, datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](3);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        return oraclize_query(timestamp, datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, bytes[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](3);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        return oraclize_query(datasource, dynargs, gaslimit);
    }

    function oraclize_query(string datasource, bytes[4] args) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](4);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        return oraclize_query(datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[4] args) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](4);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        return oraclize_query(timestamp, datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](4);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        return oraclize_query(timestamp, datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, bytes[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](4);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        return oraclize_query(datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, bytes[5] args) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](5);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        dynargs[4] = args[4];
        return oraclize_query(datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[5] args) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](5);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        dynargs[4] = args[4];
        return oraclize_query(timestamp, datasource, dynargs);
    }
    function oraclize_query(uint timestamp, string datasource, bytes[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](5);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        dynargs[4] = args[4];
        return oraclize_query(timestamp, datasource, dynargs, gaslimit);
    }
    function oraclize_query(string datasource, bytes[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
        bytes[] memory dynargs = new bytes[](5);
        dynargs[0] = args[0];
        dynargs[1] = args[1];
        dynargs[2] = args[2];
        dynargs[3] = args[3];
        dynargs[4] = args[4];
        return oraclize_query(datasource, dynargs, gaslimit);
    }

    function oraclize_cbAddress() oraclizeAPI internal returns (address){
        return oraclize.cbAddress();
    }
    function oraclize_setProof(byte proofP) oraclizeAPI internal {
        return oraclize.setProofType(proofP);
    }
    function oraclize_setCustomGasPrice(uint gasPrice) oraclizeAPI internal {
        return oraclize.setCustomGasPrice(gasPrice);
    }
    function oraclize_setConfig(bytes32 config) oraclizeAPI internal {
        return oraclize.setConfig(config);
    }

    function oraclize_randomDS_getSessionPubKeyHash() oraclizeAPI internal returns (bytes32){
        return oraclize.randomDS_getSessionPubKeyHash();
    }

    function getCodeSize(address _addr) constant internal returns(uint _size) {
        assembly {
            _size := extcodesize(_addr)
        }
    }

    function parseAddr(string _a) internal returns (address){
        bytes memory tmp = bytes(_a);
        uint160 iaddr = 0;
        uint160 b1;
        uint160 b2;
        for (uint i=2; i<2+2*20; i+=2){
            iaddr *= 256;
            b1 = uint160(tmp[i]);
            b2 = uint160(tmp[i+1]);
            if ((b1 >= 97)&&(b1 <= 102)) b1 -= 87;
            else if ((b1 >= 65)&&(b1 <= 70)) b1 -= 55;
            else if ((b1 >= 48)&&(b1 <= 57)) b1 -= 48;
            if ((b2 >= 97)&&(b2 <= 102)) b2 -= 87;
            else if ((b2 >= 65)&&(b2 <= 70)) b2 -= 55;
            else if ((b2 >= 48)&&(b2 <= 57)) b2 -= 48;
            iaddr += (b1*16+b2);
        }
        return address(iaddr);
    }

    function strCompare(string _a, string _b) internal returns (int) {
        bytes memory a = bytes(_a);
        bytes memory b = bytes(_b);
        uint minLength = a.length;
        if (b.length < minLength) minLength = b.length;
        for (uint i = 0; i < minLength; i ++)
            if (a[i] < b[i])
                return -1;
            else if (a[i] > b[i])
                return 1;
        if (a.length < b.length)
            return -1;
        else if (a.length > b.length)
            return 1;
        else
            return 0;
    }

    function indexOf(string _haystack, string _needle) internal returns (int) {
        bytes memory h = bytes(_haystack);
        bytes memory n = bytes(_needle);
        if(h.length < 1 || n.length < 1 || (n.length > h.length))
            return -1;
        else if(h.length > (2**128 -1))
            return -1;
        else
        {
            uint subindex = 0;
            for (uint i = 0; i < h.length; i ++)
            {
                if (h[i] == n[0])
                {
                    subindex = 1;
                    while(subindex < n.length && (i + subindex) < h.length && h[i + subindex] == n[subindex])
                    {
                        subindex++;
                    }
                    if(subindex == n.length)
                        return int(i);
                }
            }
            return -1;
        }
    }

    function strConcat(string _a, string _b, string _c, string _d, string _e) internal returns (string) {
        bytes memory _ba = bytes(_a);
        bytes memory _bb = bytes(_b);
        bytes memory _bc = bytes(_c);
        bytes memory _bd = bytes(_d);
        bytes memory _be = bytes(_e);
        string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
        bytes memory babcde = bytes(abcde);
        uint k = 0;
        for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
        for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
        for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
        for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
        for (i = 0; i < _be.length; i++) babcde[k++] = _be[i];
        return string(babcde);
    }

    function strConcat(string _a, string _b, string _c, string _d) internal returns (string) {
        return strConcat(_a, _b, _c, _d, "");
    }

    function strConcat(string _a, string _b, string _c) internal returns (string) {
        return strConcat(_a, _b, _c, "", "");
    }

    function strConcat(string _a, string _b) internal returns (string) {
        return strConcat(_a, _b, "", "", "");
    }

    // parseInt
    function parseInt(string _a) internal returns (uint) {
        return parseInt(_a, 0);
    }

    // parseInt(parseFloat*10^_b)
    function parseInt(string _a, uint _b) internal returns (uint) {
        bytes memory bresult = bytes(_a);
        uint mint = 0;
        bool decimals = false;
        for (uint i=0; i<bresult.length; i++){
            if ((bresult[i] >= 48)&&(bresult[i] <= 57)){
                if (decimals){
                   if (_b == 0) break;
                    else _b--;
                }
                mint *= 10;
                mint += uint(bresult[i]) - 48;
            } else if (bresult[i] == 46) decimals = true;
        }
        if (_b > 0) mint *= 10**_b;
        return mint;
    }

    function uint2str(uint i) internal returns (string){
        if (i == 0) return "0";
        uint j = i;
        uint len;
        while (j != 0){
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (i != 0){
            bstr[k--] = byte(48 + i % 10);
            i /= 10;
        }
        return string(bstr);
    }

    using CBOR for Buffer.buffer;
    function stra2cbor(string[] arr) internal constant returns (bytes) {
        safeMemoryCleaner();
        Buffer.buffer memory buf;
        Buffer.init(buf, 1024);
        buf.startArray();
        for (uint i = 0; i < arr.length; i++) {
            buf.encodeString(arr[i]);
        }
        buf.endSequence();
        return buf.buf;
    }

    function ba2cbor(bytes[] arr) internal constant returns (bytes) {
        safeMemoryCleaner();
        Buffer.buffer memory buf;
        Buffer.init(buf, 1024);
        buf.startArray();
        for (uint i = 0; i < arr.length; i++) {
            buf.encodeBytes(arr[i]);
        }
        buf.endSequence();
        return buf.buf;
    }

    string oraclize_network_name;
    function oraclize_setNetworkName(string _network_name) internal {
        oraclize_network_name = _network_name;
    }

    function oraclize_getNetworkName() internal returns (string) {
        return oraclize_network_name;
    }

    function oraclize_newRandomDSQuery(uint _delay, uint _nbytes, uint _customGasLimit) internal returns (bytes32){
        if ((_nbytes == 0)||(_nbytes > 32)) throw;
	// Convert from seconds to ledger timer ticks
        _delay *= 10;
        bytes memory nbytes = new bytes(1);
        nbytes[0] = byte(_nbytes);
        bytes memory unonce = new bytes(32);
        bytes memory sessionKeyHash = new bytes(32);
        bytes32 sessionKeyHash_bytes32 = oraclize_randomDS_getSessionPubKeyHash();
        assembly {
            mstore(unonce, 0x20)
            // the following variables can be relaxed
            // check relaxed random contract under ethereum-examples repo
            // for an idea on how to override and replace comit hash vars
            mstore(add(unonce, 0x20), xor(blockhash(sub(number, 1)), xor(coinbase, timestamp)))
            mstore(sessionKeyHash, 0x20)
            mstore(add(sessionKeyHash, 0x20), sessionKeyHash_bytes32)
        }
        bytes memory delay = new bytes(32);
        assembly {
            mstore(add(delay, 0x20), _delay)
        }

        bytes memory delay_bytes8 = new bytes(8);
        copyBytes(delay, 24, 8, delay_bytes8, 0);

        bytes[4] memory args = [unonce, nbytes, sessionKeyHash, delay];
        bytes32 queryId = oraclize_query("random", args, _customGasLimit);

        bytes memory delay_bytes8_left = new bytes(8);

        assembly {
            let x := mload(add(delay_bytes8, 0x20))
            mstore8(add(delay_bytes8_left, 0x27), div(x, 0x100000000000000000000000000000000000000000000000000000000000000))
            mstore8(add(delay_bytes8_left, 0x26), div(x, 0x1000000000000000000000000000000000000000000000000000000000000))
            mstore8(add(delay_bytes8_left, 0x25), div(x, 0x10000000000000000000000000000000000000000000000000000000000))
            mstore8(add(delay_bytes8_left, 0x24), div(x, 0x100000000000000000000000000000000000000000000000000000000))
            mstore8(add(delay_bytes8_left, 0x23), div(x, 0x1000000000000000000000000000000000000000000000000000000))
            mstore8(add(delay_bytes8_left, 0x22), div(x, 0x10000000000000000000000000000000000000000000000000000))
            mstore8(add(delay_bytes8_left, 0x21), div(x, 0x100000000000000000000000000000000000000000000000000))
            mstore8(add(delay_bytes8_left, 0x20), div(x, 0x1000000000000000000000000000000000000000000000000))

        }

        oraclize_randomDS_setCommitment(queryId, sha3(delay_bytes8_left, args[1], sha256(args[0]), args[2]));
        return queryId;
    }

    function oraclize_randomDS_setCommitment(bytes32 queryId, bytes32 commitment) internal {
        oraclize_randomDS_args[queryId] = commitment;
    }

    mapping(bytes32=>bytes32) oraclize_randomDS_args;
    mapping(bytes32=>bool) oraclize_randomDS_sessionKeysHashVerified;

    function verifySig(bytes32 tosignh, bytes dersig, bytes pubkey) internal returns (bool){
        bool sigok;
        address signer;

        bytes32 sigr;
        bytes32 sigs;

        bytes memory sigr_ = new bytes(32);
        uint offset = 4+(uint(dersig[3]) - 0x20);
        sigr_ = copyBytes(dersig, offset, 32, sigr_, 0);
        bytes memory sigs_ = new bytes(32);
        offset += 32 + 2;
        sigs_ = copyBytes(dersig, offset+(uint(dersig[offset-1]) - 0x20), 32, sigs_, 0);

        assembly {
            sigr := mload(add(sigr_, 32))
            sigs := mload(add(sigs_, 32))
        }


        (sigok, signer) = safer_ecrecover(tosignh, 27, sigr, sigs);
        if (address(sha3(pubkey)) == signer) return true;
        else {
            (sigok, signer) = safer_ecrecover(tosignh, 28, sigr, sigs);
            return (address(sha3(pubkey)) == signer);
        }
    }

    function oraclize_randomDS_proofVerify__sessionKeyValidity(bytes proof, uint sig2offset) internal returns (bool) {
        bool sigok;

        // Step 6: verify the attestation signature, APPKEY1 must sign the sessionKey from the correct ledger app (CODEHASH)
        bytes memory sig2 = new bytes(uint(proof[sig2offset+1])+2);
        copyBytes(proof, sig2offset, sig2.length, sig2, 0);

        bytes memory appkey1_pubkey = new bytes(64);
        copyBytes(proof, 3+1, 64, appkey1_pubkey, 0);

        bytes memory tosign2 = new bytes(1+65+32);
        tosign2[0] = 1; //role
        copyBytes(proof, sig2offset-65, 65, tosign2, 1);
        bytes memory CODEHASH = hex"fd94fa71bc0ba10d39d464d0d8f465efeef0a2764e3887fcc9df41ded20f505c";
        copyBytes(CODEHASH, 0, 32, tosign2, 1+65);
        sigok = verifySig(sha256(tosign2), sig2, appkey1_pubkey);

        if (sigok == false) return false;


        // Step 7: verify the APPKEY1 provenance (must be signed by Ledger)
        bytes memory LEDGERKEY = hex"7fb956469c5c9b89840d55b43537e66a98dd4811ea0a27224272c2e5622911e8537a2f8e86a46baec82864e98dd01e9ccc2f8bc5dfc9cbe5a91a290498dd96e4";

        bytes memory tosign3 = new bytes(1+65);
        tosign3[0] = 0xFE;
        copyBytes(proof, 3, 65, tosign3, 1);

        bytes memory sig3 = new bytes(uint(proof[3+65+1])+2);
        copyBytes(proof, 3+65, sig3.length, sig3, 0);

        sigok = verifySig(sha256(tosign3), sig3, LEDGERKEY);

        return sigok;
    }

    modifier oraclize_randomDS_proofVerify(bytes32 _queryId, string _result, bytes _proof) {
        // Step 1: the prefix has to match 'LP\x01' (Ledger Proof version 1)
        if ((_proof[0] != "L")||(_proof[1] != "P")||(_proof[2] != 1)) throw;

        bool proofVerified = oraclize_randomDS_proofVerify__main(_proof, _queryId, bytes(_result), oraclize_getNetworkName());
        if (proofVerified == false) throw;

        _;
    }

    function oraclize_randomDS_proofVerify__returnCode(bytes32 _queryId, string _result, bytes _proof) internal returns (uint8){
        // Step 1: the prefix has to match 'LP\x01' (Ledger Proof version 1)
        if ((_proof[0] != "L")||(_proof[1] != "P")||(_proof[2] != 1)) return 1;

        bool proofVerified = oraclize_randomDS_proofVerify__main(_proof, _queryId, bytes(_result), oraclize_getNetworkName());
        if (proofVerified == false) return 2;

        return 0;
    }

    function matchBytes32Prefix(bytes32 content, bytes prefix, uint n_random_bytes) internal returns (bool){
        bool match_ = true;

	if (prefix.length != n_random_bytes) throw;

        for (uint256 i=0; i< n_random_bytes; i++) {
            if (content[i] != prefix[i]) match_ = false;
        }

        return match_;
    }

    function oraclize_randomDS_proofVerify__main(bytes proof, bytes32 queryId, bytes result, string context_name) internal returns (bool){

        // Step 2: the unique keyhash has to match with the sha256 of (context name + queryId)
        uint ledgerProofLength = 3+65+(uint(proof[3+65+1])+2)+32;
        bytes memory keyhash = new bytes(32);
        copyBytes(proof, ledgerProofLength, 32, keyhash, 0);
        if (!(sha3(keyhash) == sha3(sha256(context_name, queryId)))) return false;

        bytes memory sig1 = new bytes(uint(proof[ledgerProofLength+(32+8+1+32)+1])+2);
        copyBytes(proof, ledgerProofLength+(32+8+1+32), sig1.length, sig1, 0);

        // Step 3: we assume sig1 is valid (it will be verified during step 5) and we verify if 'result' is the prefix of sha256(sig1)
        if (!matchBytes32Prefix(sha256(sig1), result, uint(proof[ledgerProofLength+32+8]))) return false;

        // Step 4: commitment match verification, sha3(delay, nbytes, unonce, sessionKeyHash) == commitment in storage.
        // This is to verify that the computed args match with the ones specified in the query.
        bytes memory commitmentSlice1 = new bytes(8+1+32);
        copyBytes(proof, ledgerProofLength+32, 8+1+32, commitmentSlice1, 0);

        bytes memory sessionPubkey = new bytes(64);
        uint sig2offset = ledgerProofLength+32+(8+1+32)+sig1.length+65;
        copyBytes(proof, sig2offset-64, 64, sessionPubkey, 0);

        bytes32 sessionPubkeyHash = sha256(sessionPubkey);
        if (oraclize_randomDS_args[queryId] == sha3(commitmentSlice1, sessionPubkeyHash)){ //unonce, nbytes and sessionKeyHash match
            delete oraclize_randomDS_args[queryId];
        } else return false;


        // Step 5: validity verification for sig1 (keyhash and args signed with the sessionKey)
        bytes memory tosign1 = new bytes(32+8+1+32);
        copyBytes(proof, ledgerProofLength, 32+8+1+32, tosign1, 0);
        if (!verifySig(sha256(tosign1), sig1, sessionPubkey)) return false;

        // verify if sessionPubkeyHash was verified already, if not.. let's do it!
        if (oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash] == false){
            oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash] = oraclize_randomDS_proofVerify__sessionKeyValidity(proof, sig2offset);
        }

        return oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash];
    }


    // the following function has been written by Alex Beregszaszi (@axic), use it under the terms of the MIT license
    function copyBytes(bytes from, uint fromOffset, uint length, bytes to, uint toOffset) internal returns (bytes) {
        uint minLength = length + toOffset;

        if (to.length < minLength) {
            // Buffer too small
            throw; // Should be a better way?
        }

        // NOTE: the offset 32 is added to skip the `size` field of both bytes variables
        uint i = 32 + fromOffset;
        uint j = 32 + toOffset;

        while (i < (32 + fromOffset + length)) {
            assembly {
                let tmp := mload(add(from, i))
                mstore(add(to, j), tmp)
            }
            i += 32;
            j += 32;
        }

        return to;
    }

    // the following function has been written by Alex Beregszaszi (@axic), use it under the terms of the MIT license
    // Duplicate Solidity's ecrecover, but catching the CALL return value
    function safer_ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal returns (bool, address) {
        // We do our own memory management here. Solidity uses memory offset
        // 0x40 to store the current end of memory. We write past it (as
        // writes are memory extensions), but don't update the offset so
        // Solidity will reuse it. The memory used here is only needed for
        // this context.

        // FIXME: inline assembly can't access return values
        bool ret;
        address addr;

        assembly {
            let size := mload(0x40)
            mstore(size, hash)
            mstore(add(size, 32), v)
            mstore(add(size, 64), r)
            mstore(add(size, 96), s)

            // NOTE: we can reuse the request memory because we deal with
            //       the return code
            ret := call(3000, 1, 0, size, 128, size, 32)
            addr := mload(size)
        }

        return (ret, addr);
    }

    // the following function has been written by Alex Beregszaszi (@axic), use it under the terms of the MIT license
    function ecrecovery(bytes32 hash, bytes sig) internal returns (bool, address) {
        bytes32 r;
        bytes32 s;
        uint8 v;

        if (sig.length != 65)
          return (false, 0);

        // The signature format is a compact form of:
        //   {bytes32 r}{bytes32 s}{uint8 v}
        // Compact means, uint8 is not padded to 32 bytes.
        assembly {
            r := mload(add(sig, 32))
            s := mload(add(sig, 64))

            // Here we are loading the last 32 bytes. We exploit the fact that
            // 'mload' will pad with zeroes if we overread.
            // There is no 'mload8' to do this, but that would be nicer.
            v := byte(0, mload(add(sig, 96)))

            // Alternative solution:
            // 'byte' is not working due to the Solidity parser, so lets
            // use the second best option, 'and'
            // v := and(mload(add(sig, 65)), 255)
        }

        // albeit non-transactional signatures are not specified by the YP, one would expect it
        // to match the YP range of [27, 28]
        //
        // geth uses [0, 1] and some clients have followed. This might change, see:
        //  https://github.com/ethereum/go-ethereum/issues/2053
        if (v < 27)
          v += 27;

        if (v != 27 && v != 28)
            return (false, 0);

        return safer_ecrecover(hash, v, r, s);
    }

    function safeMemoryCleaner() internal constant {
        assembly {
            let fmem := mload(0x40)
            codecopy(fmem, codesize, sub(msize, fmem))
        }
    }
}
// </ORACLIZE_API>

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMathLib{
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a * b;
    assert(a == 0 || c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }
  
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

contract ERC20Interface {

    function totalSupply() public constant returns (uint);
    function balanceOf(address tokenOwner) public constant returns (uint balance);
    function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
    function transfer(address to, uint tokens) public returns (bool success);
    function approve(address spender, uint tokens) public returns (bool success);
    function transferFrom(address from, address to, uint tokens) public returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);

}

contract BankI {
    function transfer(address _to, uint256 _value, bool _isCoin) external returns (bool success);
}

contract UserDataI {
    function modifyHoldings(address _beneficiary, uint256[] _cryptoIds, uint256[] _amounts, bool _buy) external;
}

library InvestLib {

    using SafeMathLib for uint256;
    using strings for *;

    /**
     * @dev Calculate the COIN value of the cryptos to be bought/sold.
     * @param _amounts The amount (in 10 ** 18) of the cryptos being bought.
     * @param _cryptoValues The value of the cryptos at time of call.
    **/
    function calculateValue(uint256[] memory _amounts, uint256[] memory _cryptoValues)
      public
      pure
    returns (uint256 value)
    {
        for (uint256 i = 0; i < _amounts.length; i++) {
            value = value.add(_cryptoValues[i+1].mul(_amounts[i]).div(_cryptoValues[0]));
        }
    }
    
    /**
     * @dev Converts given cryptos and amounts into a single uint256[] array.
     * @param _cryptos Array of the crypto Ids to be bought.
     * @param _amounts Array containing the amounts of each crypto to buy.
    **/
    function bitConv(uint256[] memory _cryptos, uint256[] memory _amounts)
      internal
      pure
    returns (uint256[] memory combined)
    {
        combined = new uint256[](_cryptos.length); 
        for (uint256 i = 0; i < _cryptos.length; i++) {
            combined[i] = _cryptos[i];
            combined[i] |= _amounts[i] << 8;
        }
        return combined;
    }
    
    /**
     * @dev Recovers the cryptos and amounts from combined array.
     * @param _idsAndAmts Array of uints containing both crypto Id and amount.
    **/
    function bitRec(uint256[] memory _idsAndAmts) 
      public
      pure
    returns (uint256[] memory cryptos, uint256[] memory amounts) 
    {
        cryptos = new uint256[](_idsAndAmts.length);
        amounts = new uint256[](_idsAndAmts.length);

        for (uint256 i = 0; i < _idsAndAmts.length; i++) {
            cryptos[i] = uint256(uint8(_idsAndAmts[i]));
            amounts[i] = uint256(uint248(_idsAndAmts[i] >> 8));
        }
        return (cryptos, amounts);
    }

}

contract Investment is Ownable, usingOraclize { 

    using SafeMathLib for uint256;
    using strings for *;
    using InvestLib for *;
    
    BankI public bank;
    UserDataI public userData;
    
    address public coinToken;
    address public cashToken;
    uint256 public customGasPrice;
    string public coinUrl = "http://ec2-18-234-124-53.compute-1.amazonaws.com/api/priceTest?cryptos=COIN,";
    string public cashUrl = "";
    bool public paused;
    
    uint256 public constant COIN_ID = 0;
    uint256 public constant COIN_INV = 1;
    uint256 public constant CASH_ID = 2;
    uint256 public constant CASH_INV = 3;
    
    // Stores all trade info so Oraclize can return and update.
    // idsAndAmts stores both the crypto ID and amounts with a uint8 and uint248 respectively.
    struct TradeInfo {
        bool isBuy;
        bool isCoin;
        address beneficiary;
        uint256[] idsAndAmts;
    }
    
    // Oraclize ID => TradeInfo.
    mapping(bytes32 => TradeInfo) trades;

    // Even indices are normal cryptos, odd are inverses--empty string if either does not exist.
    string[] public cryptoSymbols;

    // Balance of a user's free trades.
    mapping(address => uint256) public freeTrades;

    event newOraclizeQuery(string description);
    event Buy(
              //bytes32 indexed queryId, 
              address indexed buyer, 
              uint256[] cryptoIds, 
              uint256[] amounts, 
              uint256[] prices 
              //bool isCoin
              );
              
    event Sell(
               //bytes32 indexed queryId, 
               address indexed seller, 
               uint256[] cryptoIds, 
               uint256[] amounts, 
               uint256[] prices 
               //bool isCoin
               );

/** ********************************** Defaults ************************************* **/
    
    /**
     * @dev Constructor function, construct with coinvest token.
     * @param _coinToken The address of the Coinvest COIN token.
     * @param _cashToken Address of the Coinvest CASH token.
     * @param _bank Contract where all of the user Coinvest tokens will be stored.
     * @param _userData Contract where all of the user balances will be stored.
    **/
    constructor(address _coinToken, address _cashToken, address _bank, address _userData)
      public
      payable
    {
        coinToken = _coinToken;
        cashToken = _cashToken;
        bank = BankI(_bank);
        userData = UserDataI(_userData);

        oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
        
        addCrypto(0, "COIN,", false);
        addCrypto(0, "", false);
        addCrypto(0, "BTC,", false);
        addCrypto(0, "ETH,", false);
        addCrypto(0, "XRP,", false);
        addCrypto(0, "LTC,", false);
        addCrypto(0, "DASH,", false);
        addCrypto(0, "BCH,", false);
        addCrypto(0, "XMR,", false);
        addCrypto(0, "XEM,", false);
        addCrypto(0, "EOS,", false);

        customGasPrice = 5000000000;
        oraclize_setCustomGasPrice(customGasPrice);
    }
  
    /**
     * @dev Used by Coinvest-associated wallets to fund the contract.
            Users may also pay within a buy or sell call if no funds are available.
    **/
    function()
      external
      payable
      onlyAdmin
    {
        
    }
  
/** *************************** ApproveAndCall FallBack **************************** **/
  
    /**
     * @dev ApproveAndCall will send us data, we'll determine if the beneficiary is the sender, then we'll call this contract.
    **/
    function receiveApproval(address _from, uint256 _amount, address _token, bytes _data) 
      public
    {
        require(msg.sender == coinToken || msg.sender == cashToken);

        // check here to make sure _from == beneficiary in data
        address beneficiary;
        assembly {
            beneficiary := mload(add(_data,36))
        }
        require(_from == beneficiary);
        
        address(this).delegatecall(_data);
        _token; _amount;
    }
  
/** ********************************** External ************************************* **/
    
    /**
     * @dev User calls to invest, will then call Oraclize and Oraclize adds holdings.
     * @dev User must first approve this contract to transfer enough tokens to buy.
     * @param _beneficiary The user making the call whose balance will be updated.
     * @param _cryptoIds The Ids of the cryptos to invest in.
     * @param _amounts The amount of each crypto the user wants to buy, delineated in 10 ^ 18 wei.
     * @param _isCoin True/False of the crypto that is being used to invest is COIN/CASH.
    **/
    function buy(
        address _beneficiary, 
        uint256[] _cryptoIds, 
        uint256[] _amounts, 
        bool _isCoin)
      public
      payable
      notPaused
      onlySenderOrToken(_beneficiary)
    {
        require(_cryptoIds.length == _amounts.length);
        getPrices(_beneficiary, _cryptoIds, _amounts, _isCoin, true);
    }
    
    function sell(
        address _beneficiary, 
        uint256[] _cryptoIds, 
        uint256[] _amounts, 
        bool _isCoin)
      public
      payable
      notPaused
      onlySenderOrToken(_beneficiary)
    {
        require(_cryptoIds.length == _amounts.length);
        getPrices(_beneficiary, _cryptoIds, _amounts, _isCoin, false);
    }
    
/** ********************************** Internal ************************************ **/
    
    /**
     * @dev Broker will call this for an investor to invest in one or multiple assets
     * @param _beneficiary The address that is being bought for
     * @param _cryptoIds The list of uint IDs for each crypto to buy
     * @param _amounts The amounts of each crypto to buy (measured in 10 ** 18 wei!)
     * @param _prices The price of each bought crypto at time of callback.
     * @param _coinValue The amount of coin to transferFrom from user.
     * @param _isCoin True/False of the crypto that is being used to invest is COIN/CASH.
    **/
    function finalizeBuy(
        address _beneficiary, 
        uint256[] memory _cryptoIds, 
        uint256[] memory _amounts, 
        uint256[] memory _prices, 
        uint256 _coinValue,
        bool _isCoin
        )
      internal
    {
        ERC20Interface token;
        if (_isCoin) token = ERC20Interface(coinToken);
        else token = ERC20Interface(cashToken);

        uint256 fee = 4990000000000000000 * (10 ** 18) / _prices[0];
        if (freeTrades[_beneficiary] >  0) freeTrades[_beneficiary] = freeTrades[_beneficiary].sub(1);
        else require(token.transferFrom(_beneficiary, coinvest, fee));
        
        require(token.transferFrom(_beneficiary, bank, _coinValue));

        // We want to allow actual COIN/CASH exchange so users have easy access and we can "CASH" out fees
        if (_cryptoIds[0] == COIN_ID && _cryptoIds.length == 1) {
            require(bank.transfer(_beneficiary, _amounts[0], true));
        } else if (_cryptoIds[0] == CASH_ID && _cryptoIds.length == 1) {
            require(bank.transfer(_beneficiary, _amounts[0], false));
        } else {
            userData.modifyHoldings(_beneficiary, _cryptoIds, _amounts, true);
        }

        emit Buy(_beneficiary, _cryptoIds, _amounts, _prices);
    }
    
    /**
     * @param _beneficiary The address that is being sold for
     * @param _cryptoIds The list of uint IDs for each crypto
     * @param _amounts The amounts of each crypto to sell (measured in 10 ** 18 wei!)
     * @param _prices The prices of each crypto at time of callback.
     * @param _coinValue The amount of COIN to be transferred to user.
     * @param _isCoin True/False of the crypto that is being used to invest is COIN/CASH.
    **/
    function finalizeSell(
        address _beneficiary, 
        uint256[] memory _cryptoIds, 
        uint256[] memory _amounts, 
        uint256[] memory _prices, 
        uint256 _coinValue, 
        bool _isCoin
        )
      internal
    {   
        uint256 fee = 4990000000000000000 * (10 ** 18) / _prices[0];
        if (freeTrades[_beneficiary] > 0) freeTrades[_beneficiary] = freeTrades[_beneficiary].sub(1);
        else {
            require(_coinValue > fee);
            require(bank.transfer(coinvest, fee, _isCoin));
            _coinValue = _coinValue.sub(fee);
        }

        require(bank.transfer(_beneficiary, _coinValue, _isCoin));
        
        // Subtract from balance of each held crypto for user.
        userData.modifyHoldings(_beneficiary, _cryptoIds, _amounts, false);
        
        emit Sell(_beneficiary, _cryptoIds, _amounts, _prices);
    }
    
/** ******************************** Only Owner ************************************* **/
    
    /**
     * @dev Owner may add a crypto to the investment contract.
     * @param _index Id of the crypto if an old one is being altered, 0 if new crypto is to be added.
     * @param _symbol Symbol of the new crypto.
     * @param _inverse Whether or not an inverse should be added following a pushed crypto.
    **/
    function addCrypto(uint256 _index, string memory _symbol, bool _inverse)
      public
      onlyOwner
    {
        // If a used index is to be changed, only alter that symbol.
        if (_index > 0) {
            cryptoSymbols[_index] = _symbol;
        } else { // If we are adding a new symbol, push either the symbol or blank string after.
            cryptoSymbols.push(_symbol);
            if (_inverse) cryptoSymbols.push(_symbol);
            else cryptoSymbols.push("");
        }
    }
    
    /**
     * @dev Allows Coinvest to reward users with free platform trades.
     * @param _users List of users to reward.
     * @param _trades List of free trades to give to each.
    **/
    function addTrades(address[] _users, uint256[] _trades)
      external
      onlyAdmin
    {
        require(_users.length == _trades.length);
        for (uint256 i = 0; i < _users.length; i++) {
            freeTrades[_users[i]] = freeTrades[_users[i]].add(_trades[i]);
        }     
    }
    
    /**
     * @dev We were having gas problems on launch so we consolidated here. Will clean up soon.
    **/
    function changeVars(
        address _coinToken, 
        address _cashToken, 
        address _bank, 
        address _userData,
        string _coinUrl,
        string _cashUrl,
        bool _paused)
      external
      onlyOwner
    {
        coinToken = _coinToken;
        cashToken = _cashToken;
        bank = BankI(_bank);
        userData = UserDataI(_userData);
        coinUrl = _coinUrl;
        cashUrl = _cashUrl;
        paused = _paused;
    }
    
    /**
     * @dev Change Oraclize gas limit and price.
     * @param _newGasPrice New gas price to use in wei.
    **/
    function changeGas(uint256 _newGasPrice)
      external
      onlyAdmin
    returns (bool success)
    {
        customGasPrice = _newGasPrice;
        oraclize_setCustomGasPrice(_newGasPrice);
        return true;
    }

/** ********************************* Modifiers ************************************* **/
    
    /**
     * @dev For buys and sells we only want an approved broker or the buyer/seller
     * @dev themselves to mess with the buyer/seller's portfolio
     * @param _beneficiary The buyer or seller whose portfolio is being modified
    **/
    modifier onlySenderOrToken(address _beneficiary)
    {
        require(msg.sender == _beneficiary || msg.sender == coinToken || msg.sender == cashToken);
        _;
    }
    
    /**
     * @dev Ensures the contract cannot be used if Coinvest pauses it.
    **/
    modifier notPaused()
    {
        require(!paused);
        _;
    }
    
/** ******************************************************************************** **/
/** ******************************* Oracle Logic *********************************** **/
/** ******************************************************************************** **/

    /**
     * @dev Here we Oraclize to CryptoCompare to get prices for these cryptos.
     * @param _beneficiary The user who is executing the buy or sell.
     * @param _cryptos The IDs of the cryptos to get prices for.
     * @param _amounts Amount of each crypto to buy.
     * @param _isCoin True/False of the crypto that is being used to invest is COIN/CASH.
     * @param _buy Whether or not this is a buy (as opposed to sell).
    **/
    function getPrices(
        address _beneficiary, 
        uint256[] memory _cryptos, 
        uint256[] memory _amounts, 
        bool _isCoin, 
        bool _buy) 
      internal
    {
        if (oraclize_getPrice("URL") > address(this).balance) {
            emit newOraclizeQuery("Oraclize query was NOT sent");
        } else {
            string memory fullUrl = craftUrl(_cryptos, _isCoin);
            bytes32 queryId = oraclize_query("URL", fullUrl, 150000 + 40000 * _cryptos.length);
            trades[queryId] = TradeInfo(_buy, _isCoin, _beneficiary, InvestLib.bitConv(_cryptos, _amounts));
            emit newOraclizeQuery("Oraclize query was sent");
        }
    }
    
    /**
     * @dev Oraclize calls and should simply set the query array to the int results.
     * @param myid Unique ID of the Oraclize query, index for save idsAndAmts.
     * @param result JSON string of CryptoCompare's return.
     * @param proof Proof of validity of the Oracle call--not used.
    **/
    function __callback(bytes32 myid, string result, bytes proof)
      public
    {
        require(msg.sender == oraclize_cbAddress());

        TradeInfo memory tradeInfo = trades[myid];
        (uint256[] memory cryptos, uint256[] memory amounts) = InvestLib.bitRec(tradeInfo.idsAndAmts);

        bool isCoin = tradeInfo.isCoin;
        uint256[] memory cryptoValues = decodePrices(cryptos, result, isCoin);
        uint256 value = InvestLib.calculateValue(amounts, cryptoValues);
        
        if (tradeInfo.isBuy) finalizeBuy(tradeInfo.beneficiary, cryptos, amounts, cryptoValues, value, isCoin);
        else finalizeSell(tradeInfo.beneficiary, cryptos, amounts, cryptoValues, value, isCoin);
        
        delete trades[myid];
        proof;
    }
    
/** ******************************* Constants ************************************ **/
    
    /**
     * @dev Crafts URL for Oraclize to grab data from.
     * @param _cryptos The uint256 crypto ID of the cryptos to search.
     * @param _isCoin True if COIN is being used as the investment token.
    **/
    function craftUrl(uint256[] memory _cryptos, bool _isCoin)
      public
      view
    returns (string memory url)
    {
        if (_isCoin) url = coinUrl;
        else url = cashUrl;

        for (uint256 i = 0; i < _cryptos.length; i++) {
            uint256 id = _cryptos[i];

            // This loop ensures only one of each crypto is being bought.
            for (uint256 j = 0; j < _cryptos.length; j++) {
                if (i == j) break;
                require(id != _cryptos[j]);
            }

            require(bytes(cryptoSymbols[id]).length > 0);
            url = url.toSlice().concat(cryptoSymbols[id].toSlice());
        }
        return url;
    }

    /**
     * @dev Cycles through a list of separators to split the api
     * @dev result string. Returns list so that we can update invest contract with values.
     * @param _cryptos The cryptoIds being decoded.
     * @param _result The raw string returned from the cryptocompare api with all crypto prices.
     * @param _isCoin True/False of the crypto that is being used to invest is COIN/CASH.
    **/
    function decodePrices(uint256[] memory _cryptos, string memory _result, bool _isCoin) 
      public
      view
    returns (uint256[] memory prices)
    {
        strings.slice memory s = _result.toSlice();
        strings.slice memory delim = 'USD'.toSlice();
        s.split(delim).toString();

        prices = new uint256[](_cryptos.length + 1);
        
        //Find price of COIN first.
        string memory coinPart = s.split(delim).toString();
        prices[0] = parseInt(coinPart,18);

        // Each crypto is advanced one in the prices array because COIN/CASH is index 0.
        for(uint256 i = 0; i < _cryptos.length; i++) {
            uint256 crypto = _cryptos[i];
            bool isInverse = crypto % 2 > 0;
            
            // This loop is necessary because cryptocompare will only return 1 value when the same crypto is queried twice (in case of inverse).
            for (uint256 j = 0; j < _cryptos.length; j++) {
                if (j == i) break;
                if ((isInverse && _cryptos[j] == crypto - 1) || (!isInverse && _cryptos[j] == crypto + 1)) {
                    prices[i+1] = (10 ** 36) / prices[j+1];
                    break;
                }
            }
            
            // If the crypto is COIN or CASH buying itself we don't want it to split price (because CryptoCompare will only return the first query)
            if ((prices[i+1] == 0 && _isCoin && (crypto == COIN_ID || crypto == COIN_INV)) ||
                (prices[i+1] == 0 && !_isCoin && (crypto == CASH_ID || crypto == CASH_INV))) {
                
                if (!isInverse) prices[i+1] = prices[0];
                else prices[i+1] = (10 ** 36) / prices[0];
            }

            // Normal cases
            else if (prices[i+1] == 0) {
                string memory part = s.split(delim).toString();
        
                uint256 price = parseInt(part,18);
                if (price > 0 && !isInverse) prices[i+1] = price;
                else if (price > 0) prices[i+1] = (10 ** 36) / price;
            }
        }

        // Final check in case anything goes wrong.
        for (uint256 k = 0; k < prices.length; k++) require(prices[k] > 0);
        return prices;
    }
    
/** ************************** Only Coinvest ******************************* **/

    /**
     * @dev Allow the owner to take ERC20 tokens off of this contract if they are accidentally sent.
     * @param _tokenContract The address of the token to withdraw (0x0 if Ether).
     * @param _amount The amount of Ether to withdraw (because some needs to be left for Oraclize).
    **/
    function tokenEscape(address _tokenContract, uint256 _amount)
      external
      coinvestOrOwner
    {
        if (_tokenContract == address(0)) coinvest.transfer(_amount);
        else {
            ERC20Interface lostToken = ERC20Interface(_tokenContract);
            uint256 stuckTokens = lostToken.balanceOf(address(this));
            lostToken.transfer(coinvest, stuckTokens);
        }
    }

}

Contract Security Audit

Contract ABI

API
[{"constant":true,"inputs":[],"name":"CASH_ID","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"coinvest","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_user","type":"address"},{"name":"_status","type":"bool"}],"name":"alterAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newGasPrice","type":"uint256"}],"name":"changeGas","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_coinToken","type":"address"},{"name":"_cashToken","type":"address"},{"name":"_bank","type":"address"},{"name":"_userData","type":"address"},{"name":"_coinUrl","type":"string"},{"name":"_cashUrl","type":"string"},{"name":"_paused","type":"bool"}],"name":"changeVars","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"myid","type":"bytes32"},{"name":"result","type":"string"}],"name":"__callback","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"myid","type":"bytes32"},{"name":"result","type":"string"},{"name":"proof","type":"bytes"}],"name":"__callback","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"admins","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"cryptoSymbols","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"customGasPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CASH_INV","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"coinToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_tokenContract","type":"address"},{"name":"_amount","type":"uint256"}],"name":"tokenEscape","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"bank","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_token","type":"address"},{"name":"_data","type":"bytes"}],"name":"receiveApproval","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"COIN_INV","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_users","type":"address[]"},{"name":"_trades","type":"uint256[]"}],"name":"addTrades","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_cryptos","type":"uint256[]"},{"name":"_result","type":"string"},{"name":"_isCoin","type":"bool"}],"name":"decodePrices","outputs":[{"name":"prices","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"COIN_ID","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cashToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_cryptos","type":"uint256[]"},{"name":"_isCoin","type":"bool"}],"name":"craftUrl","outputs":[{"name":"url","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"userData","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_beneficiary","type":"address"},{"name":"_cryptoIds","type":"uint256[]"},{"name":"_amounts","type":"uint256[]"},{"name":"_isCoin","type":"bool"}],"name":"buy","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"coinUrl","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"freeTrades","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_index","type":"uint256"},{"name":"_symbol","type":"string"},{"name":"_inverse","type":"bool"}],"name":"addCrypto","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"cashUrl","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newCoinvest","type":"address"}],"name":"transferCoinvest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_beneficiary","type":"address"},{"name":"_cryptoIds","type":"uint256[]"},{"name":"_amounts","type":"uint256[]"},{"name":"_isCoin","type":"bool"}],"name":"sell","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_coinToken","type":"address"},{"name":"_cashToken","type":"address"},{"name":"_bank","type":"address"},{"name":"_userData","type":"address"}],"payable":true,"stateMutability":"payable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"description","type":"string"}],"name":"newOraclizeQuery","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"buyer","type":"address"},{"indexed":false,"name":"cryptoIds","type":"uint256[]"},{"indexed":false,"name":"amounts","type":"uint256[]"},{"indexed":false,"name":"prices","type":"uint256[]"}],"name":"Buy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"seller","type":"address"},{"indexed":false,"name":"cryptoIds","type":"uint256[]"},{"indexed":false,"name":"amounts","type":"uint256[]"},{"indexed":false,"name":"prices","type":"uint256[]"}],"name":"Sell","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]

6080604052608060405190810160405280604c81526020017f687474703a2f2f6563322d31382d3233342d3132342d35332e636f6d7075746581526020017f2d312e616d617a6f6e6177732e636f6d2f6170692f7072696365546573743f6381526020017f727970746f733d434f494e2c0000000000000000000000000000000000000000815250600d90805190602001906200009e929190620015b5565b506020604051908101604052806000815250600e9080519060200190620000c7929190620015b5565b506040516080806200761783398101806040528101908080519060200190929190805190602001909291908051906020019092919080519060200190929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600260008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600160026000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555083600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600b60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550620003e360017f01000000000000000000000000000000000000000000000000000000000000000260107f0100000000000000000000000000000000000000000000000000000000000000021762000781640100000000026401000000009004565b6200043660006040805190810160405280600581526020017f434f494e2c000000000000000000000000000000000000000000000000000000815250600062000b39640100000000026401000000009004565b6200046460006020604051908101604052806000815250600062000b39640100000000026401000000009004565b620004b760006040805190810160405280600481526020017f4254432c00000000000000000000000000000000000000000000000000000000815250600062000b39640100000000026401000000009004565b6200050a60006040805190810160405280600481526020017f4554482c00000000000000000000000000000000000000000000000000000000815250600062000b39640100000000026401000000009004565b6200055d60006040805190810160405280600481526020017f5852502c00000000000000000000000000000000000000000000000000000000815250600062000b39640100000000026401000000009004565b620005b060006040805190810160405280600481526020017f4c54432c00000000000000000000000000000000000000000000000000000000815250600062000b39640100000000026401000000009004565b6200060360006040805190810160405280600581526020017f444153482c000000000000000000000000000000000000000000000000000000815250600062000b39640100000000026401000000009004565b6200065660006040805190810160405280600481526020017f4243482c00000000000000000000000000000000000000000000000000000000815250600062000b39640100000000026401000000009004565b620006a960006040805190810160405280600481526020017f584d522c00000000000000000000000000000000000000000000000000000000815250600062000b39640100000000026401000000009004565b620006fc60006040805190810160405280600481526020017f58454d2c00000000000000000000000000000000000000000000000000000000815250600062000b39640100000000026401000000009004565b6200074f60006040805190810160405280600481526020017f454f532c00000000000000000000000000000000000000000000000000000000815250600062000b39640100000000026401000000009004565b64012a05f200600c8190555062000777600c5462000cb9640100000000026401000000009004565b5050505062001664565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161480620008045750600062000802600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166200102d640100000000026401000000009004565b145b15620008275762000825600062001038640100000000026401000000009004565b505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015620008ae57600080fd5b505af1158015620008c3573d6000803e3d6000fd5b505050506040513d6020811015620008da57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151562000a4757600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015620009c957600080fd5b505af1158015620009de573d6000803e3d6000fd5b505050506040513d6020811015620009f557600080fd5b8101908080519060200190929190505050600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663688dcfd7826040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180827effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001915050600060405180830381600087803b15801562000b1d57600080fd5b505af115801562000b32573d6000803e3d6000fd5b5050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151562000b9557600080fd5b600083111562000bd6578160118481548110151562000bb057fe5b90600052602060002001908051906020019062000bcf929190620015b5565b5062000cb4565b601182908060018154018082558091505090600182039060005260206000200160009091929091909150908051906020019062000c15929190620015b5565b5050801562000c6557601182908060018154018082558091505090600182039060005260206000200160009091929091909150908051906020019062000c5d929190620015b5565b505062000cb3565b601180600181540180825580915050906001820390600052602060002001600060206040519081016040528060008152509091909150908051906020019062000cb0929190620015b5565b50505b5b505050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148062000d3c5750600062000d3a600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166200102d640100000000026401000000009004565b145b1562000d5f5762000d5d600062001038640100000000026401000000009004565b505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801562000de657600080fd5b505af115801562000dfb573d6000803e3d6000fd5b505050506040513d602081101562000e1257600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151562000f7f57600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801562000f0157600080fd5b505af115801562000f16573d6000803e3d6000fd5b505050506040513d602081101562000f2d57600080fd5b8101908080519060200190929190505050600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ca6ad1e4826040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156200101157600080fd5b505af115801562001026573d6000803e3d6000fd5b5050505050565b6000813b9050919050565b60008062001069731d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed6200102d640100000000026401000000009004565b11156200111e57731d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550620011146040805190810160405280600b81526020017f6574685f6d61696e6e657400000000000000000000000000000000000000000081525062001599640100000000026401000000009004565b6001905062001594565b60006200114e73c03a2615d5efaf5f49f60b7bb6583eaec212fdf16200102d640100000000026401000000009004565b1115620012035773c03a2615d5efaf5f49f60b7bb6583eaec212fdf1600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550620011f96040805190810160405280600c81526020017f6574685f726f707374656e33000000000000000000000000000000000000000081525062001599640100000000026401000000009004565b6001905062001594565b60006200123373b7a07bcf2ba2f2703b24c0691b5278999c59ac7e6200102d640100000000026401000000009004565b1115620012e85773b7a07bcf2ba2f2703b24c0691b5278999c59ac7e600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550620012de6040805190810160405280600981526020017f6574685f6b6f76616e000000000000000000000000000000000000000000000081525062001599640100000000026401000000009004565b6001905062001594565b60006200131873146500cfd35b22e4a392fe0adc06de1a1368ed486200102d640100000000026401000000009004565b1115620013cd5773146500cfd35b22e4a392fe0adc06de1a1368ed48600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550620013c36040805190810160405280600b81526020017f6574685f72696e6b65627900000000000000000000000000000000000000000081525062001599640100000000026401000000009004565b6001905062001594565b6000620013fd736f485c8bf6fc43ea212e93bbf8ce046c7f1cb4756200102d640100000000026401000000009004565b11156200146357736f485c8bf6fc43ea212e93bbf8ce046c7f1cb475600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001905062001594565b6000620014937320e12a1f859b3feae5fb2a0a32c18f5a65555bbf6200102d640100000000026401000000009004565b1115620014f9577320e12a1f859b3feae5fb2a0a32c18f5a65555bbf600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001905062001594565b6000620015297351efaf4c8b3c9afbd5ab9f4bbc82784ab6ef8faa6200102d640100000000026401000000009004565b11156200158f577351efaf4c8b3c9afbd5ab9f4bbc82784ab6ef8faa600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001905062001594565b600090505b919050565b8060059080519060200190620015b1929190620015b5565b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620015f857805160ff191683800117855562001629565b8280016001018555821562001629579182015b82811115620016285782518255916020019190600101906200160b565b5b5090506200163891906200163c565b5090565b6200166191905b808211156200165d57600081600090555060010162001643565b5090565b90565b615fa380620016746000396000f300608060405260043610610196576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806302e7b53f146101f05780630958a9f31461021b57806310840303146102725780631833a548146102c15780631ff4ca091461030657806327dc297e146103e557806338bbfa501461045c578063429b62e51461051957806349c38b0a146105745780634b0720a71461061a578063569970261461064557806358797cb6146106705780635c975abb146106c757806368e09ab5146106f657806376cdb03b146107435780638da5cb5b1461079a5780638f4ffcb1146107f1578063909c9705146108a457806393911ff8146108cf5780639d4870ba146109225780639ecc626a14610a2f578063a722468714610a5a578063aa88a57c14610ab1578063bea6998f14610b9c578063c0eb2e7014610bf3578063cbaec30f14610cbb578063cca7322814610d4b578063d353ffa914610da2578063d830fb9414610e21578063dfb6c46814610eb1578063e06572ec14610ef4578063f2fde38b14610fbc575b600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615156101ee57600080fd5b005b3480156101fc57600080fd5b50610205610fff565b6040518082815260200191505060405180910390f35b34801561022757600080fd5b50610230611004565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561027e57600080fd5b506102bf600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080351515906020019092919050505061102a565b005b3480156102cd57600080fd5b506102ec60048036038101908080359060200190929190505050611179565b604051808215151515815260200191505060405180910390f35b34801561031257600080fd5b506103e3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019082018035906020019190919293919293908035906020019082018035906020019190919293919293908035151590602001909291905050506111ec565b005b3480156103f157600080fd5b5061045a6004803603810190808035600019169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050611394565b005b34801561046857600080fd5b506105176004803603810190808035600019169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506113d7565b005b34801561052557600080fd5b5061055a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506118cc565b604051808215151515815260200191505060405180910390f35b34801561058057600080fd5b5061059f600480360381019080803590602001909291905050506118ec565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156105df5780820151818401526020810190506105c4565b50505050905090810190601f16801561060c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561062657600080fd5b5061062f6119a7565b6040518082815260200191505060405180910390f35b34801561065157600080fd5b5061065a6119ad565b6040518082815260200191505060405180910390f35b34801561067c57600080fd5b506106856119b2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156106d357600080fd5b506106dc6119d8565b604051808215151515815260200191505060405180910390f35b34801561070257600080fd5b50610741600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506119eb565b005b34801561074f57600080fd5b50610758611d27565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af611d4d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107fd57600080fd5b506108a2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050611d72565b005b3480156108b057600080fd5b506108b9611ef6565b6040518082815260200191505060405180910390f35b3480156108db57600080fd5b50610920600480360381019080803590602001908201803590602001919091929391929390803590602001908201803590602001919091929391929390505050611efb565b005b34801561092e57600080fd5b506109d860048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080351515906020019092919050505061208a565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610a1b578082015181840152602081019050610a00565b505050509050019250505060405180910390f35b348015610a3b57600080fd5b50610a446124f2565b6040518082815260200191505060405180910390f35b348015610a6657600080fd5b50610a6f6124f7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610abd57600080fd5b50610b216004803603810190808035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080351515906020019092919050505061251d565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610b61578082015181840152602081019050610b46565b50505050905090810190601f168015610b8e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610ba857600080fd5b50610bb161280b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610cb9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803515159060200190929190505050612831565b005b348015610cc757600080fd5b50610cd061295d565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610d10578082015181840152602081019050610cf5565b50505050905090810190601f168015610d3d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610d5757600080fd5b50610d8c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506129fb565b6040518082815260200191505060405180910390f35b348015610dae57600080fd5b50610e1f60048036038101908080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803515159060200190929190505050612a13565b005b348015610e2d57600080fd5b50610e36612b85565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610e76578082015181840152602081019050610e5b565b50505050905090810190601f168015610ea35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610ebd57600080fd5b50610ef2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612c23565b005b610fba600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803515159060200190929190505050612cfe565b005b348015610fc857600080fd5b50610ffd600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612e2a565b005b600281565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561108557600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141515156110c157600080fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561111e57600080fd5b80600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615156111d357600080fd5b81600c819055506111e382612f7f565b60019050919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561124757600080fd5b88600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555087600b60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555086600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555085600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508484600d919061135c929190615d87565b508282600e919061136e929190615d87565b5080600f60006101000a81548160ff021916908315150217905550505050505050505050565b6113d3828260006040519080825280601f01601f1916602001820160405280156113cd5781602001602082028038833980820191505090505b506113d7565b5050565b6113df615e07565b6060806000606060006113f06132c6565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561142957600080fd5b601060008a60001916600019168152602001908152602001600020608060405190810160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff161515151581526020016000820160029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820180548060200260200160405190810160405280929190818152602001828054801561152b57602002820191906000526020600020905b815481526020019060010190808311611517575b5050505050815250509550733f6f6c65a851c49f179e6868091dc73b7a6a492d63519e7e4f87606001516040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825283818151815260200191508051906020019060200280838360005b838110156115c35780820151818401526020810190506115a8565b505050509050019250505060006040518083038186803b1580156115e657600080fd5b505af41580156115fa573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250604081101561162457600080fd5b81019080805164010000000081111561163c57600080fd5b8281019050602081018481111561165257600080fd5b815185602082028301116401000000008211171561166f57600080fd5b5050929190602001805164010000000081111561168b57600080fd5b828101905060208101848111156116a157600080fd5b81518560208202830111640100000000821117156116be57600080fd5b505092919050505094509450856020015192506116dc85898561208a565b9150733f6f6c65a851c49f179e6868091dc73b7a6a492d63ad3213e085846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561176c578082015181840152602081019050611751565b50505050905001838103825284818151815260200191508051906020019060200280838360005b838110156117ae578082015181840152602081019050611793565b5050505090500194505050505060206040518083038186803b1580156117d357600080fd5b505af41580156117e7573d6000803e3d6000fd5b505050506040513d60208110156117fd57600080fd5b810190808051906020019092919050505090508560000151156118315761182c86604001518686858588613628565b611844565b61184386604001518686858588613f80565b5b601060008a60001916600019168152602001908152602001600020600080820160006101000a81549060ff02191690556000820160016101000a81549060ff02191690556000820160026101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001820160006118bf9190615e4a565b5050505050505050505050565b60026020528060005260406000206000915054906101000a900460ff1681565b6011818154811015156118fb57fe5b906000526020600020016000915090508054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561199f5780601f106119745761010080835404028352916020019161199f565b820191906000526020600020905b81548152906001019060200180831161198257829003601f168201915b505050505081565b600c5481565b600381565b600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600f60009054906101000a900460ff1681565b600080600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611a9657506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515611aa157600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415611b4457600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f19350505050158015611b3e573d6000803e3d6000fd5b50611d21565b8391508173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611be257600080fd5b505af1158015611bf6573d6000803e3d6000fd5b505050506040513d6020811015611c0c57600080fd5b810190808051906020019092919050505090508173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015611ce457600080fd5b505af1158015611cf8573d6000803e3d6000fd5b505050506040513d6020811015611d0e57600080fd5b8101908080519060200190929190505050505b50505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611e1d5750600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515611e2857600080fd5b602482015190508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16141515611e6957600080fd5b3073ffffffffffffffffffffffffffffffffffffffff168260405180828051906020019080838360005b83811015611eae578082015181840152602081019050611e93565b50505050905090810190601f168015611edb5780820380516001836020036101000a031916815260200191505b50915050600060405180830381855af4915050505050505050565b600181565b6000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515611f5557600080fd5b8282905085859050141515611f6957600080fd5b600090505b84849050811015612083576120098383838181101515611f8a57fe5b90506020020135601260008888868181101515611fa357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546145ad90919063ffffffff16565b60126000878785818110151561201b57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508080600101915050611f6e565b5050505050565b6060612094615e6b565b61209c615e6b565b606060008060008060606000806120b28d6145cb565b99506120f26040805190810160405280600381526020017f55534400000000000000000000000000000000000000000000000000000000008152506145cb565b985061210f61210a8a8c6145f990919063ffffffff16565b614613565b5060018e51016040519080825280602002602001820160405280156121435781602001602082028038833980820191505090505b509a5061216161215c8a8c6145f990919063ffffffff16565b614613565b975061216e886012614675565b8b600081518110151561217d57fe5b9060200190602002018181525050600096505b8d5187101561249d578d878151811015156121a757fe5b90602001906020020151955060006002878115156121c157fe5b06119450600093505b8d5184101561229f57868414156121e05761229f565b8480156122065750600186038e858151811015156121fa57fe5b90602001906020020151145b806122345750841580156122335750600186018e8581518110151561222757fe5b90602001906020020151145b5b15612292578a6001850181518110151561224a57fe5b906020019060200201516ec097ce7bc90715b34b9f100000000081151561226d57fe5b048b6001890181518110151561227f57fe5b906020019060200201818152505061229f565b83806001019450506121ca565b60008b600189018151811015156122b257fe5b906020019060200201511480156122c657508b5b80156122dd575060008614806122dc5750600186145b5b80612323575060008b600189018151811015156122f657fe5b9060200190602002015114801561230b57508b155b8015612322575060028614806123215750600386145b5b5b156123c45784151561236c578a600081518110151561233e57fe5b906020019060200201518b6001890181518110151561235957fe5b90602001906020020181815250506123bf565b8a600081518110151561237b57fe5b906020019060200201516ec097ce7bc90715b34b9f100000000081151561239e57fe5b048b600189018151811015156123b057fe5b90602001906020020181815250505b612490565b60008b600189018151811015156123d757fe5b90602001906020020151141561248f576124026123fd8a8c6145f990919063ffffffff16565b614613565b925061240f836012614675565b915060008211801561241f575084155b1561244957818b6001890181518110151561243657fe5b906020019060200201818152505061248e565b600082111561248d57816ec097ce7bc90715b34b9f100000000081151561246c57fe5b048b6001890181518110151561247e57fe5b90602001906020020181815250505b5b5b5b8680600101975050612190565b600090505b8a518110156124de5760008b828151811015156124bb57fe5b906020019060200201511115156124d157600080fd5b80806001019150506124a2565b8a9a50505050505050505050509392505050565b600081565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060600080600084156125cc57600d8054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156125c05780601f10612595576101008083540402835291602001916125c0565b820191906000526020600020905b8154815290600101906020018083116125a357829003601f168201915b5050505050935061266a565b600e8054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156126625780601f1061263757610100808354040283529160200191612662565b820191906000526020600020905b81548152906001019060200180831161264557829003601f168201915b505050505093505b600092505b85518310156127ff57858381518110151561268657fe5b906020019060200201519150600090505b85518110156126e057808314156126ad576126e0565b85818151811015156126bb57fe5b9060200190602002015182141515156126d357600080fd5b8080600101915050612697565b60006011838154811015156126f157fe5b9060005260206000200180546001816001161561010002031660029004905011151561271c57600080fd5b6127f06127d960118481548110151561273157fe5b906000526020600020018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156127cf5780601f106127a4576101008083540402835291602001916127cf565b820191906000526020600020905b8154815290600101906020018083116127b257829003601f168201915b50505050506145cb565b6127e2866145cb565b61496990919063ffffffff16565b9350828060010193505061266f565b83935050505092915050565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600f60009054906101000a900460ff1615151561284d57600080fd5b838073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806128d55750600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b8061292d5750600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561293857600080fd5b8251845114151561294857600080fd5b6129568585858560016149eb565b5050505050565b600d8054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156129f35780601f106129c8576101008083540402835291602001916129f3565b820191906000526020600020905b8154815290600101906020018083116129d657829003601f168201915b505050505081565b60126020528060005260406000206000915090505481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612a6e57600080fd5b6000831115612aaa5781601184815481101515612a8757fe5b906000526020600020019080519060200190612aa4929190615e85565b50612b80565b6011829080600181540180825580915050906001820390600052602060002001600090919290919091509080519060200190612ae7929190615e85565b50508015612b33576011829080600181540180825580915050906001820390600052602060002001600090919290919091509080519060200190612b2c929190615e85565b5050612b7f565b6011806001815401808255809150509060018203906000526020600020016000602060405190810160405280600081525090919091509080519060200190612b7c929190615e85565b50505b5b505050565b600e8054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015612c1b5780601f10612bf057610100808354040283529160200191612c1b565b820191906000526020600020905b815481529060010190602001808311612bfe57829003601f168201915b505050505081565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612c7e57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515612cba57600080fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600f60009054906101000a900460ff16151515612d1a57600080fd5b838073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480612da25750600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b80612dfa5750600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515612e0557600080fd5b82518451141515612e1557600080fd5b612e238585858560006149eb565b5050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612e8557600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515612ec157600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161480612ff057506000612fee600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16614c89565b145b1561300157612fff6000614c94565b505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561308757600080fd5b505af115801561309b573d6000803e3d6000fd5b505050506040513d60208110156130b157600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561321a57600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561319e57600080fd5b505af11580156131b2573d6000803e3d6000fd5b505050506040513d60208110156131c857600080fd5b8101908080519060200190929190505050600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ca6ad1e4826040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156132ab57600080fd5b505af11580156132bf573d6000803e3d6000fd5b5050505050565b600080600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148061333857506000613336600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16614c89565b145b15613349576133476000614c94565b505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156133cf57600080fd5b505af11580156133e3573d6000803e3d6000fd5b505050506040513d60208110156133f957600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561356257600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156134e657600080fd5b505af11580156134fa573d6000803e3d6000fd5b505050506040513d602081101561351057600080fd5b8101908080519060200190929190505050600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c281d19e6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156135e857600080fd5b505af11580156135fc573d6000803e3d6000fd5b505050506040513d602081101561361257600080fd5b8101908080519060200190929190505050905090565b600080821561365b57600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150613681565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505b84600081518110151561369057fe5b906020019060200201516f03c109feac3f9bac48ec8cec000000008115156136b457fe5b0490506000601260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111561379a576137526001601260008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461512c90919063ffffffff16565b601260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506138da565b8173ffffffffffffffffffffffffffffffffffffffff166323b872dd89600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16846040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561389357600080fd5b505af11580156138a7573d6000803e3d6000fd5b505050506040513d60208110156138bd57600080fd5b810190808051906020019092919050505015156138d957600080fd5b5b8173ffffffffffffffffffffffffffffffffffffffff166323b872dd89600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16876040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b1580156139d357600080fd5b505af11580156139e7573d6000803e3d6000fd5b505050506040513d60208110156139fd57600080fd5b81019080805190602001909291905050501515613a1957600080fd5b6000876000815181101515613a2a57fe5b90602001906020020151148015613a42575060018751145b15613b7c57600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e1ad116289886000815181101515613a9557fe5b9060200190602002015160016040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001821515151581526020019350505050602060405180830381600087803b158015613b3157600080fd5b505af1158015613b45573d6000803e3d6000fd5b505050506040513d6020811015613b5b57600080fd5b81019080805190602001909291905050501515613b7757600080fd5b613e55565b6002876000815181101515613b8d57fe5b90602001906020020151148015613ba5575060018751145b15613cdf57600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e1ad116289886000815181101515613bf857fe5b9060200190602002015160006040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001821515151581526020019350505050602060405180830381600087803b158015613c9457600080fd5b505af1158015613ca8573d6000803e3d6000fd5b505050506040513d6020811015613cbe57600080fd5b81019080805190602001909291905050501515613cda57600080fd5b613e54565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166348663e7d89898960016040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001806020018060200184151515158152602001838103835286818151815260200191508051906020019060200280838360005b83811015613dd0578082015181840152602081019050613db5565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015613e12578082015181840152602081019050613df7565b505050509050019650505050505050600060405180830381600087803b158015613e3b57600080fd5b505af1158015613e4f573d6000803e3d6000fd5b505050505b5b8773ffffffffffffffffffffffffffffffffffffffff167f6a75660680cd3a8f7f34c5df6451086e3222c8a9e16e568b6e698098e8fd970b88888860405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b83811015613edb578082015181840152602081019050613ec0565b50505050905001848103835286818151815260200191508051906020019060200280838360005b83811015613f1d578082015181840152602081019050613f02565b50505050905001848103825285818151815260200191508051906020019060200280838360005b83811015613f5f578082015181840152602081019050613f44565b50505050905001965050505050505060405180910390a25050505050505050565b6000836000815181101515613f9157fe5b906020019060200201516f03c109feac3f9bac48ec8cec00000000811515613fb557fe5b0490506000601260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111561409b576140536001601260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461512c90919063ffffffff16565b601260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506141f8565b80831115156140a957600080fd5b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e1ad1162600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683856040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001821515151581526020019350505050602060405180830381600087803b15801561419c57600080fd5b505af11580156141b0573d6000803e3d6000fd5b505050506040513d60208110156141c657600080fd5b810190808051906020019092919050505015156141e257600080fd5b6141f5818461512c90919063ffffffff16565b92505b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e1ad11628885856040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001821515151581526020019350505050602060405180830381600087803b1580156142c957600080fd5b505af11580156142dd573d6000803e3d6000fd5b505050506040513d60208110156142f357600080fd5b8101908080519060200190929190505050151561430f57600080fd5b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166348663e7d88888860006040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001806020018060200184151515158152602001838103835286818151815260200191508051906020019060200280838360005b838110156144005780820151818401526020810190506143e5565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015614442578082015181840152602081019050614427565b505050509050019650505050505050600060405180830381600087803b15801561446b57600080fd5b505af115801561447f573d6000803e3d6000fd5b505050508673ffffffffffffffffffffffffffffffffffffffff167f5e1656ea49c37d58c071f8ec59918a4e2380766f4956535b3724476daad4c4fd87878760405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156145095780820151818401526020810190506144ee565b50505050905001848103835286818151815260200191508051906020019060200280838360005b8381101561454b578082015181840152602081019050614530565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561458d578082015181840152602081019050614572565b50505050905001965050505050505060405180910390a250505050505050565b60008082840190508381101515156145c157fe5b8091505092915050565b6145d3615e6b565b600060208301905060408051908101604052808451815260200182815250915050919050565b614601615e6b565b61460c838383615145565b5092915050565b606080600083600001516040519080825280601f01601f19166020018201604052801561464f5781602001602082028038833980820191505090505b50915060208201905061466b81856020015186600001516151e3565b8192505050919050565b6000606060008060008693506000925060009150600090505b835181101561494a5760307f01000000000000000000000000000000000000000000000000000000000000000284828151811015156146c957fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916101580156147e1575060397f010000000000000000000000000000000000000000000000000000000000000002848281518110151561477157fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191611155b156148925781156148045760008614156147fa5761494a565b8580600190039650505b600a830292506030848281518110151561481a57fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000027f01000000000000000000000000000000000000000000000000000000000000009004038301925061493d565b602e7f01000000000000000000000000000000000000000000000000000000000000000284828151811015156148c457fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141561493c57600191505b5b808060010191505061468e565b600086111561495c5785600a0a830292505b8294505050505092915050565b606080600083600001518560000151016040519080825280601f01601f1916602001820160405280156149ab5781602001602082028038833980820191505090505b5091506020820190506149c781866020015187600001516151e3565b6149e085600001518201856020015186600001516151e3565b819250505092915050565b606060003073ffffffffffffffffffffffffffffffffffffffff1631614a456040805190810160405280600381526020017f55524c000000000000000000000000000000000000000000000000000000000081525061522e565b1115614ab8577f46cb989ef9cef13e930e3b7f286225a086e716a90d63e0b7da85d310a9db0c9a60405180806020018281038252601b8152602001807f4f7261636c697a6520717565727920776173204e4f542073656e74000000000081525060200191505060405180910390a1614c80565b614ac2868561251d565b9150614b0e6040805190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815250838851619c4002620249f001615602565b9050608060405190810160405280841515815260200185151581526020018873ffffffffffffffffffffffffffffffffffffffff168152602001614b528888615bb6565b81525060106000836000191660001916815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506060820151816001019080519060200190614c13929190615f05565b509050507f46cb989ef9cef13e930e3b7f286225a086e716a90d63e0b7da85d310a9db0c9a6040518080602001828103825260178152602001807f4f7261636c697a65207175657279207761732073656e7400000000000000000081525060200191505060405180910390a15b50505050505050565b6000813b9050919050565b600080614cb4731d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed614c89565b1115614d5657731d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550614d4d6040805190810160405280600b81526020017f6574685f6d61696e6e6574000000000000000000000000000000000000000000815250615c87565b60019050615127565b6000614d7573c03a2615d5efaf5f49f60b7bb6583eaec212fdf1614c89565b1115614e175773c03a2615d5efaf5f49f60b7bb6583eaec212fdf1600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550614e0e6040805190810160405280600c81526020017f6574685f726f707374656e330000000000000000000000000000000000000000815250615c87565b60019050615127565b6000614e3673b7a07bcf2ba2f2703b24c0691b5278999c59ac7e614c89565b1115614ed85773b7a07bcf2ba2f2703b24c0691b5278999c59ac7e600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550614ecf6040805190810160405280600981526020017f6574685f6b6f76616e0000000000000000000000000000000000000000000000815250615c87565b60019050615127565b6000614ef773146500cfd35b22e4a392fe0adc06de1a1368ed48614c89565b1115614f995773146500cfd35b22e4a392fe0adc06de1a1368ed48600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550614f906040805190810160405280600b81526020017f6574685f72696e6b656279000000000000000000000000000000000000000000815250615c87565b60019050615127565b6000614fb8736f485c8bf6fc43ea212e93bbf8ce046c7f1cb475614c89565b111561501c57736f485c8bf6fc43ea212e93bbf8ce046c7f1cb475600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060019050615127565b600061503b7320e12a1f859b3feae5fb2a0a32c18f5a65555bbf614c89565b111561509f577320e12a1f859b3feae5fb2a0a32c18f5a65555bbf600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060019050615127565b60006150be7351efaf4c8b3c9afbd5ab9f4bbc82784ab6ef8faa614c89565b1115615122577351efaf4c8b3c9afbd5ab9f4bbc82784ab6ef8faa600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060019050615127565b600090505b919050565b600082821115151561513a57fe5b818303905092915050565b61514d615e6b565b600061516b8560000151866020015186600001518760200151615ca1565b905084602001518360200181815250508460200151810383600001818152505084600001518560200151018114156151ad5760008560000181815250506151d8565b8360000151836000015101856000018181510391508181525050836000015181018560200181815250505b829150509392505050565b60005b60208210151561520b57825184526020840193506020830192506020820391506151e6565b6001826020036101000a0390508019835116818551168181178652505050505050565b600080600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614806152a05750600061529e600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16614c89565b145b156152b1576152af6000614c94565b505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561533757600080fd5b505af115801561534b573d6000803e3d6000fd5b505050506040513d602081101561536157600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415156154ca57600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561544e57600080fd5b505af1158015615462573d6000803e3d6000fd5b505050506040513d602081101561547857600080fd5b8101908080519060200190929190505050600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663524f3889836040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015615574578082015181840152602081019050615559565b50505050905090810190601f1680156155a15780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b1580156155c057600080fd5b505af11580156155d4573d6000803e3d6000fd5b505050506040513d60208110156155ea57600080fd5b81019080805190602001909291905050509050919050565b6000806000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148061567657506000615674600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16614c89565b145b15615687576156856000614c94565b505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561570d57600080fd5b505af1158015615721573d6000803e3d6000fd5b505050506040513d602081101561573757600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415156158a057600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561582457600080fd5b505af1158015615838573d6000803e3d6000fd5b505050506040513d602081101561584e57600080fd5b8101908080519060200190929190505050600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632ef3accc86856040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001838152602001828103825284818151815260200191508051906020019080838360005b83811015615951578082015181840152602081019050615936565b50505050905090810190601f16801561597e5780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561599e57600080fd5b505af11580156159b2573d6000803e3d6000fd5b505050506040513d60208110156159c857600080fd5b81019080805190602001909291905050509050823a02670de0b6b3a7640000018111156159fb5760006001029150615bae565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c51be90f8260008888886040518663ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808581526020018060200180602001848152602001838103835286818151815260200191508051906020019080838360005b83811015615aba578082015181840152602081019050615a9f565b50505050905090810190601f168015615ae75780820380516001836020036101000a031916815260200191505b50838103825285818151815260200191508051906020019080838360005b83811015615b20578082015181840152602081019050615b05565b50505050905090810190601f168015615b4d5780820380516001836020036101000a031916815260200191505b5096505050505050506020604051808303818588803b158015615b6f57600080fd5b505af1158015615b83573d6000803e3d6000fd5b50505050506040513d6020811015615b9a57600080fd5b810190808051906020019092919050505091505b509392505050565b606060008351604051908082528060200260200182016040528015615bea5781602001602082028038833980820191505090505b509150600090505b8351811015615c7d578381815181101515615c0957fe5b906020019060200201518282815181101515615c2157fe5b906020019060200201818152505060088382815181101515615c3f57fe5b906020019060200201519060020a028282815181101515615c5c57fe5b90602001906020020181815117915081815250508080600101915050615bf2565b8191505092915050565b8060059080519060200190615c9d929190615e85565b5050565b60008060008060008060008060008b97508c8b111515615d715760208b111515615d2b5760018b60200360080260020a03196001029550858a511694508a8d8d010393508588511692505b84600019168360001916141515615d23578388101515615d10578c8c019850615d77565b8780600101985050858851169250615cec565b879850615d77565b8a8a209150600096505b8a8d0387111515615d70578a88209050806000191682600019161415615d5d57879850615d77565b6001880197508680600101975050615d35565b5b8c8c0198505b5050505050505050949350505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615dc857803560ff1916838001178555615df6565b82800160010185558215615df6579182015b82811115615df5578235825591602001919060010190615dda565b5b509050615e039190615f52565b5090565b608060405190810160405280600015158152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b5080546000825590600052602060002090810190615e689190615f52565b50565b604080519081016040528060008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615ec657805160ff1916838001178555615ef4565b82800160010185558215615ef4579182015b82811115615ef3578251825591602001919060010190615ed8565b5b509050615f019190615f52565b5090565b828054828255906000526020600020908101928215615f41579160200282015b82811115615f40578251825591602001919060010190615f25565b5b509050615f4e9190615f52565b5090565b615f7491905b80821115615f70576000816000905550600101615f58565b5090565b905600a165627a7a72305820eaf5938b02f08ff2a647e28d3eb6dbc00b5f62b4d1cba2fb3f254d3f3fad08460029000000000000000000000000eb547ed1d8a3ff1461abaa7f0022fed4836e00a4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081df38586d808f78d7741f6541f995ff2b639872000000000000000000000000dfaa6ee812792f58953aae0b762480dad6132885

Deployed Bytecode

0x608060405260043610610196576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806302e7b53f146101f05780630958a9f31461021b57806310840303146102725780631833a548146102c15780631ff4ca091461030657806327dc297e146103e557806338bbfa501461045c578063429b62e51461051957806349c38b0a146105745780634b0720a71461061a578063569970261461064557806358797cb6146106705780635c975abb146106c757806368e09ab5146106f657806376cdb03b146107435780638da5cb5b1461079a5780638f4ffcb1146107f1578063909c9705146108a457806393911ff8146108cf5780639d4870ba146109225780639ecc626a14610a2f578063a722468714610a5a578063aa88a57c14610ab1578063bea6998f14610b9c578063c0eb2e7014610bf3578063cbaec30f14610cbb578063cca7322814610d4b578063d353ffa914610da2578063d830fb9414610e21578063dfb6c46814610eb1578063e06572ec14610ef4578063f2fde38b14610fbc575b600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615156101ee57600080fd5b005b3480156101fc57600080fd5b50610205610fff565b6040518082815260200191505060405180910390f35b34801561022757600080fd5b50610230611004565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561027e57600080fd5b506102bf600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080351515906020019092919050505061102a565b005b3480156102cd57600080fd5b506102ec60048036038101908080359060200190929190505050611179565b604051808215151515815260200191505060405180910390f35b34801561031257600080fd5b506103e3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019082018035906020019190919293919293908035906020019082018035906020019190919293919293908035151590602001909291905050506111ec565b005b3480156103f157600080fd5b5061045a6004803603810190808035600019169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050611394565b005b34801561046857600080fd5b506105176004803603810190808035600019169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506113d7565b005b34801561052557600080fd5b5061055a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506118cc565b604051808215151515815260200191505060405180910390f35b34801561058057600080fd5b5061059f600480360381019080803590602001909291905050506118ec565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156105df5780820151818401526020810190506105c4565b50505050905090810190601f16801561060c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561062657600080fd5b5061062f6119a7565b6040518082815260200191505060405180910390f35b34801561065157600080fd5b5061065a6119ad565b6040518082815260200191505060405180910390f35b34801561067c57600080fd5b506106856119b2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156106d357600080fd5b506106dc6119d8565b604051808215151515815260200191505060405180910390f35b34801561070257600080fd5b50610741600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506119eb565b005b34801561074f57600080fd5b50610758611d27565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af611d4d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107fd57600080fd5b506108a2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050611d72565b005b3480156108b057600080fd5b506108b9611ef6565b6040518082815260200191505060405180910390f35b3480156108db57600080fd5b50610920600480360381019080803590602001908201803590602001919091929391929390803590602001908201803590602001919091929391929390505050611efb565b005b34801561092e57600080fd5b506109d860048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080351515906020019092919050505061208a565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610a1b578082015181840152602081019050610a00565b505050509050019250505060405180910390f35b348015610a3b57600080fd5b50610a446124f2565b6040518082815260200191505060405180910390f35b348015610a6657600080fd5b50610a6f6124f7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610abd57600080fd5b50610b216004803603810190808035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080351515906020019092919050505061251d565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610b61578082015181840152602081019050610b46565b50505050905090810190601f168015610b8e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610ba857600080fd5b50610bb161280b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610cb9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803515159060200190929190505050612831565b005b348015610cc757600080fd5b50610cd061295d565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610d10578082015181840152602081019050610cf5565b50505050905090810190601f168015610d3d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610d5757600080fd5b50610d8c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506129fb565b6040518082815260200191505060405180910390f35b348015610dae57600080fd5b50610e1f60048036038101908080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803515159060200190929190505050612a13565b005b348015610e2d57600080fd5b50610e36612b85565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610e76578082015181840152602081019050610e5b565b50505050905090810190601f168015610ea35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610ebd57600080fd5b50610ef2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612c23565b005b610fba600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803515159060200190929190505050612cfe565b005b348015610fc857600080fd5b50610ffd600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612e2a565b005b600281565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561108557600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141515156110c157600080fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561111e57600080fd5b80600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615156111d357600080fd5b81600c819055506111e382612f7f565b60019050919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561124757600080fd5b88600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555087600b60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555086600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555085600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508484600d919061135c929190615d87565b508282600e919061136e929190615d87565b5080600f60006101000a81548160ff021916908315150217905550505050505050505050565b6113d3828260006040519080825280601f01601f1916602001820160405280156113cd5781602001602082028038833980820191505090505b506113d7565b5050565b6113df615e07565b6060806000606060006113f06132c6565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561142957600080fd5b601060008a60001916600019168152602001908152602001600020608060405190810160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff161515151581526020016000820160029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820180548060200260200160405190810160405280929190818152602001828054801561152b57602002820191906000526020600020905b815481526020019060010190808311611517575b5050505050815250509550733f6f6c65a851c49f179e6868091dc73b7a6a492d63519e7e4f87606001516040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825283818151815260200191508051906020019060200280838360005b838110156115c35780820151818401526020810190506115a8565b505050509050019250505060006040518083038186803b1580156115e657600080fd5b505af41580156115fa573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250604081101561162457600080fd5b81019080805164010000000081111561163c57600080fd5b8281019050602081018481111561165257600080fd5b815185602082028301116401000000008211171561166f57600080fd5b5050929190602001805164010000000081111561168b57600080fd5b828101905060208101848111156116a157600080fd5b81518560208202830111640100000000821117156116be57600080fd5b505092919050505094509450856020015192506116dc85898561208a565b9150733f6f6c65a851c49f179e6868091dc73b7a6a492d63ad3213e085846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561176c578082015181840152602081019050611751565b50505050905001838103825284818151815260200191508051906020019060200280838360005b838110156117ae578082015181840152602081019050611793565b5050505090500194505050505060206040518083038186803b1580156117d357600080fd5b505af41580156117e7573d6000803e3d6000fd5b505050506040513d60208110156117fd57600080fd5b810190808051906020019092919050505090508560000151156118315761182c86604001518686858588613628565b611844565b61184386604001518686858588613f80565b5b601060008a60001916600019168152602001908152602001600020600080820160006101000a81549060ff02191690556000820160016101000a81549060ff02191690556000820160026101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001820160006118bf9190615e4a565b5050505050505050505050565b60026020528060005260406000206000915054906101000a900460ff1681565b6011818154811015156118fb57fe5b906000526020600020016000915090508054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561199f5780601f106119745761010080835404028352916020019161199f565b820191906000526020600020905b81548152906001019060200180831161198257829003601f168201915b505050505081565b600c5481565b600381565b600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600f60009054906101000a900460ff1681565b600080600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611a9657506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515611aa157600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415611b4457600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f19350505050158015611b3e573d6000803e3d6000fd5b50611d21565b8391508173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611be257600080fd5b505af1158015611bf6573d6000803e3d6000fd5b505050506040513d6020811015611c0c57600080fd5b810190808051906020019092919050505090508173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015611ce457600080fd5b505af1158015611cf8573d6000803e3d6000fd5b505050506040513d6020811015611d0e57600080fd5b8101908080519060200190929190505050505b50505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611e1d5750600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515611e2857600080fd5b602482015190508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16141515611e6957600080fd5b3073ffffffffffffffffffffffffffffffffffffffff168260405180828051906020019080838360005b83811015611eae578082015181840152602081019050611e93565b50505050905090810190601f168015611edb5780820380516001836020036101000a031916815260200191505b50915050600060405180830381855af4915050505050505050565b600181565b6000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515611f5557600080fd5b8282905085859050141515611f6957600080fd5b600090505b84849050811015612083576120098383838181101515611f8a57fe5b90506020020135601260008888868181101515611fa357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546145ad90919063ffffffff16565b60126000878785818110151561201b57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508080600101915050611f6e565b5050505050565b6060612094615e6b565b61209c615e6b565b606060008060008060606000806120b28d6145cb565b99506120f26040805190810160405280600381526020017f55534400000000000000000000000000000000000000000000000000000000008152506145cb565b985061210f61210a8a8c6145f990919063ffffffff16565b614613565b5060018e51016040519080825280602002602001820160405280156121435781602001602082028038833980820191505090505b509a5061216161215c8a8c6145f990919063ffffffff16565b614613565b975061216e886012614675565b8b600081518110151561217d57fe5b9060200190602002018181525050600096505b8d5187101561249d578d878151811015156121a757fe5b90602001906020020151955060006002878115156121c157fe5b06119450600093505b8d5184101561229f57868414156121e05761229f565b8480156122065750600186038e858151811015156121fa57fe5b90602001906020020151145b806122345750841580156122335750600186018e8581518110151561222757fe5b90602001906020020151145b5b15612292578a6001850181518110151561224a57fe5b906020019060200201516ec097ce7bc90715b34b9f100000000081151561226d57fe5b048b6001890181518110151561227f57fe5b906020019060200201818152505061229f565b83806001019450506121ca565b60008b600189018151811015156122b257fe5b906020019060200201511480156122c657508b5b80156122dd575060008614806122dc5750600186145b5b80612323575060008b600189018151811015156122f657fe5b9060200190602002015114801561230b57508b155b8015612322575060028614806123215750600386145b5b5b156123c45784151561236c578a600081518110151561233e57fe5b906020019060200201518b6001890181518110151561235957fe5b90602001906020020181815250506123bf565b8a600081518110151561237b57fe5b906020019060200201516ec097ce7bc90715b34b9f100000000081151561239e57fe5b048b600189018151811015156123b057fe5b90602001906020020181815250505b612490565b60008b600189018151811015156123d757fe5b90602001906020020151141561248f576124026123fd8a8c6145f990919063ffffffff16565b614613565b925061240f836012614675565b915060008211801561241f575084155b1561244957818b6001890181518110151561243657fe5b906020019060200201818152505061248e565b600082111561248d57816ec097ce7bc90715b34b9f100000000081151561246c57fe5b048b6001890181518110151561247e57fe5b90602001906020020181815250505b5b5b5b8680600101975050612190565b600090505b8a518110156124de5760008b828151811015156124bb57fe5b906020019060200201511115156124d157600080fd5b80806001019150506124a2565b8a9a50505050505050505050509392505050565b600081565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060600080600084156125cc57600d8054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156125c05780601f10612595576101008083540402835291602001916125c0565b820191906000526020600020905b8154815290600101906020018083116125a357829003601f168201915b5050505050935061266a565b600e8054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156126625780601f1061263757610100808354040283529160200191612662565b820191906000526020600020905b81548152906001019060200180831161264557829003601f168201915b505050505093505b600092505b85518310156127ff57858381518110151561268657fe5b906020019060200201519150600090505b85518110156126e057808314156126ad576126e0565b85818151811015156126bb57fe5b9060200190602002015182141515156126d357600080fd5b8080600101915050612697565b60006011838154811015156126f157fe5b9060005260206000200180546001816001161561010002031660029004905011151561271c57600080fd5b6127f06127d960118481548110151561273157fe5b906000526020600020018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156127cf5780601f106127a4576101008083540402835291602001916127cf565b820191906000526020600020905b8154815290600101906020018083116127b257829003601f168201915b50505050506145cb565b6127e2866145cb565b61496990919063ffffffff16565b9350828060010193505061266f565b83935050505092915050565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600f60009054906101000a900460ff1615151561284d57600080fd5b838073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806128d55750600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b8061292d5750600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561293857600080fd5b8251845114151561294857600080fd5b6129568585858560016149eb565b5050505050565b600d8054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156129f35780601f106129c8576101008083540402835291602001916129f3565b820191906000526020600020905b8154815290600101906020018083116129d657829003601f168201915b505050505081565b60126020528060005260406000206000915090505481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612a6e57600080fd5b6000831115612aaa5781601184815481101515612a8757fe5b906000526020600020019080519060200190612aa4929190615e85565b50612b80565b6011829080600181540180825580915050906001820390600052602060002001600090919290919091509080519060200190612ae7929190615e85565b50508015612b33576011829080600181540180825580915050906001820390600052602060002001600090919290919091509080519060200190612b2c929190615e85565b5050612b7f565b6011806001815401808255809150509060018203906000526020600020016000602060405190810160405280600081525090919091509080519060200190612b7c929190615e85565b50505b5b505050565b600e8054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015612c1b5780601f10612bf057610100808354040283529160200191612c1b565b820191906000526020600020905b815481529060010190602001808311612bfe57829003601f168201915b505050505081565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612c7e57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515612cba57600080fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600f60009054906101000a900460ff16151515612d1a57600080fd5b838073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480612da25750600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b80612dfa5750600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515612e0557600080fd5b82518451141515612e1557600080fd5b612e238585858560006149eb565b5050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515612e8557600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515612ec157600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161480612ff057506000612fee600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16614c89565b145b1561300157612fff6000614c94565b505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561308757600080fd5b505af115801561309b573d6000803e3d6000fd5b505050506040513d60208110156130b157600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561321a57600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561319e57600080fd5b505af11580156131b2573d6000803e3d6000fd5b505050506040513d60208110156131c857600080fd5b8101908080519060200190929190505050600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ca6ad1e4826040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156132ab57600080fd5b505af11580156132bf573d6000803e3d6000fd5b5050505050565b600080600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148061333857506000613336600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16614c89565b145b15613349576133476000614c94565b505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156133cf57600080fd5b505af11580156133e3573d6000803e3d6000fd5b505050506040513d60208110156133f957600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561356257600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156134e657600080fd5b505af11580156134fa573d6000803e3d6000fd5b505050506040513d602081101561351057600080fd5b8101908080519060200190929190505050600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c281d19e6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156135e857600080fd5b505af11580156135fc573d6000803e3d6000fd5b505050506040513d602081101561361257600080fd5b8101908080519060200190929190505050905090565b600080821561365b57600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150613681565b600b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505b84600081518110151561369057fe5b906020019060200201516f03c109feac3f9bac48ec8cec000000008115156136b457fe5b0490506000601260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111561379a576137526001601260008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461512c90919063ffffffff16565b601260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506138da565b8173ffffffffffffffffffffffffffffffffffffffff166323b872dd89600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16846040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561389357600080fd5b505af11580156138a7573d6000803e3d6000fd5b505050506040513d60208110156138bd57600080fd5b810190808051906020019092919050505015156138d957600080fd5b5b8173ffffffffffffffffffffffffffffffffffffffff166323b872dd89600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16876040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b1580156139d357600080fd5b505af11580156139e7573d6000803e3d6000fd5b505050506040513d60208110156139fd57600080fd5b81019080805190602001909291905050501515613a1957600080fd5b6000876000815181101515613a2a57fe5b90602001906020020151148015613a42575060018751145b15613b7c57600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e1ad116289886000815181101515613a9557fe5b9060200190602002015160016040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001821515151581526020019350505050602060405180830381600087803b158015613b3157600080fd5b505af1158015613b45573d6000803e3d6000fd5b505050506040513d6020811015613b5b57600080fd5b81019080805190602001909291905050501515613b7757600080fd5b613e55565b6002876000815181101515613b8d57fe5b90602001906020020151148015613ba5575060018751145b15613cdf57600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e1ad116289886000815181101515613bf857fe5b9060200190602002015160006040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001821515151581526020019350505050602060405180830381600087803b158015613c9457600080fd5b505af1158015613ca8573d6000803e3d6000fd5b505050506040513d6020811015613cbe57600080fd5b81019080805190602001909291905050501515613cda57600080fd5b613e54565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166348663e7d89898960016040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001806020018060200184151515158152602001838103835286818151815260200191508051906020019060200280838360005b83811015613dd0578082015181840152602081019050613db5565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015613e12578082015181840152602081019050613df7565b505050509050019650505050505050600060405180830381600087803b158015613e3b57600080fd5b505af1158015613e4f573d6000803e3d6000fd5b505050505b5b8773ffffffffffffffffffffffffffffffffffffffff167f6a75660680cd3a8f7f34c5df6451086e3222c8a9e16e568b6e698098e8fd970b88888860405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b83811015613edb578082015181840152602081019050613ec0565b50505050905001848103835286818151815260200191508051906020019060200280838360005b83811015613f1d578082015181840152602081019050613f02565b50505050905001848103825285818151815260200191508051906020019060200280838360005b83811015613f5f578082015181840152602081019050613f44565b50505050905001965050505050505060405180910390a25050505050505050565b6000836000815181101515613f9157fe5b906020019060200201516f03c109feac3f9bac48ec8cec00000000811515613fb557fe5b0490506000601260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054111561409b576140536001601260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461512c90919063ffffffff16565b601260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506141f8565b80831115156140a957600080fd5b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e1ad1162600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683856040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001821515151581526020019350505050602060405180830381600087803b15801561419c57600080fd5b505af11580156141b0573d6000803e3d6000fd5b505050506040513d60208110156141c657600080fd5b810190808051906020019092919050505015156141e257600080fd5b6141f5818461512c90919063ffffffff16565b92505b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e1ad11628885856040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001821515151581526020019350505050602060405180830381600087803b1580156142c957600080fd5b505af11580156142dd573d6000803e3d6000fd5b505050506040513d60208110156142f357600080fd5b8101908080519060200190929190505050151561430f57600080fd5b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166348663e7d88888860006040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001806020018060200184151515158152602001838103835286818151815260200191508051906020019060200280838360005b838110156144005780820151818401526020810190506143e5565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015614442578082015181840152602081019050614427565b505050509050019650505050505050600060405180830381600087803b15801561446b57600080fd5b505af115801561447f573d6000803e3d6000fd5b505050508673ffffffffffffffffffffffffffffffffffffffff167f5e1656ea49c37d58c071f8ec59918a4e2380766f4956535b3724476daad4c4fd87878760405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156145095780820151818401526020810190506144ee565b50505050905001848103835286818151815260200191508051906020019060200280838360005b8381101561454b578082015181840152602081019050614530565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561458d578082015181840152602081019050614572565b50505050905001965050505050505060405180910390a250505050505050565b60008082840190508381101515156145c157fe5b8091505092915050565b6145d3615e6b565b600060208301905060408051908101604052808451815260200182815250915050919050565b614601615e6b565b61460c838383615145565b5092915050565b606080600083600001516040519080825280601f01601f19166020018201604052801561464f5781602001602082028038833980820191505090505b50915060208201905061466b81856020015186600001516151e3565b8192505050919050565b6000606060008060008693506000925060009150600090505b835181101561494a5760307f01000000000000000000000000000000000000000000000000000000000000000284828151811015156146c957fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916101580156147e1575060397f010000000000000000000000000000000000000000000000000000000000000002848281518110151561477157fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191611155b156148925781156148045760008614156147fa5761494a565b8580600190039650505b600a830292506030848281518110151561481a57fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000027f01000000000000000000000000000000000000000000000000000000000000009004038301925061493d565b602e7f01000000000000000000000000000000000000000000000000000000000000000284828151811015156148c457fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141561493c57600191505b5b808060010191505061468e565b600086111561495c5785600a0a830292505b8294505050505092915050565b606080600083600001518560000151016040519080825280601f01601f1916602001820160405280156149ab5781602001602082028038833980820191505090505b5091506020820190506149c781866020015187600001516151e3565b6149e085600001518201856020015186600001516151e3565b819250505092915050565b606060003073ffffffffffffffffffffffffffffffffffffffff1631614a456040805190810160405280600381526020017f55524c000000000000000000000000000000000000000000000000000000000081525061522e565b1115614ab8577f46cb989ef9cef13e930e3b7f286225a086e716a90d63e0b7da85d310a9db0c9a60405180806020018281038252601b8152602001807f4f7261636c697a6520717565727920776173204e4f542073656e74000000000081525060200191505060405180910390a1614c80565b614ac2868561251d565b9150614b0e6040805190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815250838851619c4002620249f001615602565b9050608060405190810160405280841515815260200185151581526020018873ffffffffffffffffffffffffffffffffffffffff168152602001614b528888615bb6565b81525060106000836000191660001916815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506060820151816001019080519060200190614c13929190615f05565b509050507f46cb989ef9cef13e930e3b7f286225a086e716a90d63e0b7da85d310a9db0c9a6040518080602001828103825260178152602001807f4f7261636c697a65207175657279207761732073656e7400000000000000000081525060200191505060405180910390a15b50505050505050565b6000813b9050919050565b600080614cb4731d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed614c89565b1115614d5657731d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550614d4d6040805190810160405280600b81526020017f6574685f6d61696e6e6574000000000000000000000000000000000000000000815250615c87565b60019050615127565b6000614d7573c03a2615d5efaf5f49f60b7bb6583eaec212fdf1614c89565b1115614e175773c03a2615d5efaf5f49f60b7bb6583eaec212fdf1600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550614e0e6040805190810160405280600c81526020017f6574685f726f707374656e330000000000000000000000000000000000000000815250615c87565b60019050615127565b6000614e3673b7a07bcf2ba2f2703b24c0691b5278999c59ac7e614c89565b1115614ed85773b7a07bcf2ba2f2703b24c0691b5278999c59ac7e600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550614ecf6040805190810160405280600981526020017f6574685f6b6f76616e0000000000000000000000000000000000000000000000815250615c87565b60019050615127565b6000614ef773146500cfd35b22e4a392fe0adc06de1a1368ed48614c89565b1115614f995773146500cfd35b22e4a392fe0adc06de1a1368ed48600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550614f906040805190810160405280600b81526020017f6574685f72696e6b656279000000000000000000000000000000000000000000815250615c87565b60019050615127565b6000614fb8736f485c8bf6fc43ea212e93bbf8ce046c7f1cb475614c89565b111561501c57736f485c8bf6fc43ea212e93bbf8ce046c7f1cb475600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060019050615127565b600061503b7320e12a1f859b3feae5fb2a0a32c18f5a65555bbf614c89565b111561509f577320e12a1f859b3feae5fb2a0a32c18f5a65555bbf600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060019050615127565b60006150be7351efaf4c8b3c9afbd5ab9f4bbc82784ab6ef8faa614c89565b1115615122577351efaf4c8b3c9afbd5ab9f4bbc82784ab6ef8faa600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060019050615127565b600090505b919050565b600082821115151561513a57fe5b818303905092915050565b61514d615e6b565b600061516b8560000151866020015186600001518760200151615ca1565b905084602001518360200181815250508460200151810383600001818152505084600001518560200151018114156151ad5760008560000181815250506151d8565b8360000151836000015101856000018181510391508181525050836000015181018560200181815250505b829150509392505050565b60005b60208210151561520b57825184526020840193506020830192506020820391506151e6565b6001826020036101000a0390508019835116818551168181178652505050505050565b600080600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614806152a05750600061529e600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16614c89565b145b156152b1576152af6000614c94565b505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561533757600080fd5b505af115801561534b573d6000803e3d6000fd5b505050506040513d602081101561536157600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415156154ca57600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561544e57600080fd5b505af1158015615462573d6000803e3d6000fd5b505050506040513d602081101561547857600080fd5b8101908080519060200190929190505050600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663524f3889836040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015615574578082015181840152602081019050615559565b50505050905090810190601f1680156155a15780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b1580156155c057600080fd5b505af11580156155d4573d6000803e3d6000fd5b505050506040513d60208110156155ea57600080fd5b81019080805190602001909291905050509050919050565b6000806000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148061567657506000615674600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16614c89565b145b15615687576156856000614c94565b505b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561570d57600080fd5b505af1158015615721573d6000803e3d6000fd5b505050506040513d602081101561573757600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415156158a057600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338cc48316040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561582457600080fd5b505af1158015615838573d6000803e3d6000fd5b505050506040513d602081101561584e57600080fd5b8101908080519060200190929190505050600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632ef3accc86856040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001838152602001828103825284818151815260200191508051906020019080838360005b83811015615951578082015181840152602081019050615936565b50505050905090810190601f16801561597e5780820380516001836020036101000a031916815260200191505b509350505050602060405180830381600087803b15801561599e57600080fd5b505af11580156159b2573d6000803e3d6000fd5b505050506040513d60208110156159c857600080fd5b81019080805190602001909291905050509050823a02670de0b6b3a7640000018111156159fb5760006001029150615bae565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c51be90f8260008888886040518663ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808581526020018060200180602001848152602001838103835286818151815260200191508051906020019080838360005b83811015615aba578082015181840152602081019050615a9f565b50505050905090810190601f168015615ae75780820380516001836020036101000a031916815260200191505b50838103825285818151815260200191508051906020019080838360005b83811015615b20578082015181840152602081019050615b05565b50505050905090810190601f168015615b4d5780820380516001836020036101000a031916815260200191505b5096505050505050506020604051808303818588803b158015615b6f57600080fd5b505af1158015615b83573d6000803e3d6000fd5b50505050506040513d6020811015615b9a57600080fd5b810190808051906020019092919050505091505b509392505050565b606060008351604051908082528060200260200182016040528015615bea5781602001602082028038833980820191505090505b509150600090505b8351811015615c7d578381815181101515615c0957fe5b906020019060200201518282815181101515615c2157fe5b906020019060200201818152505060088382815181101515615c3f57fe5b906020019060200201519060020a028282815181101515615c5c57fe5b90602001906020020181815117915081815250508080600101915050615bf2565b8191505092915050565b8060059080519060200190615c9d929190615e85565b5050565b60008060008060008060008060008b97508c8b111515615d715760208b111515615d2b5760018b60200360080260020a03196001029550858a511694508a8d8d010393508588511692505b84600019168360001916141515615d23578388101515615d10578c8c019850615d77565b8780600101985050858851169250615cec565b879850615d77565b8a8a209150600096505b8a8d0387111515615d70578a88209050806000191682600019161415615d5d57879850615d77565b6001880197508680600101975050615d35565b5b8c8c0198505b5050505050505050949350505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615dc857803560ff1916838001178555615df6565b82800160010185558215615df6579182015b82811115615df5578235825591602001919060010190615dda565b5b509050615e039190615f52565b5090565b608060405190810160405280600015158152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b5080546000825590600052602060002090810190615e689190615f52565b50565b604080519081016040528060008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615ec657805160ff1916838001178555615ef4565b82800160010185558215615ef4579182015b82811115615ef3578251825591602001919060010190615ed8565b5b509050615f019190615f52565b5090565b828054828255906000526020600020908101928215615f41579160200282015b82811115615f40578251825591602001919060010190615f25565b5b509050615f4e9190615f52565b5090565b615f7491905b80821115615f70576000816000905550600101615f58565b5090565b905600a165627a7a72305820eaf5938b02f08ff2a647e28d3eb6dbc00b5f62b4d1cba2fb3f254d3f3fad08460029

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

000000000000000000000000eb547ed1d8a3ff1461abaa7f0022fed4836e00a4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081df38586d808f78d7741f6541f995ff2b639872000000000000000000000000dfaa6ee812792f58953aae0b762480dad6132885

-----Decoded View---------------
Arg [0] : _coinToken (address): 0xeb547ed1D8A3Ff1461aBAa7F0022FED4836E00A4
Arg [1] : _cashToken (address): 0x0000000000000000000000000000000000000000
Arg [2] : _bank (address): 0x81DF38586D808F78D7741f6541f995ff2B639872
Arg [3] : _userData (address): 0xDfaa6EE812792f58953aAe0B762480DaD6132885

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000eb547ed1d8a3ff1461abaa7f0022fed4836e00a4
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 00000000000000000000000081df38586d808f78d7741f6541f995ff2b639872
Arg [3] : 000000000000000000000000dfaa6ee812792f58953aae0b762480dad6132885


Libraries Used


Swarm Source

bzzr://eaf5938b02f08ff2a647e28d3eb6dbc00b5f62b4d1cba2fb3f254d3f3fad0846

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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