"""
This script imports PayDay 2 Model File format files to Blender.

Usage:
Execute this script from the "File->Import" menu and choose a .model file to
open.

"""

import os
import bpy
import bmesh
import ctypes
from mathutils import Matrix
from bmesh.types import BMVert
from struct import unpack

from xml.dom.minidom import parse
from xml.dom.minidom import Node

class Pd2ModelImport:

	# Definition of sections type/tag :

    animation_data_tag                = int('5DC011B8', 16)    # Animation data
    author_tag                        = int('7623C465', 16)    # Author tag
    material_group_tag                = int('29276B1D', 16)    # Material Group
    material_tag                      = int('3C54609C', 16)    # Material
    object3D_tag                      = int('0FFCD100', 16)    # Object3D
    model_data_tag                    = int('62212D88', 16)    # Model data
    geometry_tag                      = int('7AB072D3', 16)    # Geometry
    topology_tag                      = int('4C507A13', 16)    # Topology
    passthroughGP_tag                 = int('E3A3B1CA', 16)    # PassthroughGP
    topologyIP_tag                    = int('03B634BD', 16)    # TopologyIP
    quatLinearRotationController_tag  = int('648A206C', 16)    # QuatLinearRotationController
    quatBezRotationController_tag     = int('197345A5', 16)    # QuatBezRotationController
    skinbones_tag                     = int('65CC1825', 16)    # SkinBones
    bones_tag                         = int('2EB43C77', 16)    # Bones
	# section_unknown1			      = int('803BA1FF', 16)    # ?   Ex: in str_vehicle_van_player.model
	# section_unknown2                = int('8C12A526', 16)    # ?   Ex: in str_vehicle_van_player.model

    hllDll = None
    hllDllPath = "HashDLLPath"
    try:
        hllDll = ctypes.CDLL(hllDllPath)
    except:
        raise NameError("Could not load Hash64 dll %s" % hllDllPath)

    def __init__(self):
        #constructor, do initialisation and stuff
        self.buff=''
        self.dictionary = {} #Hashlist
        self.object_file = ''
        self.materials = {} #Materials by key
        self.assets_path = 'D:\\PD2 Extract\\'
        #c:\\Program Files (x86)\\Steam\\SteamApps\\common\\PAYDAY The Heist\\assets\\extract\\
        #c:\\Program Files (x86)\\Steam\\SteamApps\\common\\PAYDAY 2\\assets\\extract\\
        HashlistPath = "Hashlist Path"
        with open(HashlistPath) as f:
          lines = f.read().splitlines()
          for line in lines:
              hashcode = int(self.get_hash(str(line)))
              self.dictionary[hashcode] = line
              #print("[" + str(hashcode) + "] = " + self.dictionary[hashcode])

    def read(self, file_path):

        try:
            f = open(file_path, "rb")
        except IOError as e:
            print("({})".format(e))

        print('import file : %s' % file_path)
        self.buff = f.read()
        f.close()

        model_path = os.path.splitext(file_path)[0]

        objectData = None
        try:
            objectData = parse(model_path + '.object')
        except:
            print("Could not load object, trying .object.xml")
            try:
                objectData = parse(model_path + '.object.xml')
            except:
                raise NameError("Could not load object %s" % model_path)

        diesel = objectData.getElementsByTagName("diesel")
        mats_path = diesel[0].getAttribute("materials")
        #Can read enabled/disabled/effects later from object file
        objectData.unlink()

        mat_configData = None
        try:
            mat_configData = parse(self.assets_path + mats_path + '.material_config')
        except:
            print("Could not load material config, trying .material_config.xml")
            try:
                mat_configData = parse(self.assets_path + mats_path + '.material_config.xml')
            except:
                raise NameError("Could not load material_config %s" % mats_path)

        mat_config_materials = mat_configData.getElementsByTagName("material")
        for mat in mat_config_materials:
          mat_name = mat.getAttribute("name")
          mat_textures = mat.getElementsByTagName("diffuse_texture")
          for mat_texture in mat_textures:
            realpath = self.assets_path + mat_texture.getAttribute("file")
            try:
                img = bpy.data.images.load(realpath + ".texture")
                self.materials[mat_name] = realpath + ".texture"
            except:
                print("Could not load texture " + realpath + " attempting with .texture.dds extension")
                try:
                    img = bpy.data.images.load(realpath + ".texture.dds")
                    self.materials[mat_name] = realpath + ".texture.dds"
                except:
                    raise NameError("Cannot load image %s" % realpath)

            cTex = bpy.data.textures.new(mat_name, type = 'IMAGE')
            cTex.image = img
            # Create material
            new_mat = bpy.data.materials.new(mat_name)
            # Add texture slot for color texture
            mtex = new_mat.texture_slots.add()
            mtex.texture = cTex
            mtex.texture_coords = 'UV'
            mtex.use_map_color_diffuse = True
            mtex.use_map_color_emission = True
            mtex.emission_color_factor = 0.5
            mtex.use_map_density = True
            mtex.mapping = 'FLAT'

        mat_configData.unlink()

        # Unpack 4 bytes to interpret as a "little endian int" at offset 0x0 of buff
        # section_count = unpack("<i", self.buff[0:4])[0]
        # print('section count (1) : %d' % section_count)

        sections = self.parse_file()
        parsed_sections = {}

        for section in sections:

            if section[1] == self.animation_data_tag:
                #print("animation_data_tag")
                parsed_sections[section[2]] = self.parse_animation_data(section[0]+12, section[3], section[2])

            elif section[1] == self.author_tag:
                #print("author_tag")
                parsed_sections[section[2]] = self.parse_author(section[0]+12, section[3], section[2])

            elif section[1] == self.material_group_tag:
                #print("material_group_tag")
                parsed_sections[section[2]] = self.parse_material_group(section[0]+12, section[3], section[2])

            elif section[1] == self.material_tag:
                #print("material_tag")
                parsed_sections[section[2]] = self.parse_material(section[0]+12, section[3], section[2])

            elif section[1] == self.object3D_tag:
                #print("object3D_tag")
                parsed_sections[section[2]] = self.parse_object3d(section[0]+12, section[3], section[2])

            elif section[1] == self.geometry_tag:
                #print("geometry_tag")
                parsed_sections[section[2]] = self.parse_geometry(section[0]+12, section[3], section[2])

            elif section[1] == self.model_data_tag:
                #print("geometry_tag")
                parsed_sections[section[2]] = self.parse_model_data(section[0]+12, section[3], section[2])

            elif section[1] == self.topology_tag:
                #print("topology_tag")
                parsed_sections[section[2]] = self.parse_topology(section[0]+12, section[3], section[2])

            elif section[1] == self.passthroughGP_tag:
                #print("passthroughGP_tag")
                parsed_sections[section[2]] = self.parse_passthrough_gp(section[0]+12, section[3], section[2])

            elif section[1] == self.topologyIP_tag:
                #print("topologyIP_tag")
                parsed_sections[section[2]] = self.parse_topology_ip(section[0]+12, section[3], section[2])

            elif section[1] == self.quatLinearRotationController_tag:
                print("quatLinearRotationController_tag    /!\    No parser defined   /!\ ")
                #parsed_sections[section[2]] =

            elif section[1] == self.quatBezRotationController_tag:
                print("quatBezRotationController_tag    /!\    No parser defined   /!\ ")
                #parsed_sections[section[2]] =

            elif section[1] == self.skinbones_tag:
                print("skinbones_tag    /!\    No parser defined   /!\ ")
                #parsed_sections[section[2]] =

            elif section[1] == self.bones_tag:
                print("bones_tag    /!\    No parser defined   /!\ ")
                #parsed_sections[section[2]] =

            else:
                print("Unknown section tag %d" % section[1] )

        for section in sections:

            if section[1] == self.model_data_tag:
                model_data = parsed_sections[section[2]]
                if model_data[3] == 6:
                    continue

                model_id = self.dictionary.get(model_data[2][1], str(model_data[2][1]))
                #model_id = "model-%x" % model_data[2][2]
                geometry = parsed_sections[parsed_sections[model_data[4]][2]]
                topology = parsed_sections[parsed_sections[model_data[4]][3]]
                faces = topology[4]
                verts = geometry[6]
                uvs = geometry[7]
                normals = geometry[8]
                colors = geometry[9]
                weights = geometry[10]

                rotation_matrix = Matrix((
                  (model_data[2][4][0],model_data[2][4][4],model_data[2][4][8],model_data[2][4][12]),
                  (model_data[2][4][1],model_data[2][4][5],model_data[2][4][9],model_data[2][4][13]),
                  (model_data[2][4][2],model_data[2][4][6],model_data[2][4][10],model_data[2][4][14]),
                  (model_data[2][4][3],model_data[2][4][7],model_data[2][4][11],model_data[2][4][15])))
                #loc, rot, scale = rotation_matrix.decompose()
                rot = rotation_matrix.to_quaternion()
                loc = model_data[2][5]

                if model_data[2][6] > 0:
                    obj_parent_data = parsed_sections[model_data[2][6]]
                    if obj_parent_data[0] == 'Model':
                      obj_parent_data = obj_parent_data[2]

                    obj_parent = self.dictionary.get(obj_parent_data[2], str(obj_parent_data[2]))
                else:
                    obj_parent = str(0)

                material_names = []
                marerial_indecies = None
                if model_data[3] == 3:
                  mat_group_sec_id = model_data[8]
                  mat_group_sec_data = parsed_sections[mat_group_sec_id]
                  for item in mat_group_sec_data[3]:
                    mat_sec_data = parsed_sections[item]
                    if self.dictionary.get(mat_sec_data[2], None) != None:
                      material_names.append(self.dictionary.get(mat_sec_data[2], None))

                  marerial_indecies = model_data[7]

                self.build_model(model_id, verts, uvs, normals, faces, colors, weights, obj_parent, loc, rot, material_names, marerial_indecies)
            elif section[1] == self.object3D_tag:
                object3D_data = parsed_sections[section[2]]
                obj_name = self.dictionary.get(object3D_data[2], str(object3D_data[2]))
                obj_position = object3D_data[6]

                obj_rotationMat = Matrix((
                  (object3D_data[5][0],object3D_data[5][4],object3D_data[5][8],object3D_data[5][12]),
                  (object3D_data[5][1],object3D_data[5][5],object3D_data[5][9],object3D_data[5][13]),
                  (object3D_data[5][2],object3D_data[5][6],object3D_data[5][10],object3D_data[5][14]),
                  (object3D_data[5][3],object3D_data[5][7],object3D_data[5][11],object3D_data[5][15])))

                #loc, rot, scale = obj_rotationMat.decompose()
                rot = obj_rotationMat.to_quaternion()

                loc = object3D_data[6]

                if object3D_data[7] > 0:
                    obj_parent_data = parsed_sections[object3D_data[7]]
                    if obj_parent_data[0] == 'Model':
                      obj_parent_data = obj_parent_data[2]

                    obj_parent = self.dictionary.get(obj_parent_data[2], str(obj_parent_data[2]))
                else:
                    obj_parent = str(0)

                self.build_emptyObject(obj_name, loc, rot, obj_parent)

        print("Import done")

    def rao(self, offset, size):
        return self.buff[offset:offset+size]

    def read_string(self, offset):
        out = ''
        while self.buff[offset] != 0:
            out += chr(self.buff[offset])
            offset += 1
        return out, offset+1

    #read 3 unsigned int (little endian) at address "offset"
    def parse_section_header(self, offset):
        return unpack("<III", self.rao(offset, 12))

    def parse_file(self):
        out_sections = []
        file_size = 0

        section_count = unpack("<i", self.rao(0, 4))[0]

        current_offset = 4

        if section_count == -1:
            file_size, section_count = unpack("<ii", self.rao(4, 8))
            current_offset += 8
            print("file_size: %d bytes, section count : %d" % (file_size, section_count))

        # Sections headers contains : uint32 section_type  // Uses one of the below tags. Tags are assigned to serializable objects within the Diesel engine.
        #                             uint32 section_id    // Appears to be a random, but unique value assigned to the section. Unknown if these have any requirements or meanings.
        #                             uint32 section size
        for x in range(section_count):
            pieces = self.parse_section_header(current_offset)
            out_sections.append((current_offset, pieces[0], pieces[1], pieces[2]))
            print("current_offset %d, p0: %u, p1: %u, p2: %u" % (current_offset, pieces[0], pieces[1], pieces[2]))
            current_offset += pieces[2] + 12
            print("next_offset %d" % current_offset)

        return out_sections

    def parse_author(self, offset, size, section_id):
        unknown = unpack("<q", self.rao(offset, 8))[0]
        email, next_offset = self.read_string(offset+8)
        source_file, next_offset = self.read_string(next_offset)
        unknown2 = unpack("<i", self.rao(next_offset, 4))[0]
        return ('Author', section_id, unknown, email, source_file, unknown2)

    def parse_material_group(self, offset, size, section_id):
        count = unpack("<i", self.rao(offset, 4))[0]
        items = []
        for x in range(count):
            items.append(unpack("<i", self.rao(offset + 4 + (x*4), 4))[0])
        return ('Material Group', section_id, count, items)

    def parse_animation_data(self, offset, size, section_id):
        unknown1, unknown2, unknown3, count = unpack("<qiii", self.rao(offset, 20))
        items = []
        for x in range(count):
            items.append(unpack("<f", roa(offset + 20 + (x*4), 4))[0])
        return ('Animation Data', section_id, unknown1, unknown2, unknown3, count, items)

    def parse_geometry(self, offset, size, section_id):
        cur_offset = offset
        # 1 is verts, 7 is uvs, 2 is normals, 20 is unkown, 21 is unknown
        size_index = [0,4,8,12,16,4,4,8,12]
        count1, count2 = unpack("<ii", self.rao(offset, 8))
        cur_offset += 8
        headers = []
        calc_size = 0
        for x in range(count2):
            item_size, item_type = unpack("<ii", self.rao(cur_offset, 8))
            calc_size += size_index[item_size]
            headers.append((item_size,item_type))
            cur_offset += 8
        verts = []
        uvs = []
        normals = []
        colors = []
        weights = []
        #print('len(headers) = ' + str(len(headers)))
        for header in headers:
            if header[1] == 1:
                for x in range(count1):
                    verts.append(unpack("<fff", self.rao(cur_offset, 12)))
                    cur_offset += 12
            elif header[1] == 7:
                for x in range(count1):
                    u,v = unpack("<ff", self.rao(cur_offset, 8))
                    cur_offset += 8
                    uvs.append((u, -v))
            elif header[1] == 2:
                for x in range(count1):
                    normals.append(unpack("<fff", self.rao(cur_offset, 12)))
                    cur_offset += 12
            elif header[1] == 5:
                for x in range(count1):
                    colors.append(unpack("<BBBB", self.rao(cur_offset, 4)))
                    cur_offset += 4
            elif header[1] == 17:
                for x in range(count1):
                    weights.append(unpack("<fff", self.rao(cur_offset, 12)))
                    cur_offset += 12

            else:
                #print('header[1] = ' + str(header[1]))
                #print('size_index[header[0]] = ' + str(size_index[header[0]]))
                cur_offset += size_index[header[0]] * count1

        return ('Geometry', section_id, count1, count2, headers, count1*calc_size, verts, uvs, normals, colors, weights)

    def parse_topology(self, offset, size, section_id):
        cur_offset = offset
        unknown1, count1 = unpack("<ii", self.rao(offset, 8))
        cur_offset += 8
        facelist = []
        for x in range(int(count1/3)):
            facelist.append(unpack("<HHH", self.rao(cur_offset, 6)))
            cur_offset += 6
        count2 = unpack("<i", self.rao(offset+8+count1*2, 4))[0]
        items2 = unpack("<"+count2*"b", self.rao(offset+8+count1*2+4, count2))
        unknown2 = unpack("<q", self.rao(offset+8+4+count2+count1*2, 8))[0]
        return ("Topology", section_id, unknown1, count1, facelist, count2, items2, unknown2)

    def parse_material(self, offset, size, section_id):
        cur_offset = offset
        hashname = unpack("<Q", self.rao(offset, 8))[0]
        cur_offset += 8
        return ('Material', section_id, hashname)

    def parse_object3d(self, offset, size, section_id):
        cur_offset = offset
        hashname, count = unpack("<Qi", self.rao(offset, 12))
        cur_offset += 12
        items = []
        for x in range(count):
            items.append(unpack("<iii", self.rao(cur_offset, 12)))
            cur_offset += 12
        int_count = 64/4
        rotation_matrix = unpack("<"+int(int_count)*"f", self.rao(cur_offset, 64))
        cur_offset += 64
        position = unpack("<fff", self.rao(cur_offset, 12))
        cur_offset += 12
        parentID = unpack("<i", self.rao(cur_offset, 4))[0]
        return ('Object3D', section_id, hashname, count, items, rotation_matrix, position, parentID)

    def parse_topology_ip(self, offset, size, section_id):
        topology_section_id = unpack("<i", self.rao(offset, 4))[0]
        return ('TopologyIP', section_id, topology_section_id)

    def parse_passthrough_gp(self, offset, size, section_id):
        geometry_section, facelist_section = unpack("<ii", self.rao(offset, 8))
        return ('PassthroughGP', section_id, geometry_section, facelist_section)

    def parse_model_data(self, offset, size, section_id):
        cur_offset = offset
        hashname, count = unpack("<Qi", self.rao(offset, 12))
        cur_offset += 12
        items = []
        for x in range(count):
            items.append(unpack("<iii", self.rao(cur_offset, 12)))
            cur_offset += 12
        int_count = 64/4
        rotation_matrix = unpack("<"+int(int_count)*"f", self.rao(cur_offset, 64))
        cur_offset += 64
        position = unpack("<fff", self.rao(cur_offset, 12))
        cur_offset += 12
        parentID = unpack("<i", self.rao(cur_offset, 4))[0]
        cur_offset += 4
        object3d = ('Object3D', hashname, count, items, rotation_matrix, position, parentID)
        version = unpack("<i", self.rao(cur_offset, 4))[0]
        cur_offset += 4
        if version == 6:
            unknown5 = unpack("<fff", self.rao(cur_offset, 12))
            cur_offset += 12
            unknown6 = unpack("<fff", self.rao(cur_offset, 12))
            cur_offset += 12
            unknown7, unknown8 = unpack("<ii", self.rao(cur_offset, 8))
            return ('Model', section_id, object3d, version, unknown5, unknown6, unknown7, unknown8)
        else:
            a, b, count2 = unpack("<iii", self.rao(cur_offset, 12))
            cur_offset += 12
            items2 = []
            for x in range(count2):
                items2.append(unpack("<iiiii", self.rao(cur_offset, 20)))
                cur_offset += 20
            material_group_section_id, unknown10 = unpack("<ii", self.rao(cur_offset, 8))
            cur_offset += 8
            #There's more to this section...
            #public UInt32 unknown10;
            #public Vector3D bounds_min; // Z (max), X (low), Y (low)
            #public Vector3D bounds_max; // Z (low), X (max), Y (max)
            #public UInt32 unknown11;
            #public UInt32 unknown12;
            #public UInt32 unknown13;
            #public UInt32 skinbones_ID;

            return ('Model', section_id, object3d, version, a, b, count2, items2, material_group_section_id, unknown10)

    def build_emptyObject(self, name, position, rotation_matrix, parentID):

            bpy.ops.object.add(type='EMPTY', view_align=False, enter_editmode=False, location=position)

            bpy.context.active_object.name = name

            bpy.data.objects[name].rotation_mode = 'QUATERNION'
            bpy.data.objects[name].location = position
            bpy.data.objects[name].rotation_quaternion = rotation_matrix
            #bpy.data.objects[name].show_x_ray = True
            #bpy.data.objects[name].show_name = True

            if parentID != str(0):
              if bpy.data.objects.get(parentID) is not None:
                bpy.data.objects[name].parent = bpy.data.objects[parentID]

            #bpy.data.objects[name]

    def build_model(self, name, verts, uvs, normals, faces, colors, weights, parentID, loc, rot, material_names, material_indecies):
            mesh = bpy.data.meshes.new(name)
            #mesh.from_pydata(verts, [], faces)
            bm = bmesh.new()
            for vert in verts:
                bm.verts.new(vert)

            if hasattr(bm.verts, "ensure_lookup_table"):
                bm.verts.ensure_lookup_table()

            if len(normals) > 0:
                for x in range(len(verts)):
                    bm.verts[x].normal.x = normals[x][0]
                    bm.verts[x].normal.y = normals[x][1]
                    bm.verts[x].normal.z = normals[x][2]
            for face in faces:
                try:
                    bm.faces.new([bm.verts[face[0]], bm.verts[face[1]], bm.verts[face[2]]])
                except:
                    print("Face allready exist")

            if len(uvs) > 0:
              #mesh.uv_textures.new("UV Map")

              uv_layer = bm.loops.layers.uv.verify()
              bm.faces.layers.tex.verify()

              if hasattr(bm.faces, "ensure_lookup_table"):
                bm.faces.ensure_lookup_table()

              face = bm.faces[-1]
              for i, loop in enumerate(face.loops):
                  loop[uv_layer].uv[0] = uvs[loop.vert.index][0]
                  loop[uv_layer].uv[1] = uvs[loop.vert.index][1]

              for face in bm.faces:        # Iterate over all of the object's faces
                face.material_index = 0 # Assing random material to face

            #Weights
            if len(weights) > 0:
                dvert_lay = bm.verts.layers.deform.verify()

                for x in range(len(verts)):
                    dvert = bm.verts[x][dvert_lay]

                    dvert[0] = weights[x][0]
                    dvert[1] = weights[x][1]
                    dvert[2] = weights[x][2]

                    #if group_index in dvert:
                    #    print("Weight %f" % dvert[group_index])
                    #else:
                    #    print("Setting Weight")
                    #    dvert[0] = weights[x][0]

                '''
                ob.vertex_groups.new("Bone 1")
                ob.vertex_groups.new("Bone 2")
                ob.vertex_groups.new("Bone 3")

                b1_id = ob.vertex_groups["Bone 1"].index
                b2_id = ob.vertex_groups["Bone 2"].index
                b3_id = ob.vertex_groups["Bone 3"].index

                for grp in ob.vertex_groups:
                    grp.add(range(0,len(weights)), 1.0, 'REPLACE')

                for x in range(len(verts)):
                    bm.verts[x].groups[b1_id].weight = weights[x][0]
                    bm.verts[x].groups[b2_id].weight = weights[x][1]
                    bm.verts[x].groups[b3_id].weight = weights[x][2]

            '''

            bm.to_mesh(mesh)
            ob = bpy.data.objects.new(name, mesh)
            ob.rotation_mode = 'QUATERNION'
            ob.location = loc
            ob.rotation_quaternion = rot
            ob_mesh = ob.data

            if len(weights) > 0:
                ob.vertex_groups.new("Bone 1")
                ob.vertex_groups.new("Bone 2")
                ob.vertex_groups.new("Bone 3")

            #print("len(colors)=" + str(len(colors)))
            if len(colors) > 0:
              if not ob_mesh.vertex_colors:
                ob_mesh.vertex_colors.new()

              color_map = ob_mesh.vertex_colors["Col"]

              for poly in ob_mesh.polygons:
                  for loop_index in poly.loop_indices:
                    loop_vert_index = mesh.loops[loop_index].vertex_index
                    color_map.data[loop_index].color = [ colors[loop_vert_index][2]/255.0, colors[loop_vert_index][1]/255.0, colors[loop_vert_index][0]/255.0 ]

            #UVs
            if len(uvs) > 0:
              for poly in ob_mesh.polygons:
                    #print("Polygon", poly.index, "from loop index", poly.loop_start, "and length", poly.loop_total)
                    for i in poly.loop_indices: # <-- python Range object with the proper indices already set
                        l = ob_mesh.loops[i] # The loop entry this polygon point refers to
                        v = ob_mesh.vertices[l.vertex_index] # The vertex data that loop entry refers to
                        #print("\tLoop index", l.index, "points to vertex index", l.vertex_index, "at position", v.co)
                        for j,ul in enumerate(ob_mesh.uv_layers):
                            ul.data[l.index].uv = uvs[l.vertex_index]
                            #print("\t\tUV Map", j, "has coordinates", ul.data[l.index].uv, "for this loop index")

            bpy.context.scene.objects.link(ob)

            if parentID != str(0):
              if bpy.data.objects.get(parentID) is not None:
                if bpy.data.objects[name] != bpy.data.objects[parentID]:
                  bpy.data.objects[name].parent = bpy.data.objects[parentID]

            loaded_images = []

            for mat_name in material_names:
              if bpy.data.materials.get(mat_name) is not None:
                  bpy.data.objects[name].data.materials.append(bpy.data.materials[mat_name])
                  retrieved_material = self.materials.get(mat_name, None)
                  loaded_images.append(bpy.data.images.load(retrieved_material))

            if material_indecies != None:
              face_index = 0
              for modelItem in material_indecies:
                if len(uvs) > 0:
                  if bpy.data.objects[name].data.uv_textures.active.data:
                    for indx, uv_tex_face in enumerate(bpy.data.objects[name].data.uv_textures.active.data, start=face_index):
                      if indx == face_index + modelItem[3]:
                        break
                      print('Name='+name + " modelItem[4]="+str(modelItem[4]))
                      for uv_tex_face in bpy.data.objects[name].data.uv_textures.active.data:
                          uv_tex_face.image = loaded_images[modelItem[4]]

                    face_index += modelItem[3]

            mesh.update()

    def get_hash(self, text):
      str_bytes = bytes(text, 'UTF8')

      self.hllDll.Hash.restype = ctypes.c_ulonglong
      self.hllDll.Hash.argtypes = [(ctypes.c_ubyte * len(str_bytes)), ctypes.c_ulonglong, ctypes.c_ulonglong]

      dll_p1 = (ctypes.c_ubyte * len(str_bytes)).from_buffer_copy(str_bytes)
      dll_p2 = ctypes.c_ulonglong (len(dll_p1))
      dll_p3 = ctypes.c_ulonglong (0)

      return (self.hllDll.Hash(dll_p1, dll_p2, dll_p3))


