Example #1
0
def update_dept(req, db, context, dept_id):
    dept_id = int(dept_id)
    name = get_input(req, 'name')
    desc = get_input(req, 'desc')
    parent_id = get_input(req, 'parent_id')
    
    result = db.query(Dept).filter(Dept.id==dept_id, Dept.deleted==0)
    if result.count() == 0:
        raise DeptNotFoundError(dept_id)
    dept = result.first()

    if is_dept_admin_of(context, dept_id) == False:
        raise NotDeptAdminError(dept_id)

    if name: 
        if db.query(Dept).filter(Dept.name==name, Dept.deleted==0, Dept.id!=dept_id).count() > 0:
            raise DeptAlreadyExistError(name) 
        dept.name = name

    dept.desc = desc
    if parent_id:
        if dept_id == int(parent_id):
            raise ParentCannotBeSelfError(dept.name)
        if db.query(Dept).filter(Dept.id==parent_id, Dept.deleted==0).count() == 0:
            raise ParentDeptNotFoundError(parent_id)
        dept.parent_id = parent_id

    db.add(dept)
    db.commit()
Example #2
0
def update_dept(req, db, context, dept_id):
    dept_id = int(dept_id)
    name = get_input(req, 'name')
    desc = get_input(req, 'desc')
    parent_id = get_input(req, 'parent_id')

    result = db.query(Dept).filter(Dept.id == dept_id, Dept.deleted == 0)
    if result.count() == 0:
        raise DeptNotFoundError(dept_id)
    dept = result.first()

    if is_dept_admin_of(context, dept_id) == False:
        raise NotDeptAdminError(dept_id)

    if name:
        if db.query(Dept).filter(Dept.name == name, Dept.deleted == 0,
                                 Dept.id != dept_id).count() > 0:
            raise DeptAlreadyExistError(name)
        dept.name = name

    dept.desc = desc
    if parent_id:
        if dept_id == int(parent_id):
            raise ParentCannotBeSelfError(dept.name)
        if db.query(Dept).filter(Dept.id == parent_id,
                                 Dept.deleted == 0).count() == 0:
            raise ParentDeptNotFoundError(parent_id)
        dept.parent_id = parent_id

    db.add(dept)
    db.commit()
Example #3
0
def main():
    print("Test run")
    test = get_input('18_test')
    test = Duet(test)
    test.run()

    print("\nDuet: ")
    instructions = get_input('18_input')
    d = Duet(instructions)
    d.run()

    run_parallel(get_input('18_test2'))
    run_parallel(get_input('18_input'))
Example #4
0
def get_shape(shapes, shape=None):
    if shape is None:
        shape = common.get_input("Shape: ", shapes.keys())
    shape = shape.lower()
    if shape not in shapes:
        raise common.LoginError("Shape not found")
    return shapes[shape]
Example #5
0
def list_dept(req, db, context):
    format = get_input(req, 'format')
    if (format and format=='as_tree'):
        dept_id = context['user'].dept_id
        return '[' + json.dumps(get_dept_tree(db, dept_id)) + ']'
    else:     
        return obj_array_to_json(context['depts'], 'depts')
Example #6
0
def list_dept(req, db, context):
    format = get_input(req, 'format')
    if (format and format == 'as_tree'):
        dept_id = context['user'].dept_id
        return '[' + json.dumps(get_dept_tree(db, dept_id)) + ']'
    else:
        return obj_array_to_json(context['depts'], 'depts')
Example #7
0
 def save_poster(self, destination, choose):
     if choose:
         print 'Creating image selection palette(s)...'
         posters = _get_all_posters(self.series_data.posterUrl)
         poster_qty = len(posters)
         if poster_qty <= 1:
             print 'No palette created,', poster_qty, 'image(s) available'
             _save_poster(self.series_data.posterUrl, destination,
                          self.seriesname, 900)
             return
         draw_mosaic(posters)
         choice = get_input('Choose an image to use for series poster: ',
                            '(^$)|(^(Q|q)$)|(^\d{1,2}$)',
                            1, poster_qty)
         if re.match('^(Q|q)$', choice):
             exit()
         if not choice:
             posterUrl = self.series_data.posterUrl
         else:
             posterUrl = re.sub('(http://.*)-(\d{1,2})\.(.{3,4})',
                                '\\1-' + choice + '.\\3',
                                self.series_data.posterUrl)
         _save_poster(posterUrl, destination, self.seriesname, 900)
     else:
         _save_poster(self.series_data.posterUrl, destination,
                      self.seriesname, 900)
