# R-4.1
# Describe a recursive algorithm for finding the maximum element in a se-
# quence, S, of n elements. What is your running time and space usage?
from itertools import compress, product

def find_maximum(integers):
    """
     running time is n
    """
    if not integers:
        raise ValueError('Parameter numbers should be not empty.')

    def find_maximum_in_collection(numbers, maximum):
        if not numbers:
            return maximum
        if maximum < numbers[0]:
            maximum = numbers[0]
        return find_maximum_in_collection(numbers=numbers[1:], maximum=maximum)

    return find_maximum_in_collection(numbers=integers[1:], maximum=integers[0])

# R-4.2
# Draw the recursion trace for the computation of power(2, 5), using the
# traditional function implemented in Code Fragment 4.11.
def calculate_recursive_power(base, power):
    if base == 0:
        return 0
    if power == 0:
        return 1
    if power == 1:
        return base

    return base * calculate_recursive_power(base=base, power=power - 1)

# R-4.3
# Draw the recursion trace for the computation of power(2, 18), using the
# repeated squaring algorithm, as implemented in Code Fragment 4.12.
def calculate_fast_recursive_power(base, power):
    if base == 0:
        return 0
    if power == 0:
        return 1
    if power == 1:
        return base

    partial = calculate_fast_recursive_power(base=base, power=power // 2)
    result = partial * partial
    if power % 2 == 1:
        result *= base
    return result

# R-4.4
# Draw the recursion trace for the execution of function reverse(S, 0, 5)
# (Code Fragment 4.10) on S = [4, 3, 6, 2, 6].
def reverse(objects):
    def reverse_collection(objects, start, end):
        if start > end:
            return objects
        tmp = objects[start]
        objects[start] = objects[end]
        objects[end] = tmp

        return reverse_collection(objects, start=start + 1, end=end - 1)

    return reverse_collection(objects=objects, start=0, end=len(objects) - 1)

# R-4.5
# Draw the recursion trace for the execution of function PuzzleSolve(3, S,U )
# (Code Fragment 4.14), where S is empty and U = {a, b, c, d}.
class PermutationSolver:
    def __init__(self, elements, deep_level=None):
        self.elements = elements
        if not deep_level:
            self.deep_level = len(self.elements)
        else:
            self.deep_level = deep_level

        self._all_permutations = None

    def calculate_permutations(self):
        _result_of_permutations = []

        def _calculate_permutations(deep: int, result: tuple, elements):
            for index in range(0, len(elements)):
                if deep <= 1:
                    _result_of_permutations.append(result + tuple([elements[index]]))
                else:
                    _calculate_permutations(
                        deep=deep - 1,
                        result=result + tuple(elements[index]),
                        elements=elements[0: max(0, index)] + elements[index + 1: len(elements)]
                    )

        _calculate_permutations(deep=self.deep_level, result=tuple(), elements=self.elements)
        return _result_of_permutations

    def check_existence_in_permutation_set(self, value):
        if not self._all_permutations:
            self._all_permutations = self.calculate_permutations()

        for permutation in self._all_permutations:
            if value == permutation:
                return True
        return False

# R-4.6
# Describe a recursive function for computing the n th Harmonic number
def calculate_harmonic_number(how_many_numbers, sum_of_numbers=0.0):
    if how_many_numbers <= 1:
        return sum_of_numbers + 1.0

    return calculate_harmonic_number(
        how_many_numbers=how_many_numbers - 1,
        sum_of_numbers=sum_of_numbers + (1 / how_many_numbers)
    )

# R-4.7
# Describe a recursive function for converting a string of digits into the in-
# teger it represents. For example, 13531 represents the integer 13, 531.
def string_to_integer(value: str, multiplier=1, sum_of_numbers=0):
    if not value:
        return sum_of_numbers
    return string_to_integer(
        value=value[0:len(value) - 1],
        multiplier=multiplier * 10,
        sum_of_numbers=sum_of_numbers + (int(value[-1]) * multiplier)
    )

# C-4.9
# Write a short recursive Python function that finds the minimum and max-
# imum values in a sequence without using any loops.
def find_max_and_min(collection_of_objs, max_obj=None, min_obj=None):
    if not collection_of_objs:
        raise ValueError('objects can not be None or empty')

    if not max_obj:
        max_obj = collection_of_objs[0]
    if not min_obj:
        min_obj = collection_of_objs[0]

    def _find_max_min(collection, maximum, minimum):
        if len(collection) == 0:
            return maximum, minimum
        else:
            if collection[0] > maximum:
                maximum = collection[0]
            if collection[0] < minimum:
                minimum = collection[0]

            return find_max_and_min(collection_of_objs=collection_of_objs[1:], max_obj=maximum, min_obj=minimum)

    return _find_max_min(collection=collection_of_objs[1:], maximum=max_obj, minimum=min_obj)

# C-4.10
# Describe a recursive algorithm to compute the integer part of the base-two
# logarithm of n using only addition and integer division.
def find_logarithm_integer_part(result, base=2):
    if base <= 0:
        raise ValueError('base should not be less or equal 0')
    if base == result:
        return 1
    if result == 1:
        return 0

    # TODO logic should be improved. dirty hacks
    def _find_logarithms_integer_part(_base, _result, ):
        if result < _base:
            return 0
        return 1 + find_logarithm_integer_part(result / base, base=base)

    return _find_logarithms_integer_part(
        _base=base,
        _result=result
    )

# C-4.11
# Describe an efficient recursive function for solving the element unique-
# ness problem, which runs in time that is at most O(n 2 ) in the worst case
# without using sorting.
# =======
# possible solution, hashing, sorting, iteration, recursion
def solve_uniqueness_problem(data: list):
    def is_unique_value(data: list, value):
        if not data:
            return True

        if data[0] == value:
            return False

        return is_unique_value(data=data[1:], value=value)

    not_unique_elements = set()
    for index in range(len(data)):
        if not is_unique_value(data=data[index + 1:], value=data[index]):
            not_unique_elements.add(data[index])

    return not_unique_elements

# C-4.12
# Give a recursive algorithm to compute the product of two positive integers,
# m and n, using only addition and subtraction.
def calculate_product(number1: int, number2: int):
    if not number1 or not number2:
        return 0

    def _add_base(total_sum, base, how_many_times):
        if how_many_times == 0:
            return total_sum
        return _add_base(total_sum=total_sum + base, base=base, how_many_times=how_many_times - 1)

    return _add_base(total_sum=0, base=number1, how_many_times=number2)

# C-4.13
# In Section 4.2 we prove by induction that the number of lines printed by
# a call to draw interval(c) is 2 c − 1. Another interesting question is how
# many dashes are printed during that process. Prove by induction that the
# number of dashes printed by draw interval(c) is 2 c+1 − c − 2.
# draw_interval(3)
# - draw_interval(2)
# - draw_interval(1)
# - draw_interval(0) = > None
# - draw_line(1) = > -
# - draw_interval(0) = > None
# - draw_line(2) = > --
# - draw_interval(1)
# - draw_interval(0) = > None
# - draw_line(1) = > -
# - draw_interval(0) = > None
# draw_interval(2)
# - draw_interval(1)
# - draw_interval(0) = > None
# - draw_line(1) = > -
# - draw_interval(0) = > None
# - draw_line(2) = > --
# draw_interval(1)
# - draw_interval(0) = > None
# - draw_line(1) = > -
# - draw_interval(0) = > None
#
# draw_interval(c) = > how
# many
# printed
# lines
# 2 ^ ^ (c) - (1)
#
# draw_interval(1) = > 2 - 1 = 1
# draw_interval(2) = > 4 - 1 = 3
# draw_interval(3) = > 8 - 1 = 7
# draw_interval(4) = > 16 - 1 = 16
#
# draw_interbal(c) = > how
# many
# dashes
# printed
# 2 ^ ^ (c + 1) - c - 2
#
# draw_interval(1) = > 2 ^ ^ (1 + 1) - 1 - 2 = 0 == > 2 ^ ^ (c + 1) - c - 2
# draw_interval(2) = > 2 ^ ^ (2 + 1) - 2 - 2 = 4 == > 2 ^ ^ (c + 1) - c - 2
#
# PROOF:
# 1 + 2 * 2 ^ ^ (c) - c - 1 - 2 = 2 ^ ^ (c + 1) + c - 2

# C-4.14
# In the Towers of Hanoi puzzle, we are given a platform with three pegs, a,
# b, and c, sticking out of it. On peg a is a stack of n disks, each larger than
# the next, so that the smallest is on the top and the largest is on the bottom.
# The puzzle is to move all the disks from peg a to peg c, moving one disk
# at a time, so that we never place a larger disk on top of a smaller one.
# See Figure 4.15 for an example of the case n = 4. Describe a recursive
# algorithm for solving the Towers of Hanoi puzzle for arbitrary n. (Hint:
# Consider first the subproblem of moving all but the n th disk from peg a to
# another peg using the third as “temporary storage.”)

def solve_hanoi_towers_problem(source, auxilary, destination):
    def _move_disk(how_many_disks, source, auxilary, destination):
        print("source ", source, " auxilary ", auxilary, " destination ", destination)
        if how_many_disks > 0:
            _move_disk(how_many_disks=how_many_disks - 1, source=source, auxilary=destination, destination=auxilary)
            if source:
                print("move disk ", "source ", source, " auxilary ", auxilary, " destination ", destination)
                destination.append(source.pop())
            _move_disk(how_many_disks=how_many_disks - 1, source=auxilary, auxilary=source, destination=destination)

    return _move_disk(how_many_disks=len(source), source=source, auxilary=auxilary, destination=destination)

# C-4.15 Write a recursive function that will output all the subsets of a set of n
# elements (without repeating any subsets).
def find_unique_subsets(elements: set):
    def _find_unique_subset(items: list):
        if not items:
            return [set()]
        return (set(compress(items, mask)) for mask in product(*[[0, 1]] * len(items)))

    return _find_unique_subset(items=list(elements))

BINARY = [0, 1]

# binary permutations
def produce_binary_reprezentation_from_0_to_n(n):
    if not n:
        return []
    final_result = []

    def produce_binary(n, result: tuple):
        if n == 0:
            final_result.append(result)
            return
        for b in BINARY:
            produce_binary(n=n - 1, result=result + tuple([b]))

        return result

    produce_binary(n, result=tuple())
    return final_result

# def per(n):
#     for i in range(1<<n):
#         s=bin(i)[2:]
#         s='0'*(n-len(s))+s
#         print map(int,list(s))

# C-4.16 Write a short recursive Python function that takes a character string s and
# outputs its reverse. For example, the reverse of pots&pans would be
# snap&stop .
def reverse_separated_elements(text: str, separator: str):
    def _reverse_string(s: str):
        return s[::-1]

    def _reverse_separated_elements(separared_text: list):
        if not separared_text:
            return ''
        result = _reverse_separated_elements(separared_text=separared_text[1:])
        if result:
            result = result + separator
        return result + _reverse_string(separared_text[0])

    separared_text = [sub_string for sub_string in text.split(sep=separator) if sub_string]
    return _reverse_separated_elements(separared_text=separared_text)

# C-4.17 Write a short recursive Python function that determines if a string s is a
# palindrome, that is, it is equal to its reverse. For example, racecar and
# gohangasalamiimalasagnahog are palindromes.
def is_palindrome_recursive(text: str):
    def _is_palindrome_rescursive(s: str, start_index: int, end_index: int):
        if start_index > end_index:
            return True
        if s[start_index] != s[end_index]:
            return False
        return _is_palindrome_rescursive(s=s, start_index=start_index + 1, end_index=end_index - 1)

    if not text:
        return False

    if len(text) == 1:
        return True

    return _is_palindrome_rescursive(s=text, start_index=0, end_index=len(text) - 1)

VOWELS = {'a', 'e', 'i', 'o', 'u', 'y'}

# C-4.18 Use recursion to write a Python function for determining if a string s has
# more vowels than consonants.
def is_more_vowels_in_string(s: str):
    def _is_more_vowels_in_string(s: str, current_index, how_many_vowels: int):
        if current_index >= len(s):
            if how_many_vowels > len(s) / 2:
                return True
            else:
                return False

        if how_many_vowels > len(s) / 2:
            return True

        current_character = s[current_index]
        if current_character in VOWELS:
            how_many_vowels = how_many_vowels + 1
        return _is_more_vowels_in_string(s=s, current_index=current_index+1, how_many_vowels=how_many_vowels)

    if not s:
        return False

    return _is_more_vowels_in_string(s=s, current_index=0, how_many_vowels=0)

# C-4.19 Write a short recursive Python function that rearranges a sequence of in-
# teger values so that all the even values appear before all the odd values.
def swap_even_numbers_before_odd_numbers(numbers: list):
    numbers_length = len(numbers)

    def _swap_even_numbers_before_odd_numbers(numbers: list, even_index: int, odd_index: int):
        if even_index >= numbers_length or odd_index >= numbers_length:
            return numbers
        if numbers[even_index] % 2 != 0:
            return _swap_even_numbers_before_odd_numbers(numbers=numbers, even_index=even_index+1, odd_index=odd_index)
        if numbers[odd_index] % 2 == 0:
            return _swap_even_numbers_before_odd_numbers(numbers=numbers, even_index=even_index, odd_index=odd_index+1)
        if numbers[even_index] % 2 == 0 and numbers[odd_index] % 2 != 0:
            if even_index > odd_index:
                tmp_even = numbers[even_index]
                numbers[even_index] = numbers[odd_index]
                numbers[odd_index] = tmp_even

            return _swap_even_numbers_before_odd_numbers(numbers=numbers, even_index=even_index, odd_index=odd_index+1)
        raise ValueError('UPS')

    if not numbers or len(numbers) == 1:
        return numbers

    return _swap_even_numbers_before_odd_numbers(numbers=list(numbers), even_index=0, odd_index=0)

def find_pair_number_to_get_sum(sorted_numbers: list, sum_result: int):
    def _find_pair_number_to_get_sum(
            sorted_numbers: list,
            sum_result: int,
            start_index: int,
            end_index: int
    ):
        if start_index > end_index:
            return tuple()
        sum_of_two_numbers = sorted_numbers[start_index] + sorted_numbers[end_index]
        if sum_of_two_numbers == sum_result:
            return sorted_numbers[start_index], sorted_numbers[end_index]
        elif sum_of_two_numbers < sum_result:
            return _find_pair_number_to_get_sum(
                sorted_numbers=sorted_numbers,
                sum_result=sum_result,
                start_index=start_index+1,
                end_index=end_index
            )
        else:
            return _find_pair_number_to_get_sum(
                sorted_numbers=sorted_numbers,
                sum_result=sum_result,
                start_index=start_index,
                end_index=end_index-1
            )

    if not sorted_numbers:
        return tuple()

    return _find_pair_number_to_get_sum(
        sorted_numbers=sorted_numbers,
        sum_result=sum_result,
        start_index=0,
        end_index=len(sorted_numbers) - 1
    )


import datetime
import os

from twilio.rest import Client

CHECKIN_MSG_TEMPLATE = (
    '{date} ({day})\n' +
    'Please confirm you have taken your medicine today (Yes/No).'
)

def make_checkin_message():
    today = datetime.datetime.today()
    weekday = today.strftime("%a")
    date = "%s/%s" %(today.month, today.day)

    return CHECKIN_MSG_TEMPLATE.format(date=date,
        day=weekday)

if __name__ == "__main__":
    account = os.environ["TWILIO_ACCOUNT"]
    token = os.environ["TWILIO_AUTH_TOKEN"]
    twilio_number = os.environ["TWILIO_PHONE_NUMBER"]
    home_number = os.environ["TWILIO_HOME_PHONE_NUMBER"]

    client = Client(account, token)
    checkin_message = make_checkin_message()

    message = client.messages.create(from_=twilio_number,
        to=home_number, body=checkin_message)


import torch
from functools import reduce
from torch.optim.optimizer import Optimizer

class LBFGS(Optimizer):

    def __init__(self,
                 params,
                 lr=1,
                 max_iter=200,
                 max_eval=None,
                 tolerance_grad=1e-7,
                 tolerance_change=1e-9,
                 history_size=100):
        if max_eval is None:
            max_eval = max_iter * 5 // 4
        defaults = dict(
            lr=lr,
            max_iter=max_iter,
            max_eval=max_eval,
            tolerance_grad=tolerance_grad,
            tolerance_change=tolerance_change,
            history_size=history_size)
        super(LBFGS, self).__init__(params, defaults)

        if len(self.param_groups) != 1:
            raise ValueError("LBFGS doesn't support per-parameter options "
                             "(parameter groups)")

        self._params = self.param_groups[0]['params']
        self._numel_cache = None

    def _numel(self):
        if self._numel_cache is None:
            self._numel_cache = reduce(lambda total, p: total + p.numel(), self._params, 0)
        return self._numel_cache

    def _gather_flat_grad(self):
        views = []
        for p in self._params:
            if p.grad is None:
                view = p.new(p.numel()).zero_()
            elif p.grad.is_sparse:
                view = p.grad.to_dense().view(-1)
            else:
                view = p.grad.view(-1)
            views.append(view)
        return torch.cat(views, 0)

    def _add_grad(self, step_size, update):
        offset = 0
        for p in self._params:
            numel = p.numel()
            d = update[offset:offset + numel].view_as(p)
            p.add_(d, alpha=step_size)
            offset += numel
        assert offset == self._numel()

    def _clone_param(self):
        return [p.clone(memory_format=torch.contiguous_format) for p in self._params]

    def _set_param(self, params_data):
        for p, pdata in zip(self._params, params_data):
            p.copy_(pdata)

    def _directional_evaluate(self, closure, x, t, d):
        self._add_grad(t, d)
        loss = float(closure())
        flat_grad = self._gather_flat_grad()
        self._set_param(x)
        return loss, flat_grad

    @torch.no_grad()
    def step(self, closure):
        """Performs a single optimization step.

        Args:
            closure (callable): A closure that reevaluates the model
                and returns the loss.
        """
        assert len(self.param_groups) == 1

        # Make sure the closure is always called with grad enabled
        closure = torch.enable_grad()(closure)

        group = self.param_groups[0]
        lr = group['lr']
        max_iter = group['max_iter']
        max_eval = group['max_eval']
        tolerance_grad = group['tolerance_grad']
        tolerance_change = group['tolerance_change']
        history_size = group['history_size']

        # NOTE: LBFGS has only global state, but we register it as state for
        # the first param, because this helps with casting in load_state_dict
        state = self.state[self._params[0]]
        state.setdefault('func_evals', 0)
        state.setdefault('n_iter', 0)

        # evaluate initial f(x) and df/dx
        orig_loss = closure()
        loss = float(orig_loss)
        current_evals = 1
        state['func_evals'] += 1

        flat_grad = self._gather_flat_grad()
        opt_cond = flat_grad.abs().max() <= tolerance_grad

        # optimal condition
        if opt_cond:
            return orig_loss

        # tensors cached in state (for tracing)
        d = state.get('d')
        t = state.get('t')
        old_dirs = state.get('old_dirs')
        old_stps = state.get('old_stps')
        ro = state.get('ro')
        H_diag = state.get('H_diag')
        prev_flat_grad = state.get('prev_flat_grad')
        prev_loss = state.get('prev_loss')

        n_iter = 0
        # optimize for a max of max_iter iterations
        while n_iter < max_iter:
            # keep track of nb of iterations
            n_iter += 1
            state['n_iter'] += 1

            ############################################################
            # compute gradient descent direction
            ############################################################
            if state['n_iter'] == 1:
                d = flat_grad.neg()
                old_dirs = []
                old_stps = []
                ro = []
                H_diag = 1
            else:
                # do lbfgs update (update memory)
                y = flat_grad.sub(prev_flat_grad)
                s = d.mul(t)
                ys = y.dot(s)  # y*s
                if ys > 1e-10:
                    # updating memory
                    if len(old_dirs) == history_size:
                        # shift history by one (limited-memory)
                        old_dirs.pop(0)
                        old_stps.pop(0)
                        ro.pop(0)

                    # store new direction/step
                    old_dirs.append(y)
                    old_stps.append(s)
                    ro.append(1. / ys)

                    # update scale of initial Hessian approximation
                    H_diag = ys / y.dot(y)  # (y*y)

                # compute the approximate (L-BFGS) inverse Hessian
                # multiplied by the gradient
                num_old = len(old_dirs)

                if 'al' not in state:
                    state['al'] = [None] * history_size
                al = state['al']

                # iteration in L-BFGS loop collapsed to use just one buffer
                q = flat_grad.neg()
                for i in range(num_old - 1, -1, -1):
                    al[i] = old_stps[i].dot(q) * ro[i]
                    q.add_(old_dirs[i], alpha=-al[i])

                # multiply by initial Hessian
                # r/d is the final direction
                d = r = torch.mul(q, H_diag)
                for i in range(num_old):
                    be_i = old_dirs[i].dot(r) * ro[i]
                    r.add_(old_stps[i], alpha=al[i] - be_i)

            if prev_flat_grad is None:
                prev_flat_grad = flat_grad.clone(memory_format=torch.contiguous_format)
            else:
                prev_flat_grad.copy_(flat_grad)
            prev_loss = loss

            ############################################################
            # compute step length
            ############################################################
            # reset initial guess for step size
            if state['n_iter'] == 1:
                t = min(1., 1. / flat_grad.abs().sum()) * lr
            else:
                t = lr

            # directional derivative
            gtd = flat_grad.dot(d)  # g * d

            # directional derivative is below tolerance
            if gtd > -tolerance_change:
                break

            # optional line search: user function
            ls_func_evals = 0
            self._add_grad(t, d)
            if n_iter != max_iter:
                # re-evaluate function only if not in last iteration
                # the reason we do this: in a stochastic setting,
                # no use to re-evaluate that function here
                with torch.enable_grad():
                    loss = float(closure())
                flat_grad = self._gather_flat_grad()
                opt_cond = flat_grad.abs().max() <= tolerance_grad
                ls_func_evals = 1

            # update func eval
            current_evals += ls_func_evals
            state['func_evals'] += ls_func_evals

            ############################################################
            # check conditions
            ############################################################
            if n_iter == max_iter:
                break

            if current_evals >= max_eval:
                break

            # optimal condition
            if opt_cond:
                break

            # lack of progress
            if d.mul(t).abs().max() <= tolerance_change:
                break

            if abs(loss - prev_loss) < tolerance_change:
                break

        state['d'] = d
        state['t'] = t
        state['old_dirs'] = old_dirs
        state['old_stps'] = old_stps
        state['ro'] = ro
        state['H_diag'] = H_diag
        state['prev_flat_grad'] = prev_flat_grad
        state['prev_loss'] = prev_loss

        return orig_loss


import os
from decouple import config
from datetime import timedelta

BASE_DIR = os.path.dirname(os.path.realpath(__file__))

uri = config('DATABASE_URL') #or other relevant config var
if uri.startswith('postgres://'):
    uri = uri.replace('postgres://', 'postgresql://', 1)

authorization = {
        'security':[{"bearerAuth": []}],
        'components':{
            "securitySchemes":
                {
                    "bearerAuth": {
                        "type":"http",
                        "scheme": "bearer",
                        "bearerFormat": "JWT",
                        "description": "Add a JWT Token to the header ** < JWT > ** to get authorized"
                    }

                    # USE THE CONFIGURATION BELOW FOR apiKey
                    # "bearerAuth": {
                    #     "type":"apiKey",
                    #     "in": "header",
                    #     "name": "Authorization",
                    #     "description": "Add a JWT Token to the header with ** Bearer < JWT > ** to get authorized"
                    # }
                }
        }
    }

class Config:
    SECRET_KEY = config('SECRET_KEY', 'secret')
    JWT_ACCESS_TOKEN_EXPIRES = timedelta(minutes=60)
    JWT_REFRESH_TOKEN_EXPIRES = timedelta(minutes=60)
    JWT_SECRET_KEY = config('JWT_SECRET_KEY', 'jwt_secret')

    PROPAGATE_EXCEPTIONS = True
    API_TITLE = "Student Management API"
    API_VERSION = "v1"
    OPENAPI_DESCRIPTION = "A student Management system for registering students and courses"
    API_SPEC_OPTIONS = authorization
    OPENAPI_VERSION = "3.0.3"
    OPENAPI_URL_PREFIX = "/"
    OPENAPI_SWAGGER_UI_PATH = ""
    OPENAPI_SWAGGER_UI_URL = "https://cdn.jsdelivr.net/npm/swagger-ui-dist/"

class DevConfig(Config):
    DEBUG = True
    SQLALCHEMY_ECHO = True
    SQLALCHEMY_TRACK_MODIFICATION = False
    SQLALCHEMY_DATABASE_URI = 'sqlite:///'+os.path.join(BASE_DIR, 'db.sqlite3')

class TestConfig(Config):
    TESTING = True
    SQLALCHEMY_ECHO = True
    SQLALCHEMY_TRACK_MODIFICATION = False
    SQLALCHEMY_DATABASE_URI = 'sqlite://' #THIS USES SQL MEMORY DATABASE INSTEAD OF CREATING A NEW ONE

class ProdConfig(Config):
    SQLALCHEMY_DATABASE_URI = uri
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    DEBUG = config('DEBUG', False, cast=bool)
    # pass

config_dict = {
    'dev': DevConfig,
    'prod': ProdConfig,
    'test': TestConfig
}


import datetime
def validade():
    fabricacao_str = input('Data de fabricação: ')
    fabricacao = datetime.datetime.strptime(fabricacao_str, '')

    prazo_em_dias = int(input('Prazo de validade em dias: '))
    intervalo_validade = datetime.timedelta(day=prazo_em_dias)

    data_de_validade = fabricacao + intervalo_validade

    print(data_de_validade)

if __name__ == '__main__':
    validade()


from PyQt5.QtWidgets import QDialog, QVBoxLayout, QTabWidget, QWidget, QGridLayout, QLabel, QTextBrowser, QDialogButtonBox
from PyQt5.QtWidgets import QApplication as app
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtCore import QUrl

class About(QDialog):
    def __init__(self, parent=None):
        super(QDialog, self).__init__(parent)
        self.setMinimumSize(600, 500)
        self.setMaximumSize(600, 500)
        self.verticalLayout = QVBoxLayout(self)
        self.tabWidget = QTabWidget(self)
        self.tabVersion = QWidget()
        self.gridLayout3 = QGridLayout(self.tabVersion)
        self.labelAbout = QLabel(self.tabVersion)
        self.gridLayout3.addWidget(self.labelAbout, 0, 0, 1, 1)
        self.tabWidget.addTab(self.tabVersion, "")

        self.tabLicense = QWidget()
        self.gridLayout2 = QGridLayout(self.tabLicense)
        self.browserLicense = QTextBrowser(self.tabLicense)
        self.gridLayout2.addWidget(self.browserLicense, 0, 0, 1, 1)
        self.tabWidget.addTab(self.tabLicense, "")

        self.verticalLayout.addWidget(self.tabWidget)
        self.buttonBox = QDialogButtonBox(self)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Close)
        self.buttonBox.button(QDialogButtonBox.Close).setText(self.tr("Close"))
        self.buttonBox.button(QDialogButtonBox.Close).clicked.connect(self.reject)
        self.verticalLayout.addWidget(self.buttonBox)
        self.buttonBox.accepted.connect(self.reject)
        self.setWindowTitle(self.tr("About"))

        import os.path as os
        with open(os.join(os.dirname(os.dirname(__file__)), "LICENSE"),"r") as license:
            self.browserLicense.setText(license.read())

        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabVersion), self.tr("Version"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabLicense), self.tr("License"))
        self.labelAbout.setText(self.tr("""

{0}

Version: {1}

{0}, cross platform, free and free is a RSS/Atom reader.

PyQt5(Qt5), Python3.4, BeautifulSoup4, feedparser and sqlite3 was created with.

License: Gpl v3

Copyright \u00a9 2015 Metehan Özbek -
            metehan.us  -

""").format(app.applicationName(), app.applicationVersion()))

        self.labelAbout.linkActivated.connect(self.openUrl)

    def openUrl(self, url):
        QDesktopServices.openUrl(QUrl(url))


