Commit my random junk master
authorDavid Kerkeslager <kerkeslager@gmail.com>
Fri, 14 Jan 2022 22:02:28 +0000 (17:02 -0500)
committerDavid Kerkeslager <kerkeslager@gmail.com>
Fri, 14 Jan 2022 22:02:28 +0000 (17:02 -0500)
19 files changed:
async/test.py [new file with mode: 0644]
async/test1.py [new file with mode: 0644]
binarypuzzle/gen.py [new file with mode: 0644]
binarypuzzle/generated.txt [new file with mode: 0644]
binarypuzzle/graph.csv [new file with mode: 0644]
crypto-bot/main.py [new file with mode: 0644]
crypto-bot/run.sh [new file with mode: 0755]
cryptopals-python/cryptopals.py
cryptopals-python/set1challenge6.txt [new file with mode: 0644]
furfur/main.fur [new file with mode: 0644]
furfur/syntax.fparse [new file with mode: 0644]
pylox/main.py [new file with mode: 0644]
seive.py [new file with mode: 0644]
solidity/contracts/Migrations.sol [new file with mode: 0644]
solidity/migrations/1_initial_migration.js [new file with mode: 0644]
solidity/test/.gitkeep [new file with mode: 0644]
solidity/token.sol [new file with mode: 0644]
solidity/truffle-config.js [new file with mode: 0644]
sort2.py [new file with mode: 0644]

