from __future__ import absolute_import, division, print_function

import mesh_tensorflow as mtf
import tensorflow.compat.v1 as tf
from pydantic.dataclasses import dataclass

@dataclass
class OptimizerConfig:
    pass

def clip_by_global_norm(grads, clip_norm):
    """Clip the grads by global norm."""
    global_norm = mtf.sqrt(
        mtf.add_n([mtf.reduce_sum(mtf.square(t)) for t in grads if t is not None])
    )
    multiplier = clip_norm / mtf.maximum(global_norm, clip_norm)
    clipped_grads = [None if t is None else t * multiplier for t in grads]
    return clipped_grads, global_norm

def get_optimizer(loss, params, summary, inp_var_grads=None):
    """Creates and returns an optimizer training op."""

    global_step = tf.train.get_or_create_global_step()  # get global step
    mesh = loss.mesh  # get mesh info from loss
    graph = mesh.graph  # get graph info from mesh

    if inp_var_grads is None:
        var_grads = mtf.gradients(
            [loss], [v.outputs[0] for v in graph.trainable_variables]
        )
    else:
        var_grads = inp_var_grads

    learning_rate = tf.constant(
        value=params["lr"], shape=[], dtype=tf.float32
    )  # grab lr param

    if params["lr_decay"] == "linear":
        learning_rate = tf.train.polynomial_decay(
            learning_rate,
            global_step,
            params["train_steps"],
            end_learning_rate=params["lr"]
            * 0.1,  # decrease to 10% of initial LR according to GPT-3 paper
            power=1.0,
            cycle=False,
        )
    elif params["lr_decay"] == "cosine":
        learning_rate = tf.train.cosine_decay(
            learning_rate,
            global_step,
            params["train_steps"],
            alpha=0.1,  # alpha is min lr value as a fraction of init lr.
        )

    if params["warmup_steps"] > 0:
        global_steps_int = tf.cast(global_step, tf.int32)
        warmup_steps_int = tf.constant(params["warmup_steps"], dtype=tf.int32)

        global_steps_float = tf.cast(global_steps_int, tf.float32)
        warmup_steps_float = tf.cast(warmup_steps_int, tf.float32)

        warmup_percent_done = global_steps_float / warmup_steps_float
        warmup_learning_rate = learning_rate * warmup_percent_done

        is_warmup = tf.cast(global_steps_int < warmup_steps_int, tf.float32)
        learning_rate = (
            1.0 - is_warmup
        ) * learning_rate + is_warmup * warmup_learning_rate

    summary.scalar("lr", learning_rate)

    if params["opt_name"].lower() == "adam":
        optimizer = mtf.optimize.AdamWeightDecayOptimizer(
            learning_rate=learning_rate,
            weight_decay_rate=params["weight_decay"],
            beta_1=params["beta1"],
            beta_2=params["beta2"],
            epsilon=params["epsilon"],
            exclude_from_weight_decay=["norm", "bias"],
        )
    else:
        optimizer = mtf.optimize.AdafactorOptimizer(
            learning_rate=params["lr"],
            decay_rate=params["weight_decay"],
            beta1=params["beta1"],
            epsilon1=params["ada_epsilon1"],
            epsilon2=params["ada_epsilon2"],
        )

    if params["gradient_clipping"] is not None:
        clip_value = mtf.constant(mesh, params["gradient_clipping"], dtype=tf.float32)
        (var_grads, _) = clip_by_global_norm(var_grads, clip_norm=clip_value)

    update_ops = optimizer.apply_grads(var_grads, graph.trainable_variables)
    return learning_rate, update_ops


import yaml
from bounds import BoundsExperiment
path="C:/Users/Shruti Jadon/Desktop/IndependentStudies/IS/SampleBounds/src/main/resources/"
with open(path+"config.yml") as f:
    list_doc = yaml.load(f)

distribution=["normal","uniform","exponential","beta","mix_gauss_2_sym_uni","mix_gauss_2_sym_multi","mix_gauss_2_nonsym_uni","mix_gauss_2_nonsym_multi","mix_gauss_4_sym_uni","mix_gauss_4_sym_multi","mix_gauss_4_nonsym_uni","mix_gauss_4_nonsym_multi","student_t_3","student_t_5","double_exponential","mix_double_exponential"]
for dis in distribution:
    list_doc["sample_statistics"]["distribution"]=dis
    with open(path + "config.yml", "w") as f:
        yaml.dump(list_doc, f)
    B = BoundsExperiment(algo=["ORDSTAT","CLT","CHERNOFF_HOEFFDING","MASSART"])
    B.run_experiments()
    print (list_doc["sample_statistics"]["distribution"] +" done")


# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.

# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import os

from ansible.errors import AnsibleError, AnsibleParserError, AnsibleAssertionError
from ansible.module_utils.six import iteritems, binary_type, text_type
from ansible.module_utils.common._collections_compat import Container, Mapping, Set, Sequence
from ansible.playbook.attribute import FieldAttribute
from ansible.playbook.base import Base
from ansible.playbook.collectionsearch import CollectionSearch
from ansible.playbook.conditional import Conditional
from ansible.playbook.helpers import load_list_of_blocks
from ansible.playbook.role.metadata import RoleMetadata
from ansible.playbook.taggable import Taggable
from ansible.plugins.loader import add_all_plugin_dirs
from ansible.utils.collection_loader import AnsibleCollectionConfig
from ansible.utils.vars import combine_vars

__all__ = ['Role', 'hash_params']

# TODO: this should be a utility function, but can't be a member of
#       the role due to the fact that it would require the use of self
#       in a static method. This is also used in the base class for
#       strategies (ansible/plugins/strategy/__init__.py)

def hash_params(params):
    """
    Construct a data structure of parameters that is hashable.

    This requires changing any mutable data structures into immutable ones.
    We chose a frozenset because role parameters have to be unique.

    .. warning::  this does not handle unhashable scalars.  Two things
        mitigate that limitation:

        1) There shouldn't be any unhashable scalars specified in the yaml
        2) Our only choice would be to return an error anyway.
    """
    # Any container is unhashable if it contains unhashable items (for
    # instance, tuple() is a Hashable subclass but if it contains a dict, it
    # cannot be hashed)
    if isinstance(params, Container) and not isinstance(params, (text_type, binary_type)):
        if isinstance(params, Mapping):
            try:
                # Optimistically hope the contents are all hashable
                new_params = frozenset(params.items())
            except TypeError:
                new_params = set()
                for k, v in params.items():
                    # Hash each entry individually
                    new_params.add((k, hash_params(v)))
                new_params = frozenset(new_params)

        elif isinstance(params, (Set, Sequence)):
            try:
                # Optimistically hope the contents are all hashable
                new_params = frozenset(params)
            except TypeError:
                new_params = set()
                for v in params:
                    # Hash each entry individually
                    new_params.add(hash_params(v))
                new_params = frozenset(new_params)
        else:
            # This is just a guess.
            new_params = frozenset(params)
        return new_params

    # Note: We do not handle unhashable scalars but our only choice would be
    # to raise an error there anyway.
    return frozenset((params,))