#!/usr/bin/env python

##from https://github.com/NamWoo

from __future__ import print_function
#import roslib
#roslib.load_manifest('my_package')
import sys
import rospy
import cv2
import numpy as np
from std_msgs.msg import String
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError

from line_functions import *

class image_converter:
    def __init__(self):
    # self.image_pub = rospy.Publisher("image_topic_2",Image)
        ros_topic = "rgb"
        self.bridge = CvBridge()
        self.image_sub = rospy.Subscriber(ros_topic, Image, self.callback)
        cv2.namedWindow("output", cv2.WINDOW_GUI_EXPANDED)
        rospy.loginfo("ros camera : %s", ros_topic)

    def callback(self,data):
        try:
            cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
        except CvBridgeError as e:
            print(e)

        cv_image = line_dectecting(cv_image)

        cv2.imshow("output", cv_image)
        cv2.waitKey(3)

    # try:
    #   self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, "bgr8"))
    # except CvBridgeError as e:
    #   print(e)

def main(args):
    ic = image_converter()
    rospy.init_node('image_converter', anonymous=True)
    try:
        rospy.spin()
    except KeyboardInterrupt:
        print("Shutting down")
    cv2.destroyAllWindows()

def nothing(x):
    pass

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


"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".

Replace this with more appropriate tests for your application.
"""

from django.test import TestCase
from forms import ContactForm
from models import Contact

class ContactFormTest(TestCase):

    def test_simple_test_modelform(self):
        data = {
            "name": "test",
            "email": "test@test.com",
            "message": "Message test",
            "category": "OUT",
        }
        form = ContactForm(data)
        self.assertTrue(form.is_valid())

    def test_return_from_model(self):
        data = {
            "name": "test",
            "email": "test@test.com",
            "message": "Message test",
            "category": "OUT",
        }

        contact = Contact.objects.create(**data)
        self.assertEquals(data['name'], str(contact))


# -*- coding: utf-8 -*-

import inspect

import discord

def control(reaction):
    def inner(func):
        func.__map_reaction__ = reaction

        return func

    return inner

class MapSession:
    def __init__(self, ctx, map_array):
        self.ctx = ctx

        self.current_pos = [0, 0]
        self.msg = None
        self._task = None

        def is_control(thing):
            return inspect.ismethod(thing) and hasattr(thing, "__map_reaction__")

        self.controls = {
            emoji: func
            for emoji, func in [(x.__map_reaction__, x) for _, x in inspect.getmembers(self, is_control)]
        }

        self.original_map = map_array
        self.map_copy = map_array.copy()

    @property
    def alive(self):
        return not self._task.done()

    def start(self):
        self._task = self.ctx.bot.loop.create_task(self.task())

    async def cancel(self):
        self._task.cancel()
        del self.ctx.bot.sessions[f"{self.ctx.author.id}-{self.ctx.guild.id}"]

        if self.msg is not None:
            try:
                await self.msg.edit(content="Session cancelled.", embed=None)
            except discord.HTTPException:
                pass

            try:
                await self.msg.clear_reactions()
            except discord.HTTPException:
                try:
                    await self.msg.delete()
                except discord.HTTPException:
                    pass

    def check(self, payload):
        return (str(payload.emoji) in self.controls
                and payload.user_id == self.ctx.author.id
                and payload.message_id == self.msg.id)

    def make_embed(self):
        embed = discord.Embed(description=self.render_map())

        embed.add_field(
            name="Current tile",
            value=f"You landed on a **{self.original_map[self.current_pos[0]][self.current_pos[1]]}** tile!"
        )

        return embed

    @control("\U000025b6")
    def right(self):
        if not self.current_pos[1] == (len(self.original_map[self.current_pos[0]]) - 1):
            self.current_pos[1] += 1

    @control("\U0001f53d")
    def down(self):
        if not self.current_pos[0] == (len(self.map_copy) - 1):
            self.current_pos[0] += 1

    @control("\U000025c0")
    def left(self):
        if not self.current_pos[1] == 0:
            self.current_pos[1] -= 1

    @control("\U0001f53c")
    def up(self):
        if not self.current_pos[0] == 0:
            self.current_pos[0] -= 1

    @control("\U000023f9")
    async def stop(self):
        await self.cancel()

    async def task(self):
        self.map_copy[0][0] = 200

        self.msg = await self.ctx.send(embed=self.make_embed())

        for reaction in sorted(self.controls.keys(), reverse=True):
            await self.msg.add_reaction(reaction)

        while True:
            payload = await self.ctx.bot.wait_for("raw_reaction_add", check=self.check)

            pos = self.current_pos
            self.map_copy[pos[0]][pos[1]] = self.original_map[pos[0]][pos[1]]

            func = self.controls[str(payload.emoji)]

            if inspect.iscoroutinefunction(func):
                await func()
            else:
                func()

            self.map_copy[self.current_pos[0]][self.current_pos[1]] = 200

            await self.msg.edit(embed=self.make_embed())

    def render_map(self):
        fmt = ""

        for line in self.map_copy:
            for tile in line:
                if tile == 200:
                    fmt += "<:player:609140893563355137>"
                    continue
                fmt += f"{tile}\N{combining enclosing keycap}"
            fmt += "\n"

        return fmt


"""quarantine URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.conf.urls import include
from django.contrib import admin
from django.urls import path
from . import settings
from website import views