Example #8
0
def download_poster(self, size, destination, choose):
    '''
    download associated movie poster

    size: w92, w154, w185, w342, w500, or original
          see http://help.themoviedb.org/kb/api/configuration
    name: name to save it as
    '''

    if choose:
        print 'Creating image selection palette(s)...'
        posters = _get_all_posters(self.posters, size)
        poster_qty = len(posters)
        if poster_qty <= 1:
            print 'No palette created,', poster_qty, 'image(s) available'
            return download_file(self.poster.geturl(size), destination)
        draw_mosaic(posters)
        choice = get_input('Choose an image to use for movie poster: ',
                           '(^$)|(^(Q|q)$)|(^\d{1,2}$)',
                           1, poster_qty)
        if re.match('^(Q|q)$', choice):
            exit()
        if not choice:
            poster_url = self.poster.geturl(size)
        else:
            poster_url = self.posters[int(choice)-1].geturl(size)
    else:
        poster_url = self.poster.geturl(size)
    image = download_file(poster_url, destination)
    if destination == 'temp':
        return image
    is_reduced = reduce_size(destination, 90)
    if is_reduced:
        notify('warning', 'image quality reduced and useless data removed for '
                + os.path.splitext(os.path.basename(destination))[0], sys.stderr)
Example #9
0
def create_user(req, db, context):
    name = get_required_input(req, 'username')
    password = get_required_input(req, 'password')
    email = get_input(req, 'email')
    dept_id = int(get_required_input(req, 'dept_id'))
    role_id = get_input(req, 'role_id')

    if db.query(User).filter(User.name==name, User.deleted==0).count() > 0:
        raise UsernameAlreadyExistError(name)

    if db.query(User).filter(User.email==email, User.deleted==0).count() > 0:
        raise EmailAlreadyExistError(email)

    if is_dept_admin_of(context, dept_id) == False:
        raise NotDeptAdminError(dept_id)

    if role_id == None:
        user_role = db.query(Role).filter(Role.name=='普通用户').first()
        role_id = user_role.id
    else:
        role_id = int(role_id)
        operator_role_id = int(context['membership'].role_id)
        if role_id < operator_role_id:
            raise RolePermissionDenyError(role_id)

    try:
        user = User(name=name, password=password, email=email, dept_id=dept_id)
        db.add(user)
        db.flush()
        membership = UserRoleMembership(user_id=user.id, role_id=role_id)
        db.add(membership)
        db.commit()
        log.debug(user)
        return obj_to_json(user, 'user')
    except Exception, e:
        handle_db_error(db, e)
Example #10
0
def encryption_weakness():
    invalid = first_invalid()

    # Complexity if we don't consider part 1 (previous line):
    # O(n+c) time and O(1) space
    # with n: length of input, c: length of contiguous sequence

    numbers = get_input()
    left, right = contiguous_sequence_pointers(numbers, invalid)
    max_item = numbers[left]
    min_item = numbers[left]
    for i in range(left, right + 1):
        max_item = max(max_item, numbers[i])
        min_item = min(min_item, numbers[i])
    return min_item + max_item
Example #11
0
def main():
    memory_banks = get_input("6_input", 1, func=int)
    print(memory_banks)

    saved_states = {}
    cycle = 0

    key = ",".join(map(str, memory_banks))
    while key not in saved_states.keys():
        saved_states[key] = cycle
        redistribute_blocks(memory_banks)
        cycle += 1
        key = ",".join(map(str, memory_banks))

    print(len(saved_states), len(saved_states) - saved_states[key])
Example #12
0
def required_bags():
    luggage_rules = get_input()
    bag_map = {}

    def traverse(key="shiny gold"):
        # O(k) time and space thanks to dynamic programming
        # with k: number of rules where our key is involved
        if key in bag_map.keys(): return bag_map[key]
        total = 0
        for container, amount in luggage_rules[key].items():
            total += amount
            total += amount * traverse(container)
        bag_map[key] = total
        return total

    return traverse()
Example #13
0
def potential_containers():
    luggage_rules = get_input()

    def traverse(key="shiny gold", visited=None):
        # O(n) time and space
        # with n: number of rules (bag types) → we visit each rule at most once
        if visited is None: visited = set()
        total = 0
        for container in luggage_rules.keys():
            if container in visited: continue
            if key in luggage_rules[container]:
                visited.add(container)
                total += 1
                total += traverse(container, visited)
        return total

    return traverse()