class Role(Base, Conditional, Taggable, CollectionSearch):

    _delegate_to = FieldAttribute(isa='string')
    _delegate_facts = FieldAttribute(isa='bool')

    def __init__(self, play=None, from_files=None, from_include=False):
        self._role_name = None
        self._role_path = None
        self._role_collection = None
        self._role_params = dict()
        self._loader = None

        self._metadata = None
        self._play = play
        self._parents = []
        self._dependencies = []
        self._task_blocks = []
        self._handler_blocks = []
        self._compiled_handler_blocks = None
        self._default_vars = dict()
        self._role_vars = dict()
        self._had_task_run = dict()
        self._completed = dict()

        if from_files is None:
            from_files = {}
        self._from_files = from_files

        # Indicates whether this role was included via include/import_role
        self.from_include = from_include

        super(Role, self).__init__()

    def __repr__(self):
        return self.get_name()

    def get_name(self, include_role_fqcn=True):
        if include_role_fqcn:
            return '.'.join(x for x in (self._role_collection, self._role_name) if x)
        return self._role_name

    @staticmethod
    def load(role_include, play, parent_role=None, from_files=None, from_include=False):

        if from_files is None:
            from_files = {}
        try:
            # The ROLE_CACHE is a dictionary of role names, with each entry
            # containing another dictionary corresponding to a set of parameters
            # specified for a role as the key and the Role() object itself.
            # We use frozenset to make the dictionary hashable.

            params = role_include.get_role_params()
            if role_include.when is not None:
                params['when'] = role_include.when
            if role_include.tags is not None:
                params['tags'] = role_include.tags
            if from_files is not None:
                params['from_files'] = from_files
            if role_include.vars:
                params['vars'] = role_include.vars

            params['from_include'] = from_include

            hashed_params = hash_params(params)
            if role_include.get_name() in play.ROLE_CACHE:
                for (entry, role_obj) in iteritems(play.ROLE_CACHE[role_include.get_name()]):
                    if hashed_params == entry:
                        if parent_role:
                            role_obj.add_parent(parent_role)
                        return role_obj

            # TODO: need to fix cycle detection in role load (maybe use an empty dict
            #  for the in-flight in role cache as a sentinel that we're already trying to load
            #  that role?)
            # see https://github.com/ansible/ansible/issues/61527
            r = Role(play=play, from_files=from_files, from_include=from_include)
            r._load_role_data(role_include, parent_role=parent_role)

            if role_include.get_name() not in play.ROLE_CACHE:
                play.ROLE_CACHE[role_include.get_name()] = dict()

            # FIXME: how to handle cache keys for collection-based roles, since they're technically adjustable per task?
            play.ROLE_CACHE[role_include.get_name()][hashed_params] = r
            return r

        except RuntimeError:
            raise AnsibleError("A recursion loop was detected with the roles specified. Make sure child roles do not have dependencies on parent roles",
                               obj=role_include._ds)

    def _load_role_data(self, role_include, parent_role=None):
        self._role_name = role_include.role
        self._role_path = role_include.get_role_path()
        self._role_collection = role_include._role_collection
        self._role_params = role_include.get_role_params()
        self._variable_manager = role_include.get_variable_manager()
        self._loader = role_include.get_loader()

        if parent_role:
            self.add_parent(parent_role)

        # copy over all field attributes from the RoleInclude
        # update self._attributes directly, to avoid squashing
        for (attr_name, _) in iteritems(self._valid_attrs):
            if attr_name in ('when', 'tags'):
                self._attributes[attr_name] = self._extend_value(
                    self._attributes[attr_name],
                    role_include._attributes[attr_name],
                )
            else:
                self._attributes[attr_name] = role_include._attributes[attr_name]

        # vars and default vars are regular dictionaries
        self._role_vars = self._load_role_yaml('vars', main=self._from_files.get('vars'), allow_dir=True)
        if self._role_vars is None:
            self._role_vars = dict()
        elif not isinstance(self._role_vars, dict):
            raise AnsibleParserError("The vars/main.yml file for role '%s' must contain a dictionary of variables" % self._role_name)

        self._default_vars = self._load_role_yaml('defaults', main=self._from_files.get('defaults'), allow_dir=True)
        if self._default_vars is None:
            self._default_vars = dict()
        elif not isinstance(self._default_vars, dict):
            raise AnsibleParserError("The defaults/main.yml file for role '%s' must contain a dictionary of variables" % self._role_name)

        # load the role's other files, if they exist
        metadata = self._load_role_yaml('meta')
        if metadata:
            self._metadata = RoleMetadata.load(metadata, owner=self, variable_manager=self._variable_manager, loader=self._loader)
            self._dependencies = self._load_dependencies()
        else:
            self._metadata = RoleMetadata()

        # reset collections list; roles do not inherit collections from parents, just use the defaults
        # FUTURE: use a private config default for this so we can allow it to be overridden later
        self.collections = []

        # configure plugin/collection loading; either prepend the current role's collection or configure legacy plugin loading
        # FIXME: need exception for explicit ansible.legacy?
        if self._role_collection:  # this is a collection-hosted role
            self.collections.insert(0, self._role_collection)
        else:  # this is a legacy role, but set the default collection if there is one
            default_collection = AnsibleCollectionConfig.default_collection
            if default_collection:
                self.collections.insert(0, default_collection)
            # legacy role, ensure all plugin dirs under the role are added to plugin search path
            add_all_plugin_dirs(self._role_path)

        # collections can be specified in metadata for legacy or collection-hosted roles
        if self._metadata.collections:
            self.collections.extend((c for c in self._metadata.collections if c not in self.collections))

        # if any collections were specified, ensure that core or legacy synthetic collections are always included
        if self.collections:
            # default append collection is core for collection-hosted roles, legacy for others
            default_append_collection = 'ansible.builtin' if self._role_collection else 'ansible.legacy'
            if 'ansible.builtin' not in self.collections and 'ansible.legacy' not in self.collections:
                self.collections.append(default_append_collection)

        task_data = self._load_role_yaml('tasks', main=self._from_files.get('tasks'))
        if task_data:
            try:
                self._task_blocks = load_list_of_blocks(task_data, play=self._play, role=self, loader=self._loader, variable_manager=self._variable_manager)
            except AssertionError as e:
                raise AnsibleParserError("The tasks/main.yml file for role '%s' must contain a list of tasks" % self._role_name,
                                         obj=task_data, orig_exc=e)

        handler_data = self._load_role_yaml('handlers', main=self._from_files.get('handlers'))
        if handler_data:
            try:
                self._handler_blocks = load_list_of_blocks(handler_data, play=self._play, role=self, use_handlers=True, loader=self._loader,
                                                           variable_manager=self._variable_manager)
            except AssertionError as e:
                raise AnsibleParserError("The handlers/main.yml file for role '%s' must contain a list of tasks" % self._role_name,
                                         obj=handler_data, orig_exc=e)

    def _load_role_yaml(self, subdir, main=None, allow_dir=False):
        file_path = os.path.join(self._role_path, subdir)
        if self._loader.path_exists(file_path) and self._loader.is_directory(file_path):
            # Valid extensions and ordering for roles is hard-coded to maintain
            # role portability
            extensions = ['.yml', '.yaml', '.json']
            # If no <main> is specified by the user, look for files with
            # extensions before bare name. Otherwise, look for bare name first.
            if main is None:
                _main = 'main'
                extensions.append('')
            else:
                _main = main
                extensions.insert(0, '')
            found_files = self._loader.find_vars_files(file_path, _main, extensions, allow_dir)
            if found_files:
                data = {}
                for found in found_files:
                    new_data = self._loader.load_from_file(found)
                    if new_data and allow_dir:
                        data = combine_vars(data, new_data)
                    else:
                        data = new_data
                return data
            elif main is not None:
                raise AnsibleParserError("Could not find specified file in role: %s/%s" % (subdir, main))
        return None

    def _load_dependencies(self):
        '''
        Recursively loads role dependencies from the metadata list of
        dependencies, if it exists
        '''

        deps = []
        if self._metadata:
            for role_include in self._metadata.dependencies:
                r = Role.load(role_include, play=self._play, parent_role=self)
                deps.append(r)

        return deps

    # other functions

    def add_parent(self, parent_role):
        ''' adds a role to the list of this roles parents '''
        if not isinstance(parent_role, Role):
            raise AnsibleAssertionError()

        if parent_role not in self._parents:
            self._parents.append(parent_role)

    def get_parents(self):
        return self._parents

    def get_default_vars(self, dep_chain=None):
        dep_chain = [] if dep_chain is None else dep_chain

        default_vars = dict()
        for dep in self.get_all_dependencies():
            default_vars = combine_vars(default_vars, dep.get_default_vars())
        if dep_chain:
            for parent in dep_chain:
                default_vars = combine_vars(default_vars, parent._default_vars)
        default_vars = combine_vars(default_vars, self._default_vars)
        return default_vars

    def get_inherited_vars(self, dep_chain=None):
        dep_chain = [] if dep_chain is None else dep_chain

        inherited_vars = dict()

        if dep_chain:
            for parent in dep_chain:
                inherited_vars = combine_vars(inherited_vars, parent._role_vars)
        return inherited_vars

    def get_role_params(self, dep_chain=None):
        dep_chain = [] if dep_chain is None else dep_chain

        params = {}
        if dep_chain:
            for parent in dep_chain:
                params = combine_vars(params, parent._role_params)
        params = combine_vars(params, self._role_params)
        return params

    def get_vars(self, dep_chain=None, include_params=True):
        dep_chain = [] if dep_chain is None else dep_chain

        all_vars = self.get_inherited_vars(dep_chain)

        for dep in self.get_all_dependencies():
            all_vars = combine_vars(all_vars, dep.get_vars(include_params=include_params))

        all_vars = combine_vars(all_vars, self.vars)
        all_vars = combine_vars(all_vars, self._role_vars)
        if include_params:
            all_vars = combine_vars(all_vars, self.get_role_params(dep_chain=dep_chain))

        return all_vars

    def get_direct_dependencies(self):
        return self._dependencies[:]

    def get_all_dependencies(self):
        '''
        Returns a list of all deps, built recursively from all child dependencies,
        in the proper order in which they should be executed or evaluated.
        '''

        child_deps = []

        for dep in self.get_direct_dependencies():
            for child_dep in dep.get_all_dependencies():
                child_deps.append(child_dep)
            child_deps.append(dep)

        return child_deps

    def get_task_blocks(self):
        return self._task_blocks[:]

    def get_handler_blocks(self, play, dep_chain=None):
        # Do not recreate this list each time ``get_handler_blocks`` is called.
        # Cache the results so that we don't potentially overwrite with copied duplicates
        #
        # ``get_handler_blocks`` may be called when handling ``import_role`` during parsing
        # as well as with ``Play.compile_roles_handlers`` from ``TaskExecutor``
        if self._compiled_handler_blocks:
            return self._compiled_handler_blocks

        self._compiled_handler_blocks = block_list = []

        # update the dependency chain here
        if dep_chain is None:
            dep_chain = []
        new_dep_chain = dep_chain + [self]

        for dep in self.get_direct_dependencies():
            dep_blocks = dep.get_handler_blocks(play=play, dep_chain=new_dep_chain)
            block_list.extend(dep_blocks)

        for task_block in self._handler_blocks:
            new_task_block = task_block.copy()
            new_task_block._dep_chain = new_dep_chain
            new_task_block._play = play
            block_list.append(new_task_block)

        return block_list

    def has_run(self, host):
        '''
        Returns true if this role has been iterated over completely and
        at least one task was run
        '''

        return host.name in self._completed and not self._metadata.allow_duplicates

    def compile(self, play, dep_chain=None):
        '''
        Returns the task list for this role, which is created by first
        recursively compiling the tasks for all direct dependencies, and
        then adding on the tasks for this role.

        The role compile() also remembers and saves the dependency chain
        with each task, so tasks know by which route they were found, and
        can correctly take their parent's tags/conditionals into account.
        '''

        block_list = []

        # update the dependency chain here
        if dep_chain is None:
            dep_chain = []
        new_dep_chain = dep_chain + [self]

        deps = self.get_direct_dependencies()
        for dep in deps:
            dep_blocks = dep.compile(play=play, dep_chain=new_dep_chain)
            block_list.extend(dep_blocks)

        for idx, task_block in enumerate(self._task_blocks):
            new_task_block = task_block.copy()
            new_task_block._dep_chain = new_dep_chain
            new_task_block._play = play
            if idx == len(self._task_blocks) - 1:
                new_task_block._eor = True
            block_list.append(new_task_block)

        return block_list

    def serialize(self, include_deps=True):
        res = super(Role, self).serialize()

        res['_role_name'] = self._role_name
        res['_role_path'] = self._role_path
        res['_role_vars'] = self._role_vars
        res['_role_params'] = self._role_params
        res['_default_vars'] = self._default_vars
        res['_had_task_run'] = self._had_task_run.copy()
        res['_completed'] = self._completed.copy()

        if self._metadata:
            res['_metadata'] = self._metadata.serialize()

        if include_deps:
            deps = []
            for role in self.get_direct_dependencies():
                deps.append(role.serialize())
            res['_dependencies'] = deps

        parents = []
        for parent in self._parents:
            parents.append(parent.serialize(include_deps=False))
        res['_parents'] = parents

        return res

    def deserialize(self, data, include_deps=True):
        self._role_name = data.get('_role_name', '')
        self._role_path = data.get('_role_path', '')
        self._role_vars = data.get('_role_vars', dict())
        self._role_params = data.get('_role_params', dict())
        self._default_vars = data.get('_default_vars', dict())
        self._had_task_run = data.get('_had_task_run', dict())
        self._completed = data.get('_completed', dict())

        if include_deps:
            deps = []
            for dep in data.get('_dependencies', []):
                r = Role()
                r.deserialize(dep)
                deps.append(r)
            setattr(self, '_dependencies', deps)

        parent_data = data.get('_parents', [])
        parents = []
        for parent in parent_data:
            r = Role()
            r.deserialize(parent, include_deps=False)
            parents.append(r)
        setattr(self, '_parents', parents)

        metadata_data = data.get('_metadata')
        if metadata_data:
            m = RoleMetadata()
            m.deserialize(metadata_data)
            self._metadata = m

        super(Role, self).deserialize(data)

    def set_loader(self, loader):
        self._loader = loader
        for parent in self._parents:
            parent.set_loader(loader)
        for dep in self.get_direct_dependencies():
            dep.set_loader(loader)


import pygame as pg
import random as rd
import datetime as dt

