#import matplotlib.pyplot as plt
from fractions import gcd

import math
import numpy as np
import itertools
from itertools import product
from functools import reduce

import prime
import sys

def sol_41():
    max_number = 0

    def is_pandigital(n):
        compare_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
        if sorted(list(str(n))) == sorted(compare_list):
            return True
        return False

    def get_generator(skiplist):
        iterlist = ['1', '2', '3', '4', '5', '6', '7']#, '8']# , '9']
        for number in skiplist:
            del iterlist[iterlist.index(str(number))]
        return iterlist

    for a in get_generator([]):
        for b in get_generator([a]):
            for c in get_generator([a, b]):
                for d in get_generator([a, b, c]):
                    for e in get_generator([a, b, c, d]):
                        for f in get_generator([a, b, c, d, e]):
                            for g in get_generator([a, b, c, d, e, f]):
                                #for h in get_generator([a, b, c, d, e, f, g]):
                                    #for i in get_generator([a, b, c, d, e, f, g, h]):
                                number = int(''.join(list(map(str, [a, b, c, d, e, f, g]))))
                                #print(number)
                                if prime.is_prime(number):
                                    #print(number)
                                    if number > max_number:
                                        max_number = number

    # iterlist = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
    # iteration_indexes = []
    # for iteration_index in iterlist:
    #    new_iterlist = iterlist
    #    del new_iterlist[new_iterlist.index(iteration_index)]
    #    pass

    # for i in range(987654321, 0, -1):
    #    print(i)
    #    if prime.is_prime(i) and is_pandigital(i):
    #        return i
    return max_number

def sol_42():
    f = open('42.txt', 'r')

    alphabet_lookup = [chr(i) for i in range(ord('A'), ord('Z')+1)]
    triangle_lookup = [n*(n+1)/2 for n in range(1, 100)]

    count = 0
    for row in f:
        words = row.split(',')
        for word in words:
            word = word.strip('"')
            wordsum = 0
            for s in word:
                wordsum += alphabet_lookup.index(s)+1
            if wordsum in triangle_lookup:
                count += 1
    return count

def sol_43():
    def check_special_property():
        pass

    def get_generator(skiplist):
        iterlist = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
        for number in skiplist:
            del iterlist[iterlist.index(str(number))]
        return iterlist

    total_sum = 0
    for a in get_generator(['0']):
        for b in get_generator([a]):
            for c in get_generator([a, b]):
                for d in get_generator([a, b, c]):
                    for e in get_generator([a, b, c, d]):
                        for f in get_generator([a, b, c, d, e]):
                            for g in get_generator([a, b, c, d, e, f]):
                                for h in get_generator([a, b, c, d, e, f, g]):
                                    for i in get_generator([a, b, c, d, e, f, g, h]):
                                        for j in get_generator([a, b, c, d, e, f, g, h, i]):
                                            #number = int(''.join(list(map(str, [a, b, c, d, e, f, g, h, i, j]))))
                                            #print(number)
                                            number_list = [a, b, c, d, e, f, g, h, i, j]
                                            print(number_list)
                                            truth_value = True
                                            for x, prime in enumerate([2, 3, 5, 7, 11, 13, 17]):
                                                number = int(''.join(number_list[x+1:x+4]))
                                                print(number)
                                                if number % prime == 0:
                                                    truth_value = (truth_value and True)
                                                else:
                                                    truth_value = False
                                            if truth_value:
                                                total_sum += int(''.join(number_list))
                                                print(int(''.join(number_list)))
    return total_sum

def sol_44():
    def check_pentagonal(num):
        n = 1/6 + np.sqrt(1/36+2*num/3)
        n = int(round(n))
        if (3*n*n - n == 2*num):
            return True
        else:
            return False

    min_diff = 1e12
    for j in range(1, 10000):  # Note; w.l.o.g i<j
        for i in range(1, 10000):
            if i == j:
                continue
            a = int(j*(3*j-1)/2)
            b = int(i*(3*i-1)/2)
            diff = int(abs(a-b))
            s = int(a+b)
            #print(a)
            #print(b)
            #print(diff)
            #print(s)
            if check_pentagonal(s) and check_pentagonal(diff):
                #print(diff)
                if diff < min_diff:
                    min_diff = diff
    return min_diff

def sol_45():
    def check_pentagonal(num):
        n = 1/6 + np.sqrt(1/36+2*num/3)
        n = int(round(n))
        # print('pentagonal')
        # print(3*n**2-n)
        # print(2*num)
        if (3*n*n - n == 2*num):# < 1e-12:
            # print('hit')
            # print(n)
            # print(2*num)
            return True
        else:
            return False

    def check_hexagonal(num):
        n = 1/4 + np.sqrt(1/16+num/2)
        n = int(round(n))
        if (2*n**2 - n == num):# < 1e-12:
            #print('hit hexagonal')
            return True
        return False

    for i in range(2, 1000000):
        triangle_number = int(i*(i+1)/2)
        #print(triangle_number)
        if check_pentagonal(triangle_number) and check_hexagonal(triangle_number):
            #print(triangle_number)
            if triangle_number > 40755:
                return triangle_number

def sol_46():
    search_size = 100000
    numbers = np.ones(search_size)
    for i in range(0, int(search_size/2)):
        numbers[i*2] = 0
    numbers[1] = 0

    primes = prime.prime_sieve(search_size)

    for p in prime.prime_sieve(search_size):
        print(p)
        for square in range(0, int(round(np.sqrt((search_size-p)/2)))):
            index = p + 2*square*square
            if index > search_size:
                continue
            else:
                numbers[index] = 0
    print(np.where(numbers == 1)[0])

def sol_47():
    for i in range(1, 1000000):
        truth_factor = True
        for j in range(0, 4):
            if len(set(prime.get_prime_factors(i+j))) == 4:
                continue
            else:
                i = j+j
                truth_factor = False
                break
        if truth_factor:
            return i

def sol_48():
    #def exp_mod_10(number, exponent):
    #    for i in range(1, exponent+1):
    #        number = (number*number)%1e11

    res = 0
    for exponent in range(1, 1001):
        res += exponent**exponent
    return str(res)[-10::]

def sol_49():
    ans = []
    for i in range(1000, 10000-3330-3330):
        a = i
        b = i+3330
        c = i+6660

        if prime.is_prime(a) and prime.is_prime(b) and prime.is_prime(c):
            #print(set(list(str(a))))
            if (set(list(str(a))) == set(list(str(b)))) and (set(list(str(b))) == set(list(str(c)))):
                if a == 1487:
                    continue
                else:
                    ans = [a, b, c]
    ans = [str(x) for x in ans]
    return ''.join(ans)

def sol_50():
    primes = prime.prime_sieve(1000000)
    print(len(primes))

    longest_prime = 1
    prime_length = 1
    for i, _ in enumerate(primes):
        if i == len(primes)-1:
            break
        j = 1
        new_prime = sum(primes[i:i+j+1])
        while new_prime < 1000000:
            if prime.is_prime(new_prime) and (j > prime_length):
                print(j)
                longest_prime = new_prime
                prime_length = j
                print(prime_length)
                print(longest_prime)
                print(primes[i:i+j+1])
            else:
                j += 1
                new_prime = sum(primes[i:j+i+1])
    return longest_prime

def sol_51():
    def count_primes(number, indices):
        count = 0
        if 0 in indices:
            for z in range(1, 10):
                number_ = []
                for num in number:
                    number_.append(num)
                for index in indices:
                    number_[index] = str(z)
                new_number = int(''.join(number_))
                print(new_number)
                if prime.is_prime(new_number):
                    count += 1
        else:
            for z in range(0,10):
                number_ = []
                for num in number:
                    number_.append(num)
                for index in indices:
                    number_[index] = str(z)
                new_number = int(''.join(number_))
                print(new_number)
                if prime.is_prime(new_number):
                    count += 1
        return count

    for i in range(56003, 200000):
        number = list(str(i))
        for subset_length in [3]:
            #print(subset_length)
            for combs in itertools.combinations(range(0,len(number)), subset_length):
                #print(number)
                #print(combs)
                num_primes = count_primes(number, combs)
                #print(num_primes)
                if num_primes > 7:
                    print(number)
                    print(combs)
                    return number

def sol_52():
    def check_digits(numbers):
        truth_val = True
        start_num = numbers[0]
        for num in numbers:
            #print(set(list(str(num)))==set(list(str(start_num))))
            truth_val = (truth_val and (set(list(str(num)))==set(list(str(start_num)))))
            start_num = num
        return truth_val
    for i in range(1, 1000000):
        numbers = [j*i for j in range(1, 7)]
        if check_digits(numbers):
            return i

def sol_53():
    def num_combinations(n,r):
        return np.math.factorial(n)/(np.math.factorial(r)*np.math.factorial(n-r))
    count = 0
    for i in range(23, 101):
        for j in range(1, i):
            if num_combinations(i, j) > 1e6:
                count += 1
    return count

def sol_54():
    def tiebreaker(p1, p2, hand):
        ordering = ['2','3','4','5','6','7','8','9','T','J','Q','K','A']

        values_p1 = [q[0] for q in p1]
        values_p2 = [q[0] for q in p2]

        if hand == 'High card':
            print(sorted([ordering.index(z) for z in values_p1])[::-1] )
            for c1, c2 in zip(sorted([ordering.index(z) for z in values_p1])[::-1], sorted([ordering.index(z) for z in values_p2])[::-1]):
                if c1 > c2:
                    return True
                elif c1 < c2:
                    return False

        elif hand == 'Pair':
            highest_pair_p1 = 0
            highest_pair_p2 = 0

            cards_p1 = list(set(values_p1))
            cards_p2 = list(set(values_p2))
            print(cards_p1)
            print(cards_p2)
            for c1, c2 in zip(cards_p1, cards_p2):
                count_p1 = values_p1.count(c1)
                count_p2 = values_p2.count(c2)
                if count_p1 == 2:
                    highest_pair_p1 = ordering.index(c1)
                if count_p2 == 2:
                    highest_pair_p2 = ordering.index(c2)

            if highest_pair_p1 > highest_pair_p2:
                return True
            elif highest_pair_p1 < highest_pair_p2:
                return False

            print(p1)
            print(p2)
            print(highest_pair_p1)
            print(highest_pair_p2)
            return False
            #s = input('---')
            #return bool(s)

        else:
            input('Fanken!')
        #elif hand == 'Straight':
        #    pass

        #elif hand == 'Three of a kind':
        #    pass
        #elif hand == 'Four of a kind':
        #    pass
        #elif hand == 'Full house':
        #    pass
        #elif hand == 'Flush':
        #    pass

    def get_hand(p):
        suits = [q[1] for q in p]
        values = [q[0] for q in p]
        ordering = ['A','2','3','4','5','6','7','8','9','T','J','Q','K','A']

        if set(values) == set(['A','K', 'Q', 'J', 'T']):
            return 'Royal flush'

        indices = [ordering.index(v) for v in values]
        if sorted(indices) == list(range(min(indices),max(indices)+1)):
            if len(list(set(suits))) == 1:
                return 'Straight flush'
            return 'Straight'

        if len(list(set(suits))) == 1:
            return 'Flush'

        counts = []
        for unique_card in list(set(values)):
            counts.append(values.count(unique_card))

        #counts = set(counts)
        if set(counts)==set([4,1]):
            return 'Four of a kind'
        elif set(counts)==set([3,2]):
            return 'Full house'
        elif set(counts) == set([3,1,1]):
            return 'Three of a kind'
        elif set(counts) == set([2, 1]) and len(counts) == 4:
            return 'Pair'
        elif set(counts) == set([2, 1]) and len(counts) == 3:
            return 'Two pairs'

        return 'High card'

    def check_winner(p1, p2):
        hands = ['High card', 'Pair', 'Two pairs', 'Three of a kind', 'Straight', 'Flush', 'Full house', 'Four of a kind', 'Straight flush', 'Royal flush']
        hand_p1 = get_hand(p1)
        hand_p2 = get_hand(p2)

        if hands.index(hand_p1) > hands.index(hand_p2):
            print('P1 winning hand')
            print(hand_p1)
            print(hand_p2)
            return True
        elif hands.index(hand_p1) < hands.index(hand_p2):
            print('P2 winning hand')
            print(hand_p1)
            print(hand_p2)
            return False

        elif hands.index(hand_p1) == hands.index(hand_p2):
            res = tiebreaker(p1, p2, hand_p1)
            return res

    f = open('54.txt','r')
    count = 0
    for i,line in enumerate(f):
        l = line.strip('\n').split(' ')
        p1 = l[0:5]
        p2 = l[5:]
        if check_winner(p1, p2) == True:
            count += 1
    return count