import sqlite3
from contextlib import closing
from heroes_app.scrape import scrape_all, scrape_hero
import pandas as pd

DB_LOCATION = "db/heroes.db"
TABLE_NAME = 'heroes'

TABLE_FORMAT = {
    'url_name': 'text',
    'name': 'text',
    'health_points': 'integer',
    'damage_per_attack': 'integer',
    'attack_speed': 'integer',
    'mana': 'integer',
    'damage_per_second': 'float',
    'gold_price': 'integer',
    'attack_range': 'float',
    'hero_type': 'text',
    'release_date': 'text',
}

class DBClass:
    def __init__(self, loc=DB_LOCATION, table_name=TABLE_NAME, table_format=TABLE_FORMAT):
        self.conn = sqlite3.connect(loc)
        self.create_table(table_name, table_format)

    def create_table(self, table_name, table_format: dict):
        format_str = ', '.join([f'{key} {value}' for key, value in table_format.items()])
        self.run_query(sql_str=f"CREATE TABLE IF NOT EXISTS {table_name} ({format_str});")

    def run_query(self, sql_str, *args):
        conn = self.conn
        with closing(conn.cursor()) as cursor:
            result = cursor.execute(sql_str, tuple(args)).fetchall()

            conn.commit()
        return result

    def add_hero_to_db(self, hero_dict: dict, table_name):

        name = hero_dict['name']

        if len(self.get_hero_from_db(name, table_name)) > 0:
            self.run_query(f'DELETE FROM {table_name} WHERE name=?', name)

        keys = tuple([x.replace(' ', '_') for x in hero_dict.keys()])
        vals = tuple(list(hero_dict.values()))

        self.run_query(f'INSERT INTO {table_name} {keys} VALUES {vals};')

    def get_hero_from_db(self, hero_name, table_name):
        hero = self.run_query(f"SELECT * FROM {table_name} WHERE name=?", hero_name)
        return hero

    def get_hero_as_df(self, hero_name, table_name):
        hero = pd.read_sql_query(f"SELECT * FROM {table_name} WHERE name='{hero_name}'", self.conn)
        return hero

    def add_all_heroes(self, n=None, table_name='heroes'):
        all_heroes = scrape_all(n=n)

        for hero_url, hero_info in all_heroes.items():
            hero_info.update({'url_name': hero_url})
            self.add_hero_to_db(hero_info, table_name)

    def add_hero(self, url_name, table_name='heroes'):
        hero_url, hero_info = scrape_hero(url_name)
        hero_info.update({'url_name': url_name})

        self.add_hero_to_db(hero_info, table_name)

    def heroes_to_df(self, table_name='heroes'):
        heroes = pd.read_sql_query(f"SELECT * FROM {table_name}", self.conn)
        return heroes

