from typing import Any, Callable


def count_calls[T](func: Callable[..., T]) -> Callable[..., T]:
    count_calls.calls = 0
    def wrapper(*args, **kwargs) -> T:
        init_calls = count_calls.calls
        count_calls.calls += 1
        result = func(*args, **kwargs)
        wrapper.calls = count_calls.calls - init_calls
        return result
    return wrapper

def f(x: int, y: int) -> int:
    if x % 2 == 0:
        return x // 2
    else:
        return x + 2 * y - 1

def count_iterations(a: int, b: int) -> int:
    f_a(a, a, b)
    return f_a.calls - 1

@count_calls
def f_a(init: int, a: int, b: int) -> None:
    if a < b:
        return
    return f_a(init, f(a, init), b)

def execute_by(n: int):
    def wrapper(fn):
        def wrapped_fn(*args, **kwargs):
            for _ in range(0, n):
                fn(*args, **kwargs)
            return wrapped_fn
        return wrapped_fn
    return wrapper

@execute_by(10)
def hello_world():
    print('hello world!')
   
@execute_by(10) 
def print_ten_times(msg: str):
    print(msg)


def execute_two_times(fn) -> Callable[..., Any]:
    def wrapper(*args, **kwargs):
        for _ in range(0, 2):
            fn(*args, **kwargs)
        return wrapper
    return wrapper

@execute_two_times
def test(msg: str):
    print(msg)

if __name__ == '__main__':
    assert (i := count_iterations(7, 6)) == 3, i
    assert (i := count_iterations(3, 2)) == 4, i
    assert (i := count_iterations(13, 9)) == 18, i
    assert (i := count_iterations(13, 10)) == 8, i
    assert (i := count_iterations(3, 4)) == 0, i
    print_ten_times("hello world")
    test("hello")
    