def sol_55():
    def is_palindrome(number):
        return str(number) == str(number)[::-1]

    def is_lychrel(number):
        for i in range(1, 50):
            number = number + int(''.join(list(str(number))[::-1]))
            if is_palindrome(number):
                return False
        return True

    count = 0
    for i in range(0, 10000):
        if is_lychrel(i):
            count += 1
        else:
            print(i)
    return count

def sol_56():
    max_digit_sum = 0
    for a in range(1, 100):
        for b in range(1, 100):
            digit_sum = sum(list(map(int,str(a**b))))
            if digit_sum > max_digit_sum:
                max_digit_sum = digit_sum
    return max_digit_sum

from decimal import *

def sol_57():
    def recursive_sqrt_2(iterations):
        if iterations == 0:
            return 0
        else:
            return Decimal(1)/(Decimal(2)+recursive_sqrt_2(iterations-1))

    import sys
    import fractions
    getcontext().prec = 28

    sys.setrecursionlimit(5000)

    numerator = 1
    denominator = 2

    count = 0
    for i in range(1, 1001):
        cmp_numerator = numerator + denominator
        cmp_denominator = denominator

        if len(str(cmp_numerator)) > len(str(cmp_denominator)):
            count += 1

        n = numerator
        m = denominator
        numerator = m
        denominator = 2*m + n

        #i = Decimal(i)
        #approximation = 1+recursive_sqrt_2(i)
        #f = fractions.Fraction(approximation)
        #print(f)
        #print(str(f).split('/')[0])
        #print(list(str(f).split('/')[0]))
        #print(len(list(str(f).split('/')[0])))
        #print(len(list(str(f).split('/')[1])))
        #if len(list(str(f).split('/')[0])) > len(list(str(f).split('/')[1])):
        #    count += 1
        #print(approximation)
        #input()
    return count

def sol_58():
    def take_diagonal_lap(lap_number, index, diagonal_1, diagonal_2):
        side_length = 2*lap_number+1
        for increment in [side_length-1, 2*(side_length-1), 3*(side_length-1), 4*(side_length-1)]:
            new_number = index+increment
            if increment == side_length-1:
                diagonal_1.append(new_number)
            if increment == (side_length-1+side_length-1):
                diagonal_2.append(new_number)
            if increment == 3*(side_length-1):
                diagonal_1.append(new_number)
            if increment == 4*(side_length-1):
                diagonal_2.append(new_number)
        lap_number += 1
        return lap_number, index+increment, diagonal_1, diagonal_2

    index = 1
    lap_number = 1

    ratio = 1
    diagonal_1 = []
    diagonal_2 = []
    while ratio > 0.1:
        if lap_number == 1:
            ratio = 0
        lap_number, index, diagonal_1, diagonal_2 = take_diagonal_lap(lap_number, index, diagonal_1, diagonal_2)
        #print(diagonal_1)
        #print(diagonal_2)
        new_primes = sum([1 for i in diagonal_1[-2:] if prime.is_prime(i)]) + sum([1 for j in diagonal_2[-2:] if prime.is_prime(j)])
        ratio = (ratio*(2*len(diagonal_1)+1-4)+new_primes)/(2*len(diagonal_1)+1)
        #ratio = (sum([1 for i in diagonal_1 if prime.is_prime(i)]) + sum([1 for j in diagonal_2 if prime.is_prime(j)]))/(2*len((diagonal_1))+1)
        print(ratio)
        if lap_number < 10:
            print(lap_number)
            print(diagonal_1)
            print(diagonal_2)
            print(ratio)
            print((sum([1 for i in diagonal_1 if prime.is_prime(i)]) + sum([1 for j in diagonal_2 if prime.is_prime(j)]))/(2*len((diagonal_1))+1))
            input()
        if lap_number % 1000000 == 0:
            print(lap_number)
            print(ratio)
            print(diagonal_1)
        #i, j, index = take_lap(lap_number, index, i, j, spiral)
        #ratio = get_prime_ratio(spiral, lap_number)
        #lap_number += 1
        #if lap_number % 100 == 0:
        #    print(lap_number)
        #    print(ratio)
        #    input()
        #if lap_number > (size-1)/2:
        #    quit()

    return 2*lap_number-1

def sol_59():
    def xor(c1, c2):
        return int(c1) ^ int(c2)

    def decipher(msg, key):
        deciphered_text = []
        for i, char in enumerate(msg):
            deciphered_text.append(chr(int(xor(char, key[int(i%3)]))))
        return deciphered_text

    def is_cleartext(msg, words):
        msg_str = ''.join(msg)
        import re
        for word in words.split(' '):
            if (re.search(word,msg_str) is not None):
                return True
        return False

    def count_normal_letters(msg):
        allowed_range = []
        allowed_range.extend(list(range(ord('0'), ord('9')+1)))
        allowed_range.extend(list(range(ord('a'), ord('z')+1)))
        allowed_range.extend(list(range(ord('A'), ord('Z')+1)))
        allowed_range.extend([ord(' ')])
        allowed_range.extend([ord('.')])
        allowed_range.extend([ord(',')])
        allowed_range.extend([ord(':')])
        allowed_range.extend([ord('!')])
        allowed_range.extend([ord('?')])
        allowed_range.extend([ord('(')])
        allowed_range.extend([ord(')')])

        #allowed_range.extend([ord('+')])
        #print(len(allowed_range))
        res = 0
        for i, char in enumerate(msg):
            if ord(char) in allowed_range:
                res += 1

        return res

    def is_normal(msg):
        allowed_range = []
        allowed_range.extend(list(range(ord('0'), ord('9')+1)))
        allowed_range.extend(list(range(ord('a'), ord('z')+1)))
        allowed_range.extend(list(range(ord('A'), ord('Z')+1)))
        allowed_range.extend([ord(' ')])
        allowed_range.extend([ord('.')])
        print(len(allowed_range))
        for i, char in enumerate(msg):
            if ord(char) not in allowed_range:
                return False
        return True

    def is_numbers(msg):
        allowed_range = range(ord('0'), ord('9')+1)
        for i, char in enumerate(msg):
            if ord(char) not in allowed_range:
                return False
        return True

    with open('59.txt','r') as f:
        for line in f:
            ciphertext = []
            for letter in line.split(','):
                ciphertext.append(letter)

            #while True:
            #s = input('Words to search for: ')
            count = 0
            counts = {}
            eta_score = 0
            top_list = ['e', 't', 'a', 'o', 'i', 'n']
            for e1 in range(ord('a'),ord('z')+1):
                for e2 in range(ord('a'),ord('z')+1):
                    for e3 in range(ord('a'),ord('z')+1):
                        key = [e1,e2,e3]
                        deciphered_text = decipher(ciphertext, key)

                        unique_chars = list(set(deciphered_text))
                        unique_chars_count = []

                        #print(len(unique_chars))
                        #for uc in unique_chars:
                        #    unique_chars_count.append(deciphered_text.count(uc))

                        #if unique_chars[np.argmax(unique_chars_count)] == 'e':
                        #    print(''.join(deciphered_text))

                        nl = count_normal_letters(deciphered_text)
                        str_key = [chr(i) for i in key]
                        counts[''.join(str_key)] = nl

            top_keys = sorted(counts.items(), key=lambda v: v[1])[::-1][0:10]
            print(top_keys)
            for i, key in enumerate(top_keys):
                c = [ord(i) for i in key[0]]
                deciphered_text = decipher(ciphertext, c)
                print(''.join(deciphered_text))

            deciphered_text = decipher(ciphertext, [ord(i) for i in top_keys[0][0]])
            dec = [ord(d) for d in deciphered_text]
            return sum(dec)
                        #if nl > count:
                            #    count = nl
                            #    print(''.join(deciphered_text))

                            #if is_normal(deciphered_text):
                            #    print(''.join(deciphered_text))

                            #if is_numbers(deciphered_text):
                            #    print(''.join(deciphered_text))

                            #if is_cleartext(deciphered_text, s):
                            #    print(''.join(deciphered_text))

def sol_60():
    def dual_concat(p1, p2):
        comparison_1 = int((str(p1)+str(p2)))
        comparison_2 = int((str(p2)+str(p1)))
        if prime.is_prime(comparison_1) and prime.is_prime(comparison_2):
            return True
        return False

    def recursive_chain(chain, chain_number):
        if len(chain) < 2:
            return [], False

        print(chain)
        if chain_number == 4:
            return [chain[0],chain[1]], True

        base_prime = chain[0]
        print(base_prime)
        subchains = build_subchains(chain, 10)

        for subchain in subchains:
            new_primes, truth_value = recursive_chain(subchain, chain_number+1)
            if truth_value:
                return [base_prime, new_primes], True
        return [], False

    def build_subchains(chain, first_n):
        subchains = []
        for p in chain[1:first_n]:
            subchain = []
            subchain.append(p)
            for q in chain:
                if q <= p:
                    continue
                if dual_concat(p, q):
                    subchain.append(q)
            subchains.append(subchain)
        return subchains

    primes = prime.prime_sieve(35000)

    initial_subchains = build_subchains(primes, 50)
    for chain in initial_subchains:
        base_prime = chain[0]
        for chain_2 in build_subchains(chain, 50):
            base_prime_2 = chain_2[0]
            for chain_3 in build_subchains(chain_2, 50):
                base_prime_3 = chain_3[0]
                for chain_4 in build_subchains(chain_3, 40):
                    base_prime_4 = chain_4[0]
                    if len(chain_4) > 1:
                        print(base_prime)
                        print(base_prime_2)
                        print(base_prime_3)
                        print(base_prime_4)
                        print(chain_4)
                        print(base_prime+base_prime_2+base_prime_3+base_prime_4+chain_4[1])
                        input()
    #    returned_primes, truth_value = recursive_chain(chain, chain_number=1)
    #    if truth_value:
    #        print(returned_primes)
    #        input()