def update_db():
    dbc = DBClass()
    dbc.add_all_heroes()

def main():
    pass

if __name__ == '__main__':
    main()


import os

from flask import redirect, render_template, request, url_for, current_app, jsonify, send_from_directory
from flask_paginate import Pagination
from app.admin import admin
from app.admin.forms import ProductForm, ProductFilterForm
from app.decorators import admin_required
from app.models import User, Supplier, Category, Product

@admin.route('/', methods=['GET', 'POST'])
@admin_required
def panel():
    return render_template('admin/panel.html')

@admin.route('/users', methods=['GET'])
@admin_required
def users():
    q = request.args.get('q')
    search = q is not None
    page = request.args.get('page', type=int, default=1)
    total, users = User.get_paginated_users(page=page)
    pagination = Pagination(page=page, total=total, search=search, css_framework='foundation',
        per_page=User.per_page)
    return render_template('admin/users.html', users=users, pagination=pagination)

@admin.route('/products', methods=['GET', 'POST'])
@admin_required
def product_list():
    form = ProductFilterForm()

    if form.validate_on_submit():
        if form.reset.data: return redirect(url_for('admin.product_list'))

        elif form.search.data or form.query.data:

            data = {'value': form.filter_mode.data, 'query': form.query.data}
            pagination, products = Product.get_paginated_by(data, request.args)
            return render_template('admin/product_list.html', form=form,
                products=products, pagination=pagination
            )

    elif request.args.get('page'):
        data = {'value': Product.last_option, 'query': Product.last_query}
        pagination, products = Product.get_paginated_by(data, request.args)
        return render_template('admin/product_list.html', form=form,
                products=products, pagination=pagination
        )

    pagination, products = Product.get_paginated_by({'value': 0}, request.args)
    return render_template('admin/product_list.html', form=form,
        products=products, pagination=pagination
    )

@admin.route('/products/add', methods=['GET', 'POST'])
@admin_required
def product_add():
    form = ProductForm()
    form.category_id.choices = Category.get_all_choices()
    form.supplier_id.choices = Supplier.get_all_choices()

    if form.validate_on_submit():
        Product.save_product(
            form.supplier_id.data,
            form.category_id.data,
            form.product_name.data,
            form.sku.data,
            form.unit_price.data,
            form.discount.data,
            form.units_in_stock.data,
            form.description.data
        )
        Product.save_images(request.files.getlist('images'), form.sku.data)
        if form.save.data: return redirect(url_for('admin.panel'))
        else: return redirect(url_for('admin.product_add'))

    return render_template('admin/product_add.html', form=form)

@admin.route('/products/update/<int:pk>', methods=['GET', 'POST'])
@admin_required
def product_update(pk):
    form = ProductForm()
    form.category_id.choices = Category.get_all_choices()
    form.supplier_id.choices = Supplier.get_all_choices()

    if form.validate_on_submit():
        Product.update_product(
            pk,
            form.supplier_id.data,
            form.category_id.data,
            form.product_name.data,
            form.sku.data,
            form.unit_price.data,
            form.discount.data,
            form.units_in_stock.data,
            form.description.data
        )
        Product.save_images(request.files.getlist('images'), form.sku.data)
        if form.save.data: return redirect(url_for('admin.panel'))
        else: return redirect(url_for('admin.product_update', pk=pk))

    return render_template('admin/product_update.html', form=form, pk=pk)

@admin.route('/products/<int:pk>', methods=['DELETE'])
@admin_required
def product_delete(pk):
    Product.delete(pk)
    return {'success': True}

@admin.route('/products/<int:pk>', methods=['GET'])
@admin_required
def product_get(pk):
    response = Product.get_json(pk)
    return response

@admin.route('/products/<int:pk>/images', methods=['GET'])
def product_images(pk):
    img_dir = '/'.join(['products', str(pk)])
    img_path = os.path.join(current_app.config['UPLOAD_PATH'], img_dir)
    img_names = os.listdir(img_path) if os.path.exists(img_path) else []
    images = [url_for('static', filename=os.path.join(img_dir, img)) for img in img_names]
    return jsonify(images=images)


#!/usr/bin/env python
# -*- coding:utf-8 -*-
#@Time    :    2020/5/11 0011 23:56
#@Author  :    tb_youth
#@FileName:    childFatherWindow.py
#@SoftWare:    PyCharm
#@Blog    :    https://blog.csdn.net/tb_youth

from PyQt5.QtWidgets import QWidget, QDialog, QApplication, QVBoxLayout
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtCore import Qt

class ChildWidget(QDialog):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.resize(500,500)
        self.setWindowTitle('Child')
        self.setWindowFlags(Qt.Dialog | Qt.WindowCloseButtonHint|Qt.WindowMaximizeButtonHint|Qt.WindowMinimizeButtonHint)

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

    def initUI(self):
        self.resize(600,600)
        self.setWindowTitle('Parent')
        self.btn = QPushButton('show child')
        self.child_widget = ChildWidget(self)
        layout = QVBoxLayout()
        layout.addWidget(self.btn)
        self.setLayout(layout)
        self.btn.clicked.connect(self.onClickedBtn)

    def onClickedBtn(self):
        self.child_widget.exec_()

if __name__=='__main__':
    import sys
    app = QApplication(sys.argv)
    w = ParentWidget()
    w.show()
    sys.exit(app.exec_())


import requests
import json
import datetime
import pandas
import http.client
import traceback
from utils import parse_prices
from utils import parse_prices_line
from constants import ts_client_secret
from constants import ts_client_id
from constants import ts_api_auth_url

def get_token(token, auth_code):
  res = requests.post(ts_api_auth_url, data = {
    "grant_type": "authorization_code",
    "client_id": ts_client_id,
    "redirect_uri": "https://api-ml-web-tool.herokuapp.com/account/tsapi_callback/" + token,
    "client_secret": ts_client_secret,
    "code": auth_code,
    "response_type": "token"
  })

  if res.status_code == 200:
    return res.json()
  else:
    print (res)
  return None

def get_access_token(refresh_token):
  res = requests.post(ts_api_auth_url, data = {
    "grant_type": "refresh_token",
    "client_id": ts_client_id,
    "redirect_uri": "http://ec2-52-201-19-122.compute-1.amazonaws.com:3002/app/ml-app", #https://ml-web-tool.herokuapp.com/
    "client_secret": ts_client_secret,
    "refresh_token": refresh_token,
    "response_type": "token"
  })

  if res.status_code == 200:
    return res.json()['access_token']
  return None