from django.contrib.staticfiles.urls import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.views.static import serve
from django.conf.urls import url

urlpatterns = [

    path('x', views.login, name='login'),
    path('admin/', admin.site.urls),
    path('', views.home_view, name='home'),
    path('login/', views.login, name='login'),
    path('home/', views.home_view, name='home'),
    path('success/', views.success, name='success'),
    path('unsuccessful/', views.unsuccessful, name='unsuccessful'),
    path('success1/', views.success1, name='success1'),
    path('room/success/', views.success1, name='success1'),
    path('accounts/', include('allauth.urls')),
    path('accounts/login/login', views.home_view,name="home"),
    path('host/rooms', views.roomRegistration_view, name='rooms'),
    path('view/mumbai', views.mumbai_view,name='houses'),
    path('view/bangalore', views.bangalore_view,name='houses'),
    path('view/delhi', views.delhi_view,name='houses'),
    path('view/pune', views.pune_view,name='houses'),
    path('dashboard/', views.dashboard_view,name='dashboard'),
    path('room/<int:pk>', views.RoomBookingView.as_view(), name='room-detail'),
    path('test', views.test_view,name='test'),
    path('confirm',views.confirm,name='confirm'),
    path('covidtracker', views.covidView,name='covidtracker'),
    url(r'^media/(?P<path>.*)$', serve,{'document_root':       settings.MEDIA_ROOT}),
    url(r'^static/(?P<path>.*)$', serve,{'document_root': settings.STATIC_ROOT}),

]

urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


import io