diff --git a/async/test.py b/async/test.py
new file mode 100644 (file)
index 0000000..1b1b014
--- /dev/null
@@ -0,0 +1,71 @@
+import asyncio
+import logging
+import random
+import string
+import uuid
+
+import attr
+
+logging.basicConfig(
+    level=logging.INFO,
+    format='%(asctime)s,%(msecs)d %(levelname)s: %(message)s',
+    datefmt='%H:%M:%S',
+)
+
+@attr.s
+class PubSubMessage:
+    instance_name = attr.ib()
+    message_id    = attr.ib(repr=False)
+    hostname      = attr.ib(repr=False, init=False)
+
+    def __attrs_post_init__(self):
+        self.hostname = f'{self.instance_name}.example.net'
+
+
+# simulating an external publisher of events
+
+async def publish(queue):
+    choices = string.ascii_lowercase + string.digits
+
+    while True:
+        msg_id = str(uuid.uuid4())
+        host_id = "".join(random.choices(choices, k=4))
+        instance_name = f"cattle-{host_id}"
+        msg = PubSubMessage(message_id=msg_id, instance_name=instance_name)
+        # publish an item
+        asyncio.create_task(queue.put(msg))
+        logging.info(f"Published message {msg}")
+        # simulate randomness of publishing messages
+        await asyncio.sleep(random.random())
+
+
+async def consume(queue):
+    while True:
+        # wait for an item from the publisher
+        msg = await queue.get()
+        if msg is None:  # publisher is done
+            break
+
+        # process the msg
+        logging.info(f'Consumed {msg}')
+        # unhelpful simulation of i/o work
+        await asyncio.sleep(random.random())
+
+
+def main():
+    queue = asyncio.Queue()
+    loop = asyncio.get_event_loop()
+
+    try:
+        loop.create_task(publish(queue))
+        loop.create_task(consume(queue))
+        loop.run_forever()
+    except KeyboardInterrupt:
+        logging.info("Process interrupted")
+    finally:
+        loop.close()
+        logging.info("Successfully shutdown the Mayhem service.")
+
+
+if __name__ == '__main__':
+    main()
diff --git a/async/test1.py b/async/test1.py
new file mode 100644 (file)
index 0000000..7b64042
--- /dev/null
@@ -0,0 +1,100 @@
+import asyncio
+import functools
+import logging
+import random
+import signal
+import string
+import uuid
+
+import attr
+
+logging.basicConfig(
+    level=logging.INFO,
+    format='%(asctime)s,%(msecs)d %(levelname)s: %(message)s',
+    datefmt='%H:%M:%S',
+)
+
+@attr.s
+class PubSubMessage:
+    instance_name = attr.ib()
+    message_id    = attr.ib(repr=False)
+    hostname      = attr.ib(repr=False, init=False)
+    restarted     = attr.ib(repr=False, default=False)
+    saved         = attr.ib(repr=False, default=False)
+    acked         = attr.ib(repr=False, default=False)
+    extended_cnt  = attr.ib(repr=False, default=0)
+
+    def __attrs_post_init__(self):
+        self.hostname = f"{self.instance_name}.example.net"
+
+async def publish(queue):
+    choices = string.ascii_lowercase + string.digits
+
+    while True:
+        msg_id = str(uuid.uuid4())
+        host_id = "".join(random.choices(choices, k=4))
+        instance_name = f"cattle-{host_id}"
+        msg = PubSubMessage(message_id=msg_id, instance_name=instance_name)
+        # publish an item
+        asyncio.create_task(queue.put(msg))
+        logging.debug(f"Published message {msg}")
+        # simulate randomness of publishing messages
+        await asyncio.sleep(random.random())
+
+async def restart_host(msg):
+    # unhelpful simulation of i/o work
+    await asyncio.sleep(random.random())
+    msg.restart = True
+    logging.info(f"Restarted {msg.hostname}")
+
+async def save(msg):
+    # unhelpful simulation of i/o work
+    await asyncio.sleep(random.random())
+    msg.save = True
+    logging.info(f"Saved {msg} into database")
+
+async def cleanup(msg, event):
+    # this will block the rest of the coro until `event.set` is called
+    await event.wait()
+    # unhelpful simulation of i/o work
+    await asyncio.sleep(random.random())
+    msg.acked = True
+    logging.info(f"Done. Acked {msg}")
+
+async def extend(msg, event):
+    while not event.is_set():
+        msg.extended_cnt += 1
+        logging.info(f"Extended deadline by 3 seconds for {msg}")
+        # want to sleep for less than the deadline amount
+        await asyncio.sleep(2)
+
+async def handle_message(msg):
+    event = asyncio.Event()
+    asyncio.create_task(extend(msg, event))
+    asyncio.create_task(cleanup(msg, event))
+
+    await asyncio.gather(save(msg), restart_host(msg))
+    event.set()
+
+async def consume(queue):
+    while True:
+        msg = await queue.get()
+        logging.info(f"Consumed {msg}")
+        asyncio.create_task(handle_message(msg))
+
+def main():
+    queue = asyncio.Queue()
+    loop = asyncio.get_event_loop()
+
+    try:
+        loop.create_task(publish(queue))
+        loop.create_task(consume(queue))
+        loop.run_forever()
+    except KeyboardInterrupt:
+        logging.info("Process interrupted")
+    finally:
+        loop.close()
+        logging.info("Successfully shutdown the Mayhem service.")
+
+if __name__ == "__main__":
+    main()
diff --git a/binarypuzzle/gen.py b/binarypuzzle/gen.py
new file mode 100644 (file)
index 0000000..2ee7395
--- /dev/null
@@ -0,0 +1,117 @@
+import itertools, math, re, sys
+
+size = 4
+
+if size % 2 != 0:
+    raise Exception('Size must be an even number')
+
+fmt = '{{:0{}b}}'.format(size)
+
+valid_rows = []
+
+num_zeroes = size // 2
+
+for i in range(pow(2,size)):
+    row = fmt.format(i)
+
+    if row.count('0') == num_zeroes and ('000' not in row) and ('111' not in row):
+        valid_rows.append(row)
+
+valid_rows_count = len(valid_rows)
+
+print('{} valid rows of {} digits found.'.format(valid_rows_count, size))
+print('This will generate and test {} boards.'.format(math.prod(range(
+    valid_rows_count - size + 1,
+    valid_rows_count + 1,
+))))
+
+decision = input('Proceed with generation? (y/n) ')
+
+while decision.lower() not in ('y', 'n'):
+    decision = input('Proceed with generation? (y/n) ')
+
+if decision == 'n':
+    sys.exit(0)
+
+valid_rows_set = set(valid_rows)
+
+def rotate(board):
+    return tuple(''.join(row) for row in zip(*board))
+
+def all_rows_valid(board):
+    return all((row in valid_rows_set) for row in board)
+
+def all_rows_unique(board):
+    return not any((r0 == r1) for r0, r1 in itertools.combinations(board, 2))
+
+valid_boards = []
+
+for board in itertools.permutations(valid_rows, size):
+    # We know that all the rows are valid and unique but we don't know if the
+    # columns are.
+    board = rotate(board)
+    # Now we know that all the columns are valid and unique but we don't know
+    # if the rows are.
+
+    if all_rows_valid(board) and all_rows_unique(board):
+        valid_boards.append(''.join(board))
+        print('\n'.join(board) + '\n')
+
+print('{} valid boards found.'.format(len(valid_boards)))
+
+decision = input('Proceed with generation? (y/n) ')
+
+while decision.lower() not in ('y', 'n'):
+    decision = input('Proceed with generation? (y/n) ')
+
+if decision == 'n':
+    sys.exit(0)
+
+area = size * size
+filters = { valid_boards[0]: ['.' * area] }
+
+for board_count in range(1, len(valid_boards)):
+    current_board = valid_boards[board_count]
+
+    new_filters = {}
+
+    new_filters[current_board] = set()
+
+    for previous_board in filters:
+        differences = [i for i in range(size) if previous_board[i] != current_board[i]]
+
+        new_filters[previous_board] = set()
+
+        for old_filter in filters[previous_board]:
+            if re.match(old_filter, current_board):
+                for d in differences:
+                    new_filters[previous_board].add(
+                        old_filter[:d] + previous_board[d] + old_filter[d + 1:]
+                    )
+                    new_filters[current_board].add(
+                        old_filter[:d] + current_board[d] + old_filter[d + 1:]
+                    )
+
+            else:
+                new_filters[previous_board].add(old_filter)
+
+    print('Round {} complete, {} filters'.format(board_count, len(new_filters)))
+
+    filters = new_filters
+
+    removed_count = 0
+
+    for b in filters:
+        c = filters[b].copy()
+
+        for f0, f1 in itertools.permutations(c, 2):
+            if re.match(f0, f1):
+                filters[b].remove(f1)
+                removed_count += 1
+
+    print(removed_count)
+
+
+with open('generated.txt', 'w') as gen_file:
+    for f in filters:
+        gen_file.write('\n'.join(f[i:i + size] for i in range(0, area, size)) + '\n\n')
diff --git a/binarypuzzle/generated.txt b/binarypuzzle/generated.txt
new file mode 100644 (file)
index 0000000..4c77308
--- /dev/null
@@ -0,0 +1,360 @@
+1100
+1010
+0101
+0011
+
+1100
+1001
+0110
+0011
+
+1100
+1010
+0011
+0101
+
+1100
+1001
+0011
+0110
+
+1010
+1100
+0101
+0011
+
+1001
+1100
+0110
+0011
+
+1010
+1100
+0011
+0101
+
+1001
+1100
+0011
+0110
+
+1010
+1001
+0110
+0101
+
+1010
+1001
+0101
+0110
+
+1001
+1010
+0110
+0101
+
+1001
+1010
+0101
+0110
+
+1100
+0110
+1001
+0011
+
+1100
+0101
+1010
+0011
+
+1100
+0011
+1010
+0101
+
+1100
+0011
+1001
+0110
+
+1010
+0101
+1100
+0011
+
+1001
+0110
+1100
+0011
+
+1010
+0110
+1001
+0101
+
+1010
+0101
+1001
+0110
+
+1001
+0110
+1010
+0101
+
+1001
+0101
+1010
+0110
+
+1010
+0011
+1100
+0101
+
+1001
+0011
+1100
+0110
+
+1100
+0110
+0011
+1001
+
+1100
+0101
+0011
+1010
+
+1100
+0011
+0110
+1001
+
+1100
+0011
+0101
+1010
+
+1010
+0110
+0101
+1001
+
+1010
+0101
+0110
+1001
+
+1001
+0110
+0101
+1010
+
+1001
+0101
+0110
+1010
+
+1010
+0101
+0011
+1100
+
+1001
+0110
+0011
+1100
+
+1010
+0011
+0101
+1100
+
+1001
+0011
+0110
+1100
+
+0110
+1100
+1001
+0011
+
+0101
+1100
+1010
+0011
+
+0110
+1001
+1100
+0011
+
+0101
+1010
+1100
+0011
+
+0110
+1010
+1001
+0101
+
+0110
+1001
+1010
+0101
+
+0101
+1010
+1001
+0110
+
+0101
+1001
+1010
+0110
+
+0011
+1100
+1010
+0101
+
+0011
+1100
+1001
+0110
+
+0011
+1010
+1100
+0101
+
+0011
+1001
+1100
+0110
+
+0110
+1100
+0011
+1001
+
+0101
+1100
+0011
+1010
+
+0110
+1010
+0101
+1001
+
+0110
+1001
+0101
+1010
+
+0101
+1010
+0110
+1001
+
+0101
+1001
+0110
+1010
+
+0110
+1001
+0011
+1100
+
+0101
+1010
+0011
+1100
+
+0011
+1100
+0110
+1001
+
+0011
+1100
+0101
+1010
+
+0011
+1010
+0101
+1100
+
+0011
+1001
+0110
+1100
+
+0110
+0101
+1010
+1001
+
+0110
+0101
+1001
+1010
+
+0101
+0110
+1010
+1001
+
+0101
+0110
+1001
+1010
+
+0110
+0011
+1100
+1001
+
+0101
+0011
+1100
+1010
+
+0110
+0011
+1001
+1100
+
+0101
+0011
+1010
+1100
+
+0011
+0110
+1100
+1001
+
+0011
+0101
+1100
+1010
+
+0011
+0110
+1001
+1100
+
+0011
+0101
+1010
+1100
+
diff --git a/binarypuzzle/graph.csv b/binarypuzzle/graph.csv
new file mode 100644 (file)
index 0000000..fcd635d
--- /dev/null
@@ -0,0 +1,42 @@
+20, 19609
+21, 22461
+22, 24390
+23, 26881
+24, 30287
+25, 34593
+26, 37834
+27, 42331
+28, 46786
+29, 52063
+30, 58843
+31, 65144
+32, 70762
+33, 77387
+34, 83950
+35, 91087
+36, 95096
+37, 100310
+38, 104217
+39, 108787
+40, 113440
+41, 118336
+42, 125003
+43, 131756
+44, 138756
+45, 145995
+46, 152953
+47, 160377
+48, 170951
+49, 184353
+50, 193999
+51, 204494
+52, 214852
+53, 228348
+54, 239542
+55, 253858
+56, 266775
+57, 281233
+58, 296618
+59, 311858
+60, 323663
+61, 335655
diff --git a/crypto-bot/main.py b/crypto-bot/main.py
new file mode 100644 (file)
index 0000000..1d815d4
--- /dev/null
@@ -0,0 +1,30 @@
+from web3 import Web3
+
+# To Connect to Ethereum Mainnet
+# w3 = Web3(Web3.HTTPProvider('https://mainnet.infura.io/v3/2981846319d3433d83aecfda7d175554'))
+
+w3 = Web3(Web3.HTTPProvider('https://polygon-mainnet.infura.io/v3/a6a37efdbfe141a898135c1848d2352b'))
+
+from web3.middleware import geth_poa_middleware
+w3.middleware_onion.inject(geth_poa_middleware, layer=0)
+
+WEI_PER_ETH = 1000000000000000000
+
+balance = w3.eth.get_balance('0x87885F4D036d8BBf56c1721e9975073b81f5Cd9c')
+
+COIN_CONTRACTS = {
+    'CRV': 0x172370d5cd63279efa6d502dab29171933a610af,
+    'LINK': 0x53E0bca35eC356BD5ddDFebbD1Fc0fD03FaBad39,
+    'NORD': 0xf6f85b3f9fd581c2ee717c404f7684486f057f95,
+    'USDC': 0x2791bca1f2de4661ed88a30c99a7a9449aa84174,
+    'WETH': 0x7ceb23fd6bc0add59e62ac25578270cff1b9f619,
+}
+
+SUSHISWAP_CONTRACT = w3.eth.contract(
+    address='0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
+    abi='''
+[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
+    ''',
+)
+
+import ipdb; ipdb.set_trace()
diff --git a/crypto-bot/run.sh b/crypto-bot/run.sh
new file mode 100755 (executable)
index 0000000..1a9e849
--- /dev/null
@@ -0,0 +1 @@
+PYTHONWARNINGS=default python main.py
index ee81112..24392b8 100644 (file)
@@ -41,6 +41,19 @@ def encrypt_with_repeating_xor(plaintext, key):
         (key_bytes * ((len(plaintext_bytes) // len(key_bytes)) + 1))[:len(plaintext_bytes)],
     )
 
+def hamming_weight(_bytes):
+    def hamming_weight_of_byte(b):
+        count = 0
+        while b > 0:
+            count += 1
+            b &= b - 1
+        return count
+
+    return sum(hamming_weight_of_byte(b) for b in _bytes)
+
+def hamming_distance(bytes0, bytes1):
+    return hamming_weight(xor_bytes(bytes0, bytes1))
+
 class Set1Challenge1Tests(unittest.TestCase):
     def test_converts_hex_to_base64(self):
         expected = 'SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t\n'
@@ -127,5 +140,19 @@ class Set1Challenge5Tests(unittest.TestCase):
 
         self.assertEqual(expected, actual)
 
+with open('set1challenge6.txt','r') as f:
+    set1challenge6text = f.read()
+
+class Set1Challenge6Tests(unittest.TestCase):
+    def test_hamming_distance(self):
+        expected = 37
+        actual = hamming_distance(b'this is a test', b'wokka wokka!!!')
+        self.assertEqual(expected, actual)
+
+    def test_find_repeated_xor_keysize(self):
+        expected = 0
+        actual = find_repeated_xor_keysize(set1challenge6text)
+        self.assertEqual(expected, actual)
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/cryptopals-python/set1challenge6.txt b/cryptopals-python/set1challenge6.txt
new file mode 100644 (file)
index 0000000..cecdb81
--- /dev/null
@@ -0,0 +1,64 @@
+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
diff --git a/furfur/main.fur b/furfur/main.fur
new file mode 100644 (file)
index 0000000..0a12cc0
--- /dev/null
@@ -0,0 +1,76 @@
+enum TokenType
+  CLOSE_BRACE,
+  CLOSE_BRACKET,
+  CLOSE_PARENTHESE,
+  COLON,
+  COMMA,
+  DEF,
+  DO,
+  END,
+  ENUM,
+  EQUALS,
+  IDENTIFIER,
+  IF,
+  OPEN_BRACE,
+  OPEN_BRACKET,
+  OPEN_PARENTHESE,
+  PERIOD,
+  STRING_LITERAL,
+  WITH,
+end
+
+struct Token
+  TokenType tokenType
+  string lexeme
+end
+
+def scan(source)
+  SINGLE_CHARACTER_TOKENS = {
+    '}': TokenType.CLOSE_BRACE,
+    ']': TokenType.CLOSE_BRACKET,
+    ')': TokenType.CLOSE_PARENTHESE,
+    ':': TokenType.COLON,
+    ',': TokenType.COMMA,
+    '{': TokenType.OPEN_BRACE,
+    '[': TokenType.OPEN_BRACKET,
+    '(': TokenType.OPEN_PARENTHESE,
+    '.': TokenType.PERIOD,
+  }
+
+  def match(source)
+    if source[0] in SINGLE_CHARACTER_TOKENS
+      Token {
+        tokenType: SINGLE_CHARACTER_TOKENS[source[0]],
+        lexeme: source[0]
+      }
+    else
+    end
+  end
+end
+
+def parse(tokens)
+end
+
+def generate(ast)
+end
+
+def compile(source)
+  tokens = scan(source)
+  ast = parse(tokens)
+  generate(ast)
+end
+
+source_file_path = __arguments__[0]
+destination_file_path = __argument__[1]
+
+with open(source_file_path, 'r') as source_file
+  source = source_file.read()
+end
+
+c = compile(source)
+
+with open(destination_file_path, 'w') as destination_file do
+  destination_file.write(c)
+end
+
+
diff --git a/furfur/syntax.fparse b/furfur/syntax.fparse
new file mode 100644 (file)
index 0000000..356762e
--- /dev/null
@@ -0,0 +1,20 @@
+__IGNORE__ = /[ \n\t]*/
+
+CLOSE_PARENTHESE = ')'
+EQUALS = '='
+OPEN_PARENTHESE = '('
+
+DEF = 'def'
+END = 'end'
+
+IDENTIFIER = /[A-Za-z_][A-Za-z_0-9]*/
+NUMBER = /\d+(\.\d+)?/
+STRING = /'(.*?|\\')'|"(.*?|\\")"/
+
+expression = 
+
+assignment_statement = IDENTIFIER EQUALS expression
+function_definition_statement = DEF IDENTIFIER OPEN_PARENTHESE argument_definition_list CLOSE_PARENTHESE statement_list END
+expression_statement = expression
+
+statement = assignment_statement | function_definition_statement
diff --git a/pylox/main.py b/pylox/main.py
new file mode 100644 (file)
index 0000000..1972baa
--- /dev/null
@@ -0,0 +1,88 @@
+import enum
+import sys
+
+class TokenType(enum.Enum):
+    LEFT_PARENTHESE = enum.auto()
+    RIGHT_PARENTHESE = enum.auto()
+    LEFT_BRACE = enum.auto()
+    RIGHT_BRACE = enum.auto()
+    LEFT_BRACKET = enum.auto()
+    RIGHT_BRACKET = enum.auo()
+    COMMA = enum.auto()
+    DOT = enum.auto()
+    MINUS = enum.auto()
+    PLUS = enum.auto()
+    SLASH = enum.auto()
+    STAR = enum.auto()
+    PERCENT = enum.auto()
+
+    BANG = enum.auto()
+    BANG_EQUALS = enum.auto()
+    EQUAL = enum.auto()
+    EQUALS_EQUALS = enum.auto()
+    LESS_THAN = enum.auto()
+    LESS_THAN_EQUALS = enum.auto()
+    GREATER_THAN = enum.auto()
+    GREATER_THAN_EQUALS = enum.auto()
+
+    IDENTIFIER = enum.auto()
+    STRING = enum.auto()
+    NUMBER = enum.auto()
+
+    AND = enum.auto()
+    ELSE = enum.auto()
+    END = enum.auto()
+    FALSE = enum.auto()
+    FOR = enum.auto()
+    IF = enum.auto()
+    NIL = enum.auto()
+    NOT = enum.auto()
+    OR = enum.auto()
+    TRUE = enum.auto()
+
+
+had_error = False
+
+def error(line, message):
+    report(line, '', message)
+
+def report(line, where, message):
+    print('[line {}] Error {}: {}'.format(
+        line,
+        where,
+        message,
+    )
+
+    had_error = True
+
+def run(source):
+    tokens = scan_tokens(source)
+
+    for token in tokens:
+        print(token)
+
+def run_file(path):
+    with open(path, 'r') as f:
+        run(f.read())
+
+    if had_error:
+        sys.exit(65)
+
+def run_prompt():
+    while True:
+        line = input('> ')
+        if not line:
+            break
+        run(line)
+        had_error = False
+
+if __name__ == '__main__':
+    if len(sys.argv) > 2:
+        print('Usage: pylox [script]')
+        sys.exit(65)
+
+    elif len(sys.argv) == 2:
+        run_file(sys.args[1])
+
+    else:
+        run_prompt()
diff --git a/seive.py b/seive.py
new file mode 100644 (file)
index 0000000..41ed324
--- /dev/null
+++ b/seive.py
@@ -0,0 +1,13 @@
+seive = {}
+counter = 2
+limit = 1000
+
+while counter < limit:
+    if counter in seive:
+        for factor in seive[counter]:
+            seive[counter + factor] = seive.get(counter + factor, []) + [factor]
+    else:
+        print(counter)
+        seive[counter**2] = [counter]
+
+    counter += 1
diff --git a/solidity/contracts/Migrations.sol b/solidity/contracts/Migrations.sol
new file mode 100644 (file)
index 0000000..9aac975
--- /dev/null
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: MIT
+pragma solidity >=0.4.22 <0.9.0;
+
+contract Migrations {
+  address public owner = msg.sender;
+  uint public last_completed_migration;
+
+  modifier restricted() {
+    require(
+      msg.sender == owner,
+      "This function is restricted to the contract's owner"
+    );
+    _;
+  }
+
+  function setCompleted(uint completed) public restricted {
+    last_completed_migration = completed;
+  }
+}
diff --git a/solidity/migrations/1_initial_migration.js b/solidity/migrations/1_initial_migration.js
new file mode 100644 (file)
index 0000000..16a7ba5
--- /dev/null
@@ -0,0 +1,5 @@
+const Migrations = artifacts.require("Migrations");
+
+module.exports = function (deployer) {
+  deployer.deploy(Migrations);
+};
diff --git a/solidity/test/.gitkeep b/solidity/test/.gitkeep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/solidity/token.sol b/solidity/token.sol
new file mode 100644 (file)
index 0000000..6a34925
--- /dev/null
@@ -0,0 +1,350 @@
+pragma solidity ^0.8.4;
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Interface of the ERC20 standard as defined in the EIP.
+ */
+interface IERC20 {
+    /**
+     * @dev Returns the amount of tokens in existence.
+     */
+    function totalSupply() external view returns (uint256);
+
+    /**
+     * @dev Returns the amount of tokens owned by `account`.
+     */
+    function balanceOf(address account) external view returns (uint256);
+
+    /**
+     * @dev Moves `amount` tokens from the caller's account to `recipient`.
+     *
+     * Returns a boolean value indicating whether the operation succeeded.
+     *
+     * Emits a {Transfer} event.
+     */
+    function transfer(address recipient, uint256 amount) external returns (bool);
+
+    /**
+     * @dev Returns the remaining number of tokens that `spender` will be
+     * allowed to spend on behalf of `owner` through {transferFrom}. This is
+     * zero by default.
+     *
+     * This value changes when {approve} or {transferFrom} are called.
+     */
+    function allowance(address owner, address spender) external view returns (uint256);
+
+    /**
+     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
+     *
+     * Returns a boolean value indicating whether the operation succeeded.
+     *
+     * IMPORTANT: Beware that changing an allowance with this method brings the risk
+     * that someone may use both the old and the new allowance by unfortunate
+     * transaction ordering. One possible solution to mitigate this race
+     * condition is to first reduce the spender's allowance to 0 and set the
+     * desired value afterwards:
+     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+     *
+     * Emits an {Approval} event.
+     */
+    function approve(address spender, uint256 amount) external returns (bool);
+
+    /**
+     * @dev Moves `amount` tokens from `sender` to `recipient` using the
+     * allowance mechanism. `amount` is then deducted from the caller's
+     * allowance.
+     *
+     * Returns a boolean value indicating whether the operation succeeded.
+     *
+     * Emits a {Transfer} event.
+     */
+    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
+
+    /**
+     * @dev Emitted when `value` tokens are moved from one account (`from`) to
+     * another (`to`).
+     *
+     * Note that `value` may be zero.
+     */
+    event Transfer(address indexed from, address indexed to, uint256 value);
+
+    /**
+     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
+     * a call to {approve}. `value` is the new allowance.
+     */
+    event Approval(address indexed owner, address indexed spender, uint256 value);
+}
+
+contract Token is IERC20 {
+    mapping (address => uint256) private _balances;
+
+    mapping (address => mapping (address => uint256)) private _allowances;
+
+    uint256 private _totalSupply;
+
+    string private _name;
+    string private _symbol;
+
+    /**
+     * @dev Sets the values for {name} and {symbol}.
+     *
+     * The defaut value of {decimals} is 18. To select a different value for
+     * {decimals} you should overload it.
+     *
+     * All two of these values are immutable: they can only be set once during
+     * construction.
+     */
+    constructor (string memory name_, string memory symbol_) {
+        _name = name_;
+        _symbol = symbol_;
+    }
+
+    /**
+     * @dev Returns the name of the token.
+     */
+    function name() public view virtual override returns (string memory) {
+        return _name;
+    }
+
+    /**
+     * @dev Returns the symbol of the token, usually a shorter version of the
+     * name.
+     */
+    function symbol() public view virtual override returns (string memory) {
+        return _symbol;
+    }
+
+    /**
+     * @dev Returns the number of decimals used to get its user representation.
+     * For example, if `decimals` equals `2`, a balance of `505` tokens should
+     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
+     *
+     * Tokens usually opt for a value of 18, imitating the relationship between
+     * Ether and Wei. This is the value {ERC20} uses, unless this function is
+     * overridden;
+     *
+     * NOTE: This information is only used for _display_ purposes: it in
+     * no way affects any of the arithmetic of the contract, including
+     * {IERC20-balanceOf} and {IERC20-transfer}.
+     */
+    function decimals() public view virtual override returns (uint8) {
+        return 18;
+    }
+
+    /**
+     * @dev See {IERC20-totalSupply}.
+     */
+    function totalSupply() public view virtual override returns (uint256) {
+        return _totalSupply;
+    }
+
+    /**
+     * @dev See {IERC20-balanceOf}.
+     */
+    function balanceOf(address account) public view virtual override returns (uint256) {
+        return _balances[account];
+    }
+
+    /**
+     * @dev See {IERC20-transfer}.
+     *
+     * Requirements:
+     *
+     * - `recipient` cannot be the zero address.
+     * - the caller must have a balance of at least `amount`.
+     */
+    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
+        _transfer(_msgSender(), recipient, amount);
+        return true;
+    }
+
+    /**
+     * @dev See {IERC20-allowance}.
+     */
+    function allowance(address owner, address spender) public view virtual override returns (uint256) {
+        return _allowances[owner][spender];
+    }
+
+    /**
+     * @dev See {IERC20-approve}.
+     *
+     * Requirements:
+     *
+     * - `spender` cannot be the zero address.
+     */
+    function approve(address spender, uint256 amount) public virtual override returns (bool) {
+        _approve(_msgSender(), spender, amount);
+        return true;
+    }
+
+    /**
+     * @dev See {IERC20-transferFrom}.
+     *
+     * Emits an {Approval} event indicating the updated allowance. This is not
+     * required by the EIP. See the note at the beginning of {ERC20}.
+     *
+     * Requirements:
+     *
+     * - `sender` and `recipient` cannot be the zero address.
+     * - `sender` must have a balance of at least `amount`.
+     * - the caller must have allowance for ``sender``'s tokens of at least
+     * `amount`.
+     */
+    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
+        _transfer(sender, recipient, amount);
+
+        uint256 currentAllowance = _allowances[sender][_msgSender()];
+        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
+        _approve(sender, _msgSender(), currentAllowance - amount);
+
+        return true;
+    }
+
+    /**
+     * @dev Atomically increases the allowance granted to `spender` by the caller.
+     *
+     * This is an alternative to {approve} that can be used as a mitigation for
+     * problems described in {IERC20-approve}.
+     *
+     * Emits an {Approval} event indicating the updated allowance.
+     *
+     * Requirements:
+     *
+     * - `spender` cannot be the zero address.
+     */
+    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
+        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
+        return true;
+    }
+
+    /**
+     * @dev Atomically decreases the allowance granted to `spender` by the caller.
+     *
+     * This is an alternative to {approve} that can be used as a mitigation for
+     * problems described in {IERC20-approve}.
+     *
+     * Emits an {Approval} event indicating the updated allowance.
+     *
+     * Requirements:
+     *
+     * - `spender` cannot be the zero address.
+     * - `spender` must have allowance for the caller of at least
+     * `subtractedValue`.
+     */
+    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
+        uint256 currentAllowance = _allowances[_msgSender()][spender];
+        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
+        _approve(_msgSender(), spender, currentAllowance - subtractedValue);
+
+        return true;
+    }
+
+    /**
+     * @dev Moves tokens `amount` from `sender` to `recipient`.
+     *
+     * This is internal function is equivalent to {transfer}, and can be used to
+     * e.g. implement automatic token fees, slashing mechanisms, etc.
+     *
+     * Emits a {Transfer} event.
+     *
+     * Requirements:
+     *
+     * - `sender` cannot be the zero address.
+     * - `recipient` cannot be the zero address.
+     * - `sender` must have a balance of at least `amount`.
+     */
+    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
+        require(sender != address(0), "ERC20: transfer from the zero address");
+        require(recipient != address(0), "ERC20: transfer to the zero address");
+
+        _beforeTokenTransfer(sender, recipient, amount);
+
+        uint256 senderBalance = _balances[sender];
+        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
+        _balances[sender] = senderBalance - amount;
+        _balances[recipient] += amount;
+
+        emit Transfer(sender, recipient, amount);
+    }
+
+    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
+     * the total supply.
+     *
+     * Emits a {Transfer} event with `from` set to the zero address.
+     *
+     * Requirements:
+     *
+     * - `to` cannot be the zero address.
+     */
+    function _mint(address account, uint256 amount) internal virtual {
+        require(account != address(0), "ERC20: mint to the zero address");
+
+        _beforeTokenTransfer(address(0), account, amount);
+
+        _totalSupply += amount;
+        _balances[account] += amount;
+        emit Transfer(address(0), account, amount);
+    }
+
+    /**
+     * @dev Destroys `amount` tokens from `account`, reducing the
+     * total supply.
+     *
+     * Emits a {Transfer} event with `to` set to the zero address.
+     *
+     * Requirements:
+     *
+     * - `account` cannot be the zero address.
+     * - `account` must have at least `amount` tokens.
+     */
+    function _burn(address account, uint256 amount) internal virtual {
+        require(account != address(0), "ERC20: burn from the zero address");
+
+        _beforeTokenTransfer(account, address(0), amount);
+
+        uint256 accountBalance = _balances[account];
+        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
+        _balances[account] = accountBalance - amount;
+        _totalSupply -= amount;
+
+        emit Transfer(account, address(0), amount);
+    }
+
+    /**
+     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
+     *
+     * This internal function is equivalent to `approve`, and can be used to
+     * e.g. set automatic allowances for certain subsystems, etc.
+     *
+     * Emits an {Approval} event.
+     *
+     * Requirements:
+     *
+     * - `owner` cannot be the zero address.
+     * - `spender` cannot be the zero address.
+     */
+    function _approve(address owner, address spender, uint256 amount) internal virtual {
+        require(owner != address(0), "ERC20: approve from the zero address");
+        require(spender != address(0), "ERC20: approve to the zero address");
+
+        _allowances[owner][spender] = amount;
+        emit Approval(owner, spender, amount);
+    }
+
+    /**
+     * @dev Hook that is called before any transfer of tokens. This includes
+     * minting and burning.
+     *
+     * Calling conditions:
+     *
+     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
+     * will be to transferred to `to`.
+     * - when `from` is zero, `amount` tokens will be minted for `to`.
+     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
+     * - `from` and `to` are never both zero.
+     *
+     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+     */
+    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
+}
diff --git a/solidity/truffle-config.js b/solidity/truffle-config.js
new file mode 100644 (file)
index 0000000..5d3c0e5
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+ * Use this file to configure your truffle project. It's seeded with some
+ * common settings for different networks and features like migrations,
+ * compilation and testing. Uncomment the ones you need or modify
+ * them to suit your project as necessary.
+ *
+ * More information about configuration can be found at:
+ *
+ * trufflesuite.com/docs/advanced/configuration
+ *
+ * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider)
+ * to sign your transactions before they're sent to a remote public node. Infura accounts
+ * are available for free at: infura.io/register.
+ *
+ * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
+ * public/private key pairs. If you're publishing your code to GitHub make sure you load this
+ * phrase from a file you've .gitignored so it doesn't accidentally become public.
+ *
+ */
+
+// const HDWalletProvider = require('@truffle/hdwallet-provider');
+// const infuraKey = "fj4jll3k.....";
+//
+// const fs = require('fs');
+// const mnemonic = fs.readFileSync(".secret").toString().trim();
+
+module.exports = {
+  /**
+   * Networks define how you connect to your ethereum client and let you set the
+   * defaults web3 uses to send transactions. If you don't specify one truffle
+   * will spin up a development blockchain for you on port 9545 when you
+   * run `develop` or `test`. You can ask a truffle command to use a specific
+   * network from the command line, e.g
+   *
+   * $ truffle test --network <network-name>
+   */
+
+  networks: {
+    // Useful for testing. The `development` name is special - truffle uses it by default
+    // if it's defined here and no other network is specified at the command line.
+    // You should run a client (like ganache-cli, geth or parity) in a separate terminal
+    // tab if you use this network and you must also set the `host`, `port` and `network_id`
+    // options below to some value.
+    //
+    development: {
+     host: "127.0.0.1",     // Localhost (default: none)
+     port: 8545,            // Standard Ethereum port (default: none)
+     network_id: "*",       // Any network (default: none)
+    },
+    // Another network with more advanced options...
+    // advanced: {
+    // port: 8777,             // Custom port
+    // network_id: 1342,       // Custom network
+    // gas: 8500000,           // Gas sent with each transaction (default: ~6700000)
+    // gasPrice: 20000000000,  // 20 gwei (in wei) (default: 100 gwei)
+    // from: <address>,        // Account to send txs from (default: accounts[0])
+    // websocket: true        // Enable EventEmitter interface for web3 (default: false)
+    // },
+    // Useful for deploying to a public network.
+    // NB: It's important to wrap the provider as a function.
+    // ropsten: {
+    // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
+    // network_id: 3,       // Ropsten's id
+    // gas: 5500000,        // Ropsten has a lower block limit than mainnet
+    // confirmations: 2,    // # of confs to wait between deployments. (default: 0)
+    // timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50)
+    // skipDryRun: true     // Skip dry run before migrations? (default: false for public nets )
+    // },
+    // Useful for private networks
+    // private: {
+    // provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
+    // network_id: 2111,   // This network is yours, in the cloud.
+    // production: true    // Treats this network as if it was a public net. (default: false)
+    // }
+  },
+
+  // Set default mocha options here, use special reporters etc.
+  mocha: {
+    // timeout: 100000
+  },
+
+  // Configure your compilers
+  compilers: {
+    solc: {
+      // version: "0.5.1",    // Fetch exact version from solc-bin (default: truffle's version)
+      // docker: true,        // Use "0.5.1" you've installed locally with docker (default: false)
+      // settings: {          // See the solidity docs for advice about optimization and evmVersion
+      //  optimizer: {
+      //    enabled: false,
+      //    runs: 200
+      //  },
+      //  evmVersion: "byzantium"
+      // }
+    }
+  },
+
+  // Truffle DB is currently disabled by default; to enable it, change enabled: false to enabled: true
+  //
+  // Note: if you migrated your contracts prior to enabling this field in your Truffle project and want
+  // those previously migrated contracts available in the .db directory, you will need to run the following:
+  // $ truffle migrate --reset --compile-all
+
+  db: {
+    enabled: false
+  }
+};
diff --git a/sort2.py b/sort2.py
new file mode 100644 (file)
index 0000000..c08072d
--- /dev/null
+++ b/sort2.py
@@ -0,0 +1,69 @@
+def merge(x:list, a:int, b:int, c:int):
+    if b == c:
+        return
+    while a < b and x[a] < x[b]:
+        a += 1
+
+    if a == b:
+        return
+    while b < c and x[b - 1] < x[c - 1]:
+        c -= 1
+
+    w = min(b - a, c - b)
+
+    tmp = x[b - w:b]
+    x[b - w:b] = x[b:b + w]
+    x[b:b + w] = tmp
+
+    merge(x, a, b - w, b)
+    merge(x, b, b + w, c)
+    merge(x, a, b, c)
+
+def getrun(x:list, a:int, depth:int):
+    if a == len(x):
+        return a
+
+    if depth == 0:
+        b = a + 1
+
+        while b < len(x) and x[b - 1] < x[b]:
+            b += 1
+
+        return b
+
+    b = getrun(x, a, depth - 1)
+    c = getrun(x, b, depth - 1)
+    merge(x, a, b, c)
+    return c
+
+def sort(x:list):
+    depth = 0
+    a = 0
+    b = getrun(x, a, depth)
+    c = getrun(x, b, depth)
+    merge(x, a, b, c)
+
+    while c < len(x):
+        depth += 1
+        b = c
+        c = getrun(x, b, depth)
+        merge(x, a, b, c)
+
+def is_sorted(x:list) -> bool:
+    for i in range(len(x) - 1):
+        if x[i] >= x[i + 1]:
+            return False
+    return True
+
+if __name__ == '__main__':
+    import random, unittest
+
+    class SortTests(unittest.TestCase):
+        def test_sorts(self):
+            for i in range(100):
+                x = [i for i in range(25)]
+                random.shuffle(x)
+                sort(x)
+                self.assertTrue(is_sorted(x))
+
+    unittest.main()