def sol_61():
    def overlap(m, n):
        if str(m)[2:] == str(n)[0:2]:
            return True
        return False

    def recursive_check(number, numbs, remaining_indices, starting_number):
        #print(remaining_indices)
        if remaining_indices == []:
            if overlap(number, starting_number):
                print(number)
                return True

        for i in remaining_indices:
            for m in numbs[i]:
                if overlap(number, m):
                    indices = [x for x in remaining_indices if not x==i]
                    flag = recursive_check(m, numbs, indices, starting_number)
                    if flag:
                        print(m)
                        return True
        return False

    def get_rings(numbs):
        indices = [0, 1, 2, 3, 4, 5]
        starting_type = numbs[5]
        del indices[5]
        for m in starting_type:
            flag = recursive_check(m, numbs, indices, m)
            if flag:
                print(m)
    def generate_numbers():
        res = [[],[],[],[],[],[]]
        k = [0 for x in res]
        p = 0
        while min([len(str(q)) for q in k]) < 5:
            k[0] = p*(p+1)/2
            k[1] = p*p
            k[2] = p*(3*p-1)/2
            k[3] = p*(2*p-1)
            k[4] = p*(5*p-3)/2
            k[5] = p*(3*p-2)
            k = [int(i) for i in k]
            for i, z in enumerate(k):
                if len(str(z))==4:
                    res[i].append(z)
            p += 1
        return res
    nums = generate_numbers()
    rings = get_rings(nums)
    print(rings)

def sol_69():
    m = 0
    n = 0
    for i in range(2, 1000000):
        factors = prime.get_prime_factors(i)
        prod = 1
        for p in list(set(factors)):
            prod = prod*(p)/(p-1)
        if prod > m:
            n = i
            m = prod
    print(m)
    print(n)

def sol_70():
    def is_permutation(tot, n):
        return sorted(str(tot))==sorted(str(n))

    minimum = 100
    min_n = 0
    for n in range(2, 10000000):
        factors = prime.get_prime_factors(n)
        tot = n
        for p in list(set(factors)):
            tot = tot*(p-1)/p
        tot = int(tot)

        if is_permutation(tot, n):
            if n/tot < minimum:
                minimum = n/tot
                min_n = n
    print(min_n)
    print(minimum)

def sol_72():
    def totient(d):
        factors = prime.get_prime_factors(d)
        res = d
        for p in list(set(factors)):
            res = res*(p-1)/p
        return int(res)

    count = 0
    for d in range(1, 1000001):
        #if d % 100000:
        #    print(d)
        #s    print(totient(d))
        count += totient(d)
        if d == 13:
            print(d)
            print(totient(d))
        if d == 1:
            print(d)
            print(totient(d))
    return count-1 # Remove 1/1

def sol_79():
    f = open('79.txt', 'r')
    res = []
    for line in f:
        res.append(line.strip('\n'))
    print(res)

def sol_71():
    results = []
    target = 3/7
    targets = []
    for d in range(1, 1000001):
        n = math.floor(d*3/7)
        if n== 0:
            continue
        targets.append([n/d, d, n])

    sorted_results = sorted(targets, key=lambda x: x[0])[::-1]
    for i in sorted_results:
        if i[0] < 3/7:
            print(i[1])
            return i[2]
    print(sorted_results[0:100])

def sol_73():
    def is_reducible(d, n):
        if gcd(d, n) == 1:
            return False
        else:
            return True

    def in_bounds(n, d, lower_bound, upper_bound):
        if n/d > lower_bound and n/d < upper_bound:
            return True

        if d%2==0 and n%2==0:
            return True
        elif d%3==0 and n%3==0:
            return True
        #elif d%5==0 and n%5==0:
        #    return True
        else:
            for i in range(3, int(d**0.5)+1, 2):
                if d % i == 0 and n % i == 0:
                    return True
        return False

    primes = prime.prime_sieve(12000)

    lower_bound = 1/3
    upper_bound = 1/2

    count = 0
    for d in range(1, 12001):
        print(d)

        start_index = int(d*lower_bound)
        end_index = int(d*upper_bound)+1

        res = []
        for n in range(start_index, end_index):
            if in_bounds(n, d, lower_bound, upper_bound) and not is_reducible(n, d):
                res.append([n, d])
                count += 1
        if d % 1000==0:
            print(d)

        start_index = math.floor(d*lower_bound)-1
        end_index = math.ceil(d*upper_bound)+1

        print(start_index)
        print(end_index)

        for n in range(start_index, end_index+1):
            if n/d > lower_bound and n/d < upper_bound:
                if not is_reducible(d, n):
                    count += 1
    return count

def sol_74():
    def factorial(i):
        res = 1
        while i > 0:
            res = res*i
            i -= 1
        return res

    def sum_factorial(i):
        res = 0
        for s in str(i):
            res += factorial(int(s))
        return int(res)

    def count_chain_length(i, chain_lengths):
        previous_numbers = []
        previous_numbers.append(i)
        hit = False

        length = 0
        while not hit:
            i = sum_factorial(i)
            length += 1
            if i in previous_numbers:
                hit = True
            previous_numbers.append(i)
        return length

    def recursive_count(n, memory, chain):
        new_number = sum_factorial(n)
        if new_number in chain:
            return 0
        chain.append(new_number)
        if new_number > memory.shape[0]:
            return 1 + recursive_count(new_number, memory, chain)
        else:
            if memory[new_number] == 0:
                length = 1 + recursive_count(new_number, memory, chain)
                memory[new_number] = length
                return length
            else:
                return int(memory[new_number])

    memory = np.zeros(1000000)
    for n in range(999999, 0, -1):
        print(n)
        len_n = 1+recursive_count(n, memory, [n])
        memory[n] = int(len_n)
        print(len_n)

    print(memory)
    return np.where(memory==60)[0].shape[0]

def sol_75():
    # a+b+c = L
    # a**2 + b**2 = c**2

    #Intractable
    #count = 0
    #for l in range(12, 1500001, 2):
    #    print(l)
    #    hits = 0
    #    for a in range(1, int(l/3)):
    #        c = int((2*a**2+l**2-2*a*l)/(2*l-2*a))
    #        b = l-a-c
    #        if a+b+c == l and a**2+b**2 == c**2:
    #            hits += 1
    #        if hits > 1:
    #            break
    #    if hits == 1:
    #        count += 1

    #counts = np.zeros(1500001)
    #for a in range(1, int(1500000/3)):
    #    print(a)
    #    for b in range(a, int((1500000-a)/2)):
    #        c = (a**2+b**2)**(1/2)
    #        if a**2 + b**2 == c**2 and (a+b+c)<1500000:
    #            counts[a+b+c] += 1

    counts = np.zeros(1500001)
    print('here')
    print(np.sqrt(1500000))
    print(1500000**(1/2))
    for m in range(1, int(np.sqrt(1500000))+1, 2):
        print(m)
        for n in range(1, m, 2):
            if math.gcd(m, n) == 1:
                primitive_a = m*n
                primitive_b = int((m**2-n**2)/2)
                primitive_c = int((m**2+n**2)/2)

                for k in range(1, int(1500000/(primitive_a+primitive_b+primitive_c)) + 1):
                    a = k*primitive_a
                    b = k*primitive_b
                    c = k*primitive_c
                    if a+b+c <=1500000 and (a**2+b**2)==c**2:
                        counts[a+b+c] += 1

    print(np.where(counts==1)[0][0:10])
    return np.where(counts==1)[0].shape[0]

def sol_76():
    # see solution of 78.
    return 190569291

def sol_77():
    def recursively_generate_sums(current_target, primes, prime_index, result, current_result):
        if prime_index == 0:
            current_result = []

        if prime_index == (len(primes)-1):
            for n in range(int(current_target/primes[prime_index])+1):
                next_current_result = [c for c in current_result]
                next_current_result.append(n)
                result.append(next_current_result)
            return

        for n in range(int(current_target/primes[prime_index])+1):
            next_current_result = [c for c in current_result]
            next_current_result.append(n)
            new_current_target = current_target - n*primes[prime_index]
            new_prime_index = prime_index + 1
            recursively_generate_sums(new_current_target, primes, new_prime_index, result, next_current_result)

    for target_value in range(66, 80):
        count = 0
        current_target = target_value
        primes = prime.prime_sieve(target_value)
        prime_index = 0

        result = []
        recursively_generate_sums(current_target, primes, prime_index, result, [])
        count = 0
        for res in result:
            s = 0
            for n, p in zip(res, primes):
                s += n*p
            if s == target_value:
                count += 1
        if count > 5000:
            return target_value

def sol_78():
    def count_partitions(n, memory):
        num_partitions = 0

        sign_counter = 1
        sign = 1

        i = 1
        pent = 1
        print(sign*pent)
        while (n - pent) > -1:
            num_partitions += sign*int(memory[n-pent])

            sign_counter = (sign_counter + 1) % 2
            if sign_counter == 0:
                i = -i
            else:
                i = -i
                i += 1

            pent = int((3*i**2-i)/2)
            sign = (-1)**(abs(i)-1)

        memory.append(num_partitions)
        return num_partitions

    memory = []
    memory.append(1)
    memory.append(1)
    for n in range(2, 100001):
        cp = count_partitions(n, memory)
        print(cp)
        if cp % 1000000 == 0:
            return n

def sol_79():
    f = open('79.txt','r')
    attempts = []
    for row in f:
        attempts.append(row.split('\n')[0])
    attempts = list(set(attempts))

    def get_valid_indices(result, s):
        resulting_indices = []
        for i, x in enumerate(result):
            if x == [] or x == s:
                resulting_indices.append(i)
        return resulting_indices

    def recursive_solve(result, attempts, i, solutions):
        if i == len(attempts):
            # print(len(result))
            # print('Hit!')
            # print(result)
            solutions.append(result)
            return True

        s = attempts[i]
        inx_1 = get_valid_indices(result, s[0])
        inx_2 = get_valid_indices(result, s[1])
        inx_3 = get_valid_indices(result, s[2])
        if len(inx_1) == 0:
            return False
        if len(inx_2) == 0:
            return False
        if len(inx_3) == 0:
            return False

        for x in inx_1:
            new_inx_2 = [inx for inx in inx_2 if (inx > x)]
            for y in new_inx_2:
                new_inx_3 = [inx for inx in inx_3 if inx > y]
                for z in new_inx_3:
                    new_result = [r for r in result]
                    new_result[x] = s[0]
                    new_result[y] = s[1]
                    new_result[z] = s[2]
                    # print(new_result)
                    flag = recursive_solve(new_result, attempts, i+1, solutions)
                    if flag:
                        return True
        return False

    for m in range(5, 20):
        result = [[] for n in range(0, m)]

        solutions = []
        flag = recursive_solve(result, attempts, 0, solutions)
        #print(m)
        #print(solutions)
        solutions = [[s for s in sol if s != []] for sol in solutions]
        solutions = [''.join(sol) for sol in solutions]
        #print(solutions)
        print(list(set(solutions)))
        input()
        if flag:
            pass

    return num_characters