from telegram import Update, CallbackQuery
from telegram.ext import ContextTypes, CallbackContext
from telegram.error import Forbidden

from Constants.Env import ID_ADMIN
from Models.User import User
from Models.Reservation import Reservation

class AdminController:

    # Verify if this user is admin
    @staticmethod
    def is_from_admin(user_id) -> bool:
        return user_id == ID_ADMIN

    # Comunication with users
    async def forward_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
        id = update.effective_user.id
        if( not AdminController.is_from_admin(id) ):
            return
        for chat_id in User.get_all_users_chat_id():
            (user_id,) = chat_id
            try:
                await context.bot.send_message( chat_id=user_id, text=update.message.text.removeprefix("/forward "))
            except Forbidden:
                print(f"User blocked the bot : {update.effective_user.id}")

    async def forward_message_and_clean_reservations(update: Update, context: ContextTypes.DEFAULT_TYPE):
        id = update.effective_user.id
        if( not AdminController.is_from_admin(id) ):
            return

        Reservation.clean()
        for chat_id in User.get_all_users_chat_id():
            (user_id,) = chat_id
            try:
                await context.bot.send_message( chat_id=user_id, text=update.message.text.removeprefix("/forward_clean "))
            except Forbidden:
                print(f"User blocked the bot : {update.effective_user.id}")

    # Admin Utilities
    async def clean(update: Update, context: ContextTypes.DEFAULT_TYPE):
        id = update.effective_user.id
        if( not AdminController.is_from_admin(id) ):
            return
        Reservation.clean()

    async def get_locations(update: Update, context: ContextTypes.DEFAULT_TYPE):
        locations = Reservation.get_all_locations()
        answer = "ðŸŒ‰ Puentes a parar:\n --------------------------------------\n"
        for location, in locations:
            answer += f"- {location}\n"
        await update.message.reply_text(answer)

    async def get_list_reservation(update: Update, context: ContextTypes.DEFAULT_TYPE):
        all_reservation = Reservation.get_all_reservations()
        answer = "ðŸŸ© Listado de reservas \nOrden | Nombre | Puente | Reservado por \n --------------------------------------------------\n"
        for reservation in all_reservation:
            order, name, location, reserved_by = reservation
            answer += f"{order}  {name} || Puente: {location} || Por {reserved_by}\n"
        await update.message.reply_text(answer)

    @staticmethod
    async def get_list_reservation_file(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        all_reservation = Reservation.get_all_reservations()
        answer = "ðŸŸ© Listado de reservas \nOrden | Nombre | Puente \n --------------------------------------------------\n"
        for reservation in all_reservation:
            order, name, location, *rest = reservation
            answer += f"{order}  {name} || Puente: {location}\n"

        list_txt = io.BytesIO(answer.encode())
        list_txt.name = "Lista.txt"
        await update.message.reply_document(document=list_txt, filename="Lista Guagua Pinar")


import numpy as np

from torch import nn

from .ode_solvers import euler_step
from .neural_ode_solvers import AdjointODE

class ResidualBlock(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(ResidualBlock, self).__init__()
        stride = (1, 1)
        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=(3, 3),
                               stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=(3, 3),
                               stride=(1, 1), padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channels)

    def forward(self, x):
        residual = x
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        out += residual
        out = self.relu(out)
        return out

class ODEResFunc(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(ODEResFunc, self).__init__()
        stride = (1, 1)
        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=(3, 3),
                               stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=(3, 3),
                               stride=(1, 1), padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channels)

    def forward(self, x):
        x = x[1]
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)
        return out

class ODEBlock(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(ODEBlock, self).__init__()
        ode_solver = euler_step
        timestamps = np.linspace(0, 1., 11)
        self.neural_ode = AdjointODE(ode_func=ODEResFunc(in_channels, out_channels),
                                     timestamps=timestamps,
                                     ode_solver=ode_solver)

    def forward(self, x):
        self.neural_ode(x)
        return x

class MNISTClassifier(nn.Module):
    def __init__(self, block_type, channels=(1, 64, 64, 128, 128, 10)):
        super(MNISTClassifier, self).__init__()
        stride = (1, 1)
        self.conv1 = nn.Conv2d(channels[0], channels[1], kernel_size=(3, 3),
                               stride=stride, padding=1, bias=False)

        self.layer1 = nn.Sequential(
            block_type(channels[1], channels[1]),
            block_type(channels[1], channels[1]))

        self.maxpool1 = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2), padding=(1, 1), dilation=1, ceil_mode=False)

        self.conv2 = nn.Conv2d(channels[1], channels[2], kernel_size=(3, 3),
                               stride=stride, padding=1, bias=False)
        self.layer2 = nn.Sequential(
            block_type(channels[2], channels[2]),
            block_type(channels[2], channels[2]))

        self.maxpool2 = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2), padding=(1, 1), dilation=1, ceil_mode=False)

        self.conv3 = nn.Conv2d(channels[2], channels[3], kernel_size=(3, 3),
                               stride=stride, padding=1, bias=False)
        self.layer3 = nn.Sequential(
            block_type(channels[3], channels[3]),
            block_type(channels[3], channels[3]))

        self.maxpool3 = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2), padding=(1, 1), dilation=1, ceil_mode=False)

        self.conv4 = nn.Conv2d(channels[3], channels[4], kernel_size=(3, 3),
                               stride=stride, padding=1, bias=False)

        self.layer4 = nn.Sequential(
            block_type(channels[4], channels[4]),
            block_type(channels[4], channels[4]))

        self.maxpool4 = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2), padding=(1, 1), dilation=1, ceil_mode=False)

        self.avgpool = nn.AdaptiveAvgPool2d(output_size=1)
        self.dropout = nn.Dropout(0.5)

        self.fc = nn.Linear(channels[4], channels[5])
        self.softmax = nn.LogSoftmax(dim=-1)

    def forward(self, x):
        out = self.conv1(x)
        out = self.layer1(out)
        out = self.maxpool1(out)

        out = self.conv2(out)
        out = self.layer2(out)
        out = self.maxpool2(out)

        out = self.conv3(out)
        out = self.layer3(out)
        out = self.maxpool3(out)

        out = self.conv4(out)
        out = self.layer4(out)
        out = self.maxpool4(out)

        out = self.avgpool(out)
        out = self.dropout(out)
        out = out[:, :, 0, 0]
        out = self.fc(out)
        out = self.softmax(out)
        return out


from airflow import DAG
from datetime import datetime, timedelta
from airflow.operators.python_operator import PythonOperator
import time
default_args = {
    'owner': 'airflow',
    'depends_on_past': False,
    'start_date': datetime(2018, 9, 13),
    'email': ['airflow@example.com'],
    'email_on_failure': False,
    'email_on_retry': False,
    'retries': 1,
    'retry_delay': timedelta(minutes=1),
}

dag = DAG(
    'hello_world2', default_args=default_args, schedule_interval=None)

def print_context():
    with open('/storage/1.txt','a') as a:
        a.write("Executed"+str(datetime.now()))
    return 'Whatever you return gets printed in the logs'

def task1():
    time.sleep(15)
    return 'task1'

def task2():
    time.sleep(20)
    return 'task2'

def joinTask(**context):
    print("Hi")
    ti = context['ti']
    print("task1: ",ti.xcom_pull(task_ids='task1'))
    print("task2: ",ti.xcom_pull(task_ids='task2'))
    return None

t1 = PythonOperator(
    task_id='print_the_context',
    python_callable=print_context,
    dag=dag)
t2 = PythonOperator(
    task_id='task1',
    python_callable=task1,
    dag=dag)
t3 = PythonOperator(
    task_id='task2',
    python_callable=task2,
    dag=dag)
t4 = PythonOperator(
    task_id='joinTask',
    python_callable=joinTask,
    provide_context=True,
    dag=dag)
t1>>t2
t1>>t3
t2>>t4
t3>>t4


# pyright: strict

from dataclasses import dataclass

from ....refdata import Facts
from ....utils import div, MILLION
from ....common.invest import Invest

@dataclass(kw_only=True)
class GGridOnshoreOrPV(Invest):
    invest_per_x: float = 0
    pct_of_wage: float = 0
    ratio_wage_to_emplo: float = 0
    power_to_be_installed: float = 0
    cost_mro: float = 0

    @classmethod
    def calc(
        cls,
        facts: Facts,
        duration_until_target_year: int,
        power_to_be_installed: float,
        invest_per_x: float,
        mro: float,
    ) -> "GGridOnshoreOrPV":
        fact = facts.fact

        pct_of_wage = fact("Fact_B_P_constr_main_revenue_pct_of_wage_2017")
        ratio_wage_to_emplo = fact("Fact_B_P_constr_main_ratio_wage_to_emplo_2017")
        invest = power_to_be_installed * invest_per_x
        cost_mro = invest * mro / MILLION
        invest_pa = invest / duration_until_target_year
        cost_wage = invest_pa * pct_of_wage
        demand_emplo = div(cost_wage, ratio_wage_to_emplo)
        demand_emplo_new = demand_emplo

        return cls(
            cost_wage=cost_wage,
            demand_emplo=demand_emplo,
            demand_emplo_new=demand_emplo_new,
            invest=invest,
            invest_pa=invest_pa,
            invest_per_x=invest_per_x,
            pct_of_wage=pct_of_wage,
            ratio_wage_to_emplo=ratio_wage_to_emplo,
            power_to_be_installed=power_to_be_installed,
            cost_mro=cost_mro,
        )


import csv
import json
from collections import Counter

def paisSelva():
    archivo_csv= open("areaselvatica.csv","r",encoding="utf-8")
    csvreader = csv.reader(archivo_csv, delimiter=",")

    archivo_json = open("archivoJsonS.txt","x")
    dic={}

    for linea in csvreader:
        if linea[61] !="":
            dic[linea[0]]=float(linea[61])
    dic = Counter(dic)

    json.dump(dic.most_common(11), archivo_json)

    archivo_csv.close()

    archivo_json.close()

def paisRural():

    archivo_csv = open("rural.csv","r",encoding="utf-8")
    csvreader = csv.reader(archivo_csv, delimiter=",")

    archivo_json = open("archivoJsonR.txt","x")

    for linea in csvreader:
        if linea[62] !="":
            if int(linea[62])>60000000:
                json.dump(linea[0], archivo_json)

    archivo_csv.close()

    archivo_json.close()


import networkx as nx

def cal_degree_distribution(graph):
    '''
    计算度分布
    '''
    degree_count = {}
    for i in range(nx.number_of_nodes(graph)):
        deg = graph.degree(i)
        if deg in degree_count: degree_count[deg] += 1
        else: degree_count[deg] = 1
    degree_count = sorted(degree_count.items())
    ave = nx.number_of_edges(graph) * 2 / nx.number_of_nodes(graph)

    with open('result/degree_distribution.txt', 'w', encoding = 'utf-8') as out_file:
        print('The average of degree:%.2f'%ave, file = out_file)
        for l in degree_count:
            print('%3d : %4d'% (l[0], l[1]), file = out_file)

def cal_views_distribution(node_info):
    '''
    计算views属性的分布
    '''
    views_count = {}
    total = 0
    for node in node_info:
        total += int(node['views'])
        views = int(node['views']) // 1000
        if views in views_count: views_count[views] += 1
        else: views_count[views] = 1
    ave = total / len(node_info)
    count_list = sorted(views_count.items())

    with open('result/views_distribution.txt', 'w', encoding = 'utf-8') as out_file:
        print('The average of views:%.2f'%ave, file = out_file)
        for l in count_list:
            print('%dK-%dK : %d' % (l[0], l[0] + 1,  l[1]), file = out_file)


#!/usr/bin/env python3

from sys import argv, exit
from svgnarrative import Model
import json

earth_prefix = 'earth'