def plaay():
    pg.init()

    SCREEN_WIDTH = 1000
    SCREEN_HEIGHT  = 1000
    SCREEN = pg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pg.display.set_caption("game")
    background = pg.image.load("image.png")
    clock = pg.time.Clock()

    class obj:
        def __init__(self):
            self.x = 0
            self.y = 0
            self.move = 0
        def put_img(self,address):
            self.img = pg.image.load(address)
            self.sx,self.sy = self.img.get_size()
        def change_size(self,sx,sy):
            self.img = pg.transform.scale(self.img,(sx,sy))
            self.sx,self.sy = self.img.get_size()
        def show(self):
            SCREEN.blit(self.img,(self.x,self.y))

    def crash(a,b):
        if (a.x - b.sx <= b.x) and (b.x <= a.x + a.sx):
            if (a.y - b.sy <= b.y) and (b.y - a.y + a.sy):
                return True
            else:
                return False
        else:
            return False

    durability = 100

    monster_spawn = 199

    over = False

    t1 = obj()
    t1.put_img("IMG_0381.png")
    t1.change_size(100,150)
    t1.x = SCREEN_WIDTH / 8 - t1.sx / 2
    t1.y =  (SCREEN_HEIGHT / 2 + 160) - t1.sy / 2

    t2 = obj()
    t2.put_img("IMG_0382.png")
    t2.change_size(100,150)
    t2.x = (SCREEN_WIDTH / 8 + 150) - t2.sx / 2
    t2.y =  (SCREEN_HEIGHT / 2 + 160) - t2.sy / 2

    t3 = obj()
    t3.put_img("IMG_0385.png")
    t3.change_size(100,150)
    t3.x = (SCREEN_WIDTH / 8 + 350) - t3.sx / 2
    t3.y =  (SCREEN_HEIGHT / 2 + 160) - t3.sy / 2

    t4 = obj()
    t4.put_img("IMG_0387.png")
    t4.change_size(100,150)
    t4.x = (SCREEN_WIDTH / 8 + 500) - t4.sx / 2
    t4.y =  (SCREEN_HEIGHT / 2 + 160) - t4.sy / 2

    m1_list = []
    m2_list = []
    m3_list = []
    m4_list = []

    r1_list = []
    r2_list = []
    r3_list = []
    r4_list = []

    k1 = 0
    k2 = 0
    k3 = 0
    k4 = 0

    at1 = 40
    at2 = 40
    at3 = 40
    at4 = 40

    coin = 0

    start_time = dt.datetime.now()

    play = True
    while play:
        clock.tick(60)
        for event in pg.event.get():
            if event.type == pg.QUIT:
                play = False

            if event.type == pg.KEYDOWN:
                if event.key == pg.K_LEFT:
                    if coin >= 100:
                        coin -= 100
                        r1 = rd.randrange(1,101)
                        if r1 <= 50:
                            at1 = 40
                        elif r1 > 50 and r1 <= 75:
                            at1 = 30
                        elif r1 >75 and r1 <= 88:
                            at1 = 20
                        elif r1 > 88 and r1 <= 96:
                            at1 = 10
                        elif r1 > 96 and r1 <= 100:
                            at1 = 5

                if event.key == pg.K_UP:
                    if coin >= 100:
                        coin -= 100
                        r1 = rd.randrange(1,101)
                        if r1 <= 50:
                            at2 = 40
                        elif r1 > 50 and r1 <= 75:
                            at2 = 30
                        elif r1 >75 and r1 <= 88:
                            at2 = 20
                        elif r1 > 88 and r1 <= 96:
                            at2 = 10
                        elif r1 > 96 and r1 <= 100:
                            at2 = 5

                if event.key == pg.K_DOWN:
                    if coin >= 100:
                        coin -= 100
                        r1 = rd.randrange(1,101)
                        if r1 <= 50:
                            at3 = 40
                        elif r1 > 50 and r1 <= 75:
                            at3 = 30
                        elif r1 >75 and r1 <= 88:
                            at3 = 20
                        elif r1 > 88 and r1 <= 96:
                            at3 = 10
                        elif r1 > 96 and r1 <= 100:
                            at3 = 5

                if event.key == pg.K_RIGHT:
                    if coin >= 100:
                        coin -= 100
                        r1 = rd.randrange(1,101)
                        if r1 <= 50:
                            at4 = 40
                        elif r1 > 50 and r1 <= 75:
                            at4 = 30
                        elif r1 >75 and r1 <= 88:
                            at4 = 20
                        elif r1 > 88 and r1 <= 96:
                            at4 = 10
                        elif r1 > 96 and r1 <= 100:
                            at4 = 5

        coin += 1

        now_time = dt.datetime.now()
        delta_time = round((now_time - start_time).total_seconds())

        if rd.randint(1,201) > monster_spawn:
            m1 = obj()
            m1.put_img("IMG_0337.png")
            m1.change_size(50,50)
            m1.x = SCREEN_WIDTH / 8 - m1.sx / 2
            m1.y = 0
            m1.move = 5
            m1_list.append(m1)

        d_list = []

        for i in range(len(m1_list)):
            mo1 = m1_list[i]
            mo1.y += mo1.move
            if mo1.y >= 560:
                d_list.append(i)

        d_list.reverse()

        for d in d_list:
            del m1_list[d]
            durability -= 1

        if rd.randint(1,201) > monster_spawn:
            m2 = obj()
            m2.put_img("IMG_0337.png")
            m2.change_size(50,50)
            m2.x = (SCREEN_WIDTH / 8 + 150) - m2.sx / 2
            m2.y = 0
            m2.move = 5
            m2_list.append(m2)

        d_list = []

        for i in range(len(m2_list)):
            mo2 = m2_list[i]
            mo2.y += mo2.move
            if mo2.y >= 560:
                d_list.append(i)

        d_list.reverse()

        for d in d_list:
            del m2_list[d]
            durability -= 1

        if rd.randint(1,201) > monster_spawn:
            m3 = obj()
            m3.put_img("IMG_0341.png")
            m3.change_size(50,50)
            m3.x = (SCREEN_WIDTH / 8 + 350) - m3.sx / 2
            m3.y = 0
            m3.move = 5
            m3_list.append(m3)

        d_list = []

        for i in range(len(m3_list)):
            mo3 = m3_list[i]
            mo3.y += mo3.move
            if mo3.y >= 560:
                d_list.append(i)

        d_list.reverse()

        for d in d_list:
            del m3_list[d]
            durability -= 1

        if rd.randint(1,201) > monster_spawn:
            m4 = obj()
            m4.put_img("IMG_0364.png")
            m4.change_size(50,50)
            m4.x = (SCREEN_WIDTH / 8 + 500) - m4.sx / 2
            m4.y = 0
            m4.move = 5
            m4_list.append(m4)

        d_list = []

        for i in range(len(m4_list)):
            mo4 = m4_list[i]
            mo4.y += mo4.move
            if mo4.y >= 560:
                d_list.append(i)

        d_list.reverse()

        for d in d_list:
            del m4_list[d]
            durability -= 1

        if k1 > at1:
            k1 = 0
            r1 = obj()
            r1.put_img("missle.png")
            r1.change_size(50,50)
            r1.x = (SCREEN_WIDTH / 8 - r1.sx / 2)
            r1.y = (SCREEN_HEIGHT / 2 + 80) - r1.sy
            r1.move = 10
            r1_list.append(r1)

        d_list = []
        k1 += 1
        k2 += 1
        k3 += 1
        k4 += 1
        for i in range(len(r1_list)):
            ro1 = r1_list[i]
            ro1.y -= ro1.move
            if ro1.y <= 0:
                d_list.append(i)

        d_list.reverse()

        for d in d_list:
            del r1_list[d]

        if k2 > at2:
            k2 = 0
            r2 = obj()
            r2.put_img("missle.png")
            r2.change_size(50,50)
            r2.x = ((SCREEN_WIDTH / 8 + 150) - r2.sx / 2)
            r2.y = (SCREEN_HEIGHT / 2 + 80) - r2.sy
            r2.move = 10
            r2_list.append(r2)

        d_list = []

        for i in range(len(r2_list)):
            ro2 = r2_list[i]
            ro2.y -= ro2.move
            if ro2.y <= 0:
                d_list.append(i)

        d_list.reverse()

        for d in d_list:
            del r2_list[d]

        if k3 > at3:
            k3 = 0
            r3 = obj()
            r3.put_img("missle.png")
            r3.change_size(50,50)
            r3.x = ((SCREEN_WIDTH / 8 + 350) - r3.sx / 2)
            r3.y = (SCREEN_HEIGHT / 2 + 80) - r3.sy
            r3.move = 10
            r3_list.append(r3)

        d_list = []

        for i in range(len(r3_list)):
            ro3 = r3_list[i]
            ro3.y -= ro3.move
            if ro3.y <= 0:
                d_list.append(i)

        d_list.reverse()

        for d in d_list:
            del r3_list[d]

        if k4 > at4:
            k4 = 0
            r4 = obj()
            r4.put_img("missle.png")
            r4.change_size(50,50)
            r4.x = ((SCREEN_WIDTH / 8 + 500) - r4.sx / 2)
            r4.y = (SCREEN_HEIGHT / 2 + 80) - r4.sy
            r4.move = 10
            r4_list.append(r4)

        d_list = []

        for i in range(len(r4_list)):
            ro4 = r4_list[i]
            ro4.y -= ro4.move
            if ro4.y <= 0:
                d_list.append(i)

        d_list.reverse()

        for d in d_list:
            del r4_list[d]

        dm_list = []
        dr_list = []

        for i in range(len(r1_list)):
            for j in range(len(m1_list)):
                mo1 = m1_list[j]
                ro1 = r1_list[i]
                if crash(ro1,mo1) == True:
                    dm_list.append(i)
                    dr_list.append(j)

        dm_list = list(set(dm_list))
        dr_list = list(set(dr_list))

        dm_list.reverse()
        dr_list.reverse()

        try:
            for dm in dm_list:
                del m1_list[dm]
            for dr in dr_list:
                del r1_list[dr]
        except:
            pass

        dm_list = []
        dr_list = []

        for i in range(len(r2_list)):
            for j in range(len(m2_list)):
                mo2 = m2_list[j]
                ro2 = r2_list[i]
                if crash(ro2,mo2) == True:
                    dm_list.append(i)
                    dr_list.append(j)

        dm_list = list(set(dm_list))
        dr_list = list(set(dr_list))

        dm_list.reverse()
        dr_list.reverse()

        try:
            for dm in dm_list:
                del m2_list[dm]
            for dr in dr_list:
                del r2_list[dr]
        except:
            pass

        dm_list = []
        dr_list = []

        for i in range(len(r3_list)):
            for j in range(len(m3_list)):
                mo3 = m3_list[j]
                ro3 = r3_list[i]
                if crash(ro3,mo3) == True:
                    dm_list.append(i)
                    dr_list.append(j)

        dm_list = list(set(dm_list))
        dr_list = list(set(dr_list))

        dm_list.reverse()
        dr_list.reverse()

        try:
            for dm in dm_list:
                del m3_list[dm]
            for dr in dr_list:
                del r3_list[dr]
        except:
            pass

        dm_list = []
        dr_list = []

        for i in range(len(r4_list)):
            for j in range(len(m4_list)):
                mo4 = m4_list[j]
                ro4 = r4_list[i]
                if crash(ro4,mo4) == True:
                    dm_list.append(i)
                    dr_list.append(j)

        dm_list = list(set(dm_list))
        dr_list = list(set(dr_list))

        dm_list.reverse()
        dr_list.reverse()

        try:
            for dm in dm_list:
                del m4_list[dm]
            for dr in dr_list:
                del r4_list[dr]
        except:
            pass

        SCREEN.blit(background,(0,0))
        for mo1 in m1_list:
            mo1.show()
        for mo2 in m2_list:
            mo2.show()
        for mo3 in m3_list:
            mo3.show()
        for mo4 in m4_list:
            mo4.show()
        t1.show()
        t2.show()
        t3.show()
        t4.show()
        for ro1 in r1_list:
            ro1.show()
        for ro2 in r2_list:
            ro2.show()
        for ro3 in r3_list:
            ro3.show()
        for ro4 in r4_list:
            ro4.show()

        font = pg.font.Font(None,30)
        text_durability = font.render("durability : {} / 100".format(durability),True, (0,0,0))
        SCREEN.blit(text_durability,(760,100))

        text_time = font.render("time : {} ".format(delta_time),True, (0,0,0))
        SCREEN.blit(text_time,(760,70))

        text_coin = font.render("coin : {} ".format(coin),True, (0,0,0))
        SCREEN.blit(text_coin,(760,130))

        monster_spawn -= 0.002

        if durability <= 0:
            play = False
            over = True

        pg.display.flip()

    while over == True:
        clock.tick(60)
        for event in pg.event.get():
            if event.type == pg.QUIT:
                over = False
        font = pg.font.Font(None,100)
        text = font.render("Game over",True,(0,0,0))
        SCREEN.blit(text,(350,350))

        font = pg.font.Font(None,50)
        teext = font.render("time : {}".format(delta_time),True,(0,0,0))
        SCREEN.blit(teext,(350,450))
        pg.display.flip()
    pg.quit()