def sol_80():
    from decimal import Decimal, getcontext
    getcontext().prec = 150

    s = 0
    for i in range(1, 101):
        if int((i**(1/2)))**2 == i:
            print(i)
            continue
        else:
            num = str(Decimal(i).sqrt())
            #print(len(num[2:102]))
            decimal_part = num[2:102]
            #print(sum(map(int, decimal_part)))
            x = num.split('.')
            y = [x[0]]
            y.extend(x[1])
            #print(y)
            #print(len(y))
            print(sum(map(int, y[0:100])))

            contrib = sum(map(int, y[0:100]))
            # print(len(str(num)))
            # print(str(num)[0:10])
            # print(str(num)[2:102])
            # print(len(str(num)[2:102]))

            s += contrib
            print(s)
    return s

def sol_81():
    # See Dijkstras algorithm

    def make_array(file):
        distances = np.zeros((80, 80))
        for i, row in enumerate(file):
            x = row.split(',')
            for j, s in enumerate(x):
                distances[i, j] = int(s)
        return distances

    def get_proximate_indices(i, j, size):
        proximate_indices = []
        if i == (size-1):
            if j == (size-1):
                pass
            else:
                proximate_indices.append([i, j+1])
        else:
            if j == (size-1):
                proximate_indices.append([i+1, j])
            else:
                proximate_indices.append([i+1, j])
                proximate_indices.append([i, j+1])

        return proximate_indices

    distances = make_array(open('81.txt', 'r'))
    min_distances = np.zeros(distances.shape)
    remembering_array = np.zeros(distances.shape)
    tentative_indices = []

    i, j = 0, 0
    min_distances[i, j] = distances[i, j]
    remembering_array[i, j] = 2

    min_distances[i+1, j] = distances[i, j] + distances[i+1, j]
    min_distances[i, j+1] = distances[i, j] + distances[i, j+1]
    remembering_array[i+1, j] = 1
    remembering_array[i, j+1] = 1

    tentative_indices.append([i+1, j, min_distances[i+1, j]])
    tentative_indices.append([i, j+1, min_distances[i, j+1]])

    print(tentative_indices)

    while len(tentative_indices) > 1:
        tentative = sorted(tentative_indices, key=lambda x: x[2])[0]
        i, j, _ = tentative
        print(i)
        print(j)
        proximate_indices = get_proximate_indices(i, j, distances.shape[0])

        for m, n in proximate_indices:
            print(m)
            print(n)
            if remembering_array[m, n] == 2:
                continue

            elif remembering_array[m, n] == 1:
                if tentative[2] + distances[m, n] < min_distances[i, j]:
                    min_distances[m, n] = tentative[2] + distances[m, n]

            else:
                min_distances[m, n] = tentative[2] + distances[m, n]
                remembering_array[m, n] = 1
                tentative_indices.append([m, n, min_distances[m, n]])

        del tentative_indices[tentative_indices.index(tentative)]
        remembering_array[i, j] = 2
    print(min_distances[-1, -1])

def sol_82():
    # See Dijkstras algorithm

    def make_array(file):
        distances = np.zeros((80, 80))
        for i, row in enumerate(file):
            x = row.split(',')
            for j, s in enumerate(x):
                distances[i, j] = int(s)
        return distances

    def get_proximate_indices(i, j, size):
        proximate_indices = []
        if i == (size-1):
            if j == (size-1):
                proximate_indices.append([i-1, j])
            else:
                proximate_indices.append([i, j+1])
                proximate_indices.append([i-1, j])
        elif i == 0:
            if j == (size-1):
                proximate_indices.append([i+1, j])
            else:
                proximate_indices.append([i, j+1])
                proximate_indices.append([i+1, j])
        else:
            if j == (size-1):
                proximate_indices.append([i+1, j])
                proximate_indices.append([i-1, j])
            else:
                proximate_indices.append([i, j+1])
                proximate_indices.append([i+1, j])
                proximate_indices.append([i-1, j])

        return proximate_indices

    distances = make_array(open('82.txt', 'r'))

    minimal_sum = 1000000

    for starting_point in range(0, distances.shape[0]):
        print(starting_point)

        min_distances = np.zeros(distances.shape)
        remembering_array = np.zeros(distances.shape)
        tentative_indices = []

        i, j = starting_point, 0
        min_distances[i, j] = distances[i, j]
        remembering_array[i, j] = 2

        if starting_point == 0:
            print('here....')
            min_distances[i+1, j] = distances[i, j] + distances[i+1, j]
            min_distances[i, j+1] = distances[i, j] + distances[i, j+1]

            remembering_array[i+1, j] = 1
            remembering_array[i, j+1] = 1

            tentative_indices.append([i+1, j, min_distances[i+1, j]])
            tentative_indices.append([i, j+1, min_distances[i, j+1]])

        elif starting_point == (distances.shape[0]-1):
            print('here!')
            min_distances[i-1, j] = distances[i, j] + distances[i-1, j]
            min_distances[i, j+1] = distances[i, j] + distances[i, j+1]

            remembering_array[i-1, j] = 1
            remembering_array[i, j+1] = 1

            tentative_indices.append([i, j+1, min_distances[i, j+1]])
            tentative_indices.append([i-1, j, min_distances[i-1, j]])
            print(tentative_indices)
            input()

        else:
            min_distances[i-1, j] = distances[i, j] + distances[i-1, j]
            min_distances[i+1, j] = distances[i, j] + distances[i+1, j]
            min_distances[i, j+1] = distances[i, j] + distances[i, j+1]

            remembering_array[i-1, j] = 1
            remembering_array[i+1, j] = 1
            remembering_array[i, j+1] = 1

            tentative_indices.append([i+1, j, min_distances[i+1, j]])
            tentative_indices.append([i, j+1, min_distances[i, j+1]])
            tentative_indices.append([i-1, j, min_distances[i-1, j]])

        print(tentative_indices)

        while len(tentative_indices) > 1:
            tentative = sorted(tentative_indices, key=lambda x: x[2])[0]
            i, j, _ = tentative

            if starting_point ==(distances.shape[0]-1):
                print(min_distances)

            #print(i)
            #print(j)
            proximate_indices = get_proximate_indices(i, j, distances.shape[0])

            for m, n in proximate_indices:
                if remembering_array[m, n] == 2:
                    continue

                elif remembering_array[m, n] == 1:
                    if tentative[2] + distances[m, n] < min_distances[i, j]:
                        min_distances[m, n] = tentative[2] + distances[m, n]

                else:
                    min_distances[m, n] = tentative[2] + distances[m, n]
                    remembering_array[m, n] = 1
                    tentative_indices.append([m, n, min_distances[m, n]])

            del tentative_indices[tentative_indices.index(tentative)]
            remembering_array[i, j] = 2

        print(min_distances.shape)
        minimum_distance = min(min_distances[:, -1])

        print(minimum_distance)
        if minimum_distance < minimal_sum:
            minimal_sum = minimum_distance

    return minimal_sum

def sol_83():
    # See Dijkstras algorithm

    def make_array(file):
        distances = np.zeros((80, 80))
        for i, row in enumerate(file):
            x = row.split(',')
            for j, s in enumerate(x):
                distances[i, j] = int(s)
        return distances

    def get_proximate_indices(i, j, size):
        proximate_indices = []
        if i == 0:
            if j == 0:
                proximate_indices.append([i+1, j])
                proximate_indices.append([i, j+1])
            elif j == (size-1):
                proximate_indices.append([i+1, j])
                proximate_indices.append([i, j-1])
            else:
                proximate_indices.append([i+1, j])
                proximate_indices.append([i, j-1])
                proximate_indices.append([i, j+1])

        elif i == (size-1):
            if j == 0:
                proximate_indices.append([i-1, j])
                proximate_indices.append([i, j+1])
            elif j == (size-1):
                proximate_indices.append([i-1, j])
                proximate_indices.append([i, j-1])
            else:
                proximate_indices.append([i-1, j])
                proximate_indices.append([i, j-1])
                proximate_indices.append([i, j+1])
        else:
            if j == 0:
                proximate_indices.append([i-1, j])
                proximate_indices.append([i+1, j])
                proximate_indices.append([i, j+1])
            elif j == (size-1):
                proximate_indices.append([i-1, j])
                proximate_indices.append([i+1, j])
                proximate_indices.append([i, j-1])
            else:
                proximate_indices.append([i-1, j])
                proximate_indices.append([i+1, j])
                proximate_indices.append([i, j-1])
                proximate_indices.append([i, j+1])
        return proximate_indices

    distances = make_array(open('83.txt', 'r'))

    min_distances = np.zeros(distances.shape)
    remembering_array = np.zeros(distances.shape)
    tentative_indices = []

    i, j = 0, 0
    min_distances[i, j] = distances[i, j]
    remembering_array[i, j] = 2

    min_distances[i+1, j] = distances[i, j] + distances[i+1, j]
    min_distances[i, j+1] = distances[i, j] + distances[i, j+1]
    remembering_array[i+1, j] = 1
    remembering_array[i, j+1] = 1

    tentative_indices.append([i+1, j, min_distances[i+1, j]])
    tentative_indices.append([i, j+1, min_distances[i, j+1]])

    print(tentative_indices)

    while len(tentative_indices) > 1:
        tentative = sorted(tentative_indices, key=lambda x: x[2])[0]
        i, j, _ = tentative
        print(i)
        print(j)
        proximate_indices = get_proximate_indices(i, j, distances.shape[0])

        for m, n in proximate_indices:
            print(m)
            print(n)
            if remembering_array[m, n] == 2:
                continue

            elif remembering_array[m, n] == 1:
                if tentative[2] + distances[m, n] < min_distances[i, j]:
                    min_distances[m, n] = tentative[2] + distances[m, n]

            else:
                min_distances[m, n] = tentative[2] + distances[m, n]
                remembering_array[m, n] = 1
                tentative_indices.append([m, n, min_distances[m, n]])

        del tentative_indices[tentative_indices.index(tentative)]
        remembering_array[i, j] = 2
    print(min_distances[-1, -1])