def read_description (filename):
    with open(filename) as fo:
        return json.load(fo)

# handle command-line arguments
if len(argv) != 6:
    print('Syntax: %s PATH_TO_JSON_DESCRIPTION PATH_TO_TEMPLATE PATH_TO_MAP PATH_TO_ROAST OUTPUT_FILENAME' % argv[0])
    print('        %s ../var/coffees/kenya_matunda.json ../var/templates/default.svg ../var/templates/roast.svg ../var/templates/World_map_blank_with_blue_sea.svg kenya_matunda.svg' % argv[0])
    exit(1)
description_filename = argv[1]
template_filename    = argv[2]
map_filename         = argv[3]
roast_filename       = argv[4]
output_filename      = argv[5]

template    = Model(template_filename)
earth       = Model(map_filename)
roast       = Model(roast_filename)
description = read_description(description_filename)

template.set_text('name', description['name'])
template.insert(earth, earth_prefix, 15, 10, 0.03)
template.fill(map(lambda o: '%s%s' % (earth_prefix, o), description['origin']), '#880000')
for i in range(2):
    roast_prefix = 'roast%d' % i
    template.insert(roast, roast_prefix, 5, 60+70*i)
    template.set_text('%stspan2411-1-5'%roast_prefix, description['date'] if 'date' in description else '')

    for j in range(1, 6):
        template.set_text('%stemp%d'%(roast_prefix, j), '')

    for j in range(1, 5):
        template.set_text('%stime%d'%(roast_prefix, j), '')

template.store(output_filename)


import simpy
import random
from collections import deque

from framework.utils import Location
from framework.Node import Node, EnergyProfile
from framework.Gateway import Gateway
from framework.TransmissionInterface import AirInterface
from framework.Backend import Server, Application
from framework.LoRaParameters import LoRaParameters
from framework.Environment import *
import os.path
import pickle