if __name__ == '__main__':
    plaay()


# Importar as bibliotecas
import pygame

# Importar os módulos criados
from decoracao import Ceu
from dados_jogo import levels
from suporte import importar_arquivos

class No(pygame.sprite.Sprite):
    def __init__(self, posicao, estado, velocidade_icone, caminho):
        super().__init__()
        # Criar a imagem e o rect do nó
        self.frames = importar_arquivos(caminho)
        self.indice_frame = 0
        self.velocidade_animacao = 0.15
        self.image = self.frames[self.indice_frame]
        if estado == 'disponivel':
            self.estado = 'disponivel'
        else:
            self.estado = 'indisponivel'
        self.rect = self.image.get_rect(center=posicao)

        # Configurações da zona de detecção de colisão
        esquerda = self.rect.centerx - (velocidade_icone / 2)
        topo = self.rect.centery - (velocidade_icone / 2)
        self.zona_deteccao = pygame.Rect(esquerda, topo, velocidade_icone, velocidade_icone)

    def animar(self):
        """Função responsável por animar os nós no Overworld"""
        self.indice_frame += self.velocidade_animacao
        if self.indice_frame >= len(self.frames):
            self.indice_frame = 0
        self.image = self.frames[int(self.indice_frame)]

    def update(self):
        """Função responsável por atualizar os nós no Overworld"""
        # Animar os nós somente quando o level estiver disponível
        if self.estado == 'disponivel':
            self.animar()
        # Deixar apagado os nós que estão indisponíveis
        else:
            # Copiar a imagem
            no_indisponivel = self.image.copy()

            # Preencher a imagem
            # 1: Cor
            # 2: Objeto Rect
            # 3: Flags (essa flag usada serve para pintar somente os pixels que está o sprite,
            #           onde não tiver sprite, ou seja, o valor de Alfa como 0, não é pintado)
            no_indisponivel.fill('black', None, pygame.BLEND_RGBA_MULT)

            # Colocar a máscara nos nós indisponíveis
            self.image.blit(no_indisponivel, (0, 0))

class Icone(pygame.sprite.Sprite):
    def __init__(self, posicao):
        super().__init__()
        # Criar a imagem e o rect do ícone no Overworld
        self.posicao = posicao  # isso permite usar valores "float" para movimentar o ícone
        self.image = pygame.image.load('../graficos/overworld/chapeu.png').convert_alpha()
        self.rect = self.image.get_rect(center=posicao)

    def update(self):
        """Função responsável por atualizar o sprite do ícone no Overworld"""
        self.rect.center = self.posicao

class Overworld:
    def __init__(self, level_inicial, level_final, tela, criar_level):
        # Configurações iniciais
        self.tela = tela
        self.level_final = level_final
        self.level_atual = level_inicial
        self.criar_level = criar_level
        horizonte = 8

        # Configurações da lógica do movimento no Overworld
        self.movendo = False
        self.velocidade = 8
        self.mover_direcao = pygame.math.Vector2(0, 0)

        # Configurações dos sprites
        self.configuracao_nos()
        self.configuracao_icone()
        self.ceu = Ceu(horizonte, 'overworld')

    def configuracao_nos(self):
        """Função responsável por configurar os nós do mapa do Overworld"""
        # Criar o grupo dos sprites para os nós
        self.nos = pygame.sprite.Group()

        # Verificar se o level do nó é menor ou igual ao "level_final" e colocar cada nó na tela
        for indice_no, dados_nos in enumerate(levels.values()):
            if indice_no <= self.level_final:
                sprite_no = No(dados_nos['pos_no'],
                               'disponivel',
                               self.velocidade,
                               dados_nos['graficos_no'])
            else:
                sprite_no = No(dados_nos['pos_no'],
                               'indisponivel',
                               self.velocidade,
                               dados_nos['graficos_no'])

            # Adicionar os sprites dos nós ao grupo
            self.nos.add(sprite_no)

    def configuracao_icone(self):
        """Função responsável por configurar o ícone do mapa do Overworld"""
        # Criar o grupo de sprite para o ícone
        self.icone = pygame.sprite.GroupSingle()

        # Criar um sprite para o ícone
        # Usar os sprites dos nós, uma vez que já possuímos a posição XY e em qual "self.level_atual"
        # essa posição está na tela
        sprite_icone = Icone(self.nos.sprites()[self.level_atual].rect.center)

        # Adicionar o sprite do ícone ao grupo
        self.icone.add(sprite_icone)

    def desenhar_linhas(self):
        """Função responsável por desenhar as linhas entre os nós"""
        # Desenhar as linhas entre os levels no Overworld depois que o jogador passar do primeiro level
        if self.level_final > 0:
            # Criar uma lista com as posições dos nós para desenhar as linhas
            pontos = [no['pos_no'] for indice_no,
                      no in enumerate(levels.values()) if indice_no <= self.level_final]

            # Desenhar as linhas entre os nós
            # 1: Onde desenhar
            # 2: Cor
            # 3: Preenchimento
            # 4: Ponto de partida e de chegada
            # 5: Espessura da linha
            pygame.draw.lines(self.tela, '#a04f45', False, pontos, 6)

    def entrada(self):
        """Função responsável por obter a entrada de teclas do jogador"""
        # Criar uma lista com as teclas
        teclas = pygame.key.get_pressed()

        # O ícone só se moverá depois de um certo tempo
        if not self.movendo:
            # Verificar se as teclas foram pressionadas
            if teclas[pygame.K_RIGHT] and self.level_atual < self.level_final:
                # Mover o ícone pelo Overworld
                self.mover_direcao = self.obter_dados_movimento('seguinte')
                # Ir para frente até o valor de "self.level_final"
                self.level_atual += 1
                self.movendo = True

            elif teclas[pygame.K_LEFT] and self.level_atual > 0:
                # Mover o ícone pelo Overworld
                self.mover_direcao = self.obter_dados_movimento('anterior')
                # Ir para trás somente quando o ícone não estiver em "self.level_atual" igual a 0
                self.level_atual -= 1
                self.movendo = True

            elif teclas[pygame.K_SPACE]:
                # Entrar no level em que o ícone estiver
                self.criar_level(self.level_atual)

    def obter_dados_movimento(self, sentido):
        """Função responsável a obter os dados dos movimentos do ícone no Overworld"""
        # Obter a posição de saída
        comeco = pygame.math.Vector2(self.nos.sprites()[self.level_atual].rect.center)

        # Posição de cheganda a frente
        if sentido == 'seguinte':
            # Obter a posição de chegada
            final = pygame.math.Vector2(self.nos.sprites()[self.level_atual + 1].rect.center)

        # Posição de chegada atrás
        elif sentido == 'anterior':
            # Obter a posição de chegada
            final = pygame.math.Vector2(self.nos.sprites()[self.level_atual - 1].rect.center)

        # Obter o delta
        delta = final - comeco

        # Normalizar os valores para que fiquem dentro dos limites da tela
        return delta.normalize()

    def movimentar_icone(self):
        """Função responsável a movimentar o ícone no Overworld"""
        # Movimentar o ícone somente quando for permitido e quando estiver no centro do nó
        if self.movendo and self.mover_direcao:
            # Colocar o ícone no centro do nó de "self.level_atual"
            self.icone.sprite.posicao += self.mover_direcao * self.velocidade
            no_alvo = self.nos.sprites()[self.level_atual]

            # Detectar a colisão do sprite do ícone com o Rect inscrito no nó
            if no_alvo.zona_deteccao.collidepoint(self.icone.sprite.posicao):
                self.movendo = False
                self.mover_direcao = pygame.math.Vector2(0, 0)

    def executar(self):
        """Função responsável por executar o Overworld"""
        # Entrada de teclas do jogador
        self.entrada()

        # Movimentar o ícone no Overworld
        self.movimentar_icone()

        # Atualizar o ícone no Overworld
        self.icone.update()

        # Animar os nós no Overworld
        self.nos.update()

        # Desenhar o céu ao fundo do Overworld
        self.ceu.desenhar(self.tela)

        # Desenhar as linhas que ligam os nós
        self.desenhar_linhas()

        # Desenhar o Overworld na tela
        self.nos.draw(self.tela)

        # Desenhar o ícone em cima do nó
        self.icone.draw(self.tela)


import sys
from setuptools import setup, find_packages

NAME = ""
VERSION = "1.0.0"
# To install the library, run the following
#
# python setup.py install
#
# prerequisite: setuptools
# http://pypi.python.org/pypi/setuptools

REQUIRES = ["boto3", "urllib3 >= 1.15", "six >= 1.10", "certifi", "python-dateutil"]

setup(
    name="goldfin_ocr",
    version="1.0.1",
    description="Goldfin Backend Services",
    install_requires=REQUIRES,
    packages=find_packages(),
    include_package_data=True,
    long_description="""\
    Python services for OCR and data series processing
    """,
    entry_points = {
        'console_scripts': [
            'datactl=goldfin_ocr.datactl',
            'scanctl=goldfin_ocr.scanctl',
            'invoicectl=goldfin_ocr.table.invoicectl:exec_cmd'
         ]
    }
)


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

"""
Installs and configures Cinder
"""

import os
import re
import uuid
import logging

from packstack.installer import exceptions
from packstack.installer import processors
from packstack.installer import validators
from packstack.installer.utils import split_hosts

from packstack.installer import basedefs
from packstack.installer import utils

from packstack.modules.shortcuts import get_mq
from packstack.modules.ospluginutils import (getManifestTemplate,
                                             appendManifestFile)

from packstack.installer import exceptions
from packstack.installer import output_messages

#------------------ oVirt installer initialization ------------------