def sol_84():
    board = ['GO', 'A1', 'CC1', 'A2', 'T1', 'R1', 'B1', 'CH1', 'B2', 'B3',
             'JAIL', 'C1', 'U1', 'C2', 'C3', 'R2', 'D1', 'CC2', 'D2', 'D3',
             'FP', 'E1', 'CH2', 'E2', 'E3', 'R3', 'F1', 'F2', 'U2', 'F3',
             'G2J', 'G1', 'G2', 'CC3', 'G3', 'R4', 'CH3', 'H1', 'T2', 'H2']
    board_len = len(board)

    cc_counter = 0
    ch_counter = 0
    double_count = 0

    counts = [0 for b in board]

    position = 0
    counts[position] += 1

    for roll in range(0, 10000000):
        r1 = np.random.randint(1, 5)
        r2 = np.random.randint(1, 5)
        if r1 == r2:
            double_count += 1
            if double_count == 3:
                position == board.index('JAIL')
                double_count = 0
                continue

        r = r1+r2
        position = (position + r) % board_len

        if position == board.index('CC2') or position == board.index('CC1')  or position==board.index('CC3'):
            if cc_counter == 1:
                position = board.index('JAIL')
            elif cc_counter == 2:
                position = board.index('GO')
            cc_counter = (cc_counter +1)% 16

        elif position == board.index('CH1') or position == board.index('CH2') or position == board.index('CH3'):
            if ch_counter == 1:
                position = board.index('GO')
            elif ch_counter == 2:
                position = board.index('JAIL')
            elif ch_counter == 3:
                position = board.index('C1')
            elif ch_counter == 4:
                position = board.index('E3')
            elif ch_counter == 5:
                position = board.index('H2')
            elif ch_counter == 6:
                position = board.index('R1')
            elif ch_counter == 7:
                if position == board.index('CH1'):
                    position = board.index('R2')
                elif position == board.index('CH2'):
                    position = board.index('R3')
                elif position == board.index('CH3'):
                    position = board.index('R1')
            elif ch_counter == 8:
                if position == board.index('CH1'):
                    position = board.index('R2')
                elif position == board.index('CH2'):
                    position = board.index('R3')
                elif position == board.index('CH3'):
                    position = board.index('R1')
            elif ch_counter == 9:
                if position == board.index('CH1'):
                    position = board.index('U1')
                elif position == board.index('CH2'):
                    position = board.index('U2')
                elif position == board.index('CH3'):
                    position = board.index('U1')
            elif ch_counter == 10:
                position = position - 3
            ch_counter = (ch_counter + 1)%16

        elif position == board.index('G2J'):
            position = board.index('JAIL')

        counts[position] += 1
    print(counts)
    max_indices = np.argpartition(counts, -4)[-4::]
    print(max_indices)
    print([counts[m] for m in max_indices])
    print([board[m] for m in max_indices])

def sol_85():
    least = 100
    best_m, best_n = 0, 0
    for m in range(1, 1000):
        for n in range(1, m+1):
            print(m)
            print(n)
            count = m*n*(m*n+m+n+1) + (m+1)*(n+1)*m*n/4 - m*m*(n+1)*n/2 - n*n*(m+1)*m/2 - (n+1)*n*m/2 - (m+1)*m*n/2
            print(count)
            proximity = 2000000-count
            if abs(proximity) < least:
                least = abs(proximity)
                best_m = m
                best_n = n

    return best_m*best_n

def sol_86():
    count = 0
    a = 1
    while count < 1000000:
        print(a)
        for b in range(1, a+1):
            for c in range(1, b+1):
                l = np.sqrt(a*a+(b+c)**2)
                #l = get_shortest_path(a, b, c)
                if l == int(l):
                    count += 1
                continue
        a += 1
        print(count)
    print(a)
    print(count)

def sol_87():
    limit = 50000000

    primes = prime.prime_sieve(limit)
    numbers = np.zeros(limit+1)

    primes_1 = [p for p in primes if p < (limit)**(1/2)]
    primes_2 = [p for p in primes if p < (limit)**(1/3)]
    primes_3 = [p for p in primes if p < (limit)**(1/4)]

    for p1 in primes_1:
        for p2 in primes_2:
            for p3 in primes_3:
                p = p1**2 + p2**3 + p3**4

                if p > limit:
                    continue
                else:
                    print(p)
                    numbers[int(p)] = 1
                print(p)

    return len((np.where(numbers==1))[0])

def sol_88():
    def partition(collection):
        if len(collection) == 1:
            yield [ collection ]
            return

        first = collection[0]
        for smaller in partition(collection[1:]):
            # insert `first` in each of the subpartition's subsets
            for n, subset in enumerate(smaller):
                yield smaller[:n] + [[ first ] + subset]  + smaller[n+1:]
            # put `first` in its own subset
            yield [ [ first ] ] + smaller

    minimal_product_sum_numbers = [2*n for n in range(0, 12001)]
    print(minimal_product_sum_numbers[2:20])
    input()

    for product in range(2, 24002):
        factors = prime.get_prime_factors(product)
        print(product)

        for part in partition(factors):
            s = 0
            p = product
            for factor in part:
                s += reduce(lambda x,y: x*y, factor, 1)

            if p == s:
                l = len(part)
            elif s < p:
                n = p-s
                l = len(part) + n
            else:
                continue

            if l < 12001 and p < minimal_product_sum_numbers[l]:
                minimal_product_sum_numbers[l] = p

    print(minimal_product_sum_numbers[2:20])
    return sum(list(set(minimal_product_sum_numbers[2:12001])))

def sol_89():
    def get_dict():
        roman_to_int = {
            'I': 1,
            'V': 5,
            'X': 10,
            'L': 50,
            'C': 100,
            'D': 500,
            'M': 1000
        }
        return roman_to_int

    def represent(number):
        if number >= 1000:
            return 'M' + represent(number-1000)
        elif number >= 900:
            return 'CM' + represent(number-900)
        #elif number >= 800:
        #    return 'CCM' + represent(number-800) ##
        elif number >= 500:
            return 'D' + represent(number-500)
        elif number >= 400:
            return 'CD' + represent(number-400)
        #elif number >= 300:
        #    return 'CCD' + represent(number-300) ##
        elif number >= 100:
            return 'C' + represent(number-100)
        elif number >= 90:
            return 'XC' + represent(number-90)
        #elif number >= 80:
        #    return 'XXC' + represent(number-80) #
        elif number >= 50:
            return 'L' + represent(number-50)
        elif number >= 40:
            return 'XL' + represent(number-40)
        elif number >= 10:
            return 'X' + represent(number-10)
        elif number >= 9:
            return 'IX' + represent(number-9)
        #elif number >= 8:
        #    return 'IIX' + represent(number-8)
        elif number >= 5:
            return 'V' + represent(number-5)
        elif number >= 4:
            return 'IV' + represent(number-4)
        elif number >= 1:
            return 'I' + represent(number-1)
        else:
            return ''

    def parse_roman(roman):
        roman_to_int = get_dict()
        s = roman[::-1]

        value = 0
        current_value = 0
        current_token = None
        for token in s:
            if not current_token == None:
                if roman_to_int[token] < current_token:
                    current_value -= roman_to_int[token]
                elif roman_to_int[token] == current_token:
                    current_value += current_token
                else:
                    value += current_value
                    current_token = roman_to_int[token]
                    current_value = current_token
                continue
            current_token = roman_to_int[token]
            current_value += current_token
        value += current_value
        return value

    saving = 0
    f = open('89.txt', 'r')
    for line in f:
        numeral = line.split('\n')[0]
        print(numeral)
        print(parse_roman(numeral))
        shortest_roman = represent(parse_roman(numeral))
        print(shortest_roman)
        saving += (len(numeral) - len(shortest_roman))
    return saving

def sol_90():
    def valid(dice_1, dice_2, squares):
        dice_1 = list(dice_1)
        dice_2 = list(dice_2)
        if '6' in dice_1:
            dice_1.append('9')
        elif '9' in dice_1:
            dice_1.append('6')
        if '6' in dice_2:
            dice_2.append('9')
        elif '9' in dice_2:
            dice_2.append('6')

        for s in squares:
            if s[0] in dice_1:
                if s[1] in dice_2:
                    continue
                elif s[1] in dice_1:
                    if s[0] in dice_2:
                        continue
                    else:
                        return False
                else:
                    return False

            elif s[1] in dice_1:
                if s[0] in dice_2:
                    continue
                else:
                    return False
            else:
                return False

        return True

    square_numbers = []
    sq = [str(s**2) for s in range(1, 10)]
    for s in sq:
        if len(s) == 1:
            square_numbers.append('0'+s)
        else:
            square_numbers.append(s)

    count = 0
    numbers = [str(a) for a in range(0, 10)]
    for dice_1 in itertools.combinations(numbers, 6):
        for dice_2 in itertools.combinations(numbers, 6):
            #if '6' in dice_1 and '9' in dice_1:
            #    continue
            #elif '6' in dice_2 and '9' in dice_2:
            #    continue
            print(square_numbers)
            if valid(dice_1, dice_2, square_numbers):
                count += 1
    return count/2

def sol_91():
    def vis_triangle(x1, y1, x2, y2):
        pass

    def check_triangle(x1, y1, x2, y2):
        l1 = x1**2 + y1**2
        l2 = x2**2 + y2**2
        l3 = (x2-x1)**2+(y2-y1)**2
        if l1 + l2 == l3 or l2 + l3 == l1 or l3 + l1 == l2:
            return True
        return False

    num_triangles = 0

    limit = 50
    x1 = 0
    for y1 in range(1, limit+1):
        for x2 in range(1, limit+1):
            for y2 in range(0, limit+1):
                if check_triangle(x1, y1, x2, y2):
                    num_triangles += 1

    for x1 in range(1, limit+1):
        for y1 in range(1, limit+1):
            for x2 in range(1, limit+1):
                for y2 in range(0, int(math.floor(y1*x2/x1))):
                    if check_triangle(x1, y1, x2, y2):
                        num_triangles += 1

    return num_triangles

def sol_92():
    def recursive_chain(i, arrival):
        if i > (len(arrival)-1):
            i = sum([int(x)**2 for x in map(int, str(i))])
            res = recursive_chain(i, arrival)
            return res
        if arrival[i] == 1 or i==1:
            return 1
        elif arrival[i] == 89 or i==89:
            return 89
        else:
            i = sum([int(x)**2 for x in map(int, str(i))])
            res = recursive_chain(i, arrival)
            arrival[i] = res
            return res

    sys.setrecursionlimit(5000)

    arrival = np.zeros(10000000)
    for i in range(1, 10000000):
        print(i)
        arrival[i] = recursive_chain(i, arrival)

    return len(np.where(arrival==89)[0])

def sol_93():
    def get_combination_length(result):
        for i in range(1, len(result)):
            if i in result:
                continue
            else:
                break
        return i-1

    def recursive_generator(iterlist, results):
        if len(iterlist) == 2:
            for x1, x2 in itertools.permutations(iterlist, 2):
                #print([x1, x2])
                results.append(x1+x2)
                results.append(x1-x2)
                results.append(x1*x2)
                if x2 != 0:
                    results.append(x1/x2)
        else:
            for x1, x2 in itertools.permutations(iterlist, 2):
                new_iterlist = [i for i in iterlist]
                new_iterlist.remove(x1)
                new_iterlist.remove(x2)

                iterlists = []

                iterlist_ = [x for x in new_iterlist]
                iterlist_.append(x1+x2)
                iterlists.append(iterlist_)

                iterlist_ = [x for x in new_iterlist]
                iterlist_.append(x1-x2)
                iterlists.append(iterlist_)

                iterlist_ = [x for x in new_iterlist]
                iterlist_.append(x1*x2)
                iterlists.append(iterlist_)
                if x2 != 0:
                    iterlist_ = [x for x in new_iterlist]
                    iterlist_.append(x1/x2)
                    iterlists.append(iterlist_)

                # print([x1, x2])
                # print(iterlists)
                # input()
                for iterlist_ in iterlists:
                    recursive_generator(iterlist_, results)

    max_len = 0
    limit = 20
    best_combo = []

    for a in range(1, limit+1):
        for b in range(a+1, limit+1):
            for c in range(b+1, limit+1):
                for d in range(c+1, limit+1):
                    #generate_combinations(a, b, c, d)
                    #print([a, b, c, d])
                    x = []
                    recursive_generator([a, b, c, d], x)
                    #print(set(x))
                    l = get_combination_length(x)
                    #print(l)
                    #input()
                    if l > max_len:
                        max_len = l
                        best_combo = [a, b, c, d]
                        print(best_combo)
                        print(max_len)
    print(best_combo)
    return max_len