def load_ts_prices(access_token, symbol, frequency, start_date):
  from utils import convert_frequency
  unit, interval = convert_frequency(frequency)

  symbol = symbol.replace('aATt', '@')
  dt_format = '%m-%d-%Y'
  today = datetime.datetime.today()
  today_str = today.strftime(dt_format)
  read_date = datetime.datetime.strptime(start_date, dt_format)
  data = []
  do_break = False
  while not do_break:
    read_date_str = read_date.strftime(dt_format)
    next_date_str = today_str
    if (today-read_date).days > 365:
      next_date = read_date + datetime.timedelta(days=365)
      next_date_str = next_date.strftime(dt_format)
      read_date = next_date + datetime.timedelta(days=1)
    else:
      do_break = True

    url = "https://api.tradestation.com/v2/stream/barchart/" + symbol + "/" + str(interval) + "/" + unit + "/" + read_date_str + "/" + next_date_str + "?access_token=" + access_token
    try:
      res = requests.get(url, stream=True)
      if res.status_code == 200:
        for line in res.iter_lines():
          if line is None or len(line) == 0:
            continue
          d = parse_prices_line(line.decode("utf-8"))
          if d is None:
            continue
          if len(d) == 0:
            break
          data.append(d)
      else:
        print("status_code = " + str(res.status_code))
        continue
    except:
      traceback.print_exc()
      continue
  if len(data) == 0:
    return None
  df = pandas.DataFrame(data, columns = ['Date', 'Time', 'Open', 'High', 'Low', 'Close', 'Vol', 'OI'])
  return df

if __name__ == "__main__":
  from constants import test_key
  access_token = get_access_token(test_key)
  df = load_ts_prices(access_token, '@BTC', '15m', '10-26-2020')
  print(df)


from keras.models import load_model
import keras.utils

import sklearn.metrics
from sklearn.svm import SVC
from sklearn.externals import joblib
from sklearn.model_selection import StratifiedShuffleSplit

import numpy as np

import os
import sys

import utils
import plot_utils

def train_svm(path_results, x_data, y_data, args):
	path_params = path_results + "/SVM/Metrics/params_test_" + str(args.step) + ".txt"

	params = eval(open(path_params).read())

	if "gamma" in params:
		classifier = SVC(kernel=params["kernel"], C=params["C"], gamma = params["gamma"],probability = True, max_iter = 10000, class_weight='balanced')

	else:
		classifier = SVC(kernel=params["kernel"], C=params["C"], probability = True, max_iter = 10000, class_weight='balanced')

	spliter = StratifiedShuffleSplit(n_splits=5, test_size=0.2, random_state=19993)
	fold = 0
	for train_index, test_index in spliter.split(x_data, y_data):
		if str(fold) == str(args.fold):
			x_train = x_data[train_index]
			x_test = x_data[test_index]

			y_train = y_data[train_index]
			y_test = y_data[test_index]

			classifier.fit(x_train, y_train)

		fold += 1

	predictions = classifier.predict(x_test)

	print(sklearn.metrics.classification_report(y_test, predictions))

	return classifier

def create_model(path_results, args):
	"""Carga la arquitectura del modelo y los pesos a esta.

	Necesita del path_results que se desee analizar

	"""

	path_model = path_results + "/Models/" + str(args.model) + "_" + str(args.step) + ".h5"
	path_weights = path_results + "/Models/" + str(args.model) + "_" + str(args.step) + "weights.hdf5"

	path_model_aux = path_results + "/Models/" + str(args.model) + "aux_" + str(args.step) + ".h5"
	path_weights_aux = path_results + "/Models/" + str(args.model) + "aux_" + str(args.step) + "weights.hdf5"

	print("path_model", path_model)
	print("path_weights", path_weights)

	model = load_model(path_model)
	model.load_weights(path_weights, by_name=False)

	model_aux = load_model(path_model_aux)
	model_aux.load_weights(path_weights_aux, by_name=False)

	print("Model loaded")

	return model, model_aux

def prepare_data(x_cbfv_data, x_cbfv_signal, args):
	"""Cambia el shape de la senial de entrada para que pueda ser predecida por el modelo.

	"""

	min_cbfv = np.amin(x_cbfv_data)
	max_cbfv = np.amax(x_cbfv_data)

	x_cbfv_normalize = utils.normalize(x_cbfv_data, min_cbfv, max_cbfv)
	x_cbfv_signal_normal = utils.normalize(x_cbfv_signal, min_cbfv, max_cbfv)

	if args.model == "resnet" or args.model == "fcn":
		x_cbfv_data = utils.prepare_data_cnn(x_cbfv_data, args)
		x_cbfv_ready = utils.prepare_data_cnn_signal(x_cbfv_signal_normal, args)

	else:
		x_cbfv_data = utils.prepare_data_lstm(x_cbfv_data, args)
		x_cbfv_ready = utils.prepare_data_lstm_signal(x_cbfv_signal_normal, args)

	return x_cbfv_data, x_cbfv_ready

def generate_invariant_data(path_data, x_cbfv_data, args):

	subjects = os.listdir(path_data)
	print("subjects",subjects)

	for subject in subjects:
		if subject == args.subject:
			#DY subject
			cbfv_signal = utils.read_cbfv_file(path_data + "/" + str(args.subject))
			#cambia frecuencia de muestreo a 0.6
			cbfv_signal = utils.lineal_interpolation(cbfv_signal)
			print("shape pre", cbfv_signal.shape)
			x_cbfv_data, x_cbfv_signal = prepare_data(x_cbfv_data, cbfv_signal, args)

	return x_cbfv_data, x_cbfv_signal

def generate_variant_data(path_data_nc, path_data_hc, x_cbfv_data, args):

	subjects = os.listdir(path_data_nc)
	print("subjects",subjects)

	for subject in subjects:
		if subject == args.subject:
			#DY subject
			cbfv_signal_nc = utils.read_cbfv_file(path_data_nc + "/" + str(args.subject))
			cbfv_signal_hc = utils.read_cbfv_file(path_data_hc + "/" + str(args.subject))

			print("len nc",len(cbfv_signal_nc))
			print("len hc",len(cbfv_signal_hc))

			if args.stick == "1":
				cbfv_signal = np.concatenate((cbfv_signal_nc[(len(cbfv_signal_nc)/2):len(cbfv_signal_nc)], cbfv_signal_hc[0:(len(cbfv_signal_hc)/2)]),axis = 0)
			else:
				cbfv_signal = np.concatenate((cbfv_signal_nc[0:(len(cbfv_signal_nc)/2)], cbfv_signal_hc[(len(cbfv_signal_hc)/2):len(cbfv_signal_hc)]),axis = 0)

			print("len pegada",len(cbfv_signal))

			#cambia frecuencia de muestreo a 0.6
			cbfv_signal = utils.lineal_interpolation(cbfv_signal)
			print("shape pre", cbfv_signal.shape)
			x_cbfv_signal = prepare_data(x_cbfv_data, cbfv_signal, args)

	return x_cbfv_signal

def select_model(path_results):
	path_metrics = path_results + "/Metrics/"

	kappas = []

	for step in range(50, 550, 50):
		with open(path_metrics + "kappa_test_" + str(step) + ".txt") as f:
			kappa = f.readline()
		element = {"kappa": str(kappa),"step": str(step)}
		kappas.append(element)

	seq_kappa = [x["kappa"] for x in kappas]

	steps = []

	for x in kappas:
		if x["kappa"] == max(seq_kappa):
			steps.append(x["step"])

	return min(steps)

def maping(path, path_env):

	#data is in Results/args.mode/args.conjunt/5fold/args.model_numberclass_500epochs_args.train_data_foldi

	#LECTURA DE DATOS PARA PODER PLOTEAR MAPA
	#EXTRACCION DE CARACTERISTICAS GENERALES DE LOS DATOS. NORMALIZACION, BATCH_SEIZE, NUMB_CLASS
	args = utils.get_args()

	#get the path of data to train and validate the model
	train_data_path = path_env + "/" + args.train_dataset_path + "/" + args.mode
	val_data_path = path_env + "/" + args.val_dataset_path + "/" + args.mode

	#root path_save
	path_save = path_env + "/" + args.path_save + "/" + args.mode

	train_dataset = train_data_path + "/" + args.train_data
	val_dataset = val_data_path + "/" + args.val_data

	y_train_real, x_train_abp, x_train_cbfv = utils.read_multivariate_data(train_dataset + '/' + 'signals.txt')
	#read hipercapnia data
	y_val_real, x_val_abp, x_val_cbfv = utils.read_multivariate_data(val_dataset + '/' + 'signals.txt')

	if args.conjunt == "Mix":
		x_cbfv = np.concatenate((x_train_cbfv,x_val_cbfv),axis=0)
	else:
		x_cbfv = x_train_cbfv

	variant_mode = str(args.train_data).split("_")[4]
	print("variant_mode", variant_mode)

	#from data choose batch size
	batch_size = min(x_train_cbfv.shape[0]/10, 16)

	#get the number of classes in the dataset
	nb_classes_train = len(np.unique(y_train_real))
	nb_classes_test = len(np.unique(y_val_real))
	nb_classes = nb_classes_train

	#number of classes in train and test must to be the same.
	assert nb_classes_train == nb_classes_test

	##DESDE ACA INICIA EL TRABAJO DE MAPEO

	path_results = path_env + "/Results/" + str(args.mode) + "/" + str(args.conjunt) + "/5fold/" + str(args.model) + "_" + str(nb_classes) + "class" + "_500epochs_" + str(args.train_data) + "_fold" + str(args.fold)

	print("path_results", path_results)

	print("step pre",args.step)

	step_model = select_model(path_results)
	args.step = step_model

	print("step post",args.step)

	#load trained model
	model, model_aux = create_model(path_results, args)

	#path for data nc and hc
	path_data_nc = path + "/nc_data/"
	path_data_hc = path + "/hc_data/"

	#read invariant signal in nc to predict
	if args.mode == "Invariant":
		x_cbfv_data, signal_to_predict = generate_invariant_data(path_data_nc, x_cbfv, args)
	else:#variant and all
		x_cbfv_data, signal_to_predict = generate_variant_data(path_data_nc, path_data_hc, x_cbfv, args)

	print("signal_to_predict",signal_to_predict.shape)

	#sys.exit("test")

	#predict signal with normal model and model_aux
	model_prediction = model.predict(signal_to_predict, batch_size=batch_size)
	model_aux_prediction = model_aux.predict(signal_to_predict, batch_size=batch_size)
	#feature_space = model_aux.predict(x_cbfv_data, batch_size=batch_size)

	#print("model_aux_prediction",len(model_aux_prediction[0]))

	#CARGAR DATOS TSNE
	#PLOTEAR CON SENIAL NUEVA

	path_features = path_results + "/Weights/" + str(args.step) + ".csv"
	x_data, y_data = utils.read_weights(path_features)

	plot_utils.plot_visualization(path_results, x_data, y_data, variant_mode, nb_classes, model_aux_prediction,args)

	#THIS IS FOR BETTER PREDICTION

	#load svm model
	svm_model = train_svm(path_results, x_data, y_data, args)

	#predict signal with feature extraction of deep model
	prediction_svm = svm_model.predict(model_aux_prediction)
	print("prediction_svm", prediction_svm.shape)
	print("class of prediction", prediction_svm)
	print(prediction_svm[0])

if __name__ == "__main__":
	#example execution
	#python maping.py -m Variant -c Mix -train_data abp_cbfv_nc_4class_variantbi_freq0.6 -val_data abp_cbfv_hc_4class_variantbi_freq0.6 -model resnet -f 1 -step 500 -subject DY0000.txt
	#python maping.py -m Invariant -c Mix -train_data abp_cbfv_nc_2class_freq0.6 -val_data abp_cbfv_hc_2class_freq0.6 -model resnet -f 1 -step 500 -subject DY0000.txt

	path = os.getcwd()
	path_env, path_source = os.path.split(path)

	maping(path, path_env)