PLUGIN_NAME = "OS-Cinder"
PLUGIN_NAME_COLORED = utils.color_text(PLUGIN_NAME, 'blue')

def initConfig(controller):
    params = [
        {"CMD_OPTION": "cinder-db-passwd",
         "USAGE": "The password to use for the Cinder to access DB",
         "PROMPT": "Enter the password for the Cinder DB access",
         "OPTION_LIST": [],
         "VALIDATORS": [validators.validate_not_empty],
         "DEFAULT_VALUE": uuid.uuid4().hex[:16],
         "MASK_INPUT": True,
         "LOOSE_VALIDATION": False,
         "CONF_NAME": "CONFIG_CINDER_DB_PW",
         "USE_DEFAULT": True,
         "NEED_CONFIRM": True,
         "CONDITION": False},

        {"CMD_OPTION": "cinder-ks-passwd",
         "USAGE": ("The password to use for the Cinder to authenticate with "
                   "Keystone"),
         "PROMPT": "Enter the password for the Cinder Keystone access",
         "OPTION_LIST": [],
         "VALIDATORS": [validators.validate_not_empty],
         "DEFAULT_VALUE": uuid.uuid4().hex[:16],
         "MASK_INPUT": True,
         "LOOSE_VALIDATION": False,
         "CONF_NAME": "CONFIG_CINDER_KS_PW",
         "USE_DEFAULT": True,
         "NEED_CONFIRM": True,
         "CONDITION": False},

        {"CMD_OPTION": "cinder-backend",
         "USAGE": ("The Cinder backend to use, valid options are: lvm, "
                   "gluster, nfs, ceph"),
         "PROMPT": "Enter the Cinder backend to be configured",
         "OPTION_LIST": ["lvm", "gluster", "nfs", "vmdk", "ceph"],
         "VALIDATORS": [validators.validate_options],
         "DEFAULT_VALUE": "lvm",
         "MASK_INPUT": False,
         "LOOSE_VALIDATION": False,
         "CONF_NAME": "CONFIG_CINDER_BACKEND",
         "USE_DEFAULT": False,
         "NEED_CONFIRM": False,
         "CONDITION": False},
    ]
    group = {"GROUP_NAME": "CINDER",
             "DESCRIPTION": "Cinder Config parameters",
             "PRE_CONDITION": "CONFIG_CINDER_INSTALL",
             "PRE_CONDITION_MATCH": "y",
             "POST_CONDITION": False,
             "POST_CONDITION_MATCH": True}
    controller.addGroup(group, params)

    def check_lvm_options(config):
        return (config.get('CONFIG_CINDER_INSTALL', 'n') == 'y' and
                config.get('CONFIG_CINDER_BACKEND', 'lvm') == 'lvm')

    params = [
        {"CMD_OPTION": "cinder-volumes-create",
         "USAGE": ("Create Cinder's volumes group. This should only be done "
                   "for testing on a proof-of-concept installation of Cinder. "
                   "This will create a file-backed volume group and is not "
                   "suitable for production usage."),
         "PROMPT": ("Should Cinder's volumes group be created (for "
                    "proof-of-concept installation)?"),
         "OPTION_LIST": ["y", "n"],
         "VALIDATORS": [validators.validate_options],
         "DEFAULT_VALUE": "y",
         "MASK_INPUT": False,
         "LOOSE_VALIDATION": False,
         "CONF_NAME": "CONFIG_CINDER_VOLUMES_CREATE",
         "USE_DEFAULT": False,
         "NEED_CONFIRM": False,
         "CONDITION": False},
    ]
    group = {"GROUP_NAME": "CINDERVOLUMECREATE",
             "DESCRIPTION": "Cinder volume create Config parameters",
             "PRE_CONDITION": check_lvm_options,
             "PRE_CONDITION_MATCH": True,
             "POST_CONDITION": False,
             "POST_CONDITION_MATCH": True}
    controller.addGroup(group, params)

    def check_lvm_vg_options(config):
        return (config.get('CONFIG_CINDER_INSTALL', 'n') == 'y' and
                config.get('CONFIG_CINDER_BACKEND', 'lvm') == 'lvm' and
                config.get('CONFIG_CINDER_VOLUMES_CREATE', 'y') == 'y')

    params = [
        {"CMD_OPTION": "cinder-volumes-size",
         "USAGE": ("Cinder's volumes group size. Note that actual volume size "
                   "will be extended with 3% more space for VG metadata."),
         "PROMPT": "Enter Cinder's volumes group usable size",
         "OPTION_LIST": [],
         "VALIDATORS": [validators.validate_not_empty],
         "DEFAULT_VALUE": "20G",
         "MASK_INPUT": False,
         "LOOSE_VALIDATION": False,
         "CONF_NAME": "CONFIG_CINDER_VOLUMES_SIZE",
         "USE_DEFAULT": False,
         "NEED_CONFIRM": False,
         "CONDITION": False},
    ]
    group = {"GROUP_NAME": "CINDERVOLUMESIZE",
             "DESCRIPTION": "Cinder volume size Config parameters",
             "PRE_CONDITION": check_lvm_vg_options,
             "PRE_CONDITION_MATCH": True,
             "POST_CONDITION": False,
             "POST_CONDITION_MATCH": True}
    controller.addGroup(group, params)

    def check_gluster_options(config):
        return (config.get('CONFIG_CINDER_INSTALL', 'n') == 'y' and
                config.get('CONFIG_CINDER_BACKEND', 'lvm') == 'gluster')

    params = [
        {"CMD_OPTION": "cinder-gluster-mounts",
         "USAGE": ("A single or comma separated list of gluster volume shares "
                   "to mount, eg: ip-address:/vol-name, domain:/vol-name "),
         "PROMPT": ("Enter a single or comma separated list of gluster volume "
                    "shares to use with Cinder"),
         "OPTION_LIST": ["^'([\d]{1,3}\.){3}[\d]{1,3}:/.*'",
                         "^'[a-zA-Z0-9][\-\.\w]*:/.*'"],
         "VALIDATORS": [validators.validate_multi_regexp],
         "PROCESSORS": [processors.process_add_quotes_around_values],
         "DEFAULT_VALUE": "",
         "MASK_INPUT": False,
         "LOOSE_VALIDATION": True,
         "CONF_NAME": "CONFIG_CINDER_GLUSTER_MOUNTS",
         "USE_DEFAULT": False,
         "NEED_CONFIRM": False,
         "CONDITION": False},
    ]
    group = {"GROUP_NAME": "CINDERGLUSTERMOUNTS",
             "DESCRIPTION": "Cinder gluster Config parameters",
             "PRE_CONDITION": check_gluster_options,
             "PRE_CONDITION_MATCH": True,
             "POST_CONDITION": False,
             "POST_CONDITION_MATCH": True}
    controller.addGroup(group, params)

    def check_nfs_options(config):
        return (config.get('CONFIG_CINDER_INSTALL', 'n') == 'y' and
                config.get('CONFIG_CINDER_BACKEND', 'lvm') == 'nfs')

    params = [
        {"CMD_OPTION": "cinder-nfs-mounts",
         "USAGE": ("A single or comma seprated list of NFS exports to mount, "
                   "eg: ip-address:/export-name "),
         "PROMPT": ("Enter a single or comma seprated list of NFS exports to "
                    "use with Cinder"),
         "OPTION_LIST": ["^'([\d]{1,3}\.){3}[\d]{1,3}:/.*'"],
         "VALIDATORS": [validators.validate_multi_regexp],
         "PROCESSORS": [processors.process_add_quotes_around_values],
         "DEFAULT_VALUE": "",
         "MASK_INPUT": False,
         "LOOSE_VALIDATION": True,
         "CONF_NAME": "CONFIG_CINDER_NFS_MOUNTS",
         "USE_DEFAULT": False,
         "NEED_CONFIRM": False,
         "CONDITION": False},
    ]
    group = {"GROUP_NAME": "CINDERNFSMOUNTS",
             "DESCRIPTION": "Cinder NFS Config parameters",
             "PRE_CONDITION": check_nfs_options,
             "PRE_CONDITION_MATCH": True,
             "POST_CONDITION": False,
             "POST_CONDITION_MATCH": True}
    controller.addGroup(group, params)

def initSequences(controller):
    if controller.CONF['CONFIG_CINDER_INSTALL'] != 'y':
        return

    cinder_steps = [
        {'title': 'Adding Cinder Keystone manifest entries',
         'functions': [create_keystone_manifest]},
        {'title': 'Adding Cinder Ceph preflight entries',
         'functions': [create_ceph_preflight_manifest]},
        {'title': 'Adding Cinder manifest entries',
         'functions': [create_manifest]}
    ]

    if controller.CONF['CONFIG_CINDER_BACKEND'] == 'lvm':
        cinder_steps.append(
            {'title': 'Checking if the Cinder server has a cinder-volumes vg',
             'functions': [check_cinder_vg]})
    controller.addSequence("Installing OpenStack Cinder", [], [], cinder_steps)

#-------------------------- step functions --------------------------