def sol_94():
    def check_triangle(n, sign):
        if sign=='+':
            s = np.sqrt((3/4)*n*n+2*n+1)
        else:
            s = np.sqrt((3/4)*n*n-2*n+1)
        if ((n/2)*s).is_integer():
            return True
        else:
            return False

    import equation_utils
    from equation_utils import solve_diophantine, solve_pell

    true_sols = []
    base_sol = solve_pell(3)
    sols = equation_utils.generate_solutions_from_minimal_solution(base_sol[0], base_sol[1], 3, 50)

    positive_perimeters = []
    negative_perimeters = []

    for x, y in sols:
        a1 = (2*x+1)//2
        a2 = (2*x-1)//2
        A1 = (x+2)*y//3
        A2 = (x-2)*y//3
        if a1 > 300000000:
            continue
        if y<= 0:
            continue
        if isinstance(a1, int) and isinstance(A1, int) and A1>0:
            negative_perimeters.append(a1)
        if isinstance(a2, int) and isinstance(A2, int) and A2>0:
            positive_perimeters.append(a2)

    perimeter_sum = 0
    for p in positive_perimeters:
        if 3*p - 1 > 1e9:
            continue
        else:
            print(p)
            perimeter_sum += 3*p - 1
    for p in negative_perimeters:
        if 3*p + 1 > 1e9:
            continue
        else:
            print(p)
            perimeter_sum += 3*p + 1
    return 518408346
    #num_triangles = 0
    #for i in range(1, 1e9+1:
    #    s = i*i
    #    r = np.sqrt(16/9 + (4/3)*s*s-4/3)
    #    n1 = -4/3 + r
    #    n2 = 4/3 + r
    #    if (n1/2)*np.sqrt(3/4*n1*n1 + 2*n1 + 1).is_integer():
    #        num_triangles += 1
    #        if 3*n1 + 2 > 1e9:
    #            num_triangles -= 1
    #    if(n2/2)*np.sqrt(3/4*n2*n2 - 2*n2 + 1).is_integer():
    #        num_triangles += 1
    #        if 3*n2 - 2 > 1e9:
    #            num_triangles -= 1
    #return num_triangles
    def count_positive():
        count = 0
        for s in range(1, int(np.sqrt(1e9))+1):
            n = (8*s*s - 2)/3
            print(n)
            #input()
            if n.is_integer():
                print(n)
                #input()
                r = int(round(np.sqrt((n+2)/2)))
                #print(n)
                #input()
                if 4*r*r - 2 == n:
                    area = n/4*(3*n+2)*(n+2)
                    count += area
                    if 3*n + 2 > 1e9:
                        count -= area
        return count

    def count_negative():
        count = 0
        for s in range(0, int(np.sqrt(1e9))+1):
            n = (8*s*s + 2)/3
            print(n)
            input()
            #input()
            if n.is_integer():
                print(n)
                r = int(round(np.sqrt((n-2)/2)))
                if 4*r*r + 2 == n:
                    area = n/4*(3*n-2)*(n-2)
                    count += area
                    if 3*n - 2 > 1e9:
                        count -= area
        return count

    def brute_forcer():
        result = []
        for n in range(2, int((1e9-2)/3) + 1):
            r1 = int(round(np.sqrt(3*n*n+8*n+4)))
            if r1**2 == 3*n*n+8*n+4:
                if (n*r1/4).is_integer():
                    print(n)
                    print('positive')
                    result.append([n, 'positive'])

            r2 = int(round(np.sqrt(3*n*n-8*n+4)))
            if r2**2 == 3*n*n-8*n+4:
                if (n*r2/4).is_integer():
                    print(n)
                    print('negative')
                    result.append([n, 'negative'])
            if n % 10000000 == 0:
                print(n)
    #result = brute_forcer()
    #area_sum = 0
    #backup_sum = 0
    #for res in result:
    #    if res[1] == 'positive':
    #        area_sum += 3*res[0]+2
    #        backup_sum += 3*res[0]-2
    #    else:
    #        area_sum += 3*res[0]-2
    #        backup_sum += 3*res[0]+2
    #print(backup_sum)
    #return area_sum

    area_sum = 0
    area_sum += count_positive()
    area_sum += count_negative()
    return area_sum

    for s in range(1, int(np.sqrt(1e9+1))):
        n1 = (2*s*s - 2)/3
        n2 = (2*s*s + 2)/3

        if np.sqrt((n1+2)/2).is_integer():
            num_triangles += 1
            print(n1)
            if 3*n1 + 2 > 1e9:
                num_triangles -= 1
        if n2/2 == 0:
            if np.sqrt((n-2)/2).is_integer():
                num_triangles += 1
                if 3*n1 + 2 > 1e9:
                    num_triangles -= 1
    return num_triangles
    num_triangles = 0

    for n in range(2, int((1e9-2)/3) + 1):
        if check_triangle(n, '+'):
            num_triangles += 1
        if check_triangle(n, '-'):
            num_triangles += 1

            #print('Double detected!')
        if n % 10000000 == 0:
            print(n)
    print(num_triangles)
    return num_triangles

def sol_95():
    pass

def sol_96():
    pass

def sol_97():
    last_10 = 1
    for i in range(0, 7830457):
        last_10 = last_10*2 % 100000000000

    last_10 = 28433*last_10+1
    last_10 = str(last_10)[-10:]
    print(len(last_10))
    print(last_10)

def sol_99():
    import functools
    def exp_compare(n, m):
        b1 = n[0]
        e1 = n[1]
        b2 = m[0]
        e2 = m[1]
        if b1**(e1/e2) > b2:
            print('ok')
            return 1
        else:
            return -1

    f = open('99.txt', 'r')
    exponentials = []
    for i, line in enumerate(f):
        exponentials.append([float(line.split(',')[0]),float(line.split(',')[1]), i])

    m = max(exponentials, key=functools.cmp_to_key(exp_compare))
    print(m)
    print(len(exponentials))
    print(exponentials[0])
    #exponentials.append(float(line.split(',')[0])**float(line.split(',')[1]))
    # print np.argmax(exponentials)

def sol_100():
    #limit = 21
    #for b in range(1, limit):
    #    print(b)
    #    t = 1/2 + np.sqrt(2*b*b - 2*b + 1/4)

    #    t = int(t)
    #    if b**2-b == (t**2-t)/2:
    #        return b

    ### Init b0 ###
    b0 = 1/2 + np.sqrt(1/2-1/8 +(10**12-1/2)**2/2)
    print(b0)
    b = int(b0)
    s0 = int(np.sqrt(2*b*b-2*b+1/4))
    s = s0
    while True:
        print(b)
        b = 1/2 + np.sqrt(1/4-1/8+s*s/2)
        b = int(b)
        if b*b-b+1/8 == s*s/2:
            return b

        print(s)
        print(b)

        s += 1
        #t = 1/2 + np.sqrt(2*b*b - 2*b + 1/4)

        #t = int(t)
        #if b**2-b == (t**2-t)/2:
        #    return b
        #else:
        #    b += 1
        #print(t)


import cv2
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn.functional as F

class GradCam():
    def __init__(self, model, img_tensor, correct_class, classes, feature_module, target_layer_names):
        use_cuda = torch.cuda.is_available()
        device = torch.device("cuda" if use_cuda else "cpu")
        self.img_tensor = img_tensor.unsqueeze_(0)
        self.classes = classes
        self.correct_class = self.classes[correct_class]
        self.model = model

        target_activations = []
        x = self.img_tensor.to(device)
        for name, module in model._modules.items():
            if module == model.layer4:
                target_activations, x = self.extract_features(x, feature_module, target_layer_names)
            elif "linear" in name.lower():
                x = F.avg_pool2d(x, 4)
                x = x.view(x.size(0), -1)
                x = module(x)
            else:
                x = module(x)

        features, output = target_activations, x
        index = np.argmax(output.cpu().data.numpy())
        self.pred_class = self.classes[index]
        one_hot = np.zeros((1, output.size()[-1]), dtype=np.float32)
        one_hot[0][index] = 1
        one_hot = torch.from_numpy(one_hot).requires_grad_(True)
        one_hot = torch.sum(one_hot.cuda() * output)

        model.layer4.zero_grad()
        model.zero_grad()
        one_hot.backward(retain_graph=True)

        grads_val = self.gradients[-1].cpu().data.numpy()

        target = features[-1]
        target = target.cpu().data.numpy()[0, :]

        weights = np.mean(grads_val, axis=(2, 3))[0, :]
        cam = np.zeros(target.shape[1:], dtype=np.float32)

        for i, w in enumerate(weights):
            cam += w * target[i, :, :]

        cam = np.maximum(cam, 0)
        cam = cv2.resize(cam, self.img_tensor.shape[2:])
        cam = cam - np.min(cam)
        self.cam = cam / np.max(cam)

    def extract_features(self, input, model, target_layers):
        x = input
        outputs = []
        self.gradients = []
        for name, module in model._modules.items():
            x = module(x)
            if name in target_layers:
                x.register_hook(lambda grad: self.gradients.append(grad))
                outputs += [x]
        return outputs, x

    def plot(self):
        heatmap = cv2.applyColorMap(np.uint8(255 * self.cam), cv2.COLORMAP_JET)
        heatmap = np.float32(heatmap) / 255
        img = self.img_tensor[0] / 2 + 0.5
        img = np.transpose(img.numpy(), (1, 2, 0))
        cam = heatmap + img
        cam = cam / np.max(cam)
        fig = plt.figure(figsize=(20, 10))

        ax = fig.add_subplot(3, 5, 1)
        ax.set_title('Input Image')
        plt.imshow(img)

        ax = fig.add_subplot(3, 5, 2)
        ax.set_title(f'pred: {self.pred_class}'
                     f' / correct: {self.correct_class}')
        plt.imshow(cam)

        fig.tight_layout()


'''
@author Gabriel Maguire
@date 4/26/2020

This script is the main control script used for triggering image capture commands for the CM360 project.
'''

from datetime import datetime
import signal, os, subprocess, sys
import time

camera_ports = []
capture_time = []

'''
This method searches for automatic processes that may start to run when a camera is initially connected.
These processes interfere with the functioning of the gphoto2 command library.
'''
def kill_gphoto2_process():
    p = subprocess.Popen(['ps', '-A'], stdout = subprocess.PIPE)
    out, err = p.communicate()

    # Search for process we want to kill
    for line in out.splitlines():
        if b'gvfsd-gphoto2' in line:
            # Kill the process
            print("Killed extra process")
            pid = int(line.split(None, 1)[0])
            os.kill(pid, signal.SIGKILL)