class Simulation:
    ENVIRONMENT_TYPE = ["temp"]

    def __init__(self, nodes_positions, gateway_positions, step_time, connection, config_name, distance, num_steps, environment="temp", offset=2000, update_rate = UPDATA_RATE):
        self.nodes = []
        self.gateways = []
        assert step_time >= offset + 3000
        self.step_time = step_time
        self.offset = offset
        self.steps = 0
        self.name = config_name + "_update_" + str(update_rate)
        self.update_rate = update_rate
        self.num_steps = num_steps
        self.sim_env = simpy.Environment()
        self.channel_nodes = {}
        for channel in range(Gateway.NO_CHANNELS):
            self.channel_nodes[channel] = []
        assert environment in Simulation.ENVIRONMENT_TYPE
        if environment == "temp":
            self.environment = TempEnvironment( Location(distance, -distance),
                                               Location(-distance, distance), 296.15, self.num_steps * self.step_time, update_rate, dx=GRID)
        else:
            assert False, "%s environment is not implemented" %(environment)
        link = []
        for loc in connection:
            for l2 in connection[loc]:
                link.append([nodes_positions.index(loc), nodes_positions.index(l2)])
        self.app = Application(list(range(len(nodes_positions))), link, update_rate)
        self.server = Server(self.gateways, self.sim_env, self.app)
        self.air_interface = AirInterface(self.sim_env, self.gateways, self.server)
        config_file = './config/'+config_name+'_lora_'+ str(Gateway.NO_CHANNELS) +'.pickle'
        lora_para_exist = False
        # if os.path.exists(config_file):
        if False:
            lora_para = pickle.load(open(config_file, 'rb'))
            lora_para_exist = True
        else:
            lora_para_exist = True
            lora_para = [ LoRaParameters(i % Gateway.NO_CHANNELS, sf=9 + i %2) for i in range(len(nodes_positions))]
        for i in range(len(nodes_positions)):
            node = Node(i, EnergyProfile(0.1), lora_para[i],
                                   self.air_interface, self.sim_env, nodes_positions[i], True)
            self.channel_nodes[lora_para[i].channel].append(node)
            node.last_payload_sent = self.environment.sense(nodes_positions[i], self.sim_env.now)
            self.nodes.append(node)
        for i in range(len(gateway_positions)):
            self.gateways.append(Gateway(i, gateway_positions[i], self.sim_env))

        self.constructed_field = {}
        self.real_field = {}
        self.temp_field = None

        if not lora_para_exist:
            print("Start generating new lora configuration file for " + config_name)
            self.pre_adr(1000, True, percentage=0.4)
            pickle.dump([n.para for n in self.nodes], open(config_file, 'wb'))
            self.reset()

    def node_states(self, *args, **kwargs):
        return list(a.get_status(*args, **kwargs) for a in self.nodes)

    def step(self, actions):
        assert len(self.nodes) == len(actions)
        assert self.sim_env.now == self.steps * self.step_time
        self.constructed_field = self.field_reconstruction()
        self.temp_field = self.environment.T_field[int(self.sim_env.now//self.update_rate)]
        self.steps += 1
        send_index = [idx for idx, send in enumerate(actions) if send]
        for i in range(len(self.nodes)):
            self.sim_env.process(self._node_send_sensed_value(i, actions[i]))
        self.sim_env.run(self.step_time * self.steps)
        received = []
        for i in send_index:
            if self.nodes[i].packet_to_send.received:
                received.append(i)
                # if self.nodes[i].last_payload_change:
                #     reward += np.exp(-20/np.absolute(self.nodes[i].last_payload_change))
        return send_index, received

    def _node_send_sensed_value(self, node_index, send):
        node = self.nodes[node_index]
        value = node.sense(self.environment)
        self.real_field[node_index] = value
        time = self.sim_env.now
        yield self.sim_env.timeout(np.random.randint(self.offset))
        if send:
            packet = node.create_unique_packet({'value':value, 'time': time}, False, False)
            yield self.sim_env.process(node.send(packet))
        yield self.sim_env.timeout(self.step_time * self.steps - self.sim_env.now)

    def _node_send_test(self, node_index):
        yield self.sim_env.timeout(np.random.randint(self.offset))
        node = self.nodes[node_index]
        packet = node.create_unique_packet(None, True, True)
        yield self.sim_env.process(node.send(packet))
        yield self.sim_env.timeout(self.step_time * self.steps - self.sim_env.now)

    def pre_adr(self, rounds: int, show=False, percentage=0.8):
        assert rounds > 50
        N = int(len(self.nodes) * percentage)
        for i in range(len(self.nodes)):
            self.nodes[i].adr = True
        record_per = []
        for i in range(rounds):
            assert self.sim_env.now == self.steps * self.step_time
            self.steps += 1
            send = []
            for channel in self.channel_nodes:
                list_of_nodes = self.channel_nodes[channel]
                send.extend(random.sample(list_of_nodes, int(percentage*len(list_of_nodes))))
            send_node = [n.id for n in send]
            for j in send_node:
                self.sim_env.process(self._node_send_test(j))
            self.sim_env.run(self.step_time * self.steps)
            count = 0
            for j, idx in enumerate(send_node):
                if self.nodes[idx].last_packet_success:
                    count += 1
            record_per.append(1 - count/len(send_node))
        latest_per = record_per[-50:]

        count = 0
        threshold = 0.3
        while not self._check_adr_convergence(latest_per, threshold):
            for i in range(50):
                assert self.sim_env.now == self.steps * self.step_time
                self.steps += 1
                send_node = random.sample(range(len(self.nodes)), N)
                for j in send_node:
                    self.sim_env.process(self._node_send_test(j))
                self.sim_env.run(self.step_time * self.steps)
                count = 0
                for j, idx in enumerate(send_node):
                    if self.nodes[idx].last_packet_success:
                        count +=1
                latest_per[i] = 1 - count/len(send_node)
            count += 1
            if count == int(10/percentage) or count == 30:
                self.reset(True)
                plt.figure(figsize=(5, 5))
                plt.scatter(range(len(record_per)), record_per)
                plt.title("Running ADR...")
                plt.xlabel("iterations")
                plt.ylabel("Packet error rate")
                plt.show()
                return self.pre_adr(rounds, show, percentage)
            record_per.extend(latest_per)
        if np.average(record_per[-50:-1]) > 0.6:
            self.reset(True)
            plt.figure(figsize=(5, 5))
            plt.scatter(range(len(record_per)), record_per)
            plt.title("Running ADR...")
            plt.xlabel("iterations")
            plt.ylabel("Packet error rate")
            plt.show()
            return self.pre_adr(rounds, show, percentage)
        if show:
            plt.figure(figsize=(5,5))
            plt.scatter(range(len(record_per)), record_per)
            plt.title("Running ADR...")
            plt.xlabel("iterations")
            plt.ylabel("Packet error rate")
        for i in range(len(self.nodes)):
            self.nodes[i].adr = False
        return record_per

    def reset(self, reset_lora=False):
        self.sim_env = simpy.Environment()
        self.steps = 0
        for i in range(len(self.nodes)):
            self.nodes[i].reset(self.sim_env)
            self.nodes[i].last_payload_sent = self.environment.sense(self.nodes[i].location, 0)
            if reset_lora:
                self.nodes[i].para = LoRaParameters(i % Gateway.NO_CHANNELS, sf=12)
        for i in range(len(self.gateways)):
            self.gateways[i].reset(self.sim_env)
        self.server.reset(self.sim_env)
        self.air_interface.reset(self.sim_env)

    def _check_adr_convergence(self, mean, difference):
        return np.max(mean) - np.min(mean) < difference

    def field_reconstruction(self):
        prediction = self.app.fusion_center.field_reconstruct(self.step_time * (self.steps))
        return prediction

    def eval_positive(self):
        diff = np.fromiter(self.real_field.values(), dtype=float)- np.fromiter(self.constructed_field.values(), dtype=float)
        return diff


import ujson
from aioredis import Redis
from constants.redis_key import JingXi
from app.deps import Depend
from app.schemas.response import CommonResponse, EmptyResponse
from app.src.jingxi.keyword_search import KeywordSearch
from fastapi import APIRouter

router = APIRouter(prefix="/jingxi", tags=["jingxi"])

@router.get("/keywordSearch", response_model=CommonResponse, name="关键词搜索")
async def keyword_search(
    keyword: str, page: int = 1, cache: Redis = Depend.redis30, session=Depend.session
):
    cache_key = f"{keyword}-{page}"
    data = await cache.hget(JingXi.KEYWORD_SEARCH_CACHE_HASH, cache_key)
    if data:
        return ujson.loads(data)
    else:
        KS = KeywordSearch(session)
        res = await KS.request(keyword, page)
        if res:
            content = CommonResponse(data=res.json())
            await cache.hset(
                JingXi.KEYWORD_SEARCH_CACHE_HASH, cache_key, content.json()
            )
            return content
        return EmptyResponse()


#!/usr/bin/env python3
import pandas as pd
import numpy as np
from math import sqrt
from stats_loader import load_stats
from profile_loader import load_profile
import time as pytime
import argparse
from preprocess import *
import sys

better_than = 0.2  # 1=go fixed if time is less than float, 0.5 if time is half then float, etc.

def load_data_onlystats(path, features=None):
	new_features, d3 = load_data_phase1(path)

	if not features:
		features = new_features

	print(features, file=sys.stderr)
	for f in features:
		if f not in d3.columns.values:
			d3[f] = 0.

	print(d3.loc[:, features].shape, file=sys.stderr)
	return d3.fillna(0), features

def load_data(path, features=None, response=None, boostfail=0):
	d3, features = load_data_onlystats(path, features)

	d3['ratio'] = d3['flo_T'] / d3['fix_T']
	w1 = d3['fix_T'] < (d3['flo_T'] * better_than)
	w2 = d3['fix_T'] < (d3['flo_T'])
	# d3['worth']=w1.astype(int)+w2.astype(int)-1
	# d3['worth']=d3['fix_T'] < (d3['flo_T'])
	d3['worth'] = ((d3['ratio'] - 1.0) / 0.2).astype(int).clip(-1, 1)
	# d3['worth'] = w1

	if boostfail > 0:
		for rowi in d3.index:
			if int(d3.loc[rowi, 'worth']) < 1:
				row = d3.loc[rowi, :]
				for repi in range(0, boostfail):
					cprow = row.copy()
					cprow.name = (cprow.name[0] + '_c' + str(repi), cprow.name[1])
					d3 = d3.append(cprow)

	# print d3['ratio'], d3['worth']
	print('<20%', sum(w1), 'of', len(d3['worth']))
	print('<100%', sum(w2) - sum(w1), 'of', len(d3['worth']))
	print('>100%', len(d3['worth']) - sum(w2), 'of', len(d3['worth']))

	if not response:
		response = ['worth']

	print(d3.loc[:, response].shape, file=sys.stderr)
	return d3.fillna(0), features, response

def split_train_test(d3):
	msk = [n < 0.8 * len(d3) for n in range(0, len(d3))]
	np.random.shuffle(msk)
	train = d3[msk]
	test = d3[[not v for v in msk]]
	return train, test

def do_test_prediction(fitr, test, features, response, oneatatime):
	if not oneatatime:
		benchs = [test.index]
	else:
		benchs = [[x] for x in test.index]
	results, times = [], []
	for bench in benchs:
		res = fitr.score(test.loc[bench, features], np.ravel(test.loc[bench, response]))
		t0 = pytime.time()
		pred = fitr.predict(test.loc[bench, features])
		t1 = pytime.time()
		print('Predict', bench, pred)
		print('Actual', np.ravel(test.loc[bench, response]))
		results += [res]
		times += [t1 - t0]
	return results, times

def train_adaboost(train, features, response):
	from sklearn.ensemble import AdaBoostClassifier
	regr = AdaBoostClassifier(n_estimators=100)
	fitr = regr.fit(train.loc[:, features], np.ravel(train.loc[:, response]))
	return fitr

def train_gradient(train, features, response):
	from sklearn.ensemble import GradientBoostingClassifier
	regr = GradientBoostingClassifier(max_features=int(sqrt(len(features))))
	fitr = regr.fit(train.loc[:, features], np.ravel(train.loc[:, response]))
	return fitr

def train_extree(train, features, response):
	from sklearn.ensemble import ExtraTreesClassifier
	regr = ExtraTreesClassifier(max_features=int(sqrt(len(features))))
	fitr = regr.fit(train.loc[:, features], np.ravel(train.loc[:, response]))
	return fitr

def train_bagging(train, features, response):
	from sklearn.ensemble import BaggingClassifier
	regr = BaggingClassifier(max_features=int(sqrt(len(features))))
	fitr = regr.fit(train.loc[:, features], np.ravel(train.loc[:, response]))
	return fitr

def train_randomforest(train, features, response):
	from sklearn.ensemble import RandomForestClassifier
	regr = RandomForestClassifier(max_features=int(sqrt(len(features))))
	fitr = regr.fit(train.loc[:, features], np.ravel(train.loc[:, response]))
	return fitr

def train_multilayerperceptron(train, features, response):
	from sklearn.neural_network import MLPClassifier
	regr = MLPClassifier(solver='lbfgs', alpha=1e-5,
						 hidden_layer_sizes=(int(len(features) / 2), int(len(features) / 8)), random_state=1)
	fitr = regr.fit(train.loc[:, features], np.ravel(train.loc[:, response]))
	return fitr

def train_svc(train, features, response):
	from sklearn.svm import SVC
	regr = SVC()
	fitr = regr.fit(train.loc[:, features], np.ravel(train.loc[:, response]))
	return fitr


import gzip
import json
import os
import time
from pathlib import Path

import boto3

COGNITO_STAGING_POOL = os.getenv("COGNITO_STAGING_POOL", "eu-west-1_mAQcge0PR")

DATA_LOCATION = os.getenv("BIOMAGE_DATA_PATH", "./data")
PULL = "PULL"

class Summary(object):
    """
    Utility singleton class used to report which files have been updated as a result of
    a given data management command.
    """

    changed_files = []
    cmd = ""
    origin = ""
    experiment_id = ""

    @classmethod
    def set_command(cls, cmd, origin, experiment_id):
        cls.cmd = cmd
        cls.origin = origin
        cls.experiment_id = experiment_id

    @classmethod
    def add_changed_file(cls, file):
        cls.changed_files.append(file)

    @classmethod
    def report_changes(cls):
        print(f"From {cls.origin}")
        print(f" * experiment {cls.experiment_id:^40s} -> {cls.cmd:>10s}")

        if len(cls.changed_files) < 1:
            print("Already up to date.")
            return

        print("Changes:")
        for file in cls.changed_files:
            print(f"{file:<70s} | Updated")

def save_cfg_file(dictionary, dst_file):
    local_file = os.path.join(DATA_LOCATION, dst_file)

    # try to create experiment folder, ignores if already exists (same as mkdir -p)
    Path(os.path.dirname(local_file)).mkdir(parents=True, exist_ok=True)

    with open(local_file, "w") as f:
        # We sort & indent the result to make it easier to inspect & debug the files
        # neither sorting nor indentation is used to check if two confis are equal
        json.dump(dictionary, f)

# If the config file was found => retun  (config file, true)
# Otherwise => (None, False)
def load_cfg_file(file):
    filepath = os.path.join(DATA_LOCATION, file)
    if os.path.exists(filepath) and not os.path.getsize(filepath) == 0:
        with open(os.path.join(DATA_LOCATION, file)) as f:
            return json.load(f), True

    return None, False

def set_modified_date(file_location, date):
    """
    Change the last-modified file parameter to date
    """
    mod_time = time.mktime(date.timetuple())

    os.utime(file_location, (mod_time, mod_time))

def get_local_S3_path(key):
    return os.path.join(DATA_LOCATION, key)

def is_modified(obj, key):
    """
    We check if the file in S3 has changed by comparing the last modified date
    which should be enough for our goals.
    Using E-tags would require either to download the file anyway to compute it or
    storing them in a local DB which seemed too complex. Moreover, there isn't a
    standard e-tag computation readily available and they can change among buckets,
    regions, etc...
    so it does not seem worth it.
    """
    local_file = get_local_S3_path(key)

    if not os.path.exists(local_file):
        return True

    if int(obj.last_modified.strftime("%s")) != int(os.path.getmtime(local_file)):
        return True

    return False

def download_S3_rds(s3_obj, key, filepath):
    local_file = get_local_S3_path(filepath)

    # try to create experiment folder, ignores if already exists (same as mkdir -p)
    Path(os.path.dirname(local_file)).mkdir(parents=True, exist_ok=True)

    with gzip.open(local_file, "wb") as f:
        f.write(s3_obj.get()["Body"].read())

    set_modified_date(file_location=local_file, date=s3_obj.last_modified)

def download_S3_json(s3_obj, key, filepath):
    local_file = get_local_S3_path(filepath)

    # try to create experiment folder, ignores if already exists (same as mkdir -p)
    Path(os.path.dirname(local_file)).mkdir(parents=True, exist_ok=True)

    s3_obj.download_file(local_file)

    set_modified_date(file_location=local_file, date=s3_obj.last_modified)

def get_cognito_username(email):
    client = boto3.client("cognito-idp")
    user_name = client.admin_get_user(Username=email, UserPoolId=COGNITO_STAGING_POOL)[
        "Username"
    ]

    return user_name

def get_experiment_project_id(experiment_id, source_table):

    table = boto3.resource("dynamodb").Table(source_table)

    project_id = table.get_item(
        Key={"experimentId": experiment_id}, ProjectionExpression="projectId"
    ).get("Item")["projectId"]

    return project_id

def add_user_to_rbac(user_name, cfg):
    if "rbac_can_write" in cfg:
        if user_name not in cfg["rbac_can_write"]["SS"]:
            cfg["rbac_can_write"]["SS"].append(user_name)
    for val in cfg.values():
        if isinstance(val, dict):
            add_user_to_rbac(user_name, val)

def add_env_user_to_experiment(cfg):
    email = os.getenv("BIOMAGE_EMAIL")
    if not email:
        raise ValueError(
            "biomage email not available to patch experiment permissions."
            + ' Set the environment variable "BIOMAGE_EMAIL" with the email you use to log in into cellenics'
            + " and try again."
        )

    user_name = get_cognito_username(email=email)

    add_user_to_rbac(user_name=user_name, cfg=cfg)

    return cfg


from VascularGenerator import VascularGenerator
from VasGen2 import VasGen2
from equations import *
from diffu2D_u0 import lab_meat_diffuse
import os
import math
import matplotlib.pyplot as plt

import random

import imageio
from natsort import natsorted, ns
from sklearn.preprocessing import minmax_scale

import autograd.numpy as np
from autograd import grad
from autograd.scipy.integrate import odeint
from autograd.builtins import tuple
from autograd.misc.optimizers import adam
import autograd.numpy.random as npr
import autograd.scipy.signal as sig
from timeit import default_timer as timer

def sigmoid(x):
    return 1 / (1 + math.exp(-x))

def gaussian(x):
    return math.exp(-x**2)

def create_remove_imgs():
    path_to_diffuse_pngs = 'Hillclimb/diffusePngs/'
    sim_img_folder = 'Hillclimb/imgs/'
    sim_graph_folder = 'Hillclimb/graphs/'
    sim_fig_folder = 'Hillclimb/figs/'
    if not os.path.exists(path_to_diffuse_pngs):
        os.makedirs(path_to_diffuse_pngs)

    if not os.path.exists(sim_img_folder):
        os.makedirs(sim_img_folder)

    if not os.path.exists(sim_graph_folder):
        os.makedirs(sim_graph_folder)

    if not os.path.exists(sim_fig_folder):
        os.makedirs(sim_fig_folder)

    for img_file in os.listdir(path_to_diffuse_pngs):
        os.remove(path_to_diffuse_pngs + img_file)

    if os.path.exists(sim_img_folder):
        for img_file in os.listdir(sim_img_folder):
            os.remove(sim_img_folder + img_file)

    if os.path.exists(sim_graph_folder):
        for img_file in os.listdir(sim_graph_folder):
            os.remove(sim_graph_folder + img_file)

    if os.path.exists(sim_fig_folder):
        for img_file in os.listdir(sim_fig_folder):
            os.remove(sim_fig_folder + img_file)

def get_submatrix_add(lst_matrix, center_pt_tuple, convolution, submatrix_size=2):
    w, h = len(lst_matrix), len(lst_matrix[0])
    orig_row, orig_col = center_pt_tuple
    row, col = orig_row, orig_col
    row_start = -1
    row_end = -1
    col_start = -1
    col_end = -1

    if row >= 0 and row < h:
        row_start = row - submatrix_size + 1 if (row - submatrix_size + 1) > 0 else 0
        row_end = row + submatrix_size if (row + submatrix_size) <= h else h
    elif row == h:
        row -= 1
        row_start = row - submatrix_size + 1 if (row - submatrix_size + 1) > 0 else 0
        row_end = row + submatrix_size if (row + submatrix_size) <= h else h
    elif row < 0 or row > h:
        print('Bad row dimension of ', row)

    if col >= 0 and col < w:
        col_start = col - submatrix_size + 1 if (col - submatrix_size + 1) > 0 else 0
        col_end = col + submatrix_size if (col + submatrix_size) <= w else w
    elif col == w:
        col -= 1
        col_start = col - submatrix_size + 1 if (col - submatrix_size + 1) > 0 else 0
        col_end = col + submatrix_size if (col + submatrix_size) <= w else w
    elif col < 0 or col > w:
        print('Bad col dimension of ', col)

    conv_row_start = 0
    conv_row_end = 3
    conv_col_start = 0
    conv_col_end = 3
    new_convolution = None

    if (orig_row - submatrix_size + 1) < 0:
        conv_row_start = 1
    if (orig_row + submatrix_size ) >= h:
        conv_row_end = 1

    if (orig_col - submatrix_size + 1) < 0:
        conv_col_start = 1
    if (orig_col + submatrix_size) >= w:
        conv_col_end = 1

    new_convolution = convolution[conv_row_start:conv_row_end][conv_col_start:conv_col_end]

    new_matrix = []
    for row_idx, lst_row in enumerate(lst_matrix):
        count = 0
        if row_idx >= row_start and row_idx < row_end and count < conv_col_end:
            val2 = new_convolution[conv_col_start + count]
            updated_lst_vals = [sum(x) for x in zip(lst_row[col_start:col_end], val2)]

            new_row=[]
            row_count = 0
            for cur_col_idx, val in enumerate(lst_row):
                if cur_col_idx >= col_start and cur_col_idx < col_end:
                    new_row.append(updated_lst_vals[0+row_count])
                    row_count = row_count + 1
                else:
                    new_row.append(val)

            count = count + 1
            lst_row = new_row

        new_matrix.append(lst_row)
    return new_matrix

def diffusion(mvble_pts, img):
    # D is the defusion constant
    # D = .225
    # B = D / 10
    D = 0.03
    B = D / 4
    # D = 0.00000001
    # B = D / 4

    #https://programtalk.com/python-examples/autograd.scipy.signal.convolve/
    for _ in range(0, 60): # how many times you run a diffusion update
        convolve = np.array([[1*D, 1*D, 1*D],[1*D,-8*D,1*D], [1*D, 1*D, 1*D]])
        deltaDiffusion = sig.convolve(np.array(img), convolve)[1:-1, 1:-1] #take off first and last
        # deltaDiffusion = deltaDiffusion + np.array(img)

        # the update to the img from one step of diffusion
        img = np.array(np.array(img) + np.array(deltaDiffusion) + np.array(nonlinearDiffusion(mvble_pts, img)))
        img = img - (B * img)

    np_img = np.array(img)
    mn, mx = np_img.min(), np_img.max()
    np_img = (np_img - mn) / (mx - mn)
    return np_img

# None linear diffusion (compute each convoution for each location)
def nonlinearDiffusion(mvble_pts, img):
    #http://greg-ashton.physics.monash.edu/applying-python-functions-in-moving-windows.html
    #https://stackoverflow.com/questions/12816293/vectorize-this-convolution-type-loop-more-efficiently-in-numpy
    h, w = np.array(img).shape
    deltaDomain2 = []
    for _ in range(w):
        deltaDomain2.append([0.0 for _ in range(h)])

    for i in range(len(mvble_pts)):
        pt = mvble_pts[i]
        x = pt[0]
        y = pt[1]
        int_x = 0
        int_y = 0

        if type(x) != type(np.array((1,1))) and type(x) != type(1):
            int_x = int(np.array(mvble_pts[i][0]))
            int_y = int(np.array(mvble_pts[i][1]))
        else:
            int_x = int(np.array(mvble_pts[i][0]))
            int_y = int(np.array(mvble_pts[i][1]))

        np_pt = np.array([x, y])

        inc = 0.5
        dist_0 = np.linalg.norm(np_pt - np.array([int_x-1 + inc, int_y-1 + inc]))
        dist_1 = np.linalg.norm(np_pt - np.array([int_x + inc, int_y-1 + inc]))
        dist_2 = np.linalg.norm(np_pt - np.array([int_x+1 + inc, int_y-1 + inc]))

        dist_3 = np.linalg.norm(np_pt - np.array([int_x-1 + inc, int_y + inc]))
        dist_4 = np.linalg.norm(np_pt - np.array([int_x + inc, int_y + inc]))
        dist_5 = np.linalg.norm(np_pt - np.array([int_x+1 + inc, int_y + inc]))

        dist_6 = np.linalg.norm(np_pt - np.array([int_x-1 + inc, int_y+1 + inc]))
        dist_7 = np.linalg.norm(np_pt - np.array([int_x + inc, int_y+1 + inc]))
        dist_8 = np.linalg.norm(np_pt - np.array([int_x+1 + inc, int_y+1 + inc]))

        X = -dist_0 - dist_1 - dist_2 - dist_3 - dist_5 - dist_6 - dist_7 - dist_8

        convolution = [[sigmoid(dist_0 - 1), sigmoid(dist_1 - 1), sigmoid(dist_2 - 1)], [sigmoid(dist_3 - 1), X, sigmoid(dist_5 - 1)], [sigmoid(dist_6 - 1), sigmoid(dist_7 - 1), sigmoid(dist_8 - 1)]]

        deltaDomain2 = get_submatrix_add(deltaDomain2, (int_x, int_y), convolution)

    return deltaDomain2

def create_loss_map(img, iter):
    h, w = np.array(img).shape
    loss_map = []
    for _ in range(w):
        loss_map.append([0.0 for _ in range(h)])

    ideal = np.ones(img.shape)[1:,1:]
    val = np.abs(ideal - img[1:,1:])
    return val

def loss_health(img, iter, vessel_points):
    threshold = 0.9
    # 2D array of neutrient values
    # sum of sigmoid values (high N is low low, low N is high loss)
    total_loss = 0.0
    for ix,iy in np.ndindex(img.shape):
        if vessel_points[(ix,iy)] > 0.0:
            val = img[ix,iy]
            loss = 1
            if val >= threshold:
                loss = 1/(1+img[ix,iy])
            total_loss += loss

    return total_loss

def adjustMoveRate(num):
    num = num/2
    if num < 0.2:
        if num > 0:
            num = 0.2
        elif num > -0.2:
            num = -0.2
    return num

def saveImageOne(iteration):
    fig.savefig('HillClimb/figs/' + str(iteration) + '.png', size=[1600,400])#, size=[1000,1000]) #, size=[700,700] IF 1000, renders each quadrant separately

if __name__ == "__main__":
    print("Climbing the hill")
    numNodes = 2
    path_to_diffuse_pngs = 'Hillclimb/diffusePngs/'
    sim_img_folder = 'Hillclimb/imgs/'
    sim_graph_folder = 'Hillclimb/graphs/'

    create_remove_imgs()

    vas_structure = VasGen2(max_range=20, num_of_nodes=numNodes, side_nodes=False)
    vas_structure.print_images(graph_name='HillClimb/HillClimb_startGraph.png', img_name='HillClimb/HillClimb_startImg.png')

    test_movement = np.array([-5, -2, -1, 0, 1, 2, 5])

    def fitness(fit_mvable_pts, iter):
        diffused_img = diffusion(fit_mvable_pts, img)
        return loss_health(diffused_img, iter, vas_structure.pts_on_vessels)

    flowDict = computeFlow(vas_structure)
    vas_structure.add_flows_to_img(flowDict)
    img = vas_structure.img
    diffused_img = img

    mvable_pts = vas_structure.moveable_pts

    all_loss = []
    time_lst = []

    fig = plt.figure(figsize=(16, 4), facecolor='white')

    ax_loss         = fig.add_subplot(151, frameon=True)
    ax_node_graph   = fig.add_subplot(152, frameon=True)

    ax_img          = fig.add_subplot(153, frameon=True)
    ax_diffused_img = fig.add_subplot(154, frameon=True)
    ax_loss_map     = fig.add_subplot(155, frameon=True)

    plt.show(block=False)
    count = 1
    imgcolorbar = None

    def callback(mvable_pts, iter):

        ####################################
        # LOSS as a function of TIME
        ax_loss.cla()
        ax_loss.set_title('Train Loss')
        ax_loss.set_xlabel('t')
        ax_loss.set_ylabel('loss')
        nowLoss = fitness(mvable_pts, iter)
        all_loss.append(nowLoss)
        time = np.arange(0, len(all_loss), 1)

        ax_loss.plot(time, all_loss, '-', linestyle = 'solid', label='loss') #, color = colors[i]
        ax_loss.set_xlim(time.min(), time.max())
        ax_loss.legend(loc = "upper left")

        ## Plots the Node Graph
        ax_node_graph.cla()
        ax_node_graph.set_title('Node Graph')
        for j, s in enumerate(vas_structure.tri.simplices):
            p = np.array(vas_structure.pts)[s].mean(axis=0)
            ax_node_graph.text(p[0], p[1], 'Cell #%d' % j, ha='center') # label triangles
        ax_node_graph.triplot(np.array(vas_structure.pts)[:,0], np.array(vas_structure.pts)[:,1], vas_structure.tri.simplices)
        ax_node_graph.plot(np.array(vas_structure.pts)[:,0], np.array(vas_structure.pts)[:,1], 'o')

        # ==== Plot Img Version ==== #
        ax_img.cla()
        imgcolorbar = None
        ax_img.set_title('Flow Image')
        ax_img.tick_params(axis='x', which='both', bottom=False, top=False, labelbottom=False)
        ax_img.tick_params(axis='y', which='both', left=False, right=False, labelleft=False)
        imgplot = ax_img.imshow(np.rot90(np.array(vas_structure.img)[1:,1:]))

        # ==== Plot Diffused Img Version ==== #
        ax_diffused_img.cla()
        diffused_img_plt1 = diffusion(mvable_pts, vas_structure.img)
        ax_diffused_img.set_title('Diffused Image')
        ax_diffused_img.tick_params(axis='x', which='both', bottom=False, top=False, labelbottom=False)
        ax_diffused_img.tick_params(axis='y', which='both', left=False, right=False, labelleft=False)
        diffusedplot = ax_diffused_img.imshow(np.rot90(diffused_img_plt1[1:,1:]), vmin=0, vmax=1)

        # ==== Plot Diffused LOSS MAP ==== #
        ax_loss_map.cla()
        loss_map = create_loss_map(np.array(diffused_img_plt1), iter)
        ax_loss_map.set_title('Diffusion Loss Map')
        ax_loss_map.tick_params(axis='x', which='both', bottom=False, top=False, labelbottom=False)
        ax_loss_map.tick_params(axis='y', which='both', left=False, right=False, labelleft=False)
        loss_plot = ax_loss_map.imshow(np.rot90(np.array(loss_map)), vmin=0, vmax=1)

        plt.draw()
        saveImageOne(iter)
        plt.pause(0.001)
        return 3

    dImproved = False
    currentLoss = fitness(mvable_pts, 0)
    temperature = 20

    for i in range(200):

        if not dImproved:
            index = random.randrange(0, numNodes)
            inc_index_x = np.random.choice(test_movement, 1, replace=False)[0]
            inc_index_y = np.random.choice(test_movement, 1, replace=False)[0]
        else:
            inc_index_x = adjustMoveRate(inc_index_x)
            inc_index_y = adjustMoveRate(inc_index_y)

        originalPoints = vas_structure.moveable_pts[index]

        test_x = vas_structure.moveable_pts[index][0] + inc_index_x
        test_y = vas_structure.moveable_pts[index][1] + inc_index_y

        if test_x < 1:
            test_x = 1
        if test_x > 19:
            test_x = 19

        if test_y < 1:
            test_y = 1
        if test_y > 19:
            test_y = 19

        vas_structure.moveable_pts[index] = [test_x, test_y]
        flowDict = computeFlow(vas_structure)
        vas_structure.add_flows_to_img(flowDict)
        mvable_pts = vas_structure.moveable_pts

        loss = fitness(mvable_pts, i)
        if loss < currentLoss:
            currentLoss = loss
            dImproved = True
            all_loss.append(loss)
            callback(mvable_pts, i)
            time_lst.append(i)
            print(i, 'REDUCED LOSS:', loss)
            vas_structure.update_hillclimb_pts(mvable_pts)
            vas_structure.print_images(graph_name=sim_graph_folder+'test_graph'+str(i)+'.png', img_name=sim_img_folder+'test_img'+str(i)+'.png')
        else:
            if temperature - (loss - currentLoss) > 0:
                temperature = temperature - (loss - currentLoss)
                currentLoss = loss
                all_loss.append(loss)
                callback(mvable_pts, i)
                time_lst.append(i)
                dImproved = False
                print(i, 'TOOK WORSE LOSS, REMAINING TEMP: ', temperature, 'NEW LOSS:', currentLoss)
                vas_structure.update_hillclimb_pts(mvable_pts)
                vas_structure.print_images(graph_name=sim_graph_folder+'test_graph'+str(i)+'.png', img_name=sim_img_folder+'test_img'+str(i)+'.png')
            else:
                vas_structure.moveable_pts[index] = originalPoints
                mvable_pts = vas_structure.moveable_pts
                dImproved = False
                print(i, 'LOSS IS >= CURRENT')

    def img_path_generator(path_to_img_dir):
        for i, file_name in enumerate(natsorted(os.listdir(path_to_img_dir), key=lambda y: y.lower())):
            if file_name.endswith('.png'):
                if not i == 0:
                    file_path = os.path.join(path_to_img_dir, file_name)
                    yield imageio.imread(file_path)

    sim_fig_folder = 'HillClimb/figs/'
    imageio.mimsave('HillClimb/HillClimb_Figs.gif', img_path_generator(sim_fig_folder), fps=8)


"""
Unit tests for the conversion of input units
"""
import pytest
import numpy as np

from astropy import units as u

from speccado.source import convert_wav_units, convert_flux_units

class TestWavUnits:
    """Tests of function sc.source.convert_wav_units"""

    @pytest.mark.parametrize("inwav, testwav",
                             [(1.234 * u.nm, 0.001234 * u.um),
                              (98765 * u.angstrom, 9.8765 * u.um),
                              (3.24 * u.um, 3.24 * u.um),
                              (3.42e-06 * u.m, 3.42 * u.um)])
    def test_wavelength(self, inwav, testwav):
        """Conversion of various wavelength units"""
        outwav = convert_wav_units(inwav)
        assert np.isclose(outwav.value, testwav.value)

    @pytest.mark.parametrize("inwav, testwav",
                             [(8103727.71474878 * u.cm**(-1), 0.001234 * u.um),
                              (101250.44297069 * u.m**(-1), 9.8765 * u.um),
                              (0.30864198 * u.um**(-1), 3.24 * u.um),
                              (292.39766082 * u.mm**(-1), 3.42 * u.um)])
    def test_wavenumber(self, inwav, testwav):
        """Conversion of wavenumber to wavelength"""
        outwav = convert_wav_units(inwav)
        assert np.isclose(outwav.value, testwav.value)

    @pytest.mark.parametrize("inwav, testwav",
                             [(2.42943645e+05 * u.THz, 0.001234* u.um),
                              (3.03541192e+04 * u.GHz, 9.8765 * u.um),
                              (9.25285364e+07 * u.MHz, 3.24* u.um),
                              (8.76586135e+13 / u.s, 3.42 * u.um)])
    def test_frequency(self, inwav, testwav):
        """Conversion of frequency to wavelength"""
        outwav = convert_wav_units(inwav)
        assert np.isclose(outwav.value, testwav.value)

    @pytest.mark.parametrize("inwav, testwav",
                             [(1.60976161e-09 * u.erg, 0.001234 * u.um),
                              (0.12553455 * u.eV, 9.8765 * u.um),
                              (6.13100563e-20 * u.J, 3.24 * u.um),
                              (0.00036253 * u.keV, 3.42 * u.um)])
    def test_photon_energy(self, inwav, testwav):
        """Conversion of photon energy to wavelength"""
        outwav = convert_wav_units(inwav)
        assert np.isclose(outwav.value, testwav.value)

    def test_incompatible_units(self):
        """Test one case of non-equivalent units"""
        inwav = 2.34 * u.m / u.s
        with pytest.raises(u.UnitConversionError):
            convert_wav_units(inwav)

class TestFluxUnits:
    """Tests of function sc.source,convert_flux_units"""

    def test_src_flam_si(self):
        """
        Conversion of SI input units to internal units, point source
        """
        si_flux = np.array([1, 3.4]) * u.J / u.m**2 / u.m / u.s
        wavelength = np.array([3.1, 4.3]) * u.um

        testflux = np.array([1.56057616e+13,
                             7.35987854e+13]) * u.ph / u.s / u.m**2 / u.um

        outflux = convert_flux_units(si_flux, wavelength)
        assert outflux.unit.is_equivalent(
            si_flux.unit,
            equivalencies=u.spectral_density(wavelength))
        assert np.allclose(outflux.value, testflux.value)

    def test_src_fnu(self):
        """
        Conversion of f_nu to f_lambda
        """
        f_nu = np.array([2.3e+4, 99.4e+4]) * u.erg / u.s / u.m**2 / u.Hz
        wavelength = np.array([3.1, 4.3]) * u.um

        testf_lam = np.array([1.11972176e+30,
                              3.48868619e+31]) * u.ph / u.s / u.m**2 / u.um

        f_lam = convert_flux_units(f_nu, wavelength)

        assert f_lam.unit.is_equivalent(
            f_nu.unit,
            equivalencies=u.spectral_density(wavelength))
        assert np.allclose(f_lam.value, testf_lam.value)

    def test_src_jansky(self):
        """
        Conversion of Jy to internal units, point source

        The test uses a reference wavelength of 3 * u.um.
        """
        jy_flux = np.array([1, 3.4]) * u.Jy
        lam_ref = np.array([3.0, 5.7]) * u.um
        testflux = np.array([5030634.01565452,
                             9002187.18590809]) * u.ph / u.m**2 / u.s / u.um

        outflux = convert_flux_units(jy_flux, wav=lam_ref)

        assert outflux.unit.is_equivalent(
            jy_flux.unit,
            equivalencies=u.spectral_density(wav=lam_ref))
        assert np.allclose(testflux.value, outflux.value)

    def test_bg_flam_per_deg2(self):
        """
        Test a simple conversion of angular scale

        This uses a influx per deg^2
        """
        influx = 2.34 * u.erg / u.s / u.m**2 / u.um / u.deg**2
        lam_ref = 4.2 * u.um

        testflux = 381753.84604285 * u.ph / u.s / u.m**2 / u.um / u.arcsec**2

        outflux = convert_flux_units(influx, lam_ref)
        print(testflux)
        print(outflux)
        assert np.allclose(outflux.value, testflux.value)

    def test_bg_flam_per_rad(self):
        """
        Test a simple conversion of angular scale

        This uses influx per rad^2
        """
        influx = 2.34 * u.erg / u.s / u.m**2 / u.um / u.rad**2
        lam_ref = 4.2 * u.um

        testflux = 116.2888 * u.ph / u.s / u.m**2 / u.um / u.arcsec**2

        outflux = convert_flux_units(influx, lam_ref)
        print(testflux)
        print(outflux)
        assert np.allclose(outflux.value, testflux.value)

    def test_bg_jansky_per_deg2(self):
        """
        Test conversion from Jy/deg^2
        """
        influx = 1.2e-5 * u.Jy / u.deg**2
        lam_ref = 9.2 * u.um

        testflux = 1.51891124e-06 * u.ph / u.s / u.m**2 / u.um / u.arcsec**2

        outflux = convert_flux_units(influx, lam_ref)
        assert np.allclose(outflux.value, testflux.value)


#[Trees - Ex4] Exercise: Implement a binary search tree
#Implement the insert() and find() methods in the following simple binary search tree class:

from logging import root

class Node:
    def __init__(self, key):
        self.key = key
        self.left = None
        self.right = None

class BST:
    def __init__(self, root:Node):
        self.root = root

    # Inserts a key into this binary search tree.
    # If there are n nodes in the tree, then the average runtime of this method should be log(n).
    # @param key The key to insert.
    # normally if i'd do this in c++, i would use find as a subroutine for insert because i can use take the mem address and assign a variable value.
    def insert(self, subroot, key):
        if subroot == None:
            return Node(key) #deciding to return the new root
        else:
            if key < subroot.key:
                print(subroot.key)
                return self.insert(subroot.left, key)
            elif key >= subroot.key:
                print(subroot.key)
                return self.insert(subroot.right, key)
            return self.subroot

    # Checks whether or not a key exists in this binary search tree.
    # If there are n nodes in the tree, then the average runtime of this method should be log(n).

    # @param key The key to check for.
    # @return true if the key is present in this binary search tree, false otherwise.
    def find(self, subroot, key):
        if self.root == None or key == self.root.key:
            return True
        if subroot == None:
            return False
        if subroot.key == key:
            return True
        elif key < subroot.key:
            return self.find(subroot.left, key)
        elif key >= subroot.key:
            return self.find(subroot.right, key)

# TESTING
sixteen = Node(16)
sixteen.left = Node(10)
sixteen.right = Node(21)
tree = BST(sixteen)

# Test Find
# print(tree.find(sixteen, 16))
# print(tree.find(sixteen, 10))
# print(tree.find(sixteen, 21))
# print(tree.find(sixteen, 15))

# Expected
# True
# True
# True
# False

# Actual
# True
# True
# True
# False

# Test Insert -- i did this kinda janky where I just print what node we are
# recursing thru so i know where it inserts
# tree.insert(sixteen, 15) #insert on left
# should print 16, 10
# tree.insert(sixteen, 150) #insert on right
# should print 16, 21


import ujson
from tornado import gen

import chatbot.services.facebook.msg as facebook_msg
from chatbot.intents import Reply, Intent, TextReply

from chatbot.misc.router import url_for

class PromotionsReply(Reply):

    def __init__(self, promotions=None):
        self.promotions = promotions or []

    def to_dict(self):
        return self.promotions

    def to_facebook(self):
        elements = [self._to_facebook_card(promotion) for promotion in self.promotions]
        template = facebook_msg.GenericTemplate(elements)
        attachment = facebook_msg.TemplateAttachment(template)
        message = facebook_msg.Message(attachment=attachment)
        return message

    def _to_facebook_card(self, promotion):
        if promotion['type'] == 'sumo_promotion':
            view_promotion_url = url_for('web.view_promo', promotion_id=promotion['id'])
            claim_promotion_url = url_for('web.claim_promo', promotion_id=promotion['id'])
        elif promotion['type'] == 'internet_deal':
            view_promotion_url = url_for('web.view_deal', promotion_id=promotion['id'])
            claim_promotion_url = url_for('web.claim_deal', promotion_id=promotion['id'])

        default_action = facebook_msg.WebUrlButton('', view_promotion_url)
        view_button = facebook_msg.WebUrlButton('View', view_promotion_url)
        claim_button = facebook_msg.WebUrlButton('Claim', claim_promotion_url)

        element = facebook_msg.Element(title=promotion['name'],
                                       subtitle=promotion['business']['name'][:80],
                                       image_url=promotion['business']['logo'],
                                       default_action=default_action,
                                       buttons=[view_button, claim_button])

        return element

class SearchIntent(Intent):

    name = 'search'

    def __init__(self, *args, **kwargs):
        super(SearchIntent, self).__init__(*args, **kwargs)

    @gen.coroutine
    def process(self, query=''):
        search_url = url_for('api.search', query=query)
        resp = yield self.fetch(search_url)
        data = ujson.loads(resp.body)
        promotions = data['promotions']

        if promotions:
            return [PromotionsReply(promotions)]
        else:
            return [TextReply(text="Sorry we can't interpret your message:( Please try again!")]