def check_cinder_vg(config, messages):
    cinders_volume = 'cinder-volumes'
    if config['CONFIG_UNSUPPORTED'] != 'y':
        config['CONFIG_STORAGE_HOST'] = config['CONFIG_CONTROLLER_HOST']

    # Do we have a cinder-volumes vg?
    have_cinders_volume = False
    server = utils.ScriptRunner(config['CONFIG_STORAGE_HOST'])
    server.append('vgdisplay %s' % cinders_volume)
    try:
        server.execute()
        have_cinders_volume = True
    except exceptions.ScriptRuntimeError:
        pass

    # Configure system LVM settings (snapshot_autoextend)
    # Only if /etc/lvm/lvm.conf exists on the system.
    server = utils.ScriptRunner(config['CONFIG_STORAGE_HOST'])
    server.append('[[ -f /etc/lvm/lvm.conf ]] && '
                  'sed -i -r "s/^ *snapshot_autoextend_threshold +=.*/'
                  '    snapshot_autoextend_threshold = 80/" '
                  '/etc/lvm/lvm.conf || '
                  'echo "No /etc/lvm/lvm.conf file found"')
    server.append('[[ -f /etc/lvm/lvm.conf ]] && '
                  'sed -i -r "s/^ *snapshot_autoextend_percent +=.*/'
                  '    snapshot_autoextend_percent = 20/" '
                  '/etc/lvm/lvm.conf || '
                  'echo "No /etc/lvm/lvm.conf file found"')
    try:
        server.execute()
    except exceptions.ScriptRuntimeError:
        logging.info("Warning: Unable to set system LVM settings.")

    if config["CONFIG_CINDER_VOLUMES_CREATE"] != "y":
        if not have_cinders_volume:
            raise exceptions.MissingRequirements("The cinder server should "
                                                 "contain a cinder-volumes "
                                                 "volume group")
    else:
        if have_cinders_volume:
            messages.append(
                output_messages.INFO_CINDER_VOLUMES_EXISTS)
            return

        # TO-DO: This is implemented in cinder::setup_test_volume class.
        #        We should use it instead of this Python code
        server = utils.ScriptRunner(config['CONFIG_STORAGE_HOST'])
        server.append('systemctl')
        try:
            server.execute()
            rst_cmd = 'systemctl restart openstack-cinder-volume.service'
        except exceptions.ScriptRuntimeError:
            rst_cmd = 'service openstack-cinder-volume restart'

        server.clear()
        logging.info("A new cinder volumes group will be created")
        server.append('yum install -y lvm2')

        # Configure system LVM settings (snapshot_autoextend)
        # Just after the lvm2 rpm installation !
        server.append('[[ -f /etc/lvm/lvm.conf ]] && '
                      'sed -i -r "s/^ *snapshot_autoextend_threshold +=.*/'
                      '    snapshot_autoextend_threshold = 80/" '
                      '/etc/lvm/lvm.conf || '
                      'echo "No /etc/lvm/lvm.conf file found"')
        server.append('[[ -f /etc/lvm/lvm.conf ]] && '
                      'sed -i -r "s/^ *snapshot_autoextend_percent +=.*/'
                      '    snapshot_autoextend_percent = 20/" '
                      '/etc/lvm/lvm.conf || '
                      'echo "No /etc/lvm/lvm.conf file found"')

        cinders_volume_path = '/var/lib/cinder'
        server.append('mkdir -p  %s' % cinders_volume_path)
        logging.debug("Volume's path: %s" % cinders_volume_path)

        match = re.match('^(?P<size>\d+)G$',
                         config['CONFIG_CINDER_VOLUMES_SIZE'].strip())
        if not match:
            msg = 'Invalid Cinder volumes VG size.'
            raise exceptions.ParamValidationError(msg)

        cinders_volume_size = int(match.group('size')) * 1024
        cinders_reserve = int(cinders_volume_size * 0.03)

        cinders_volume_size = cinders_volume_size + cinders_reserve
        cinders_volume_path = os.path.join(cinders_volume_path, cinders_volume)
        server.append('dd if=/dev/zero of=%s bs=1 count=0 seek=%sM'
                      % (cinders_volume_path, cinders_volume_size))
        server.append('LOFI=$(losetup --show -f  %s)' % cinders_volume_path)
        server.append('pvcreate $LOFI')
        server.append('vgcreate %s $LOFI' % cinders_volume)

        # Add the loop device on boot
        server.append('grep %(volume)s /etc/rc.d/rc.local || '
                      'echo "losetup -f %(path)s && '
                      'vgchange -a y %(volume)s && '
                      '%(restart_cmd)s" '
                      '>> /etc/rc.d/rc.local' %
                      {'volume': cinders_volume, 'restart_cmd': rst_cmd,
                       'path': cinders_volume_path})
        server.append('grep "#!" /etc/rc.d/rc.local || '
                      'sed -i \'1i#!/bin/sh\' /etc/rc.d/rc.local')
        server.append('chmod +x /etc/rc.d/rc.local')

        # Let's make sure it exists
        server.append('vgdisplay %s' % cinders_volume)

        try:
            server.execute()
        except exceptions.ScriptRuntimeError:
            # Release loop device if cinder's volume creation
            # fails.
            try:
                logging.debug("Release loop device, volume creation failed")
                server = utils.ScriptRunner(config['CONFIG_STORAGE_HOST'])
                server.append('losetup -d $(losetup -j %s | cut -d : -f 1)'
                              % cinders_volume_path)
                server.execute()
            except:
                pass

            raise exceptions.MissingRequirements("Cinder's volume group '%s' "
                                                 "could not be created"
                                                 % cinders_volume)

def create_keystone_manifest(config, messages):
    if config['CONFIG_UNSUPPORTED'] != 'y':
        config['CONFIG_STORAGE_HOST'] = config['CONFIG_CONTROLLER_HOST']

    manifestfile = "%s_keystone.pp" % config['CONFIG_CONTROLLER_HOST']
    manifestdata = getManifestTemplate("keystone_cinder.pp")
    appendManifestFile(manifestfile, manifestdata)

def create_manifest(config, messages):
    if config['CONFIG_UNSUPPORTED'] != 'y':
        config['CONFIG_STORAGE_HOST'] = config['CONFIG_CONTROLLER_HOST']

    manifestdata = getManifestTemplate(get_mq(config, "cinder"))
    manifestfile = "%s_cinder.pp" % config['CONFIG_STORAGE_HOST']
    manifestdata += getManifestTemplate("cinder.pp")

    if config['CONFIG_CINDER_BACKEND'] == "lvm":
        manifestdata += getManifestTemplate("cinder_lvm.pp")
    elif config['CONFIG_CINDER_BACKEND'] == "gluster":
        manifestdata += getManifestTemplate("cinder_gluster.pp")
    elif config['CONFIG_CINDER_BACKEND'] == "nfs":
        manifestdata += getManifestTemplate("cinder_nfs.pp")
    elif config['CONFIG_CINDER_BACKEND'] == "vmdk":
        manifestdata += getManifestTemplate("cinder_vmdk.pp")
    elif config['CONFIG_CINDER_BACKEND'] == "ceph":
        manifestdata += getManifestTemplate("cinder_ceph.pp")
    if config['CONFIG_CEILOMETER_INSTALL'] == 'y':
        manifestdata += getManifestTemplate('cinder_ceilometer.pp')
    if config['CONFIG_SWIFT_INSTALL'] == 'y':
        manifestdata += getManifestTemplate('cinder_backup.pp')

    config['FIREWALL_SERVICE_NAME'] = "cinder"
    config['FIREWALL_PORTS'] = "['3260']"
    config['FIREWALL_CHAIN'] = "INPUT"
    config['FIREWALL_PROTOCOL'] = 'tcp'
    if (config['CONFIG_NOVA_INSTALL'] == 'y' and
            config['CONFIG_VMWARE_BACKEND'] == 'n'):
        for host in split_hosts(config['CONFIG_COMPUTE_HOSTS']):
            config['FIREWALL_ALLOWED'] = "'%s'" % host
            config['FIREWALL_SERVICE_ID'] = "cinder_%s" % host
            manifestdata += getManifestTemplate("firewall.pp")
    else:
        config['FIREWALL_ALLOWED'] = "'ALL'"
        config['FIREWALL_SERVICE_ID'] = "cinder_ALL"
        manifestdata += getManifestTemplate("firewall.pp")
    # cinder API should be open for everyone
    config['FIREWALL_SERVICE_NAME'] = "cinder-api"
    config['FIREWALL_ALLOWED'] = "'ALL'"
    config['FIREWALL_SERVICE_ID'] = "cinder_API"
    config['FIREWALL_PORTS'] = "['8776']"
    manifestdata += getManifestTemplate("firewall.pp")
    appendManifestFile(manifestfile, manifestdata)

def create_ceph_preflight_manifest(config, messages):
    for host in split_hosts(config['CONFIG_CEPH_STORAGE_HOSTS']):
        manifest_file = "%s_ceph_firewall.pp" % host
        # Firewall Rules for dhcp in
        config['FIREWALL_PROTOCOL'] = 'tcp'
        config['FIREWALL_ALLOWED'] = "'ALL'"
        config['FIREWALL_SERVICE_NAME'] = "Ceph monitor: "
        config['FIREWALL_SERVICE_ID'] = "ceph_monitor_%s" % host
        config['FIREWALL_PORTS'] = "['6789']"
        config['FIREWALL_CHAIN'] = "INPUT"
        manifest_data = getManifestTemplate("firewall.pp")
        # Firewall Rules for dhcp out
        config['FIREWALL_PROTOCOL'] = 'tcp'
        config['FIREWALL_ALLOWED'] = "'ALL'"
        config['FIREWALL_SERVICE_NAME'] = "Ceph OSDs"
        config['FIREWALL_SERVICE_ID'] = "ceph_osds_%s" % host
        config['FIREWALL_PORTS'] = "['6800-7100']"
        config['FIREWALL_CHAIN'] = "INPUT"
        manifest_data += getManifestTemplate("firewall.pp")
        appendManifestFile(manifest_file, manifest_data)


"""
Run year-end work statistics
"""

from django.conf import settings
from django.core.management.base import BaseCommand
from django.utils import translation
from django.db.models import Sum, Count

import arbeitsplan.models as models

class Command(BaseCommand):
    """Go through all Users and Aufgaben.
    Check whether at most one Meldung exist.
    """

    args = ""
    help = "Produce statistics for yearly analysis"

    def handle(self, *args, **options):
        # set the locale right, to get the dates represented correctly
        translation.activate(settings.LANGUAGE_CODE)

        # Leistungen

        with open('leistungen.csv', 'w') as csvfile:
            csvfile.write('#AufgabeNr, Aufgabe, Gruppe, Angefordert(h), Geleistet(h), #Personen, #Durchschnitt\n')
            l = (models.Leistung.objects
                 .filter(status='AK')
                 .values('aufgabe','aufgabe__aufgabe',
                                               'aufgabe__anzahl','aufgabe__stunden',
                                               'aufgabe__gruppe__gruppe')\
                 .annotate(geleistet=Sum('zeit'))\
                 .annotate(melder=Count('melder', distinct=True))
                 )

            # self.stdout.write('#'.join(['{}-{}'.format(x[0], x[1]) for x in l[0].items()]))

            for ll in l:
                csvfile.write('{},{},{},{},{},{},{}\n'.format(
                    ll['aufgabe'],
                    ll['aufgabe__aufgabe'].encode('utf8'),
                    ll['aufgabe__gruppe__gruppe'].encode('utf8'),
                    ll['aufgabe__anzahl'] * ll['aufgabe__stunden'],
                    int(ll['geleistet']),
                    ll['melder'],
                    float(ll['geleistet'])/ll['melder'],
                ))

        translation.deactivate()


import os
import sys
import string
from itertools import (
    product
)
from typing import (
    List,
    Tuple,
    Any,
    Optional,
)
import contextlib

CSV_FIELD_DELIMITER: str = ","
OS_EOL_CHARACTER = os.linesep

@contextlib.contextmanager
def smart_open(filename=None):
    if filename and filename != '-':
        fh = open(filename, 'w', encoding='utf-8')
    else:
        fh = sys.stdout

    try:
        yield fh
    finally:
        if fh is not sys.stdout:
            fh.close()

def generate_alphabet_combinations(length: int = 2) -> List[str]:
    """Generate cartesian product of alphabet characters of up to the length
    If n is 2, then ['a', 'b', 'c', ..., 'aa', ..., 'zz']
    Args:
        length: length of the string generated
    Returns: Combination of alphabet characters up to length.
    """
    assert length > 0
    alphabets = string.ascii_lowercase

    return [
        ''.join(combination)
        for n in range(1, length+1)
        for combination in product(alphabets, repeat=n)
    ]

def is_number(entity: Any) -> Tuple[bool, Optional[float]]:
    """Check if the input is a number
    Args:
        entity: input variable to test
    Returns: (result, value) where value is float if the input is the number or None.
    """
    try:
        number: float = float(entity)
        return True, number
    except ValueError:
        return False, None

def test_is_number():
    assert is_number("-.1")[0]
    assert not is_number("hoge")[0]


from django.shortcuts import render

from .models import Article