Example #14
0
def main():
    data = flatten_list(get_input('5_input', func=int))
    # data = [0, 3, 0, 1, -3]
    steps = 0
    index = 0
    try:
        while True:
            offset = data[index]
            if offset >= 3:
                data[index] -= 1
            else:
                data[index] += 1
            index += offset
            steps += 1
    except IndexError:
        pass
    print(steps)
Example #15
0
def main():
    day1_puzzle = get_input("1_input", 0, 0)
    # day1_puzzle = "91212129"

    puzzle_len = len(day1_puzzle)
    sums = {
        "part1": {
            "step": 1,
            "sum": 0
        },
        "part2": {
            "step": int(puzzle_len / 2),
            "sum": 0
        }
    }

    for i in range(puzzle_len):
        for part, data in sums.items():
            next_index = (i + data["step"]) % puzzle_len
            if (day1_puzzle[i] == day1_puzzle[next_index]):
                data["sum"] += int(day1_puzzle[i])

    print(sums["part1"]["sum"], sums["part2"]["sum"])
Example #16
0
def list_user(req, db, context):
    depts = []
    dept_id = get_input(req, 'dept_id')

    if is_sys_admin_or_dept_admin(context):
        # 如果是管理员,能够列出所管理的所有用户
        if dept_id and dept_id!="":
            dept_id = int(dept_id)
            if is_dept_admin_of(context, dept_id) == False:
                raise NotDeptAdminError(dept_id)
            # 如果给出了dept_id, 显示所有该部门和下面子部门的用户
            for d in get_all_depts(req, db, context, dept_id):
                depts.append(d.id)
        
        else:
            # 如果没给出dept_id, 显示该管理员管理的所有部门的用户
            depts = context['dept_ids']

        results = db.query(User.id, User.name, User.password, User.email, User.dept_id, Role.id, Role.name)\
                           .filter(User.dept_id.in_(depts), 
                                User.deleted==0,
                                User.id==UserRoleMembership.user_id,
                                Role.id==UserRoleMembership.role_id).all()

    else :
        # 普通用户只能列出自己
        results = db.query(User.id, User.name, User.password, User.email, User.dept_id, Role.id, Role.name)\
                           .filter(User.id==context['user'].id,
                                   User.deleted==0,
                                   User.id==UserRoleMembership.user_id,
                                   Role.id==UserRoleMembership.role_id).all()

    users = []
    for item in results:
        users.append(tuple_to_dict(item, 'id, name, password, email, dept_id, role_id, role_name'))
    return {'users': users}
Example #17
0
def parse_input(file_name):
    return [
        set(''.join(group.split('\n')))
        for group in common.get_input(file_name).split('\n\n')
    ]
Example #18
0
    rules = get_enhancement_rules(input)
    current_state = deserialize(starting_pattern)
    for _ in range(0, iter_num):
        if len(current_state) > 3:
            result = list()
            for rows in matrix_split(current_state):
                row_result = list()
                for m in rows:
                    for p in map(serialize, get_patterns(m)):
                        if p in rules:
                            row_result.append(rules[p])
                            break
                result.append(row_result)
            current_state = merge_matrix(result)
            pass
        else:
            for p in map(serialize, get_patterns(current_state)):
                if p in rules:
                    current_state = rules[p]
                    break
        pass
    return count_pixels(current_state)


test_rules = """../.# => ##./#../...
.#./..#/### => #..#/..../..../#..#""".split('\n')
test_start = ".#./..#/###"
# assert process(test_start, test_rules, 2) == 12

print(process(test_start, get_input(), 18))
import day10
from common import get_input

test_input_data = get_input("day10_input_test.txt")
input_data = get_input("day10_input.txt")


def test_day10_part_1():
    number_list = [int(i) for i in test_input_data]
    assert day10.part1(number_list) == 220


def test_day10_part_2():
    number_list = [int(i) for i in test_input_data]
    assert day10.part2(number_list) == 19208
    number_list2 = [int(i) for i in input_data]
    assert day10.part2(number_list2) == 13816758796288
Example #20
0
#!/usr/bin/env python3

from common import get_input

src = get_input(7)