'''
This method detects every usb device (camera) connected to the Raspberry Pi and stores the port values
in a list. This is crucial, because each camera capture must be called using the specific port id, and
the port ids can change each time a camera is connected/disconnected.
'''
def detect_cameras():
    p = subprocess.Popen(["gphoto2", "--auto-detect"], stdout = subprocess.PIPE)
    out, err = p.communicate()

    usb_devices = []
    for line in out.splitlines():
        line = line.decode('utf-8') # Turns bytes into string
        id_start = line.find('usb:')
        if (id_start != -1):
            # Add usb port to usb device list
            id_end = line.find(' ', id_start)
            camera_ports.append(line[id_start:id_end])

'''
This method takes an integer value "count" (photo number) as an argument and triggers a camera
capture command for each camera in the CM360 device (currently testing with only 2). Each camera
is called in parallel tocapture an image, and immediately download the image to its specific camera
folder on the Pi.
'''
def capture_image(count):

    str_count = str(count)

    before_time = datetime.now()

    p1 = subprocess.Popen(["python3", "capture_camera_1.py", str_count, camera_ports[0]])
    p2 = subprocess.Popen(["python3", "capture_camera_2.py", str_count, camera_ports[1]])

    p1.wait()
    p2.wait()

    after_time = datetime.now()
    total_time = (after_time - before_time).total_seconds()
    capture_time.append(total_time)
    print("All cameras: {}".format(total_time))

'''
Main method that is setup to search for user input to trigger an image capture.
'''
def main():
    count = 1
    kill_gphoto2_process()
    detect_cameras()

    ''' This loop is used a temporary method of collecting user input to trigger an image capture '''
    '''
    while True:
        value = input("Command:\n")
        if value == "capture":
            print("CAPTURING IMAGE")
            capture_image(count)
            count = count + 1

        if value == "exit":
            print("EXITING")
            break
    print(type(capture_time[0]))
    '''

    '''
    These series of loops are used to test the total speed in seconds of the image capture
    and download with multiple cameras
    '''

    for _ in range(10):
        for _ in range(10):
            capture_image(count)
            count = count + 1
            time.sleep(1)
        time.sleep(5)
    print(capture_time)
    avg_capture_time = sum(capture_time) / len(capture_time)
    print("Average total capture time: {}".format(avg_capture_time))