# Create your views here.
def blog(request):

    articles = Article.objects.filter(online=True).order_by('last_update_date')
    categories = Article.get_categories_from(articles)

    context = {
        'articles': articles,
        'categories': categories,
    }

    return render(request, 'arteablog/blog/index.html', context)

def article(request, id):

    article = Article.objects.filter(id=id).first()

    context = {
        'article': article,
    }

    return render(request, 'arteablog/article/index.html', context)


import neural_network_functions as nn_funcs
from neural_network import NeuralNetwork
from matplotlib import pyplot as plt
import random

nn = NeuralNetwork([3, 1], nn_funcs.sigmoid_act_f, nn_funcs.linear_cost_f)

# DATASET -> I'm trying to create a nn that detects if sum of 3 inputs are 1.5 or higher

dataset = []
expected_outputs = []

for i in range(2000):
    dataset.append([random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1)])

    if dataset[i][0] > 0.8 or dataset[i][1] > 0.3 or dataset[i][2] > 0.3:
        expected_outputs.append([1])
    else:
        expected_outputs.append([0])

    # expected_outputs.append([1 if sum(dataset[i]) >= 1.5 else 0])

# Dividing data in two groups, training group and control group
training_data_len = int(len(dataset) * 0.7)

training_data = dataset[:training_data_len]
expected_training_data = expected_outputs[:training_data_len]

control_data = dataset[training_data_len:]
expected_control_data = expected_outputs[training_data_len:]

nn.train(training_data, expected_outputs[:training_data_len], 200, 0.01)

print(nn)

correct_predictions = 0
for data_index in range(len(control_data)):
    output = nn.get_output(control_data[data_index])
    if output[0] > 0.5:
        output = 1
    else:
        output = 0

    if output == expected_control_data[data_index][0]:
        correct_predictions += 1

print("Predicted correctly {}/{} inputs".format(correct_predictions, len(control_data)))

X = range(len(nn.historic))
Y = nn.historic
plt.scatter(X, Y)

plt.show()

print("Prueba introduciendo números del 0 al 1")

while True:
    _input = [float(input("x0: ")), float(input("x1: ")), float(input("x2: "))]
    print(nn.get_output(_input))


"""
   This script relies on settings in config.toml file
   * extract the list of workflows (vidarr .gsiWorkflow files)
   * extract all gsiOlive files, parse them to extract wf names, their versions and modules
   * find all wf repos, if missing - construct from a gsiWorkflow name
   * bring all info together and format into HTML or tsv. Also, dump a json file
"""
import collections
import tomli
import argparse
import json
import os
from git import Git
import gsiWorkflow
import gsiOlive
import gsiRepository as rP
import htmlRenderer

settings = {}

"""
     We operate with Workflow entries, which are dataclasses

     Research Tag(s): [],
     Clinical Tag(s): []
     Latest Tag:
     Repo:
     Research Olives: []
     Clinical Olives: []
     Code Modules: []
     Data Modules: []
"""

"""
   Load settings file and return a dict with obtained values
"""
def load_config(path):
    try:
        with open(path, "rb") as f:
            toml_dict = tomli.load(f)
            print("Loaded configuration file")
    except tomli.TOMLDecodeError:
        print("Failed to load settings, invalid format")
    return toml_dict

"""
   update local copy of the repo, cd in it checkout main branch and pull
"""
def update_source(path: str, main_branch: str):
    try:
        g = Git(path)
        g.checkout(main_branch)
        g.pull()
    except:
        print("failed to update sources")

"""
    From the list of names, pick the shortest and strip it of all known prefixes
"""
def get_raw_name(names: list) -> str:
    raw_name = min((word for word in names if word), key=len)
    if 'prefixes' in settings.keys():
        for prx in settings['prefixes'].values():
            raw_name = raw_name.replace(prx, "")
            raw_name = raw_name.rstrip("_")
    return raw_name

"""
    Join metadata from olives with gsiWorkflow-derived information, return hash
"""
def join_metadata(olive_data: dict, repo_data: dict, wf: str) -> dict:
    """ Join instance-specific modules with wdl-derived modules, keep things unique """
    merged_data = {}
    d_modules = set()
    c_modules = set()
    try:
        for inst in (settings['instances'].values()):
            if inst in olive_info[wf].keys():
                vetted_olives = [os.path.basename(o) for o in olive_info[wf][inst]['olives']]
                d_modules = olive_data[inst]['data_modules'].union(repo_data['data_modules'])
                c_modules = olive_data[inst]['code_modules'].union(repo_data['code_modules'])
                merged_data[inst] = {'olives': vetted_olives,
                                     'tags': list(olive_data[inst]['tags'])}
        merged_data['latest_tag'] = repo_data['latest_tag']
        merged_data['url'] = repo_data['url']
        merged_data['data_modules'] = list(d_modules)
        merged_data['code_modules'] = list(c_modules)
    except:
        print(f'ERROR: Failed to merge gsiOlive and repo data for {wf}')

    return merged_data

"""
   ====================== Main entrance point to the script =============================
   pass (or not) the following:
   -s settings: path to the TOML file with all settings
   -o output json file
   -p output HTML page

   we have defaults for everything
   at the end, script prints out data as a table and dumps data in a json
"""

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Run parsing script to generate gsiWorkflow status table')
    parser.add_argument('-s', '--settings', help='Settings file in TOML format', required=False, default="config.toml")
    parser.add_argument('-o', '--output-json', help='Output json', required=False, default="gsi_workflows.json")
    parser.add_argument('-p', '--output-page', help='Output page, HTML', required=False, default="gsi_workflows.html")
    args = parser.parse_args()

    settings_path = args.settings
    output_json = args.output_json
    output_page = args.output_page
    ''' A. Load settings and Update local copy of the repo'''
    settings = load_config(settings_path)
    try:
        update_source(settings["repo"]["local_olive_dir"], settings["repo"]["main"])
    except:
        print("ERROR: Failed to update local repo copy from the web")

    ''' B. Load gsiWorkflow names from .vidarrworkflow files without prefixes into a dict keyed by instance '''
    instances = []
    wf_names = {}
    olive_files = {}
    if "instances" in settings.keys():
        for i in settings["instances"].keys():
            instances.append(settings["instances"][i])
        prefixes = []
        if "prefixes" in settings.keys():
            prefixes = settings['prefixes'].values()
        wf_names = gsiWorkflow.extract_wf_names(settings["repo"]["local_olive_dir"], instances, prefixes)
    else:
        print("ERROR: THere are no instances to check, fix your settings")

    ''' C. collect and process olives, extract modules and tags '''
    olive_files = {}
    olive_info = {}
    if 'aliases' in settings.keys():
        olive_files = gsiOlive.collect_olives(settings["repo"]["local_olive_dir"], instances, settings['aliases'])
    else:
        olive_files = gsiOlive.collect_olives(settings["repo"]["local_olive_dir"], instances, {})
    olive_info = gsiOlive.extract_olive_info(olive_files, wf_names)

    vetted_data = {}
    ''' D. If configured, try getting list of repos from github (a dict keyed by gsiWorkflow name with no prefixes)'''
    if 'organization' in settings['repo'].keys() and 'token' in settings['repo'].keys():
        org = settings['repo']['organization']
        token = settings['repo']['token']
        myRepo = rP.githubRepo(org, token)
        repo_list = myRepo.get_repo_list()
        if len(repo_list) == 0:
            print("ERROR: Could not retrieve the list of repositories, check the queue and token are Ok")
        repo_info = {}
        ''' E. use repo list, load vidarrbuild.json and wdl and return a hash with names and modules '''
        for repo in repo_list.keys():
            print(f'Processing repository [{repo}]...')
            try:
                wf_data = myRepo.get_file_content(repo, "vidarrbuild.json")
                wf_info = json.loads(wf_data)
                wf_id = get_raw_name(wf_info['names'])
                if wf_id in olive_info.keys() and len(olive_info[wf_id]) != 0:
                    wf_wdl = myRepo.get_file_content(repo, wf_info['wdl'])
                    wf_wdl_lines = str(wf_wdl, encoding='utf-8').split("\n")
                    wf_latest = myRepo.get_latest_tag(repo)
                    wf_modules = gsiWorkflow.parse_workflow(repo, wf_wdl_lines)
                    repo_info[wf_id] = {'url': repo_list[repo],
                                        'latest_tag': wf_latest,
                                        'data_modules': wf_modules['data_modules'],
                                        'code_modules': wf_modules['code_modules']}
                else:
                    print(f'WARNING: Skipping [{wf_id}] as it is not currently in use...')
            except TypeError:
                print(f'WARNING: Repo [{repo}] Does not have information expected for a gsiWorkflow')
            except:
                print(f'ERROR: Collection of information for [{repo}] failed')

        if len(repo_info) == 0:
            print("ERROR: Information from gsiWorkflow repositories could not be collected")

        ''' F. Join two pieces of information, repo-derived info and gsiOlive-derived info '''
        for wf_id in olive_info.keys():
            if wf_id in repo_info.keys():
                vetted_data[wf_id] = join_metadata(olive_info[wf_id], repo_info[wf_id], wf_id)
            else:
                print(f'ERROR: Was not able to collect data for [{wf_id}]')
    else:
        print("ERROR: Repo credentials are not configured, no update from github is possible")

''' G. Dump the data into json file and generate a HTML page '''
if len(vetted_data) > 0:
    vetted_od = collections.OrderedDict(sorted(vetted_data.items()))
    with open(output_json, "w") as wfj:
        json.dump(vetted_od, wfj)

    html_page = htmlRenderer.convert2page(vetted_od)
    '''Return either HTML table or entire page'''
    with open(output_page, 'w') as op:
        op.write(html_page)
else:
    print("ERROR: Was not able to collect up-to-date information, examine this log and make changes")

# TODO: Fix the following:
"""
   ERROR: Was not able to collect data for [pbcmProjectMedipsPipe]
   ERROR: Was not able to collect data for [crosscheckFingerprintsCollector_fastq]
   ERROR: Was not able to collect data for [umiCollapse_CM]
   ERROR: Was not able to collect data for [dnaSeqQC_MiSeq]
"""

# See PyCharm help at https://www.jetbrains.com/help/pycharm/


from recipes.tests.recipe_test_base import RecipeTestBase
from django.core.exceptions import ValidationError
from recipes.models import Category

class TestRecipesModelCategory(RecipeTestBase):
    def setUp(self):
        self.category = self.make_category()
        super().setUp()

    def test_recipe_category_name_max_length(self):
        max_length = 65
        self.category.name = 'a' * (max_length + 1)

        with self.assertRaises(ValidationError) as e:
            self.category.full_clean()
            self.category.save()

    def test_recipe_category_str_method_returns_recipe_title(self):
        self.category.name = 'Other Category'
        self.assertEqual(str(self.category), self.category.name)


# -*- coding: utf8 -*-
import scipy
import librosa
import numpy as np
import wave
from os import path, listdir

NMFCC = 13
K = 7