import io
from http.server import BaseHTTPRequestHandler, HTTPStatus
from typing import AnyStr

from .http import simple_http_server
from sqlalchemy_media.helpers import copy_stream
from sqlalchemy_media.mimetypes_ import guess_type
from sqlalchemy_media.typing_ import FileLike

def mockup_http_static_server(content: bytes = b'Simple file content.',
                              content_type: str = None, **kwargs):
    class StaticMockupHandler(BaseHTTPRequestHandler):  # pragma: no cover
        def serve_text(self):
            self.send_header('Content-Type', "text/plain")
            self.send_header('Content-Length', str(len(content)))
            self.send_header('Last-Modified', self.date_time_string())
            self.end_headers()
            self.wfile.write(content)

        def serve_static_file(self, filename: AnyStr):
            self.send_header('Content-Type', guess_type(filename))
            with open(filename, 'rb') as f:
                self.serve_stream(f)

        def serve_stream(self, stream: FileLike):
            buffer = io.BytesIO()
            self.send_header(
                'Content-Length',
                str(copy_stream(stream, buffer))
            )
            self.end_headers()
            buffer.seek(0)
            try:
                copy_stream(buffer, self.wfile)
            except ConnectionResetError:
                pass

        def do_GET(self):
            self.send_response(HTTPStatus.OK)
            if isinstance(content, bytes):
                self.serve_text()
            elif isinstance(content, str):
                self.serve_static_file(content)
            else:
                self.send_header('Content-Type', content_type)
                self.serve_stream(content)

    return simple_http_server(StaticMockupHandler, **kwargs)


from flask import Flask, render_template, request, redirect

app = Flask(__name__)

students=[]

@app.route('/')
def index():
    return render_template("try1_index.html")

@app.route('/registrants')
def registrants():
    return render_template("register.html", students=students)

@app.route('/register', methods=["POST"])
def register():
    name = request.form.get("name")
    dorm = request.form.get("dorm")
    if not name or not dorm:
        pass
    else:
        students.append(f'{name} from {dorm}')
        return redirect('/registrants')

if __name__ == '__main__':
    app.run(debug=True)


from math import *
import gc
import pyglet
from pyglet.gl import *
import Eco

screen = None
mw, mh, sep = 2,2,1

circle_verts = [0,0]
circle_numpoints = 1

circle_radius = 0
live_color = [0, 255, 0]
sleep_color = [255, 0, 0]

def setup (w, h):
	global screen
	global circle_verts
	global circle_numpoints

	for y in range(1, int(circle_radius) + 1):
		x_boundary = sqrt(circle_radius*circle_radius - y*y)
		for x in range (1, int(x_boundary) + 1):
			circle_verts += [ x,  y]
			circle_verts += [-x,  y]
			circle_verts += [ x, -y]
			circle_verts += [-x, -y]
			circle_verts += [ 0,  y]
			circle_verts += [ 0, -y]
			circle_numpoints += 6

	for x in range(1, int(circle_radius) + 1):
		circle_verts += [ x, 0]
		circle_verts += [-x, 0]
		circle_numpoints += 2

	screen = pyglet.window.Window (width = w + 2*mw, height = h + 2*mh, caption = 'Game of Life')

class World:
	def __init__ (self, w, h, cell_d, cont, seeds = None):
		self.w = w
		self.h = h
		self.cell_d = cell_d
		self.width = mw + w*(cell_d + sep) + mw - sep
		self.height = mh + h*(cell_d + sep) + mw - sep

		self.draw_batch = pyglet.graphics.Batch ()
		self.verts = dict ()

		self.ecosys     = [[Eco.CellEntity (x, y, self.spawn, seeds[x][y] if seeds is not None else False) for y in range (h)] for x in range(w)]
		self.ecosys_pst = [[seeds[x][y] if seeds is not None else False for y in range (h)] for x in range(w)]

		self.cont     = cont
		self.hijacked = False

	@property
	def IsHijacked (self):
		return self.hijacked

	def GodBearAHandIn (self):
		self.hijacked = True

	def GodLeave (self):
		self.hijacked = False

	@property
	def EcoSys (self):
		return self.ecosys

	@property
	def EcoState (self):
		return self.ecosys_pst

	def check_neiboughs (self, x, y):
		alive_around = 0
		cands = [[x-1,y-1],[x,y-1],[x+1,y-1],
		         [x-1,y  ],[x+1,y],
		         [x-1,y+1],[x,y+1],[x+1,y+1]]
		for (cand_x,cand_y) in cands:
			if self.cont:
				sample_x = self.w - 1 if cand_x < 0 else (0 if cand_x == self.w else cand_x)
				sample_y = self.h - 1 if cand_y < 0 else (0 if cand_y == self.h else cand_y)
				alive_around += 1 if self.EcoState[sample_x][sample_y] else 0
			else:
				if (0 <= cand_x < self.w) and (0 <= cand_y < self.h):
					alive_around += 1 if self.EcoState[cand_x][cand_y] else 0

		return alive_around

	def record (self):
		self.ecosys_pst = [[self.EcoSys[x][y].IsAlive for y in range (0, self.h)] for x in range(0, self.w)]

	def spawn (self, x, y):
		if x not in self.verts:
			self.verts[x] = dict ()
		if y not in self.verts[x]:
			center = [mw + sep + x*(self.cell_d + sep) + circle_radius, mh + sep + y*(self.cell_d + sep) + circle_radius]
			self.verts[x][y] = [circle_verts[i] + center[i % 2] for i in range(len(circle_verts))]

		return self.draw_batch.add (circle_numpoints, GL_POINTS, None, ('v2f', self.verts[x][y]))

	def draw (self):
		if not self.IsHijacked:
			glColor3f(live_color[0], live_color[1], live_color[2])
		else:
			glColor3f(sleep_color[0], sleep_color[1], sleep_color[2])

		self.draw_batch.draw ()

	def generate (self):
		for x in range(self.w):
			for y in range(self.h):
				n_alive_neiboughs = self.check_neiboughs (x, y)
				if self.EcoState[x][y]:
					if (n_alive_neiboughs < 2) or (n_alive_neiboughs > 3):
						self.EcoSys[x][y].Die ()
				else:
					if (n_alive_neiboughs == 3):
						self.EcoSys[x][y].Resurrect ()

		self.record ()


import torch
import torchvision
import lightning.pytorch as pl
import pandas as pd

mapping = {'разметка_шипун' : 2, 'klikun' : 1, 'разметка_малый':0}
inv_mapping = { 2 : 'разметка_шипун', 1 : 'klikun', 0:'разметка_малый'}

def get_point(pred_id, gt_id):
    matr = [[3,-1,-3],
            [-1,3,-3],
            [-3,-3,2]]
    return matr[pred_id][gt_id]

def calc_metric(gt, pred):
    df = pd.DataFrame({'gt': gt, 'pred':pred})
    df['gt'] = df['gt'].map(mapping)
    df['pred'] = df['pred'].map(mapping)
    gt_points = []
    pred_points = []
    for i in df['gt']:
        gt_points.append(get_point(i, i))
    for i,j in zip(df['pred'],df['gt']):
        pred_points.append(get_point(i, j))
    df['gt_points'] = gt_points
    df['pred_points'] = pred_points
    return df

class SwanClassifier(pl.LightningModule):
    def __init__(self, learning_rate):
        super().__init__()
        self.learning_rate = learning_rate
        self.model = torchvision.models.resnet50(pretrained = True)
        self.model.fc = torch.nn.Linear(in_features=2048, out_features=3)
        weights = [1,1,4]
        class_weights = torch.FloatTensor(weights)
        self.criterion = torch.nn.CrossEntropyLoss(weight = class_weights)
        self.inv_mapping = { 2 : 'разметка_шипун', 1 : 'klikun', 0:'разметка_малый'}
        self.save_hyperparameters()

    def calc_score(self, preds, labels):
        gt_list = []
        pred_list = []
        max_preds = torch.argmax(preds, dim = 1)
        for pred, label in zip(max_preds, labels):
            pred_list.append(self.inv_mapping[pred.item()])
            gt_list.append(self.inv_mapping[label.item()])
        stat_df = calc_metric(gt_list, pred_list)
        return stat_df['pred_points'].sum()/stat_df['gt_points'].sum()

    def training_step(self, batch, batch_idx):
        crops = batch['image']
        labels = batch['img_class'].to(torch.long)
        preds = self.model(crops)
        loss = self.criterion(preds, labels)
        self.log("train_loss", loss)
        self.log('step', self.global_step)
        return loss

    def validation_step(self, batch, batch_idx):
        crops = batch['image']
        labels = batch['img_class'].to(torch.long)
        preds = self.model(crops)
        loss = self.criterion(preds, labels)
        self.log("validation_loss", loss, sync_dist=True)
        self.log("validation_score", self.calc_score(preds, labels), sync_dist=True)

    def forward(self, images):
        preds = self.model(images)
        preds = torch.argmax(preds, dim = 1)
        out = []
        for pred in preds:
            out.append(self.inv_mapping[pred.item()])
        return out

    def configure_optimizers(self):
        optimizer = torch.optim.Adam(self.parameters(), lr=self.learning_rate)
        def func(epoch: int):
            return  2 ** (-epoch//4)
        scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=func)
        return {
            'optimizer': optimizer,
            'lr_scheduler': {
                'scheduler': scheduler,
                'interval': 'epoch'
            }
        }


import io
import logging
from asyncio import AbstractEventLoop
from typing import Optional

import socketio
from aiohttp import web
from aiologger import Logger
from aiologger.formatters.base import Formatter
from aiologger.handlers.streams import AsyncStreamHandler
from aiologger.levels import LogLevel, check_level
from aiologger.records import LogRecord

import hello
from redirect_stdout import stdout_redirector

formatter = Formatter(
    fmt='[{name}] {asctime} {levelname}: {message}',
    datefmt='%m/%d/%Y %H:%M:%S',
    style='{'
)

logger_server = Logger(name='server', level=LogLevel.DEBUG)
logger_stdout = Logger(name="s4l", level=LogLevel.DEBUG)

sio = socketio.AsyncServer(async_mode='aiohttp')
app = web.Application()
sio.attach(app)

class SocketIOLogRedirect(AsyncStreamHandler):
    async def emit(self, record: LogRecord):
        await sio.emit('log', f"[{record.name}] {record.asctime} {record.levelname}: {record.get_message()}")

logger_stdout.add_handler(SocketIOLogRedirect())
logger_server.add_handler(SocketIOLogRedirect())

class LoggerSink(io.BytesIO):
    def __init__(self, logger):
        self.logger = logger

    def write(self, buf):
        msg = buf.decode('utf-8').rstrip('\n')
        self.logger.debug(f"Message from C {msg}")

f = LoggerSink(logger_stdout)

async def background_task():
    count = 0
    while True:
        await sio.sleep(1)
        count += 1
        await logger_server.debug(f'This is log number {count} from server')

async def background_ctask():
    count = 0
    while True:
        with stdout_redirector(f):
            hello.stdout("Foo")
            hello.stderr("Bar")

        await sio.sleep(1.0)

@sio.event
async def on_connect(sid, environ):
    await logger_server.debug(f'connect {sid}')
    await sio.emit('my_message', "asdfasdf")

@sio.event
async def disconnect(sid):
    print(sid, type(sid))
    await logger_server.debug(f'disconnect {sid}')

if __name__ == '__main__':
    sio.start_background_task(background_task)
    sio.start_background_task(background_ctask)
    web.run_app(app)


from main import *
from numpy.linalg import norm
import pytest
from itk import RTK as rtk
import configparser
import numpy as np