def decode(oc):
    soc = "{:05d}".format(oc)

    cd = int(soc[3:])

    p1m = int(soc[2])
    p2m = int(soc[1])
    p3m = int(soc[0])

    # print(cd, p1m, p2m, p3m)

    return cd, p1m, p2m, p3m


def run(prog, read_input, phase, idx, done=None):
    prog = [int(v) for v in prog.split(",")]
    outp = []
    eip = 0

    read_phase = False

    last_output = None

    def fetch(addr, mode):
Example #21
0
def update_user(req, db, context, user_id):
    user_id = int(user_id) 
    name = get_input(req, 'username')
    password = get_input(req, 'password')
    email = get_input(req, 'email')
    dept_id = get_input(req, 'dept_id')
    role_id = get_input(req, 'role_id')
    action = get_input(req, 'action')

    if action and action=='refresh_token':
        # 客户端请求更新token
        token = req.get_header('X-Auth-Token')
        delete_token(db, token)
        token = generate_token(db, context['user'].id)
        return {'success': {'token': token.id}}

    result = db.query(User).filter(User.id==user_id, User.deleted==0)
    if result.count() == 0:
        raise UserNotFoundError(user_id)
    user = result.first()

    if name:
        if db.query(User).filter(User.name==name, User.deleted==0, User.id!=user_id).count() > 0:
            raise UsernameAlreadyExistError(name)
        user.name = name

    if password:
        user.password = password

    if email:
        if db.query(User).filter(User.email==email, User.deleted==0, User.id!=user_id).count() > 0:
            raise EmailAlreadyExistError(email)
        user.email = email

    if dept_id:
        dept_id = int(dept_id)
        if user.name=='admin' and user.dept_id!=dept_id:
            raise CannotModifyAdminError

        if is_dept_admin_of(context, dept_id) == False:
            raise NotDeptAdminError(dept_id)
        user.dept_id = dept_id

    if role_id:
        role_id = int(role_id)
        if user.name == 'admin' and role_id!=1:
            raise CannotModifyAdminError

        operator_role_id = int(context['membership'].role_id)
        if role_id < operator_role_id:
            # 部门管理员不能授予用户系统管理员的权限
            raise RolePermissionDenyError(role_id)

    try:
        db.add(user)
        db.query(UserRoleMembership).filter(UserRoleMembership.user_id==user_id).delete()
        membership = UserRoleMembership(user_id=user_id, role_id=role_id)
        db.add(membership)
        db.commit()
    except Exception, e:
        handle_db_error(db, e)
Example #22
0
def process_condition(cond_token, cond_op, cond_val, registry):
    left_val = 0
    right_val = int(cond_val)
    if cond_token in registry:
        left_val = registry[cond_token]
    return operators[cond_op](left_val, right_val)


def process(input):
    registry = dict()
    max_value = 0
    for instruction in input:
        token, op, val, cond_token, cond_op, cond_val = parse_instruction(
            instruction)
        cond = process_condition(cond_token, cond_op, cond_val, registry)
        current_val = 0 if token not in registry else registry[token]
        registry[token] = operators[op](current_val,
                                        int(val)) if cond else current_val
        max_value = registry[
            token] if registry[token] > max_value else max_value
    return max(registry.values()), max_value


test_input = """b inc 5 if a > 1
a inc 1 if b < 5
c dec -10 if a >= 1
c inc -20 if c == 10"""
assert process(test_input.split('\n')) == (1, 10)

print(process(get_input()))
Example #23
0
#!/usr/bin/env python3

from common import get_input

prog = get_input(5).split(",")

# prog = "3,0,4,0,99".split(",")
# prog = "1002,4,3,4,33".split(",")
inp = [1]
outp = []

prog = [int(v) for v in prog]


def decode(oc):
    soc = "{:05d}".format(oc)

    cd = int(soc[3:])

    p1m = int(soc[2])
    p2m = int(soc[1])
    p3m = int(soc[0])

    print(cd, p1m, p2m, p3m)

    return cd, p1m, p2m, p3m


def fetch(addr, mode):
    if mode == 0:
        return prog[prog[addr]]
Example #24
0

def process(input, rounds, move):
    grid = create_grid(input)
    start = len(input) // 2
    x, y = start, start
    dir = 'N'
    infection_count = 0
    for _ in range(0, rounds):
        if x == 1 or x == (len(grid) - 2) or y == 1 or y == (len(grid) - 2):
            grow_grid(grid)
            x += 1
            y += 1
        pos, dir, infection_count = move((x, y), dir, grid, infection_count)
        x, y = pos
    return infection_count