class Char:
	def __init__(self, label, url):
		self.label = label
		self.url = url
		(y, fs) = getSignal(url)
		self.mfcc = getMFCC(y, fs)
		self.fs = fs
	def getFilename(self):
		return path.split(self.url)[-1]
	def getVideoInfo(self):
		p = self.getFilename()
		[start, end, video] = p.split('_')
		start = float(start)/self.fs
		end = float(end)/self.fs
		video = video.split('.')[0] + '.mp4'
		return [start, end, video]
	@staticmethod
	def createFromSig(y, fs):
		t = type('Char', (), {})()
		t.label = 'unknown'
		t.url = ''
		t.mfcc = getMFCC(y, fs)
		return t

class Dictionary:
	def __init__(self):
		self.sum = {}
		self.cnt = {}
		self._min = {}
		self._min_chars = {}
	def addChar(self, char, dist):
		label = char.label
		if label not in self._min:
			self.sum[label] = dist
			self.cnt[label] = 1
			self._min[label] = dist
			self._min_chars[label] = char
		else:
			self.sum[label] += dist
			self.cnt[label] += 1
			if dist < self._min[label]:
				self._min[label] = dist
				self._min_chars[label] = char
	def getClassifiedChar(self):
		min_avg_dist = np.inf
		classified_char = None
		for k in self._min:
			if(self.sum[k]/self.cnt[k] < min_avg_dist):
				min_avg_dist = self.sum[k]/self.cnt[k]
				classified_char = self._min_chars[k]
		return classified_char

def getSignal(url):
	f = wave.open(url, "rb")
	params = f.getparams()
	nchannels, sampwidth, framerate, nframes = params[:4]
	str_data = f.readframes(nframes)
	f.close()
	y = np.fromstring(str_data, dtype=np.short)
	if nchannels == 2:
		y.shape = -1, 2
		y = y.T
		y = y[0]
	return (y, framerate)

def getMFCC(y, framerate, path=None):
	mfcc = librosa.feature.mfcc(y, framerate, n_mfcc=NMFCC)
	mfcc_delta = librosa.feature.delta(mfcc)
	mfcc_2delta = librosa.feature.delta(mfcc_delta)
	return mfcc + mfcc_delta*0.6 + mfcc_2delta*0.3

def getDist(p1, p2):
	#Both of dimention NMFCC
	t = 0
	for i in range(1, NMFCC-1):
		a = (p1[i]-p1[i-1] + (p1[i+1]-p1[i-1])/2)/2
		b = (p2[i]-p2[i-1] + (p2[i+1]-p2[i-1])/2)/2
		t += (a-b)**2
	return t**0.5

def getDTW(mfcc1, mfcc2): #tail free!?
	n = len(mfcc1.T)
	m = len(mfcc2.T)
	if m > n: # I want n to be bigger!
		[mfcc1, mfcc2] = [mfcc2, mfcc1]
		[m, n] = [n, m]
	d = np.zeros(shape=(n, m)) + np.inf
	wall = int(m/2)
	new_n = m-1+wall
	if new_n > n-1:
		new_n = n-1
	recursiveGetDTW(new_n, m-1, d, mfcc1, mfcc2, wall)
	mini = np.inf
	for i in range(0, new_n):
		mini = min(mini, d[i][m-1])
	for i in range(0, m):
		mini = min(mini, d[n-1][i])
	return mini/(m+n+1)

def recursiveGetDTW(i, j, d, mfcc1, mfcc2, wall):
	if abs(i-j) > wall or i < 0 or j < 0:
		return np.inf
	if i == j and i == 0:
		return 0
	if d[i][j] != np.inf:
		return d[i][j]
	a = recursiveGetDTW(i-1, j, d, mfcc1, mfcc2, wall)
	b = recursiveGetDTW(i, j-1, d, mfcc1, mfcc2, wall)
	c = recursiveGetDTW(i-1, j-1, d, mfcc1, mfcc2, wall)
	d[i][j] = min(a, b, c) + getDist(mfcc1.T[i], mfcc2.T[j])
	return d[i][j]

def classify(chars, char):
	d = Dictionary()
	label = None
	for c in chars:
		if c.url == char.url:
			continue
		dist = getDTW(c.mfcc, char.mfcc)
		d.addChar(c, dist)
	return d.getClassifiedChar()

def getCharArray(url):
	fn = path.join(url, 'label')
	chars = []
	if not path.exists(fn):
		for name in listdir(path.join(url, 'data')):
			p = path.join(url, 'data', name)
			chars += [Char(None, path.abspath(p))]
		return chars
	f = open(fn)
	s = f.read()
	a = s.split()
	chars = []
	for i in range(0, len(a), 2):
		fn = path.join(url, 'data', a[i])
		p = path.abspath(fn)
		label = int(a[i+1])
		chars += [Char(label, p)]
	return chars


from pprint import pprint
from typing import List

def solution(arr):
    size = len(arr)
    results = []
    stack = []
    flags = [False] * size

    def backtrack():
        if len(stack) == size:
            results.append(stack.copy())
            return

        for i in range(size):
            if not flags[i]:
                stack.append(arr[i])
                flags[i] = True
                backtrack()
                stack.pop()
                flags[i] = False

    backtrack()
    return results

class Solution2:
    def permute(self, nums: List[int]) -> List[List[int]]:
        results = []
        route = []
        # cache_sum = 0
        total_sum = sum(nums)
        # print(total_sum)
        def backtrack(t_sum, total_sum):

            if len(route) == len(nums) and t_sum == total_sum:
                results.append(route[:])
                return
            elif len(route) == len(nums) and t_sum != total_sum:
                return
            for item in nums:
                t_sum += item
                route.append(item)
                backtrack(t_sum,total_sum)
                t_sum -= route.pop()

        backtrack(0, total_sum)
        return results

if __name__ == '__main__':
    # pprint(solution([1, 2, 3, 4]))
    pprint(Solution2().permute([1, 2, 3, 4]))


# importing required modules # importing required modules
import PyPDF2
import os

path = 'Address to folder with PDF(s)'
os.chdir(path)

for pdf in os.listdir(path):
    pdfFileObj = open(pdf, 'rb')
    pdfReader = PyPDF2.PdfFileReader(pdfFileObj)
    pageObj = pdfReader.getPage(0)
    text = pageObj.extractText()
    pdfFileObj.close()
    outfile = open("Address to folder you want to save TXT files" + f'{txt}'+".txt",'w', encoding= 'utf-8')
    outfile.writelines(text)


import sys
import os
import os.path
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QComboBox, QLineEdit, QPushButton, QGridLayout, \
    QCheckBox, QProgressBar, QFileDialog, QDialog

import tc_analize

class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        """
        Графический интрейфей пользователя
        :return: None
        """
        self.setFixedSize(480, 300)
        self.setWindowTitle('DOS-XML-MDB Converter')

        self.inBase = QLabel('Конвертируемая база данных:', self)
        self.inMode = QComboBox(self)
        self.inMode.addItems(['dos', 'xml', 'MDB'])
        self.inPath = QLineEdit(os.getcwd(), self)
        self.inPathPushDialog = QPushButton('Выбрать...', self)
        self.inPathPushDialog.clicked.connect(self.inputPath)
        self.inInfo = QLabel('', self)

        self.outBase = QLabel('Сохраниеть как:', self)
        self.outMode = QComboBox(self)
        self.outMode.addItems(['xml', 'MDB'])
        self.outPath = QLineEdit(os.path.expandvars('%APPDATA%'), self)
        self.outPathPushDialog = QPushButton('Выбрать...', self)
        self.outPathPushDialog.clicked.connect(self.outputPath)
        self.outInfo = QLabel('', self)

        self.hmode = QCheckBox('Сохранить структуру базы данных?', self)
        self.start = QPushButton('Приступить', self)
        self.start.clicked.connect(self.startWork)
        self.progbar = QProgressBar(self)
        self.progbar.setValue(0)
        self.toInfo = QLabel('', self)

        grid = QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(self.inBase, 0, 0, 1, 3)
        grid.addWidget(self.inMode, 1, 0)
        grid.addWidget(self.inPath, 1, 1)
        grid.addWidget(self.inPathPushDialog, 1, 2)
        grid.addWidget(self.inInfo, 2, 0, 1, 3)

        grid.addWidget(self.outBase, 3, 0, 1, 3)
        grid.addWidget(self.outMode, 4, 0)
        grid.addWidget(self.outPath, 4, 1)
        grid.addWidget(self.outPathPushDialog, 4, 2)
        grid.addWidget(self.outInfo, 5, 0, 1, 3)

        grid.addWidget(self.hmode, 6, 0, 1, 3)
        grid.addWidget(self.start, 7, 0, 1, 3)
        grid.addWidget(self.progbar, 8, 0, 1, 3)
        grid.addWidget(self.toInfo, 9, 0, 1, 3)

        self.setLayout(grid)
        self.show()

    def inputPath(self):
        """
        Файловый диалог для выбора исходной директории
        :return: None
        """
        file = os.path.normpath(QFileDialog.getExistingDirectory(self))
        self.inPath.setText(file)

    def outputPath(self):
        """
        Файловый диалог для выбора папки сохранения
        :return: None
        """
        file = os.path.normpath(QFileDialog.getExistingDirectory(self))
        self.outPath.setText(file)

    def startWork(self):
        """
        Обработка сигнала по кнопке "Приступить"
        :return: None
        """
        self.start.blockSignals(True)
        intype = self.inMode.currentText()
        inpath = os.path.normpath(self.inPath.text()).replace('\\', '/')

        outtype = self.outMode.currentText()
        outpath = os.path.normpath(self.outPath.text()).replace('\\', '/')

        strapt = self.hmode.isChecked()

        analize = tc_analize.analize(inpath, intype)

        errorcount = 0
        errorpath = os.path.join(outpath, 'errors.log')
        ferror = open(errorpath, 'w', encoding='utf-8')
        ferror.close()
        size = 0
        self.progbar.setValue(1)
        p = analize.fullsize//99
        for f in analize.files:
            f.read(intype)
            if f.error:
                errorcount += 1
                ferror = open(errorpath, 'a', encoding='utf-8')
                if intype == 'dos':
                    ferror.write('{} {} {}\n'.format(f.dos_name, f.error.name, f.error.note))
                ferror.close()
            else:
                if strapt:
                    f.save(outtype, os.path.join(outpath, os.path.relpath(f.path, inpath)))
                else:
                    f.save(outtype, outpath)
            size += f.size
            self.progbar.setValue(1 + size//p)
        if errorcount == 0:
            os.remove(errorpath)
        self.infodialog(len(analize.files), errorcount)
        self.start.blockSignals(False)

    def infodialog(self, all, errors=None):
        """
        Окно в конце обрабокти, которое показывает сколько было обработано файлов
        :param all: всего файлов
        :param errors: файлов с ошибками
        :return: None
        """
        d = QDialog()
        d.setWindowTitle("info")
        grid = QGridLayout()
        grid.setSpacing(10)
        grid.addWidget(QLabel('Обработано файлов: {}'.format(all)), 0, 0)
        if errors:
            grid.addWidget(QLabel('Успешно: {}'.format(all-errors)), 1, 0)
            grid.addWidget(QLabel('Список ошибок в errors.log'), 2, 0)
        else:
            grid.addWidget(QLabel('Ошибок нет', 1, 0))
        d.setLayout(grid)
        d.exec_()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())