def wiki_example_RTK(configFile):
    """
        Simulates a cone-beam illumination of an ellipse.

        Taken from RTK's wiki, see the following page:
        http://wiki.openrtk.org/index.php/SimpleRTK#Testing_SimpleRTK
    """
    # Read the parameters from file
    cfg = configparser.ConfigParser()
    cfg.read(configFile)
    numberOfProjections = cfg.getint('Parameters', 'Nt')
    omega = cfg.getfloat('Parameters', 'omega')
    T = cfg.getfloat('Parameters', 'T')
    firstAngle = 90 - omega * T / 2
    angularArc = omega * T
    sid = cfg.getfloat('Parameters', 'R0')  # source to isocenter distance in mm
    sdd = cfg.getfloat('Parameters', 'sdd')  # source to detector distance in mm
    isox = 0  # X coordinate on the projection image of isocenter
    isoy = 0  # Y coordinate on the projection image of isocenter
    imageSize = cfg.getint('Parameters', 'imageSize')

    # get ellipse parameters
    ellipseDensity = cfg.getfloat('Ellipse', 'density')
    ellipseAngle = cfg.getfloat('Ellipse', 'angle')
    ellipseCenterX = cfg.getfloat('Ellipse', 'x')
    ellipseCenterY = cfg.getfloat('Ellipse', 'y')
    ellipseSemiAxisX = cfg.getfloat('Ellipse', 'a')
    ellipseSemiAxisY = cfg.getfloat('Ellipse', 'b')

    # Defines the RTK geometry object
    geometry = rtk.ThreeDCircularProjectionGeometry()
    for x in range(0, numberOfProjections):
        angle = firstAngle + x * angularArc / (numberOfProjections - 1)
        geometry.AddProjection(sid, sdd, angle, isox, isoy)

    # initialization of 'blank' image
    constantImageSource = rtk.ConstantImageSource()
    sizeOutput = [imageSize, imageSize, numberOfProjections]
    spacing = [1.0, 1.0, 1.0]
    origin = (np.array(sizeOutput) - 1) * np.array(spacing) * -.5
    constantImageSource.SetOrigin(origin)
    constantImageSource.SetSpacing(spacing)
    constantImageSource.SetSize(sizeOutput)
    constantImageSource.SetConstant(0.0)
    source = constantImageSource.Execute()

    rei = rtk.RayEllipsoidIntersectionImageFilter()
    semiprincipalaxis = [ellipseSemiAxisX,
                         ellipseSemiAxisY,
                         ellipseSemiAxisY]
    center = [ellipseCenterX, ellipseCenterY, 0]
    # Set GrayScale value, axes, center...
    rei.SetDensity(ellipseDensity)
    rei.SetAngle(ellipseAngle)
    rei.SetCenter(center)
    rei.SetAxis(semiprincipalaxis)
    rei.SetGeometry(geometry)
    reiImage = rei.Execute(source)

    return rtk.GetArrayFromImage(reiImage[:, imageSize / 2, :])

configFile = 'test.ini'
tol = .01

# simulation by our algorithm
p = Parameters(configFile)
s = Simulator(p)
res = s.run()
DCC = DataConsistencyConditions(res)

# simulation with RTK's example in wiki
projWiki = wiki_example_RTK(configFile)

# difference between the two projections
diff = res.projections - projWiki

## General tests
def test_get_angle():
    """
        The angles start at 90 since we compute the angle with the
        y-axis
    """
    assert p.get_angle(0) == 90

def test_y0():
    """
        :math:`y0` is supposed to be stricly positive
    """
    assert p.y0 > 0

## Testing projection operator

def test_projections_have_proper_dimensions():
    assert res.projections.shape[0] == p.Nt
    assert res.projections.shape[1] == p.imageSize

def test_projections_fits_example_in_wiki_RTK():
    """
        Compare the two projections, in L2 norm
    """
    assert norm(diff) <= tol * norm(projWiki)
    assert norm(diff, 1) <= tol * norm(projWiki, 1)
    assert norm(diff, 2) <= tol * norm(projWiki, 2)
    assert norm(diff, np.inf) <= tol * norm(projWiki, np.inf)

## Testing post-processing

configFile = 'example.ini'
tol = .01

# simulation by our algorithm
p = Parameters(configFile)
s = Simulator(p)
res = s.run()
DCC = DataConsistencyConditions(res)

def test_interpolation_fits_actual_projections():
    """
        The interpolator must fit the actual data
    """
    res.interpolate_projection()

    T = res.projections_interpolator
    t = p.get_time_range()
    phi = p.get_alpha_range()
    Tarray = T(phi, t)

    np.testing.assert_array_almost_equal(Tarray, res.projections)

def test_fanbeam_operator_has_compact_support():
    """
        Because we image a finite object, :math:`T(\phi/2,t)` and
        :math:`T(-\phi/2,t)` are always 0.
    """
    res.interpolate_projection()
    T = res.projections_interpolator

    t = np.linspace(-1000, 1000)

    np.testing.assert_almost_equal(T(np.pi / 2, t).sum(), 0.0)
    np.testing.assert_almost_equal(T(-np.pi / 2, t).sum(), 0.0)

## Testing DCC
def test_lambda_t_0_0():
    """
        When :math:`v = 0` and :math:`x = 0`, one has :math:`\lambda(T/2) = \pi/2`
        and :math:`\lambda(-T/2) = -\pi/2`.
        Moreover, the function is not supposed to raise a warning about
        division by 0.
    """
    lambda_t_0_0 = np.vectorize(lambda t: DCC.lambda_v(t, 0, 0, 0))

    # extreme values
    np.testing.assert_almost_equal(lambda_t_0_0(p.T / 2), np.pi / 2)
    np.testing.assert_almost_equal(lambda_t_0_0(-p.T / 2), -np.pi / 2)

    # elsewhere, compare with theoretical values
    t = np.linspace(-p.T / +.01, p.T / 2 - .01, 1000)
    lambda_theo = np.arctan((p.R0 * np.sin(p.omega * t / 360 * 2 * np.pi)) \
                            / (p.R0 * np.cos(p.omega * t / 360 * 2 * np.pi) - p.y0))
    np.testing.assert_array_almost_equal(lambda_t_0_0(t), lambda_theo)

def test_beta_v2_0():
    """
        When :math:`v_2 = 0`, then :math:`\beta = 0`.
        Here, we test that beta(v1,0) is equal to 0, with a random
        value (strictly positive) for v1.
    """
    from numpy.random import randn
    v1 = np.abs(randn())

    assert DCC.beta(v1, 0) == 0.

def test_beta_raises_exception():
    """
        Assert that method beta in DCC class raises the proper
        exception, ie when denominator is equal to 0.
    """
    v1 = -2 * p.R0 * np.sin(2 * np.pi / 360 * p.omega * p.T / 2) / p.T

    with pytest.raises(ZeroDivisionError) as e_info:
        DCC.beta(v1, p.v2)

def test_virtual_source_position_begin_end():
    """
        By definition, the y-coordinates of the source is supposed
        to be the same when :math:`t=-T/2` and :math:`t=T/2`.
    """
    # y-coordinate of s_v(T/2)
    s_v_2_T_over_2 = DCC.get_virtual_source_position(p.T / 2, p.v, p.v2)[1]

    # y-coordinate of s_v(T/2)
    s_v_2_minus_T_over_2 = DCC.get_virtual_source_position(-p.T / 2, p.v, p.v2)[1]

    np.testing.assert_almost_equal(s_v_2_T_over_2, s_v_2_minus_T_over_2)

def test_simplified_formula_for_y0_prime():
    """
        Test that :math:`s^{(v)}(T/2) = s^{(v)}(-T/2) = R_0 \cos(\omega T/2 + \beta)`
    """
    y0_prime = p.R0 * np.cos(p.omega / 360 * 2 * np.pi * p.T / 2 + DCC.beta(p.v, p.v2))
    # y-coordinate of s_v(T/2)
    s_v_2_T_over_2 = DCC.get_virtual_source_position(p.T / 2, p.v, p.v2)[1]

    # y-coordinate of s_v(T/2)
    s_v_2_minus_T_over_2 = DCC.get_virtual_source_position(-p.T / 2, p.v, p.v2)[1]

    np.testing.assert_almost_equal(y0_prime, s_v_2_minus_T_over_2)
    np.testing.assert_almost_equal(s_v_2_T_over_2, y0_prime)

def test_F_0_0():
    """
        As mentioned in equation (17) of the abstract, when :math:`v=0`
        the function :math:`F` has a simpler formulation

        ..math::
        F^{(0,0)}(t,x) = \frac{x + R_0 \sin(\omega t)}{R0 \cos(\omega t)}
    """
    R0 = p.R0
    omega = p.omega / 360 * 2 * np.pi
    y0 = R0 * np.cos(omega * p.T / 2)

    from numpy.random import randn
    # virtual point, taken randomly
    x = randn()
    # time vector, taken randomly
    t = randn()

    F_theo = (x + R0 * np.sin(omega * t)) / (R0 * np.cos(omega * t) - y0)
    np.testing.assert_almost_equal(DCC.F(t, 0, 0, x), F_theo)

def test_get_virtual_source_position_v_0():
    """
        Test that when :math:`v_1 = v_2 = 0`, one has
        :math:`s^{(v)}(t) = R_0(-\sin(\omega t), \cos(\omega t))`
    """
    from numpy.random import randn
    t = randn()

    s_0_t = DCC.get_virtual_source_position(t, 0, 0)
    omega = p.omega / 360 * 2 * np.pi
    s_theo = p.R0 * np.array((-np.sin(omega * t), np.cos(omega * t)))

    np.testing.assert_almost_equal(s_0_t, s_theo)

def test_get_virtual_source_position_v2_0():
    """
        Test that when :math:`v_2 = 0`, one has
        :math:`s^{(v)}(t) = (-R_0 \sin(\omega t) - (t+T/2) v_1, \
                              R_0 \cos(\omega t))`
    """
    from numpy.random import randn
    t = randn()
    v = randn()
    R0 = p.R0
    omega = p.omega / 360 * 2 * np.pi
    T = p.T

    s_0_t = DCC.get_virtual_source_position(t, v, 0)
    omega = p.omega / 360 * 2 * np.pi

    # we will use here the same code as in previous versions
    Mvt = np.array(((t + p.T / 2) * v, 0))
    s_theo = s.source.get_position(t) - Mvt

    s_theo_analytical = np.array((-R0 * np.sin(omega * t) - \
                                  (t + T / 2) * v, R0 * np.cos(omega * t)))

    np.testing.assert_almost_equal(s_0_t, s_theo)
    np.testing.assert_almost_equal(s_0_t, s_theo_analytical)

def test_get_virtual_points_vector():
    """
        Here, we test that when :math:`v_1 = v_2 = 0`, the virtual points
        :math:`x'` are in fact points between :math:`-R_0\sin(\omega T/2)`
        and :math:`-R_0\sin(\omega T/2)`
    """
    x_prime = DCC.get_virtual_points_vector(0, 0)

    omega = p.omega / 360 * 2 * np.pi
    x_prime_theo = p.R0 * np.linspace(-np.sin(omega * p.T / 2), np.sin(omega * p.T / 2))

    np.testing.assert_almost_equal(x_prime, x_prime_theo)

def test_jacobian_with_old_formulas():
    """
        In some archives, we had the formulas for the jacobian
        when :math:`v_2=0`, so we will use it here.
    """

    # for time, degree of polynom, position: we take random values
    from numpy.random import randint
    n = randint(5)
    from numpy.random import randn
    t = np.abs(randn())
    x = randn()
    v1 = np.abs(randn())
    # important, because the test relies on the fact that v2 = 0
    v2 = 0

    # usual parameters
    R0 = p.R0
    T = p.T
    omega = p.omega / 360 * 2 * np.pi
    y0 = p.y0

    # compute weighting function with DCC class
    jacobian_new = DCC.jacobian(t, v1, v2, x)

    # compute old formula (with previous version of code)
    v = v1  # to be compatible with old notations
    # first, "jacobian"
    num = R0 ** 2 * omega - v * y0 + R0 * np.cos(omega * t) * (v - omega * y0) \
          + R0 * omega * np.sin(omega * t) * (x + (t + T / 2) * v)
    denom = (R0 * np.cos(omega * t) - y0) ** 2
    jacobian_old = num / denom

    np.testing.assert_almost_equal(jacobian_new, jacobian_old)