test_input = """..#
#..
...""".split('\n')
assert process(test_input, 70, move_one) == 41
assert process(test_input, 10000, move_one) == 5587

print(process(get_input(), 10000, move_one))

assert process(test_input, 100, move_two) == 26
assert process(test_input, 10000000, move_two) == 2511944

print(process(get_input(), 10000000, move_two))
Example #25
0
#!/usr/bin/env python3

from common import get_input

input = get_input(2).split(",")
input = [int(v) for v in input]

# input = [1, 1, 1, 4, 99, 5, 6, 0, 99]
# print(input)

input[1] = 12
input[2] = 2

eip = 0
while True:
    oc = input[eip]
    if oc == 99:
        break

    v1 = input[input[eip + 1]]
    v2 = input[input[eip + 2]]
    v3 = input[eip + 3]

    if oc == 1:
        input[v3] = v1 + v2
    if oc == 2:
        input[v3] = v1 * v2

    eip += 4

print(input)
Example #26
0
def get_group_count(relations, *args):
    groups = list()
    keys = list(relations)
    while len(keys) > 0:
        sub_group = get_subgroup(relations, keys[0], set())
        groups.append(sub_group)
        keys = np.setdiff1d(keys, list(sub_group))
    return len(groups)


def process(input, solution, param):
    relations, _ = generate_tree(input, parse_line)
    return solution(relations, param)


test_input = """0 <-> 2
1 <-> 1
2 <-> 0, 3, 4
3 <-> 2, 4
4 <-> 2, 3, 6
5 <-> 6
6 <-> 4, 5"""
assert process(test_input.split('\n'), get_number_in_group, 0) == 6

print(process(get_input(), get_number_in_group, 0))

assert process(test_input.split('\n'), get_group_count, None) == 2

print(process(get_input(), get_group_count, None))
Example #27
0
def main():
    data = get_input("day8_input.txt")
    split_instructions = (get_split_instructions(data))
    print(part_1(split_instructions))
    print(part_2(split_instructions))
Example #28
0
#!/usr/bin/env python3
from common import get_input
from math import floor

# take its mass, divide by three, round down, and subtract 2.


def fuel_req(mass):
    if mass == 0:
        return 0
    return floor(mass / 3) - 2


f = 0
for line in get_input(1).strip().split("\n"):
    f += fuel_req(int(line))

print(f)
Example #29
0
        garbage_mode = char == '<' or garbage_mode
        if char == '>':
            garbage_mode = False
        if not garbage_mode and char == '{':
            level += 1
        if not garbage_mode and char == '}':
            value_sum += level
            level -= 1
        last_char = char
    return value_sum, cancelled_chars


assert process("{}")[0] == 1
assert process("{{{}}}")[0] == 6
assert process("{{},{}}")[0] == 5
assert process("{{{},{},{{}}}}")[0] == 16
assert process("{<a>,<a>,<a>,<a>}")[0] == 1
assert process("{{<ab>},{<ab>},{<ab>},{<ab>}}")[0] == 9
assert process("{{<!!>},{<!!>},{<!!>},{<!!>}}")[0] == 9
assert process("{{<a!>},{<a!>},{<a!>},{<ab>}}")[0] == 3

assert process("<>")[1] == 0
assert process("<random characters>")[1] == 17
assert process("<<<<>")[1] == 3
assert process("<{!>}>")[1] == 2
assert process("<!!>")[1] == 0
assert process("<!!!>>")[1] == 0
assert process('<{o"i!a,<{i<a>')[1] == 10

print(process(get_input()[0]))  # returns (16869, 7284)
Example #30
0
from common import get_input


def process(input, get_offset_change):
    int_input = list(map(int, input))
    position, steps, length = 0, 0, len(int_input)
    while 0 <= position < length:
        offset = int_input[position]
        int_input[position] += get_offset_change(offset)
        position += offset
        steps += 1
    return steps


def increase_by_one(_):
    return 1


def greater_than_three(offset):
    return 1 if offset < 3 else -1


assert process(["0", "3", "0", "1", "-3"], increase_by_one) == 5

print(process(get_input(), increase_by_one))

assert process(["0", "3", "0", "1", "-3"], greater_than_three) == 10