if __name__ == "__main__":
    main()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""a test module"""

# egrep.py
import sys, re

__author__ = '74581'

# 9/stdin和stdout

# sys.argv是命令行参数的列表
# sys.argv[0]是程序自己的名字
# sys.argv[1]会是在命令行上指定的正则表达式
regex = sys.argv[1]

# 对传递到这个脚本中的每一个行
for line in sys.stdin:
    # 如果它匹配正则表达式，则把它写入stdout
    if re.search(regex, line):
        sys.stdout.write(line)


#! /usr/bin/env python3
import argparse
import sys
import os
import re
import sqlite3

conn = sqlite3.connect('example.db')
print("connect successfully")

c = conn.cursor()

c.execute('''CREATE TABLE filter (Sample  text PRIMARY KEY NOT NULL , Raw_Reads_Number int);''')
conn.execute("INSERT INTO filter VALUES('Y3','128979244') ; ")
#c.execute('''CREATE TABLE stocks
#		             (date text, trans text, symbol text, qty real, price real)''')

# Insert a row of data
#c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)")

conn.commit()
conn.close()

bindir = os.path.abspath(os.path.dirname(__file__))

__author__='Lusifen'
__mail__= 'sifenlu@163.com'

pat1=re.compile('^\s+$')

def main():
	parser=argparse.ArgumentParser(description=__doc__,
			formatter_class=argparse.RawDescriptionHelpFormatter,
			epilog='author:\t{0}\nmail:\t{1}'.format(__author__,__mail__))
	parser.add_argument('-i','--input',help='input file',dest='input',type=open,required=True)
	parser.add_argument('-o','--output',help='output file',dest='output',type=argparse.FileType('w'),required=True)
	args=parser.parse_args()

	for line in args.input:
		if line.startswith('#') or re.search(pat1,line):continue
		tmp=line.rstrip().split('\t')

if __name__ == '__main__':
	main()


import re
class Solution:
    # @param A : string
    # @return an integer
    def isPalindrome(self, A):
        end = len(A) - 1
        start = 0
        if not A:
            return 1
        while start < end:
            if A[start].isalnum() and A[end].isalnum():
                ast = A[start].lower()
                aen = A[end].lower()
                if ast != aen:
                    return 0
                else:
                    start += 1
                    end -= 1
            elif not A[start].isalnum():
                start += 1
            elif not A[end].isalnum():
                end -= 1

        return 1

    def isPalindrome2(self, A):
        rev = re.sub(r'\W+', '', A)
        print(rev)
        rev = rev.lower()
        final = rev[::-1]
        if rev == final:
            return 1
        else:
            return 0

#
arr = "A man, a plan, a canal: Panama"
s = Solution()
print(s.isPalindrome2(arr))


from typing import List, Tuple, Optional

from soupsieve.util import deprecated

from dedoc.data_structures.document_content import DocumentContent
from dedoc.data_structures.paragraph_metadata import ParagraphMetadata
from dedoc.data_structures.tree_node import TreeNode
from dedoc.data_structures.unstructured_document import UnstructuredDocument
from dedoc.structure_parser.heirarchy_level import HierarchyLevel
from dedoc.data_structures.line_with_meta import LineWithMeta
from dedoc.structure_constructor.concreat_structure_constructors.abstract_structure_constructor import \
    AbstractStructureConstructor

class TreeConstructor(AbstractStructureConstructor):

    def __init__(self):
        pass

    def structure_document(self,
                           document: UnstructuredDocument,
                           structure_type: Optional[str] = None) -> DocumentContent:
        document_name, not_document_name = self.__get_document_name(document.lines)
        not_document_name = self.__add_lists(not_document_name)
        tree = TreeNode.create(lines=document_name)
        for line in not_document_name:
            # add raw text line
            # multiline header
            if (line.hierarchy_level.can_be_multiline and
                    line.hierarchy_level == tree.hierarchy_level and
                    line.hierarchy_level.paragraph_type == tree.hierarchy_level.paragraph_type):
                tree.add_text(line)
            # move up and add child

            else:
                while tree.hierarchy_level >= line.hierarchy_level:
                    tree = tree.parent
                tree = tree.add_child(line=line)
        tree = tree.get_root()
        tree.merge_annotations()
        return DocumentContent(tables=document.tables, structure=tree)

    @deprecated("use structurize_document instead")
    def construct_tree(self, document: UnstructuredDocument) -> DocumentContent:
        return self.structure_document(document)

    def __get_document_name(self, lines: List[LineWithMeta]) -> Tuple[List[LineWithMeta], List[LineWithMeta]]:
        document_name = []
        other_lines = []
        for line in lines:
            if line.hierarchy_level.level_1 == 0 and line.hierarchy_level.level_2 == 0:
                document_name.append(line)
            else:
                other_lines.append(line)
        return document_name, other_lines

    def __add_lists(self, not_document_name: List[LineWithMeta]):
        previous_hierarchy_levels = []
        res = []
        for line in not_document_name:
            if line.hierarchy_level.is_list_item():
                while len(previous_hierarchy_levels) > 0 and previous_hierarchy_levels[-1] > line.hierarchy_level:
                    previous_hierarchy_levels.pop()
                if previous_hierarchy_levels == [] or previous_hierarchy_levels[-1] < line.hierarchy_level:
                    list_line = self.__create_list_line(line)
                    res.append(list_line)
                    previous_hierarchy_levels.append(line.hierarchy_level)
            elif not line.hierarchy_level.is_raw_text():
                previous_hierarchy_levels = []
            res.append(line)
        return res

    @staticmethod
    def __create_list_line(line: LineWithMeta):
        return LineWithMeta(line="",
                            hierarchy_level=HierarchyLevel(
                                level_1=line.hierarchy_level.level_1,
                                level_2=line.hierarchy_level.level_2 - 0.5,  # noqa  it is intentionaly for lists
                                paragraph_type="list",
                                can_be_multiline=False
                            ),
                            metadata=ParagraphMetadata(paragraph_type="list",
                                                       page_id=line.metadata.page_id,
                                                       line_id=line.metadata.line_id,
                                                       predicted_classes=None),
                            annotations=[])


# To run this, you can install BeautifulSoup
# https://pypi.python.org/pypi/beautifulsoup4

# Or download the file
# http://www.py4e.com/code3/bs4.zip
# and unzip it in the same directory as this file

from urllib.request import urlopen
from bs4 import BeautifulSoup
import ssl

# Ignore SSL certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

url = input('Enter - ')
html = urlopen(url, context=ctx).read()

# html.parser is the HTML parser included in the standard Python 3 library.
# information on other HTML parsers is here:
# http://www.crummy.com/software/BeautifulSoup/bs4/doc/#installing-a-parser
soup = BeautifulSoup(html, "html.parser")

# Retrieve all of the span tags
spans = soup('span')

comment_counts = []

for tag in spans:
    comment_counts.append(int(tag.string))

sum_counts = sum(comment_counts)

print (sum_counts)

Python for Everybody/Using Python to Access Web Data/Assignments/Scraping Numbers from HTML using BeautifulSoup/urllink2.py


#!/usr/bin/env python3

import json
import unittest

REQUIRED_FALLBACK_KEYS = [
    'powerOriginRatios',
    'carbonIntensity',
]

class Co2EqTestcase(unittest.TestCase):
    def setUp(self):
        with open('config/co2eq_parameters.json') as f:
            self.co2eq_parameters = json.load(f)

    def test_consistent_fallback_zone_mixes(self):
        for (zone_id, zone_obj) in self.co2eq_parameters['fallbackZoneMixes']['zoneOverrides'].items():
            for k in REQUIRED_FALLBACK_KEYS:
                self.assertIsNotNone(zone_obj.get(k), msg=f"zone={zone_id},key={k}")


#!/usr/bin/env python

from __future__ import print_function

import os
import sys
import argparse
import netCDF4 as nc
import numpy as np
import matplotlib
import mpl_toolkits
#matplotlib.use('Agg')
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt

from esmgrids import mom1_grid, woa_grid
from esmgrids import regrid_helper as rh

"""
Plot spatial difference between two fields possibly on different grids.
"""

grid_defs_error = \
"""
Grid definitions directory {} not found.
please download it with:
wget http://s3-ap-southeast-2.amazonaws.com/dp-drop/esmplots/grid_defs.tar.gz
and unzip into the same directory as this script.
"""

def grid_defs_dir():
    """
    Get path to directory where MOM, NEMO grid definitions are
    found.
    """

    if getattr(sys, 'frozen', False):
        basedir = sys._MEIPASS
    else:
        basedir = os.path.dirname(os.path.realpath(__file__))
    return os.path.join(basedir, 'grid_defs')

def plot_sst(field, grid, output_dir):

    # Calculate projection. mill is 'Miller Cylindrical'.
    # gall is 'Gall Stereographic Equidistant.
    m = Basemap(projection='gall', resolution='h',
                llcrnrlon=np.min(grid.x_t), llcrnrlat=np.min(grid.y_t),
                urcrnrlon=np.max(grid.x_t), urcrnrlat=np.max(grid.y_t), lon_0=0)
    x, y = m(grid.x_t, grid.y_t)

    im = m.contourf(x, y, field, extend='both', cmap=plt.get_cmap('RdBu_r'))
    cbar = m.colorbar(im)

    # Add axes labels. round_to_base() and map() are used to thin out
    # the lats and lons.
    def round_to_base(x, base=5):
        return int(base * round(float(x) / base))

    meridians = map(round_to_base, np.arange(np.min(grid.x_t),
                                             np.max(grid.x_t), 40))
    m.drawmeridians(meridians, linewidth=0, labels=[0,0,0,1])
    parallels = map(round_to_base, np.arange(np.min(grid.y_t),
                                             np.max(grid.y_t), 40))
    m.drawparallels(parallels, linewidth=0, labels=[1,0,0,0])

    fig = matplotlib.pyplot.gcf()
    fig.set_size_inches(10, 5)
    plt.savefig(os.path.join(output_dir, 'sst.png'))

def regrid_fields(input_a, input_b, grid_a, grid_b, dest_grid):

    nn_weights_a = rh.create_regrid_weights(grid_a, grid_a, 'neareststod',
                                            unmasked_src=False,
                                            unmasked_dest=True)
    bi_weights_a = rh.create_regrid_weights(grid_a, dest_grid, 'bilinear')
    if nn_weights_a is None or bi_weights_a is None:
        return 1

    input_a_nn = rh.regrid(nn_weights_a, input_a, grid_a)
    input_a_bi = rh.regrid(bi_weights_a, input_a_nn, dest_grid)
    # Manually mask because ESMF only uses zeros.
    input_a_bi = np.ma.array(input_a_bi, mask=dest_grid.mask_t[0, :, :])

    input_b_nn = rh.regrid(nn_weights_a, input_b, grid_b)
    input_b_bi = rh.regrid(bi_weights_a, input_b_nn, dest_grid)
    input_b_bi = np.ma.array(input_b_bi, mask=dest_grid.mask_t[0, :, :])

    return input_a_bi, input_b_bi

def main():

    parser = argparse.ArgumentParser()
    parser.add_argument('type', help='Type of plot. Can be one of SST.')
    parser.add_argument('model_a', help='Name of model A. Can be MOM1')
    parser.add_argument('input_file_a', help='Input data file from model A.')
    parser.add_argument('field_a', help='The input field from model A.')
    parser.add_argument('model_b', help='Name of model B. Can be MOM1')
    parser.add_argument('input_file_b', help='Input data file from model B.')
    parser.add_argument('field_b', help='The input field from model B.')
    parser.add_argument('--time_idx', type=int, default=0)
    parser.add_argument('--output_dir', default='./',
                        help="Directory where plots will be output.")

    args = parser.parse_args()

    assert args.type == 'SST'

    grid_defs = grid_defs_dir()
    if not os.path.exists(grid_defs):
        print(grid_defs_error.format(grid_defs), file=sys.stderr)
        return 1

    with nc.Dataset(args.input_file_a) as f:
        dims = len(f.variables[args.field_a].shape)
        assert dims == 3 or dims == 4

        if dims == 4:
            input_a = f.variables[args.field_a][args.time_idx, 0, :, :]
        else:
            input_a = f.variables[args.field_a][args.time_idx, :, :]

    with nc.Dataset(args.input_file_b) as f:
        dims = len(f.variables[args.field_b].shape)
        assert dims == 3 or dims == 4

        if dims == 4:
            input_b = f.variables[args.field_b][args.time_idx, 0, :, :]
        else:
            input_b = f.variables[args.field_b][args.time_idx, :, :]

    # Make the grids for these inputs.
    if args.model_a == 'MOM1':
        grid_a = mom1_grid.Mom1Grid(os.path.join(grid_defs,
                                              'grid_spec.nc'))
    else:
        assert False, "Model grid {} not supported".format(args.model_a)

    if args.model_b == 'MOM1':
        grid_b = mom1_grid.Mom1Grid(os.path.join(grid_defs,
                                              'grid_spec.nc'))
    else:
        assert False, "Model grid {} not supported".format(args.model_b)

    # Use WOA as a general destination grid.
    dest_grid = woa_grid.WoaGrid(os.path.join(grid_defs,
                                              'woa13_decav_t00_01v2.nc'))

    input_a_bi, input_b_bi = regrid_fields(input_a, input_b, grid_a, grid_b,
                                           dest_grid)

    if args.type == 'SST':
        field = input_a_bi - input_b_bi
        plot_sst(field, dest_grid, args.output_dir)

if __name__ == '__main__':
    sys.exit(main())


import math
from PyCal.Memory.data_factory import DataFactory
from PyCal.Brain.function.if_abstract_formular import IFF
class IF_EG_2_1(IFF):
    def __init__(self, subFunction):
        super(IF_EG_2_1, self).__init__(subFunction)
    """
    STEP 1 (WORK DURATION)
    """
    def __step1(self, fid):
        result = {}
        fl_job = self.data_factory.getTab(self.data_type, "Job", {"FID": [fid], "JID":[], "Duration":[], self.domainORsubdomain:[]})
        fl_assignment = self.data_factory.getTab(self.data_type, "Assignment", {"FID": [fid], "JID": [], "Duration":[], self.domainORsubdomain:[]})

        """
        For each JOB ID related to the FREELANCER ID:
        1. Check FUNCTION (Domain) column in the job tab
        A) If there is an input there (it means its not a consultancy) then:
        """
        fdomain_not_empty = fl_job[fl_job[self.domainORsubdomain].notnull()]
        """
        2. Use the next formula to calculate the duration (months):
        DURATION (months) related to the specific FUNCTION obtained from Job tab
        """
        fdomain_not_empty_grouped = fdomain_not_empty.groupby(self.domainORsubdomain)["Duration"]
        fdomain_not_empty_out = {k: math.fsum(list(v)) for k,v in fdomain_not_empty_grouped}
        fdomain_not_empty_jids = fdomain_not_empty["JID"].values

        fdomain_not_empty_fdomains = fdomain_not_empty[self.domainORsubdomain].values
        jid_fdomain = dict(zip(fdomain_not_empty_jids, fdomain_not_empty_fdomains))

        """
        -(minus)- the sum of DURATIONS (months) related to the ASSIGNMENTS of the same Job ID which have FUNCTIONS (Domain) (assignment tab) different from the FUNCTION (Domain) in the job tab.
        """
        jid_diff_fdomain_duration = {}
        for i in jid_fdomain:
            df = fl_assignment[(fl_assignment["JID"] == i) & (fl_assignment[self.domainORsubdomain] != jid_fdomain[i])]
            total = math.fsum(df["Duration"].values)
            if i in jid_diff_fdomain_duration:
                jid_diff_fdomain_duration[i] += total
            else:
                jid_diff_fdomain_duration[i] = total

        for i in jid_diff_fdomain_duration:
            domain = jid_fdomain[i]
            fdomain_not_empty_out[domain] -= jid_diff_fdomain_duration[i]

        """
        3. then go to assignment tab and work only with Assignments related to that specific Job ID
        """
        df = fl_assignment[fl_assignment["JID"].isin(fdomain_not_empty_jids)][~fl_assignment[self.domainORsubdomain].isin(fdomain_not_empty_fdomains)]
        df_grouped = df.groupby(self.domainORsubdomain)["Duration"]
        """
        4. then sum up only the DURATION (months) related to each particular FUNCTION (Domain) (Assignment tab) which is different from FUNCTION (Domain) (Job tab)
        """
        temp = {k: math.fsum(list(v)) for k,v in df_grouped}
        a_out = {**fdomain_not_empty_out, **temp} #A OUT

        """
        B) If there is no input (its because its a Consultancy) then:
        2. go to assignment tab and work only with Assignments related to that specific (consultancy) Job ID
        """
        fdomain_empty = fl_job[fl_job[self.domainORsubdomain].isnull()]
        fdomain_empty_jids = fdomain_empty["JID"].values
        fdomain_empty_assignment = fl_assignment[fl_assignment["JID"].isin(fdomain_empty_jids)]

        """
        3. then sum up the DURATION (months) related to each particular FUNCTION (Domain) (Assignment tab)
        """
        fdomain_empty_assignment_grouped = fdomain_empty_assignment.groupby(self.domainORsubdomain)["Duration"]
        b_out = {k: math.fsum(list(v)) for k,v in fdomain_empty_assignment_grouped} #B OUT
        result = a_out
        for i in b_out:
            if i in result: result[i] += b_out[i]
            else: result[i] = b_out[i]

        return result

    """
    STEP 2: (EDUCATION DURATION)
    """
    def __step2(self, fid):
        result = {}
        """
        1. Check the FUNCTION (Domain) column in the Education tab
        """
        fl_edu = self.data_factory.getTab(self.data_type, "Education", {"FID": [fid], "Duration":[], self.domainORsubdomain:[]})

        """
        2. Take the DURATION (months) related to that specific FUNCTION (Domain)
        """
        fl_edu_grouped = fl_edu.groupby(self.domainORsubdomain)["Duration"]
        """
        3. Sum up all the DURATIONS(months) related to each FUNCTION (Domain) and multiply them by the factor x 0.5 (cero point five)
        """
        result = {k: math.fsum(list(v)) for k,v in fl_edu_grouped}
        return result

    """
    STEP 3 (SUM and obtain TOTAL DURATION)
    1. Sum up all the DURATIONS related to each FUNCTION (Domain) obtained from step 1 and 2
    """
    def getScore(self, fid):
        result = {}
        eg_2_1 = "EG_2_1"
        step1 = self.__step1(fid)
        step2 = self.__step2(fid)
        result[eg_2_1] = {k: step1.get(k, 0) + step2.get(k, 0) for k in set(step1) | set(step2)}

        return result


#!/usr/bin/env python3

""" Module to test exercise2.py """
import pytest

__author__ = 'Tracy Sallaway, Sarah-Anne Schultheis'
__email__ = "tracy.armstrong@mail.utoronto.ca, sarah.schultheis@mail.utoronto.ca"

__copyright__ = "2014 Susan Sim"
__license__ = "MIT License"

__status__ = "Prototype"

# imports one per line
import pytest
from exercise2 import checksum

def test_checksum():
    """
    Inputs that are the correct format and length
    """
    assert checksum("786936224306") is True
    assert checksum("085392132225") is True
    assert checksum("717951000841") is False
    assert checksum("892685001003") is True
    assert checksum("012345678905") is True
    assert checksum("692771017440") is True
    assert checksum("827624391275") is False
    assert checksum("012345678901") is False

def test_input():

    """
    Inputs that are incorrect
    """
    with pytest.raises(TypeError):
        checksum(1.0)
        checksum(786936224306)

    with pytest.raises(ValueError):
        checksum("1")
        checksum("1234567890")
        checksum("UPC")