def test_integrand_with_old_formulas():
    """
        In some archives, we had the formulas for the weighting function
        and the jacobian when :math:`v_2=0`, so we will use it here.
    """

    # for time, degree of polynom, position: we take random values
    from numpy.random import randint
    n = randint(5)
    from numpy.random import randn
    t = np.abs(randn())
    x = randn()
    v1 = np.abs(randn())
    # important, because the test relies on the fact that v2 = 0
    v2 = 0

    # usual parameters
    R0 = p.R0
    T = p.T
    omega = p.omega / 360 * 2 * np.pi
    y0 = R0 * np.cos(omega * T / 2)

    # compute weighting function with DCC class
    weight_new = DCC.W(n, t, v1, v2, x)

    # compute old formula (with previous version of code)
    v = v1  # to be compatible with old notations
    # first, "jacobian"
    num = R0 ** 2 * omega - v * y0 + R0 * np.cos(omega * t) * (v - omega * y0) \
          + R0 * omega * np.sin(omega * t) * (x + (t + T / 2) * v)
    denom = (R0 * np.cos(omega * t) - y0) ** 2
    J_x_t_v = num / denom

    # then, function W_n(t,x)
    s_v_t = DCC.get_virtual_source_position(t, v1, v2)
    from scipy.spatial import distance
    D_x_t = distance.euclidean(s_v_t, (x, y0))
    num = (x + R0 * np.sin(omega * t) + (t + T / 2) * v) ** n
    denom = D_x_t * (R0 * np.cos(omega * t) - y0) ** (n - 1)
    W_n_t_x = num / denom

    weight_old = J_x_t_v * W_n_t_x

    np.testing.assert_almost_equal(weight_old, weight_new)

def test_two_different_formulas_for_weight_function():
    """
        In Theorem 1, the weight function is defined as

        ..math::
        W(t) = \tan^n(\lambda) \cos(\lambda) \partial_t \lambda

        We can also show that

        ..math::
        W(t) = \frac{F(t)^n}{\sqrt{1+F^(t)}} F'(t),

        where :math:`F(t) := \arctan(\lambda)`. This is what
        we will test here.
    """
    # for time, degree of polynom, position, velocity,
    # we take random values
    from numpy.random import randint
    n = randint(5)
    from numpy.random import randn
    t = np.abs(randn())
    x = randn()
    v1 = np.abs(randn())
    v2 = np.abs(randn())

    # usual parameters
    R0 = p.R0
    T = p.T
    omega = p.omega / 360 * 2 * np.pi
    y0 = R0 * np.cos(omega * T / 2)

    # compute weighting function with DCC class
    weight_DCC = DCC.W(n, t, v1, v2, x)

    # compute formula
    F_t_x = DCC.F(t, v1, v2, x)
    diff_t_F = DCC.jacobian(t, v1, v2, x)  # computes F'(t)
    weight_alternative = F_t_x ** n / np.sqrt(1 + F_t_x ** 2) * diff_t_F

    np.testing.assert_almost_equal(weight_DCC, weight_alternative)


import datetime
import random
from random import randint

from faker import Faker

def rand_ratio():
    return f'https://loremflickr.com/{randint(840, 900)}/{randint(473, 573)}/cook,food/'

def data_hora_aleatoria():
    ano_atual = datetime.datetime.now().year
    ano_aleatorio = random.randint(2022, ano_atual)
    mes_aleatorio = random.randint(1, 12)
    dia_aleatorio = random.randint(1, 28)
    hora_aleatoria = random.randint(0, 23)
    minuto_aleatorio = random.randint(0, 59)

    data_hora = datetime.datetime(
        ano_aleatorio, mes_aleatorio, dia_aleatorio, hora_aleatoria, minuto_aleatorio)

    return data_hora.strftime('%d/%m/%Y às %H:%M')

fake = Faker('pt_BR')

def make_recipe():
    return {
        'id': fake.random_number(digits=4, fix_len=True),
        'title': fake.sentence(nb_words=6),
        'description': fake.sentence(nb_words=12),
        'preparation_time': fake.random_number(digits=2, fix_len=True),
        'preparation_time_unit': 'Minutos',
        'servings': fake.random_number(digits=2, fix_len=True),
        'servings_unit': 'Porçõe',
        'preparation_steps': fake.text(3000),
        'timestamp': data_hora_aleatoria(),
        'author': {
            'first_name': fake.first_name(),
            'last_name': fake.last_name()
        },
        'category': {
            'name': fake.word()
        },
        'cover': {
            'url': rand_ratio()
        }
    }

if __name__ == '__main__':
    from pprint import pprint
    pprint(make_recipe())


# -*- coding: utf-8 -*-
"""
Created on Tue May  9 22:08:34 2017

@author: hyj
"""

import numpy as np

from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d import proj3d
# ############## 3d tranform lib  ######################
#            几何变换的一些函数，欧拉角，　旋转矩阵等
##############################################

def Rx(phi):
    return np.array([[1, 0, 0],
                     [0, np.cos(phi), np.sin(phi)],
                     [0, -np.sin(phi), np.cos(phi)]])

def Ry(theta):
    return np.array([[np.cos(theta), 0, -np.sin(theta)],
                     [0, 1, 0],
                     [np.sin(theta), 0, np.cos(theta)]])

def Rz(psi):
    return np.array([[np.cos(psi), np.sin(psi), 0],
                     [-np.sin(psi), np.cos(psi), 0],
                     [0, 0, 1]])

def euler2Rbn(eulerAngles):
    ''' navigation frame to body frame '''
    return Rx(eulerAngles[0]).dot(   Ry(eulerAngles[1]).dot( Rz(eulerAngles[2]) )  )

def euler2Rnb(eulerAngles):
    """ body frame to navigation frame ,
        euler2Rnb = euler2Rnb^t """
    return Rz(-eulerAngles[2]).dot( Ry(-eulerAngles[1]).dot( Rx(-eulerAngles[0]) )  )

# Checks if a matrix is a valid rotation matrix.
def isRotationMatrix(R) :
    Rt = np.transpose(R)
    shouldBeIdentity = np.dot(Rt, R)
    I = np.identity(3, dtype = R.dtype)
    n = np.linalg.norm(I - shouldBeIdentity)
    return n < 1e-6

# Calculates rotation matrix to euler angles
# The result is the same as MATLAB except the order
# of the euler angles ( x and z are swapped ).
def rotationMatrixToEulerAngles(R) :

    assert(isRotationMatrix(R))

    sy = np.sqrt(R[0,0] * R[0,0] +  R[1,0] * R[1,0])
    singular = sy < 1e-6

    if  not singular :
        x = np.atan2(R[2,1] , R[2,2])
        y = np.atan2(-R[2,0], sy)
        z = np.atan2(R[1,0], R[0,0])
    else :
        x = np.atan2(-R[1,2], R[1,1])
        y = np.atan2(-R[2,0], sy)
        z = 0

    return np.array([x, y, z])

def Transfrome(eulerAngles, t, point):
    ''' eulerAngles = np.array([roll, pitch, yaw] ) , t = np.array( [tx, ty, tz]) ,  point = np.array( [px, py, pz])'''
    return euler2Rnb(eulerAngles).dot(point) + t

# ############## 3d draw lib  ######################
#            some function used to draw 3d arrows
##############################################

# draw 3d arrow
class Arrow3D(FancyArrowPatch):
    def __init__(self, xs, ys, zs, *args, **kwargs):
        FancyArrowPatch.__init__(self, (0,0), (0,0), *args, **kwargs)
        self._verts3d = xs, ys, zs

    def draw(self, renderer):
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
        self.set_positions((xs[0],ys[0]),(xs[1],ys[1]))
        FancyArrowPatch.draw(self, renderer)

def drawCoordinateFrame( ax, rpy, t):

    # define origin
    o = np.array([0,0,0])
    # define ox0y0z0 axes
    x0 = np.array([1,0,0])
    y0 = np.array([0,1,0])
    z0 = np.array([0,0,1])

    R = euler2Rnb(rpy)

    # transfrom b0 frame to the new bi frame
    o1 = R.dot(o) + t
    x1 = R.dot(x0) + t
    y1 = R.dot(y0) + t
    z1 = R.dot(z0) + t

    x = Arrow3D(   [o1[0], x1[0]],    [o1[1], x1[1]],     [o1[2], x1[2]] ,  mutation_scale=20, arrowstyle='-|>', color='r')
    y = Arrow3D(   [o1[0], y1[0]],    [o1[1], y1[1]],     [o1[2], y1[2]] ,  mutation_scale=20, arrowstyle='-|>', color='b')
    z = Arrow3D(   [o1[0], z1[0]],    [o1[1], z1[1]],     [o1[2], z1[2]] ,  mutation_scale=20, arrowstyle='-|>', color='g')

   # draw
    ax.add_artist( x)
    ax.add_artist( y )
    ax.add_artist( z )


from . import rust_ext

__version__ = "0.1.0"

import numpy as np
from sklearn.base import BaseEstimator, RegressorMixin

class psd1d(BaseEstimator, RegressorMixin):
    def __init__(self, max_lag=100, delta=1.0):
        self.max_lag = max_lag
        self.delta = delta

    def fit(self, y, x=None):
        """
        y:
        x: Ingored
        """
        if y.ndim > 1:
            raise ValueError
        self.max_lag = min(self.max_lag, y.shape[0])

        if y.dtype in (np.float64, np.complex128):
            pass
        elif y.dtype in (np.complex64, np.complex256):
            y = y.astype(np.complex128)
        else:
            y = y.astype(np.float64)

        if y.dtype == np.float64:
            self.gamma_ = rust_ext.reflection_coeff_f64(self.max_lag, y)
            assert self.gamma_.shape[0] == self.max_lag + 1
            self.p_ = rust_ext.variance_f64(self.gamma_.diagonal(), y)
            self.lag_ = self.max_lag
        elif y.dtype == np.complex128:
            self.gamma_ = rust_ext.reflection_coeff_c64(self.max_lag, y)
            assert self.gamma_.shape[0] == self.max_lag + 1
            self.p_ = rust_ext.variance_c64(self.gamma_.diagonal(), y)
            self.lag_ = self.max_lag
        else:
            raise ValueError

        return self

    def predict(self, x):
        """
        x:
        """
        if x.ndim > 1:
            raise ValueError
        if self.lag_ > self.max_lag:
            raise ValueError

        if self.gamma_.dtype == np.float64:
            return rust_ext.power_spector_f64(
                self.delta, self.p_[self.lag_], self.gamma_[self.lag_, :], x
            )
        elif self.gamma_.dtype == np.complex128:
            return rust_ext.power_spector_c64(
                self.delta, self.p_[self.lag_], self.gamma_[self.lag_, :], x
            )
        else:
            raise ValueError


"""
`Aloe-Webdriver` includes several utilities for writing Selenium_ tests.
"""

import operator
from copy import copy
from functools import wraps
from time import time, sleep

try:
    reduce
except NameError:
    from functools import reduce  # pylint:disable=redefined-builtin,ungrouped-imports

from selenium.common.exceptions import NoSuchElementException

# pylint:disable=missing-docstring,redefined-outer-name,redefined-builtin
# pylint:disable=invalid-name

# Pylint cannot infer the attributes on world
# pylint:disable=no-member