print(process(get_input(), greater_than_three))
Example #31
0
    split_input = list(input)
    result = 0
    for i in range(-1, len(split_input) - 1):
        result = result + (int(split_input[i]) if split_input[i] == func(i, split_input) else 0)
    return result


def get_next_element(index, array):
    return array[index + 1]


def get_next_halfway(index, array):
    next_el = (index + int(len(array)/2)) % len(array)
    return array[next_el]


assert process(get_next_element, '1122') == 3
assert process(get_next_element, '1111') == 4
assert process(get_next_element, '1234') == 0
assert process(get_next_element, '91212129') == 9

print(process(get_next_element, get_input()[0]))

assert process(get_next_halfway, '1212') == 6
assert process(get_next_halfway, '1221') == 0
assert process(get_next_halfway, '123425') == 4
assert process(get_next_halfway, '123123') == 12
assert process(get_next_halfway, '12131415') == 4

print(process(get_next_halfway, get_input()[0]))
Example #32
0
    return list(map(lambda w: ''.join(sorted(w)), password.split()))


def is_valid(password, condition):
    words = condition(password)
    unique_words = set(words)
    return len(words) == len(unique_words)


def process(input, condition):
    valid_count = 0
    for password in input:
        if is_valid(password, condition):
            valid_count += 1
    return valid_count


assert is_valid('aa bb cc dd ee', is_unique) is True
assert is_valid('aa bb cc dd aa', is_unique) is False
assert is_valid('aa bb cc dd aaa', is_unique) is True

print(process(get_input(), is_unique))

assert is_valid('abcde fghij', no_anagrams) is True
assert is_valid('abcde xyz ecdab', no_anagrams) is False
assert is_valid('a ab abc abd abf abj', no_anagrams) is True
assert is_valid('iiii oiii ooii oooi oooo', no_anagrams) is True
assert is_valid('oiii ioii iioi iiio', no_anagrams) is False

print(process(get_input(), no_anagrams))
Example #33
0
#!/usr/bin/python
# -*- coding: utf-8 -*-
import ConfigParser
import sys

from common import get_input, config, smug_auth, album_select

s = smug_auth()
to_delete = album_select(s, config.get('smugmug', 'username'))

print("Delete albums:")
for a in to_delete:
    print("\t%s" % a['Title'])

print("Is this OK? Type 'delete' to continue")
val = get_input()
if val != 'delete':
    print("Aborting!")
    sys.exit(0)

for a in to_delete:
    sys.stdout.write("Deleting %s..." % (a['Title']))
    resp = s.albums_delete(AlbumID=a['id'])
    if resp['stat'] == 'ok':
        print("done")
    else:
        print("error")

print("All done.")
Example #34
0
def union_count():
    # O(n*a) time and space
    # with n: number of passengers, a: longest answer set
    return sum([len(set.union(*group)) for group in get_input()])
Example #35
0
#!/usr/bin/env python3

from common import get_input

src = get_input(8)
# src = "0222112222120000"

dim_x = 25
dim_y = 6

# dim_x = 2
# dim_y = 2

layer_sz = dim_x * dim_y

assert len(src) % (layer_sz) == 0

layer_count = int(len(src) / (layer_sz))

layers = []
for i in range(layer_count):
    layers.append(src[i * layer_sz:(i + 1) * layer_sz])

for j, layer in enumerate(layers):
    nlayer = []
    for i in range(dim_y):
        nlayer.append(layer[i * dim_x:(i + 1) * dim_x])
    layers[j] = nlayer

# zeros = 10000
# zi = 0
Example #36
0
def redistribute_blocks(memory):
    max_value = max(memory)
    index = memory.index(max_value)
    memory[index] = 0
    while max_value > 0:
        index = (index + 1) % len(memory)
        memory[index] += 1
        max_value -= 1
    return memory


def process(input):
    memory = list(map(int, input.split()))
    state_cache = {}
    cycles_to_loop = 0
    while serialize(memory) not in state_cache:
        state_cache[serialize(memory)] = 1
        memory = redistribute_blocks(memory)
        cycles_to_loop += 1
    cycles_in_loop = 0
    while state_cache[serialize(memory)] != 2:
        state_cache[serialize(memory)] += 1
        memory = redistribute_blocks(memory)
        cycles_in_loop += 1
    return cycles_to_loop, cycles_in_loop


assert process("0\t2\t7\t0") == (5, 4)

print(process(get_input()[0]))