def string_literal(content):
    """
    Choose a string literal that can wrap our string.

    If your string contains a ``\'`` the result will be wrapped in ``\"``.
    If your string contains a ``\"`` the result will be wrapped in ``\'``.

    Cannot currently handle strings which contain both ``\"`` and ``\'``.
    """

    if '"' in content and "'" in content:
        # there is no way to escape string literal characters in XPath
        raise ValueError("Cannot represent this string in XPath")

    if '"' in content:  # if it contains " wrap it in '
        content = "'%s'" % content
    else:  # wrap it in "
        content = '"%s"' % content

    return content

class ElementSelector(object):
    """
    A set of elements on a page matching an XPath query.

    :param browser: ``world.browser``
    :param str xpath: XPath query
    :param list elements: list of :class:`selenium.WebElement` objects
    :param bool filter_displayed: whether to only return displayed elements
    :param bool filter_enabled: whether to only return enabled elements

    Delays evaluation to batch the queries together, allowing operations on
    selectors (e.g. union) to be performed first, and then issuing as few
    requests to the browser as possible.

    One of `xpath` or `elements` must be passed. Passing `xpath` creates a
    selector delaying evaluation until it's needed, passing `elements`
    stores the elements immediately.

    Can behave as an iterable of elements or a single element by proxying all
    method calls, asserting that there is only one element selected.

    Can be combined using the addition operator (``+``) to `OR` XPath queries
    together.
    """

    def __init__(self, browser, xpath=None, elements=None,  # pylint:disable=too-many-arguments
                 filter_displayed=False, filter_enabled=False):
        """
        Initialise the selector.

        One of `xpath` or `elements` must be passed. Passing `xpath` creates a
        selector delaying evaluation until it's needed, passing `elements`
        stores the elements immediately.
        """
        self.browser = browser

        if xpath is None and elements is None:
            raise ValueError("Must supply either xpath or elements.")

        if xpath is not None:
            self.xpath = xpath
        else:
            self._elements_cached = elements

        self.filter_displayed = filter_displayed
        self.filter_enabled = filter_enabled

    @property
    def evaluated(self):
        """Whether the selector has already been evaluated."""

        return hasattr(self, '_elements_cached')

    def filter(self, displayed=False, enabled=False):
        """
        Filter elements by visibility and enabled status.

        :param displayed: whether to filter out invisible elements
        :param enabled: whether to filter out disabled elements

        Returns: an :class:`ElementSelector`
        """

        if self.evaluated:
            # Filter elements one by one
            result = self

            if displayed:
                result = ElementSelector(
                    result.browser,
                    elements=[e for e in result if e.is_displayed()]
                )

            if enabled:
                result = ElementSelector(
                    result.browser,
                    elements=[e for e in result if e.is_enabled()]
                )

        else:
            result = copy(self)
            if displayed:
                result.displayed = True
            if enabled:
                result.enabled = True

        return result

    def _select(self):
        """Fetch the elements from the browser."""

        for element in self.browser.find_elements_by_xpath(self.xpath):
            if self.filter_displayed:
                if not element.is_displayed():
                    continue

            if self.filter_enabled:
                if not element.is_enabled():
                    continue

            yield element

    def _elements(self):
        """
        The cached list of elements.
        """
        if not self.evaluated:
            setattr(self, '_elements_cached', list(self._select()))
        return self._elements_cached

    def __add__(self, other):
        """
        Return a union of the two selectors.

        Where possible, avoid evaluating either selector to batch queries.
        """

        if not self.evaluated \
                and isinstance(other, ElementSelector) \
                and not other.evaluated \
                and self.filter_displayed == other.filter_displayed \
                and self.filter_enabled == other.filter_enabled:
            # Both summands are delayed, return a new delayed selector
            return ElementSelector(
                self.browser,
                xpath=self.xpath + '|' + other.xpath,
                filter_displayed=self.filter_displayed,
                filter_enabled=self.filter_enabled,
            )
        else:
            # Have to evaluate everything now
            # other can be either an already evaluated ElementSelector, a list
            # or a single element
            try:
                other = list(other)
            except TypeError:
                other = [other]

            return ElementSelector(self.browser, elements=list(self) + other)

    # The class behaves as a container for the elements, fetching the list from
    # the browser on the first attempt to enumerate itself.

    def __len__(self):
        return len(self._elements())

    def __getitem__(self, key):
        return self._elements()[key]  # pylint:disable=unsubscriptable-object

    def __iter__(self):
        for el in self._elements():  # pylint:disable=not-an-iterable
            yield el

    def __nonzero__(self):
        return bool(self._elements())

    def __getattr__(self, attr):
        """
        Delegate all calls to the only element selected.
        """

        if attr == '_elements_cached':
            # Never going to be on the element
            raise AttributeError()

        assert len(self) == 1, \
            'Must be a single element, have {0}'.format(len(self))
        return getattr(self[0], attr)

def element_id_by_label(browser, label):
    """
    The ID of an element referenced by a `label`s ``for`` attribute. The label
    must be visible.

    :param browser: ``world.browser``
    :param label: label text to return the referenced element for

    Returns: ``for`` attribute value
    """
    label = ElementSelector(browser,
                            str('//label[contains(., %s)]' %
                                string_literal(label)))
    if not label:
        return False
    return label.get_attribute('for')

def field_xpath(field, attribute):
    """
    Field helper functions to locate select, textarea, and the other
    types of input fields (text, checkbox, radio)

    :param field: One of the values 'select', 'textarea', 'option', or
    'button-element' to match a corresponding HTML element (and to
    match a <button> in the case of 'button-element'). Otherwise a
    type to match an <input> element with a type=<field> attribute.

    :param attribute: An attribute to be matched against, or 'value'
    to match against the content within element being matched.
    """
    if field in ['select', 'textarea']:
        xpath = './/{field}[@{attr}=%s]'

    elif field == 'button-role':
        if attribute == 'value':
            xpath = './/*[@role="button"][contains(., %s)]'
        else:
            xpath = './/*[@role="button"][@{attr}=%s]'

    elif field == 'button-element':
        field = 'button'
        if attribute == 'value':
            xpath = './/{field}[contains(., %s)]'
        else:
            xpath = './/{field}[@{attr}=%s]'

    elif field == 'option':
        xpath = './/{field}[@{attr}=%s]'

    else:
        xpath = './/input[@{attr}=%s][@type="{field}"]'

    return xpath.format(field=field, attr=attribute)

def find_button(browser, value):
    """
    Find a button with the given value.

    Searches for the following different kinds of buttons:

        <input type="submit">
        <input type="reset">
        <input type="button">
        <input type="image">
        <button>
        <{a,p,div,span,...} role="button">

    Returns: an :class:`ElementSelector`
    """
    field_types = (
        'submit',
        'reset',
        'button-element',
        'button',
        'image',
        'button-role',
    )

    return reduce(
        operator.add,
        (find_field_with_value(browser, field_type, value)
         for field_type in field_types)
    )

def find_field_with_value(browser, field, value):
    return find_field_by_id(browser, field, value) + \
        find_field_by_name(browser, field, value) + \
        find_field_by_value(browser, field, value)

def find_option(browser, select_name, option_name):
    # First, locate the select
    select_box = find_field(browser, 'select', select_name)
    assert select_box, "Cannot find a '{}' select.".format(select_name)

    # Now locate the option
    option_box = find_field(select_box, 'option', option_name)
    if not option_box:
        # Locate by contents
        option_box = select_box.find_element_by_xpath(str(
            './/option[contains(., "%s")]' % option_name))
    return option_box

def find_field(browser, field_type, value):
    """
    Locate an input field.

    :param browser: ``world.browser``
    :param string field_type: a field type (i.e. `button`)
    :param string value: an id, name or label

    This first looks for `value` as the id of the element, else
    the name of the element, else as a label for the element.

    Returns: an :class:`ElementSelector`
    """
    return find_field_by_id(browser, field_type, value) + \
        find_field_by_name(browser, field_type, value) + \
        find_field_by_label(browser, field_type, value)

def find_any_field(browser, field_types, field_name):
    """
    Find a field of any of the specified types.

    :param browser: ``world.browser``
    :param list field_types: a list of field type (i.e. `button`)
    :param string value: an id, name or label

    Returns: an :class:`ElementSelector`

    See also: :func:`find_field`.
    """

    return reduce(
        operator.add,
        (find_field(browser, field_type, field_name)
         for field_type in field_types)
    )

def find_field_by_id(browser, field_type, id):
    """
    Locate the control input with the given ``id``.

    :param browser: ``world.browser``
    :param string field_type: a field type (i.e. `button`)
    :param string id: ``id`` attribute

    Returns: an :class:`ElementSelector`
    """
    return ElementSelector(
        browser,
        xpath=field_xpath(field_type, 'id') % string_literal(id),
        filter_displayed=True,
    )

def find_field_by_name(browser, field_type, name):
    """
    Locate the control input with the given ``name``.

    :param browser: ``world.browser``
    :param string field_type: a field type (i.e. `button`)
    :param string name: ``name`` attribute

    Returns: an :class:`ElementSelector`
    """
    return ElementSelector(
        browser,
        field_xpath(field_type, 'name') %
        string_literal(name),
        filter_displayed=True,
    )

def find_field_by_value(browser, field_type, name):
    """
    Locate the control input with the given ``value``. Useful for buttons.

    :param browser: ``world.browser``
    :param string field_type: a field type (i.e. `button`)
    :param string name: ``value`` attribute

    Returns: an :class:`ElementSelector`
    """
    xpath = field_xpath(field_type, 'value') % string_literal(name)
    elems = ElementSelector(
        browser,
        xpath=str(xpath),
        filter_displayed=True,
        filter_enabled=True,
    )

    # sort by shortest first (most closely matching)
    if field_type in ('button-element', 'button-role'):
        elems = sorted(elems, key=lambda elem: len(elem.text))
    else:
        elems = sorted(elems,
                       key=lambda elem: len(elem.get_attribute('value')))

    if elems:
        elems = [elems[0]]

    return ElementSelector(browser, elements=elems)

def find_field_by_label(browser, field_type, label):
    """
    Locate the control input that has a label pointing to it.

    :param browser: ``world.browser``
    :param string field_type: a field type (i.e. `button`)
    :param string label: label text

    This will first locate the label element that has a label of the given
    name. It then pulls the id out of the 'for' attribute, and uses it to
    locate the element by its id.

    Returns: an :class:`ElementSelector`
    """

    return ElementSelector(
        browser,
        xpath=field_xpath(field_type, 'id') %
        '//label[contains(., {0})]/@for'.format(
            string_literal(label)),
        filter_displayed=True,
    )

def option_in_select(browser, select_name, option):
    """
    Returns the Element specified by @option or None

    Looks at the real <select> not the select2 widget, since that doesn't
    create the DOM until we click on it.
    """

    select = find_field(browser, 'select', select_name)
    assert select, "Cannot find a '{}' select.".format(select_name)

    try:
        return select.find_element_by_xpath(str(
            './/option[normalize-space(text())=%s]' % string_literal(option)))
    except NoSuchElementException:
        return None

TIMEOUT = 15
CHECK_EVERY = 0.2

def wait_for(func):
    """
    A decorator to invoke a function, retrying on assertion errors for a
    specified time interval.

    Adds a kwarg `timeout` to `func` which is a number of seconds to try
    for (default 15).
    """

    @wraps(func)
    def wrapped(*args, **kwargs):
        timeout = kwargs.pop('timeout', TIMEOUT)

        start = None

        while True:
            try:
                return func(*args, **kwargs)
            except AssertionError:
                # The function took some time to test the assertion, however,
                # the result might correspond to the state of the world at any
                # point in time, perhaps earlier than the timeout. Therefore,
                # start counting time from the first assertion fail, not from
                # before the function was called.
                if not start:
                    start = time()
                if time() - start < timeout:
                    sleep(CHECK_EVERY)
                    continue
                raise

    return wrapped