diff --git a/oscurart_tools/__init__.py b/oscurart_tools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..ba217ac5e681b749901c2154172aebc190017fef
--- /dev/null
+++ b/oscurart_tools/__init__.py
@@ -0,0 +1,391 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+bl_info = {
+    "name": "Oscurart Tools",
+    "author": "Oscurart, CodemanX",
+    "version": (3, 2),
+    "blender": (2, 77, 0),
+    "location": "View3D > Tools > Oscurart Tools",
+    "description": "Tools for objects, render, shapes, and files.",
+    "warning": "",
+    "wiki_url":
+        "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/Oscurart_Tools",
+    "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
+    "category": "Object",
+    }
+
+import bpy
+from bpy.types import (
+            AddonPreferences,
+            Panel,
+            PropertyGroup,
+            )
+
+from bpy.props import (
+            StringProperty,
+            BoolProperty,
+            IntProperty,
+            )
+
+from . import oscurart_files
+from . import oscurart_meshes
+from . import oscurart_objects
+from . import oscurart_shapes
+from . import oscurart_render
+from . import oscurart_animation
+
+
+class View3DOscPanel(PropertyGroup):
+    # CREA PANELES EN TOOLS
+    osc_object_tools = BoolProperty(default=True)
+    osc_mesh_tools = BoolProperty(default=True)
+    osc_shapes_tools = BoolProperty(default=True)
+    osc_render_tools = BoolProperty(default=True)
+    osc_files_tools = BoolProperty(default=True)
+    osc_animation_tools = BoolProperty(default=True)
+
+    quick_animation_in = IntProperty(
+                        default=1
+                        )
+    quick_animation_out = IntProperty(
+                        default=250
+                        )
+    # SETEO VARIABLE DE ENTORNO
+    SearchAndSelectOt = StringProperty(
+                        default="Object name initials"
+                        )
+    # RENDER CROP
+    rcPARTS = IntProperty(
+                        default=1,
+                        min=2,
+                        max=50,
+                        step=1
+                            )
+    RenameObjectOt = StringProperty(
+                        default="Type here"
+                        )
+
+
+class VarColArchivos(PropertyGroup):
+    filename = bpy.props.StringProperty(
+                        name="",
+                        default=""
+                        )
+    value = bpy.props.IntProperty(
+                        name="",
+                        default=10
+                        )
+    fullpath = bpy.props.StringProperty(
+                        name="",
+                        default=""
+                        )
+    checkbox = bpy.props.BoolProperty(
+                        name="",
+                        default=True
+                        )
+
+
+# PANELES
+class OscPanelControl(Panel):
+    bl_idname = "Oscurart Panel Control"
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_category = "Oscurart Tools"
+    bl_label = "Panels Switcher"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw(self, context):
+        layout = self.layout
+        scene = context.scene
+        oscurart = scene.oscurart
+
+        col = layout.column(align=1)
+        col.prop(oscurart, "osc_object_tools", text="Object", icon="OBJECT_DATAMODE")
+        col.prop(oscurart, "osc_mesh_tools", text="Mesh", icon="EDITMODE_HLT")
+        col.prop(oscurart, "osc_shapes_tools", text="Shapes", icon="SHAPEKEY_DATA")
+        col.prop(oscurart, "osc_animation_tools", text="Animation", icon="POSE_DATA")
+        col.prop(oscurart, "osc_render_tools", text="Render", icon="SCENE")
+        col.prop(oscurart, "osc_files_tools", text="Files", icon="IMASEL")
+
+
+class OscPanelObject(Panel):
+    bl_idname = "Oscurart Object Tools"
+    bl_label = "Object Tools"
+    bl_category = "Oscurart Tools"
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.scene.oscurart.osc_object_tools
+
+    def draw(self, context):
+        layout = self.layout
+        col = layout.column(align=1)
+
+        colrow = col.row(align=1)
+        colrow.operator("object.relink_objects_between_scenes", icon="LINKED")
+        colrow = col.row(align=1)
+        colrow.operator("object.copy_objects_groups_layers", icon="LINKED")
+        colrow.operator("object.set_layers_to_other_scenes", icon="LINKED")
+        colrow = col.row(align=1)
+        colrow.operator("object.objects_to_groups", icon="GROUP")
+        colrow = col.row(align=1)
+        colrow.prop(bpy.context.scene.oscurart, "SearchAndSelectOt", text="")
+        colrow.operator("object.search_and_select_osc", icon="ZOOM_SELECTED")
+        colrow = col.row(align=1)
+        colrow.prop(bpy.context.scene.oscurart, "RenameObjectOt", text="")
+        colrow.operator("object.rename_objects_osc", icon="SHORTDISPLAY")
+        col.operator(
+            "object.distribute_osc",
+            icon="OBJECT_DATAMODE",
+            text="Distribute")
+        col.operator(
+            "object.duplicate_object_symmetry_osc",
+            icon="OUTLINER_OB_EMPTY",
+            text="Duplicate Sym")
+        colrow = col.row(align=1)
+        colrow.operator(
+            "object.modifiers_remove_osc",
+            icon="MODIFIER",
+            text="Remove Modifiers")
+        colrow.operator(
+            "object.modifiers_apply_osc",
+            icon="MODIFIER",
+            text="Apply Modifiers")
+        colrow = col.row(align=1)
+        colrow.operator(
+            "group.group_in_out_camera",
+            icon="RENDER_REGION",
+            text="Make Groups in out Camera")
+
+
+class OscPanelMesh(Panel):
+    bl_idname = "Oscurart Mesh Tools"
+    bl_label = "Mesh Tools"
+    bl_category = "Oscurart Tools"
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.scene.oscurart.osc_mesh_tools
+
+    def draw(self, context):
+        layout = self.layout
+        col = layout.column(align=1)
+
+        col.operator("mesh.object_to_mesh_osc", icon="MESH_MONKEY")
+        col.operator("mesh.select_side_osc", icon="VERTEXSEL")
+        colrow = col.row(align=1)
+        colrow.operator("mesh.resym_save_map", icon="UV_SYNC_SELECT")
+        colrow = col.row(align=1)
+        colrow.operator(
+            "mesh.resym_mesh",
+            icon="UV_SYNC_SELECT",
+            text="Resym Mesh")
+        colrow.operator("mesh.resym_vertex_weights_osc", icon="UV_SYNC_SELECT")
+        colrow = col.row(align=1)
+        colrow.operator("mesh.reconst_osc", icon="UV_SYNC_SELECT")
+        colrow = col.row(align=1)
+        colrow.operator("mesh.overlap_uv_faces", icon="UV_FACESEL")
+        colrow = col.row(align=1)
+        colrow.operator("view3d.modal_operator", icon="STICKY_UVS_DISABLE")
+        colrow = col.row(align=1)
+        colrow.operator("file.export_groups_osc", icon='GROUP_VCOL')
+        colrow.operator("file.import_groups_osc", icon='GROUP_VCOL')
+        colrow = col.row(align=1)
+        colrow.operator("mesh.export_vertex_colors", icon='COLOR')
+        colrow.operator("mesh.import_vertex_colors", icon='COLOR')
+
+
+class OscPanelShapes(Panel):
+    bl_idname = "Oscurart Shapes Tools"
+    bl_label = "Shapes Tools"
+    bl_category = "Oscurart Tools"
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.scene.oscurart.osc_shapes_tools
+
+    def draw(self, context):
+        layout = self.layout
+        col = layout.column(align=1)
+
+        col.operator("object.shape_key_to_objects_osc", icon="OBJECT_DATAMODE")
+        col.operator("mesh.create_lmr_groups_osc", icon="GROUP_VERTEX")
+        col.operator("mesh.split_lr_shapes_osc", icon="SHAPEKEY_DATA")
+        colrow = col.row(align=1)
+        colrow.operator("mesh.create_symmetrical_layout_osc", icon="SETTINGS")
+        colrow.operator("mesh.create_asymmetrical_layout_osc", icon="SETTINGS")
+
+
+class OscPanelRender(Panel):
+    bl_idname = "Oscurart Render Tools"
+    bl_label = "Render Tools"
+    bl_category = "Oscurart Tools"
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.scene.oscurart.osc_render_tools
+
+    def draw(self, context):
+        layout = self.layout
+        col = layout.column(align=1)
+
+        colrow = col.row(align=1)
+        colrow.operator(
+            "render.copy_render_settings_osc",
+            icon="LIBRARY_DATA_DIRECT",
+            text="Copy Render Settings").mode = "render"
+        colrow.operator(
+            "render.copy_render_settings_osc",
+            icon="LIBRARY_DATA_DIRECT",
+            text="Copy Cycles Settings").mode = "cycles"
+        colrow = col.row(align=1)
+        colrow.operator(
+            "render.render_all_scenes_osc",
+            icon="RENDER_STILL",
+            text="All Scenes").frametype = False
+        colrow.operator(
+            "render.render_all_scenes_osc",
+            text="> Frame").frametype = True
+        colrow = col.row(align=1)
+        colrow.operator(
+            "render.render_current_scene_osc",
+            icon="RENDER_STILL",
+            text="Active Scene").frametype = False
+        colrow.operator(
+            "render.render_current_scene_osc",
+            text="> Frame").frametype = True
+
+        colrow = col.row(align=1)
+        colrow.operator("render.render_crop_osc", icon="RENDER_REGION")
+        colrow.prop(bpy.context.scene.oscurart, "rcPARTS", text="Parts")
+
+        boxcol = layout.box().column(align=1)
+        colrow = boxcol.row(align=1)
+        colrow.operator(
+            "render.render_selected_scenes_osc",
+            icon="RENDER_STILL",
+            text="Selected Scenes").frametype = False
+        colrow.operator(
+            "render.render_selected_scenes_osc",
+            text="> Frame").frametype = True
+
+        for sc in bpy.data.scenes[:]:
+            boxcol.prop(sc, "use_render_scene", text=sc.name)
+
+
+class OscPanelFiles(Panel):
+    bl_idname = "Oscurart Files Tools"
+    bl_label = "Files Tools"
+    bl_category = "Oscurart Tools"
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.scene.oscurart.osc_files_tools
+
+    def draw(self, context):
+        layout = self.layout
+        col = layout.column(align=1)
+        col.operator("image.reload_images_osc", icon="IMAGE_COL")
+        col.operator("file.sync_missing_groups", icon="LINK_AREA")
+
+
+class OscPanelAnimation(Panel):
+    bl_idname = "Oscurart Animation Tools"
+    bl_label = "Animation Tools"
+    bl_category = "Oscurart Tools"
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.scene.oscurart.osc_animation_tools
+
+    def draw(self, context):
+        layout = self.layout
+        col = layout.column(align=1)
+        row = col.row()
+
+        col.operator("anim.quick_parent_osc", icon="OUTLINER_DATA_POSE")
+        row = col.row(align=1)
+        row.prop(bpy.context.scene.oscurart, "quick_animation_in", text="")
+        row.prop(bpy.context.scene.oscurart, "quick_animation_out", text="")
+
+
+class OscurartToolsAddonPreferences(bpy.types.AddonPreferences):
+    # this must match the addon name, use '__package__'
+    # when defining this in a submodule of a python package.
+    bl_idname = __name__
+
+    category = StringProperty(
+            name="Category",
+            description="Choose a name for the category of the panel",
+            default="Oscurart Tools",
+            )
+
+    def draw(self, context):
+        layout = self.layout
+        row = layout.row()
+        col = row.column()
+        col.label(text="Category:")
+        col.prop(self, "category", text="")
+
+# ========================= FIN DE SCRIPTS =========================
+
+
+def register():
+    bpy.utils.register_module(__name__)
+
+    bpy.types.Scene.oscurart = bpy.props.PointerProperty(
+                                        type=View3DOscPanel
+                                        )
+    bpy.types.Scene.use_render_scene = bpy.props.BoolProperty()
+
+    bpy.types.Scene.broken_files = bpy.props.CollectionProperty(
+                                        type=VarColArchivos
+                                        )
+
+
+def unregister():
+    del bpy.types.Scene.oscurart
+    del bpy.types.Scene.use_render_scene
+    del bpy.types.Scene.broken_files
+
+    bpy.utils.unregister_module(__name__)
+
+
+if __name__ == "__main__":
+    register()
diff --git a/oscurart_tools/oscurart_animation.py b/oscurart_tools/oscurart_animation.py
new file mode 100644
index 0000000000000000000000000000000000000000..8a3e552afbb4797ee002136b52ef2dfb193a7378
--- /dev/null
+++ b/oscurart_tools/oscurart_animation.py
@@ -0,0 +1,70 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from mathutils import Matrix
+
+# -------------------------QUICK PARENT------------------
+
+
+def DefQuickParent(inf, out):
+    if bpy.context.object.type == "ARMATURE":
+        ob = bpy.context.object
+        target = [object for object in bpy.context.selected_objects if object != ob][0]
+        ob = (bpy.context.active_pose_bone if bpy.context.object.type == 'ARMATURE' else bpy.context.object)
+        target.select = False
+        bpy.context.scene.frame_set(frame=bpy.context.scene.oscurart.quick_animation_in)
+        a = Matrix(target.matrix_world)
+        a.invert()
+        i = Matrix(ob.matrix)
+        for frame in range(inf, out):
+            bpy.context.scene.frame_set(frame=frame)
+            ob.matrix = target.matrix_world * a * i
+            bpy.ops.anim.keyframe_insert(type="LocRotScale")
+    else:
+        ob = bpy.context.object
+        target = [object for object in bpy.context.selected_objects if object != ob][0]
+        ob = (bpy.context.active_pose_bone if bpy.context.object.type == 'ARMATURE' else bpy.context.object)
+        target.select = False
+        bpy.context.scene.frame_set(frame=bpy.context.scene.oscurart.quick_animation_in)
+        a = Matrix(target.matrix_world)
+        a.invert()
+        i = Matrix(ob.matrix_world)
+        for frame in range(inf, out):
+            bpy.context.scene.frame_set(frame=frame)
+            ob.matrix_world = target.matrix_world * a * i
+            bpy.ops.anim.keyframe_insert(type="LocRotScale")
+
+
+class QuickParent(bpy.types.Operator):
+    bl_idname = "anim.quick_parent_osc"
+    bl_label = "Quick Parent"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                len(context.selected_objects) > 1)
+
+    def execute(self, context):
+        DefQuickParent(
+            bpy.context.scene.oscurart.quick_animation_in,
+            bpy.context.scene.oscurart.quick_animation_out)
+        return {'FINISHED'}
diff --git a/oscurart_tools/oscurart_files.py b/oscurart_tools/oscurart_files.py
new file mode 100644
index 0000000000000000000000000000000000000000..c3a82d7f41cfe93a6a6db8ac0418e3e22caec56c
--- /dev/null
+++ b/oscurart_tools/oscurart_files.py
@@ -0,0 +1,50 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from bpy.types import Operator
+
+
+# ---------------------RELOAD IMAGES------------------
+
+class reloadImages(Operator):
+    bl_idname = "image.reload_images_osc"
+    bl_label = "Reload Images"
+    bl_options = {"REGISTER", "UNDO"}
+
+    def execute(self, context):
+        for imgs in bpy.data.images:
+            imgs.reload()
+        return {'FINISHED'}
+
+
+# --------------- SYNC MISSING GROUPS -----------------
+
+class reFreshMissingGroups(Operator):
+    bl_idname = "file.sync_missing_groups"
+    bl_label = "Sync Missing Groups"
+    bl_options = {"REGISTER", "UNDO"}
+
+    def execute(self, context):
+        for group in bpy.data.groups:
+            if group.library is not None:
+                with bpy.data.libraries.load(group.library.filepath, link=True) as (linked, local):
+                    local.groups = linked.groups
+        return {'FINISHED'}
diff --git a/oscurart_tools/oscurart_meshes.py b/oscurart_tools/oscurart_meshes.py
new file mode 100644
index 0000000000000000000000000000000000000000..99116a0873cb969b8d80841144762043bbef2d97
--- /dev/null
+++ b/oscurart_tools/oscurart_meshes.py
@@ -0,0 +1,562 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from bpy.types import Operator
+from bpy.props import (
+            IntProperty,
+            BoolProperty,
+            FloatProperty,
+            EnumProperty,
+            )
+import os
+import bmesh
+import time
+import blf
+from bpy_extras.view3d_utils import location_3d_to_region_2d
+
+
+# -----------------------------RECONST---------------------------
+
+def defReconst(self, OFFSET):
+    bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+    bpy.context.tool_settings.mesh_select_mode = (True, True, True)
+    ob = bpy.context.active_object
+    bm = bmesh.from_edit_mesh(ob.data)
+    bm.select_flush(False)
+    for vertice in bm.verts[:]:
+        if abs(vertice.co[0]) < OFFSET:
+            vertice.co[0] = 0
+    for vertice in bm.verts[:]:
+        if vertice.co[0] < 0:
+            bm.verts.remove(vertice)
+            bmesh.update_edit_mesh(ob.data)
+    # mod = ob.modifiers.new("Mirror", "MIRROR")
+    # uv = ob.data.uv_textures.new(name="SYMMETRICAL")
+    for v in bm.faces:
+        v.select = 1
+    bmesh.update_edit_mesh(ob.data)
+    ob.data.uv_textures.active = ob.data.uv_textures['SYMMETRICAL']
+    bpy.ops.uv.unwrap(
+        method='ANGLE_BASED',
+        fill_holes=True,
+        correct_aspect=False,
+        use_subsurf_data=0)
+    bpy.ops.object.mode_set(mode="OBJECT", toggle=False)
+    bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Mirror")
+    bpy.ops.object.mode_set(mode="EDIT", toggle=False)
+    bm = bmesh.from_edit_mesh(ob.data)
+    bm.select_flush(0)
+    # uv = ob.data.uv_textures.new(name="ASYMMETRICAL")
+    ob.data.uv_textures.active = ob.data.uv_textures['ASYMMETRICAL']
+    bpy.ops.uv.unwrap(
+        method='ANGLE_BASED',
+        fill_holes=True,
+        correct_aspect=False,
+        use_subsurf_data=0)
+
+
+class reConst(Operator):
+    bl_idname = "mesh.reconst_osc"
+    bl_label = "ReConst Mesh"
+    bl_options = {"REGISTER", "UNDO"}
+    OFFSET = FloatProperty(
+            name="Offset",
+            default=0.001,
+            min=-0,
+            max=0.1
+            )
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    def execute(self, context):
+        defReconst(self, self.OFFSET)
+        return {'FINISHED'}
+
+
+# -----------------------------------SELECT LEFT---------------------
+
+def side(self, nombre, offset):
+
+    bpy.ops.object.mode_set(mode="EDIT", toggle=0)
+    OBJECT = bpy.context.active_object
+    ODATA = bmesh.from_edit_mesh(OBJECT.data)
+    bpy.context.tool_settings.mesh_select_mode = (True, False, False)
+    for VERTICE in ODATA.verts[:]:
+        VERTICE.select = False
+    if nombre is False:
+        for VERTICES in ODATA.verts[:]:
+            if VERTICES.co[0] < (offset):
+                VERTICES.select = 1
+    else:
+        for VERTICES in ODATA.verts[:]:
+            if VERTICES.co[0] > (offset):
+                VERTICES.select = 1
+    ODATA.select_flush(False)
+    bpy.ops.object.mode_set(mode="EDIT", toggle=0)
+
+
+class SelectMenor (Operator):
+    bl_idname = "mesh.select_side_osc"
+    bl_label = "Select Side"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    side = BoolProperty(
+            name="Greater than zero",
+            default=False
+            )
+    offset = FloatProperty(
+            name="Offset",
+            default=0
+            )
+
+    def execute(self, context):
+
+        side(self, self.side, self.offset)
+
+        return {'FINISHED'}
+
+
+# -------------------------RESYM VG----------------------------------
+
+class resymVertexGroups(Operator):
+    bl_idname = "mesh.resym_vertex_weights_osc"
+    bl_label = "Resym Vertex Weights"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    def execute(self, context):
+
+        with open("%s_%s_SYM_TEMPLATE.xml" % (os.path.join(os.path.dirname(bpy.data.filepath),
+                                              bpy.context.scene.name), bpy.context.object.name)) as file:
+            ob = bpy.context.object
+            actgr = ob.vertex_groups.active
+            actind = ob.vertex_groups.active_index
+            ls = eval(file.read())
+            wdict = {left: actgr.weight(right) for left, right in ls.items()
+                     for group in ob.data.vertices[right].groups if group.group == actind}
+            actgr.remove(
+                [vert.index for vert in ob.data.vertices if vert.co[0] <= 0])
+            for ind, weight in wdict.items():
+                actgr.add([ind], weight, 'REPLACE')
+            bpy.context.object.data.update()
+
+        return {'FINISHED'}
+
+
+# ------------------------IMPORT EXPORT GROUPS--------------------
+
+class OscExportVG(Operator):
+    bl_idname = "file.export_groups_osc"
+    bl_label = "Export Groups"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    def execute(self, context):
+
+        ob = bpy.context.object
+        with open(os.path.join(os.path.dirname(bpy.data.filepath), ob.name + ".txt"), mode="w") as file:
+            vgindex = {vg.index: vg.name for vg in ob.vertex_groups[:]}
+            vgdict = {}
+            for vert in ob.data.vertices:
+                for vg in vert.groups:
+                    vgdict.setdefault(vg.group, []).append(
+                        (vert.index, vg.weight))
+            file.write(str(vgdict) + "\n")
+            file.write(str(vgindex))
+
+        return {'FINISHED'}
+
+
+class OscImportVG(Operator):
+    bl_idname = "file.import_groups_osc"
+    bl_label = "Import Groups"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    def execute(self, context):
+
+        ob = bpy.context.object
+        with open(os.path.join(os.path.dirname(bpy.data.filepath), ob.name + ".txt"), mode="r") as file:
+            vgdict = eval(file.readlines(1)[0].replace("\n", ""))
+            vgindex = eval(file.readlines(2)[0].replace("\n", ""))
+
+        for index, name in vgindex.items():
+            ob.vertex_groups.new(name=name)
+
+        for group, vdata in vgdict.items():
+            for index, weight in vdata:
+                ob.vertex_groups[group].add(
+                    index=[index],
+                    weight=weight,
+                    type="REPLACE")
+
+        return {'FINISHED'}
+
+
+# ------------------------------------ RESYM MESH-------------------------
+
+def reSymSave(self, quality):
+
+    bpy.ops.object.mode_set(mode='OBJECT')
+
+    object = bpy.context.object
+
+    rdqual = quality
+    rd = lambda x: round(x, rdqual)
+    absol = lambda x: (abs(x[0]), x[1], x[2])
+
+    inddict = {
+        tuple(map(rd, vert.co[:])): vert.index for vert in object.data.vertices[:]}
+    reldict = {inddict[vert]: inddict.get(absol(vert), inddict[vert])
+               for vert in inddict if vert[0] <= 0}
+
+    ENTFILEPATH = "%s_%s_SYM_TEMPLATE.xml" % (
+        os.path.join(os.path.dirname(bpy.data.filepath),
+                     bpy.context.scene.name),
+        bpy.context.object.name)
+    with open(ENTFILEPATH, mode="w") as file:
+        file.writelines(str(reldict))
+        reldict.clear()
+
+
+def reSymMesh(self, SELECTED, SIDE):
+    bpy.ops.object.mode_set(mode='EDIT')
+    ENTFILEPATH = "%s_%s_SYM_TEMPLATE.xml" % (
+        os.path.join(os.path.dirname(bpy.data.filepath),
+                     bpy.context.scene.name),
+        bpy.context.object.name)
+    with open(ENTFILEPATH, mode="r") as file:
+        SYMAP = eval(file.readlines()[0])
+        bm = bmesh.from_edit_mesh(bpy.context.object.data)
+        object = bpy.context.object
+
+        def MAME(SYMAP):
+            if SELECTED:
+                for vert in SYMAP:
+                    if bm.verts[SYMAP[vert]].select:
+                        bm.verts[vert].co = (-1 * bm.verts[SYMAP[vert]].co[0],
+                                             bm.verts[SYMAP[vert]].co[1],
+                                             bm.verts[SYMAP[vert]].co[2])
+            else:
+                for vert in SYMAP:
+                    bm.verts[vert].co = (-1 * bm.verts[SYMAP[vert]].co[0],
+                                         bm.verts[SYMAP[vert]].co[1],
+                                         bm.verts[SYMAP[vert]].co[2])
+            bmesh.update_edit_mesh(object.data)
+
+        def MEMA(SYMAP):
+            if SELECTED:
+                for vert in SYMAP:
+                    if bm.verts[vert].select:
+                        bm.verts[SYMAP[vert]].co = (-1 * bm.verts[vert].co[0],
+                                                    bm.verts[vert].co[1],
+                                                    bm.verts[vert].co[2])
+            else:
+                for vert in SYMAP:
+                    bm.verts[SYMAP[vert]].co = (-1 * bm.verts[vert].co[0],
+                                                bm.verts[vert].co[1],
+                                                bm.verts[vert].co[2])
+            bmesh.update_edit_mesh(object.data)
+
+        if SIDE == "+-":
+            MAME(SYMAP)
+        else:
+            MEMA(SYMAP)
+
+
+class OscResymSave(Operator):
+    bl_idname = "mesh.resym_save_map"
+    bl_label = "Resym save XML Map"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    quality = IntProperty(
+            default=4,
+            name="Quality"
+            )
+
+    def execute(self, context):
+        reSymSave(self, self.quality)
+        return {'FINISHED'}
+
+
+class OscResymMesh(Operator):
+    bl_idname = "mesh.resym_mesh"
+    bl_label = "Resym save Apply XML"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    selected = BoolProperty(
+            default=False,
+            name="Only Selected"
+            )
+    side = EnumProperty(
+            name="Side:",
+            description="Select Side",
+            items=(('+-', "+X to -X", "+X to -X"),
+                   ('-+', "-X to +X", "-X to +X")),
+            default='+-',
+            )
+
+    def execute(self, context):
+        reSymMesh(self, self.selected, self.side)
+        return {'FINISHED'}
+
+
+# -------------------------- OBJECT TO MESH ------------------------------
+
+def DefOscObjectToMesh():
+    ACTOBJ = bpy.context.object
+    MESH = ACTOBJ.to_mesh(
+        scene=bpy.context.scene,
+        apply_modifiers=True,
+        settings="RENDER",
+        calc_tessface=True)
+    OBJECT = bpy.data.objects.new(("%s_Freeze") % (ACTOBJ.name), MESH)
+    bpy.context.scene.objects.link(OBJECT)
+
+
+class OscObjectToMesh(Operator):
+    bl_idname = "mesh.object_to_mesh_osc"
+    bl_label = "Object To Mesh"
+    bl_description = "Works on Meshes, Meta objects, Curves and Surfaces"
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type in
+                {'MESH', 'META', 'CURVE', 'SURFACE'})
+
+    def execute(self, context):
+        print("Active type object is", context.object.type)
+        DefOscObjectToMesh()
+        return {'FINISHED'}
+
+
+# ----------------------------- OVERLAP UV -------------------------------
+
+def DefOscOverlapUv(valpresicion):
+    inicio = time.time()
+    mode = bpy.context.object.mode
+    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+
+    rd = valpresicion
+    ob = bpy.context.object
+    absco = lambda x: (abs(round(x[0], rd)), round(x[1], rd), round(x[2], rd))
+    rounder = lambda x: (round(x[0], rd), round(x[1], rd), round(x[2], rd))
+
+    # vertice a vertex
+    vertvertex = {}
+    for vert in ob.data.loops:
+        vertvertex.setdefault(vert.vertex_index, []).append(vert.index)
+
+    vertexvert = {}
+    for vertex in ob.data.loops:
+        vertexvert[vertex.index] = vertex.vertex_index
+
+    # posicion de cada vertice y cada face
+    vertloc = {rounder(vert.co[:]): vert for vert in ob.data.vertices}
+    faceloc = {rounder(poly.center[:]): poly for poly in ob.data.polygons}
+
+    # relativo de cada vertice y cada face
+    verteqind = {vert.index: vertloc.get(
+                 absco(co),
+                 vertloc[co]).index for co,
+                 vert in vertloc.items() if co[0] <= 0}
+    polyeq = {face: faceloc.get(
+              absco(center),
+              faceloc[center]) for center,
+              face in faceloc.items() if center[0] <= 0}
+
+    # loops in faces
+    lif = {poly: [i for i in poly.loop_indices] for poly in ob.data.polygons}
+
+    # acomoda
+    for l, r in polyeq.items():
+        if l.select:
+            for lloop in lif[l]:
+                for rloop in lif[r]:
+                    if (verteqind[vertexvert[lloop]] == vertexvert[rloop] and
+                       ob.data.uv_layers.active.data[rloop].select):
+
+                        ob.data.uv_layers.active.data[
+                            lloop].uv = ob.data.uv_layers.active.data[
+                                rloop].uv
+
+    bpy.ops.object.mode_set(mode=mode, toggle=False)
+
+    print("Time elapsed: %4s seconds" % (time.time() - inicio))
+
+
+class OscOverlapUv(Operator):
+    bl_idname = "mesh.overlap_uv_faces"
+    bl_label = "Overlap Uvs"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    presicion = IntProperty(
+            default=4,
+            min=1,
+            max=10,
+            name="precision"
+            )
+
+    def execute(self, context):
+        DefOscOverlapUv(self.presicion)
+        return {'FINISHED'}
+
+
+# ------------------------------- IO VERTEX COLORS --------------------
+
+def DefOscExportVC():
+    with open(os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.object.name) + ".vc", mode="w") as file:
+        ob = bpy.context.object
+        di = {loopind: ob.data.vertex_colors.active.data[loopind].color[:]
+              for face in ob.data.polygons for loopind in face.loop_indices[:]}
+        file.write(str(di))
+
+
+def DefOscImportVC():
+    with open(os.path.join(os.path.dirname(bpy.data.filepath), bpy.context.object.name) + ".vc", mode="r") as file:
+        di = eval(file.read())
+        for loopind in di:
+            bpy.context.object.data.vertex_colors.active.data[
+                loopind].color = di[loopind]
+
+
+class OscExportVC(Operator):
+    bl_idname = "mesh.export_vertex_colors"
+    bl_label = "Export Vertex Colors"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    def execute(self, context):
+        DefOscExportVC()
+        return {'FINISHED'}
+
+
+class OscImportVC(Operator):
+    bl_idname = "mesh.import_vertex_colors"
+    bl_label = "Import Vertex Colors"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    def execute(self, context):
+        DefOscImportVC()
+        return {'FINISHED'}
+
+
+# ------------------ PRINT VERTICES ----------------------
+
+def dibuja_callback(self, context):
+    font_id = 0
+    bm = bmesh.from_edit_mesh(bpy.context.object.data)
+    for v in bm.verts:
+        cord = location_3d_to_region_2d(
+            context.region,
+            context.space_data.region_3d,
+            self.matr * v.co)
+        blf.position(font_id, cord[0], cord[1], 0)
+        blf.size(font_id, self.tsize, 72)
+        blf.draw(font_id, str(v.index))
+
+
+class ModalIndexOperator(Operator):
+    bl_idname = "view3d.modal_operator"
+    bl_label = "Print Vertices"
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    def modal(self, context, event):
+        context.area.tag_redraw()
+        if event.type == 'MOUSEMOVE':
+            self.x = event.mouse_region_x
+            self.matr = context.object.matrix_world
+        elif event.type == 'LEFTMOUSE':
+            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
+            return {'FINISHED'}
+        elif event.type == 'PAGE_UP':
+            self.tsize += 1
+        elif event.type == 'PAGE_DOWN':
+            self.tsize -= 1
+        elif event.type in {'RIGHTMOUSE', 'ESC', 'TAB'}:
+            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
+            context.area.header_text_set()
+            return {'CANCELLED'}
+
+        return {'PASS_THROUGH'}
+
+    def invoke(self, context, event):
+        if context.area.type == "VIEW_3D":
+            context.area.header_text_set("Esc: exit, PageUP/Down: text size")
+            bpy.ops.object.mode_set(mode="EDIT")
+            self.tsize = 20
+            args = (self, context)
+            self._handle = bpy.types.SpaceView3D.draw_handler_add(
+                dibuja_callback, args, "WINDOW", "POST_PIXEL")
+            context.window_manager.modal_handler_add(self)
+            return{'RUNNING_MODAL'}
+        else:
+            self.report({"WARNING"}, "Is not a 3D Space")
+            return {'CANCELLED'}
diff --git a/oscurart_tools/oscurart_objects.py b/oscurart_tools/oscurart_objects.py
new file mode 100644
index 0000000000000000000000000000000000000000..ffae4aaef1838243afb516b20469a40d287f98ca
--- /dev/null
+++ b/oscurart_tools/oscurart_objects.py
@@ -0,0 +1,526 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from bpy.types import Operator
+from bpy.props import BoolProperty
+import os
+from bpy_extras.object_utils import world_to_camera_view
+
+
+# ------------------------ SEARCH AND SELECT ------------------------
+
+class SearchAndSelectOt(Operator):
+    bl_idname = "object.search_and_select_osc"
+    bl_label = "Search And Select"
+    bl_description = "Selection based upon object names in the scene"
+    bl_options = {"REGISTER", "UNDO"}
+
+    start = BoolProperty(name="Start With", default=True)
+    count = BoolProperty(name="Contain", default=True)
+    end = BoolProperty(name="End", default=True)
+
+    def execute(self, context):
+        for objeto in bpy.context.scene.objects:
+            variableNombre = bpy.context.scene.oscurart.SearchAndSelectOt
+            if self.start:
+                if objeto.name.startswith(variableNombre):
+                    objeto.select = True
+            if self.count:
+                if objeto.name.count(variableNombre):
+                    objeto.select = True
+            if self.end:
+                if objeto.name.count(variableNombre):
+                    objeto.select = True
+        return {'FINISHED'}
+
+
+# -------------------------RENAME OBJECTS----------------------------------
+
+class renameObjectsOt (Operator):
+    bl_idname = "object.rename_objects_osc"
+    bl_label = "Rename Objects"
+    bl_options = {"REGISTER", "UNDO"}
+
+    def execute(self, context):
+        listaObj = bpy.context.selected_objects[:]
+        for objeto in listaObj:
+            objeto.name = bpy.context.scene.oscurart.RenameObjectOt
+        return {'FINISHED'}
+
+
+# ---------------------------REMOVE MODIFIERS Y APPLY MODIFIERS-----------
+
+class oscRemModifiers (Operator):
+    bl_idname = "object.modifiers_remove_osc"
+    bl_label = "Remove modifiers"
+    bl_description = "Removes all modifiers on all selected objects"
+    bl_options = {"REGISTER", "UNDO"}
+
+    def execute(self, context):
+        for objeto in bpy.context.selected_objects:
+            for modificador in objeto.modifiers:
+                print(modificador.type)
+                bpy.context.scene.objects.active = objeto
+                bpy.ops.object.modifier_remove(modifier=modificador.name)
+        return {'FINISHED'}
+
+
+class oscApplyModifiers (Operator):
+    bl_idname = "object.modifiers_apply_osc"
+    bl_label = "Apply modifiers"
+    bl_description = ("Applies all modifiers on all selected objects \n"
+                      "Warning: Make single user will be applied on Linked Object data")
+    bl_options = {"REGISTER", "UNDO"}
+
+    def execute(self, context):
+        for objeto in bpy.context.selected_objects:
+            bpy.ops.object.select_all(action='DESELECT')
+            bpy.context.scene.objects.active = objeto
+            objeto.select = True
+            if objeto.data.users >= 2:
+                bpy.ops.object.make_single_user(
+                    type='SELECTED_OBJECTS',
+                    object=True,
+                    obdata=True,
+                    material=False,
+                    texture=False,
+                    animation=False)
+            for modificador in objeto.modifiers:
+                try:
+                    bpy.ops.object.modifier_apply(
+                        apply_as="DATA",
+                        modifier=modificador.name)
+                except:
+                    bpy.ops.object.modifier_remove(modifier=modificador.name)
+                    print("* Modifier %s skipping apply" % (modificador.name))
+
+        return {'FINISHED'}
+
+
+# ------------------------------------ RELINK OBJECTS---------------------
+
+def relinkObjects(self):
+
+    LISTSCENE = []
+    if bpy.selection_osc:
+        for SCENE in bpy.data.scenes[:]:
+            if SCENE.objects:
+                if bpy.selection_osc[-1] in SCENE.objects[:]:
+                    LISTSCENE.append(SCENE)
+
+        if LISTSCENE:
+            OBJECTS = bpy.selection_osc[:-1]
+            ACTOBJ = bpy.selection_osc[-1]
+            OBJSEL = bpy.selection_osc[:]
+
+            LISTSCENE.remove(bpy.context.scene)
+
+            bpy.ops.object.select_all(action='DESELECT')
+
+            for OBJETO in OBJECTS:
+                if OBJETO.users != len(bpy.data.scenes):
+                    print(OBJETO.name)
+                    OBJETO.select = True
+
+            for SCENE in LISTSCENE:
+                bpy.ops.object.make_links_scene(scene=SCENE.name)
+
+            bpy.context.scene.objects.active = ACTOBJ
+            for OBJ in OBJSEL:
+                OBJ.select = True
+        else:
+            self.report({'INFO'}, message="Scenes are empty")
+
+
+class OscRelinkObjectsBetween(Operator):
+    bl_idname = "object.relink_objects_between_scenes"
+    bl_label = "Relink Objects Between Scenes"
+    bl_options = {"REGISTER", "UNDO"}
+
+    def execute(self, context):
+        relinkObjects(self)
+        return {'FINISHED'}
+
+
+# ------------------------------------ COPY GROUPS AND LAYERS-------------
+
+def CopyObjectGroupsAndLayers(self):
+
+    OBSEL = bpy.selection_osc[:]
+    if OBSEL:
+        GLOBALLAYERS = list(OBSEL[-1].layers[:])
+        ACTSCENE = bpy.context.scene
+        GROUPS = OBSEL[-1].users_group
+        ACTOBJ = OBSEL[-1]
+
+        for OBJECT in OBSEL[:-1]:
+            for scene in bpy.data.scenes[:]:
+
+                # SI EL OBJETO ACTIVO ESTA EN LA ESCENA
+                if ACTOBJ in scene.objects[:] and OBJECT in scene.objects[:]:
+                    scene.object_bases[
+                        OBJECT.name].layers[
+                            :] = scene.object_bases[
+                                ACTOBJ.name].layers[
+                                    :]
+                elif ACTOBJ not in scene.objects[:] and OBJECT in scene.objects[:]:
+                    scene.object_bases[OBJECT.name].layers[:] = list(GLOBALLAYERS)
+
+            # REMUEVO DE TODO GRUPO
+            for GROUP in bpy.data.groups[:]:
+                if GROUP in OBJECT.users_group[:]:
+                    GROUP.objects.unlink(OBJECT)
+
+            # INCLUYO OBJETO EN GRUPOS
+            for GROUP in GROUPS:
+                GROUP.objects.link(OBJECT)
+
+        bpy.context.window.screen.scene = ACTSCENE
+        bpy.context.scene.objects.active = ACTOBJ
+
+
+class OscCopyObjectGAL (Operator):
+    bl_idname = "object.copy_objects_groups_layers"
+    bl_label = "Copy Groups And Layers"
+    bl_options = {"REGISTER", "UNDO"}
+
+    def execute(self, context):
+        CopyObjectGroupsAndLayers(self)
+        return {'FINISHED'}
+
+
+# ------------------------------------ SELECTION -------------------------
+bpy.selection_osc = []
+
+
+def select_osc():
+    if bpy.context.mode == "OBJECT":
+        obj = bpy.context.object
+        sel = len(bpy.context.selected_objects)
+
+        if sel == 0:
+            bpy.selection_osc = []
+        else:
+            if sel == 1:
+                bpy.selection_osc = []
+                bpy.selection_osc.append(obj)
+            elif sel > len(bpy.selection_osc):
+                for sobj in bpy.context.selected_objects:
+                    if (sobj in bpy.selection_osc) is False:
+                        bpy.selection_osc.append(sobj)
+
+            elif sel < len(bpy.selection_osc):
+                for it in bpy.selection_osc:
+                    if (it in bpy.context.selected_objects) is False:
+                        bpy.selection_osc.remove(it)
+
+
+class OscSelection(bpy.types.Header):
+    bl_label = "Selection Osc"
+    bl_space_type = "VIEW_3D"
+
+    def __init__(self):
+        select_osc()
+
+    def draw(self, context):
+        """
+        layout = self.layout
+        row = layout.row()
+        row.label("Sels: "+str(len(bpy.selection_osc)))
+        """
+
+
+# =============== DISTRIBUTE ======================
+
+def ObjectDistributeOscurart(self, X, Y, Z):
+    if len(bpy.selection_osc[:]) > 1:
+        # VARIABLES
+        dif = bpy.selection_osc[-1].location - bpy.selection_osc[0].location
+        chunkglobal = dif / (len(bpy.selection_osc[:]) - 1)
+        chunkx = 0
+        chunky = 0
+        chunkz = 0
+        deltafst = bpy.selection_osc[0].location
+
+        # ORDENA
+        for OBJECT in bpy.selection_osc[:]:
+            if X:
+                OBJECT.location.x = deltafst[0] + chunkx
+            if Y:
+                OBJECT.location[1] = deltafst[1] + chunky
+            if Z:
+                OBJECT.location.z = deltafst[2] + chunkz
+            chunkx += chunkglobal[0]
+            chunky += chunkglobal[1]
+            chunkz += chunkglobal[2]
+    else:
+        self.report({'INFO'}, "Needs at least two selected objects")
+
+
+class DialogDistributeOsc(Operator):
+    bl_idname = "object.distribute_osc"
+    bl_label = "Distribute Objects"
+    Boolx = BoolProperty(name="X")
+    Booly = BoolProperty(name="Y")
+    Boolz = BoolProperty(name="Z")
+
+    def execute(self, context):
+        ObjectDistributeOscurart(self, self.Boolx, self.Booly, self.Boolz)
+        return {'FINISHED'}
+
+    def invoke(self, context, event):
+        self.Boolx = True
+        self.Booly = True
+        self.Boolz = True
+        return context.window_manager.invoke_props_dialog(self)
+
+
+# ======================== SET LAYERS TO OTHER SCENES ====================
+
+def DefSetLayersToOtherScenes():
+    actsc = bpy.context.screen.scene
+    for object in bpy.context.selected_objects[:]:
+        bpy.context.screen.scene = actsc
+        lyrs = object.layers[:]
+        for scene in bpy.data.scenes[:]:
+            if object in scene.objects[:]:
+                bpy.context.screen.scene = scene
+                object.layers = lyrs
+            else:
+                print("* %s is not in %s" % (object.name, scene.name))
+
+    bpy.context.screen.scene = actsc
+
+
+class SetLayersToOtherScenes (Operator):
+    bl_idname = "object.set_layers_to_other_scenes"
+    bl_label = "Copy actual Layers to Other Scenes"
+    bl_options = {"REGISTER", "UNDO"}
+
+    def execute(self, context):
+        DefSetLayersToOtherScenes()
+        return {'FINISHED'}
+
+
+# ======================== RENDER OBJECTS IN CAMERA ======================
+
+
+def DefRenderOnlyInCamera():
+    # crea grupos
+    if "INCAMERA" not in bpy.data.groups:
+        bpy.data.groups.new("INCAMERA")
+    if "NOTINCAMERA" not in bpy.data.groups:
+        bpy.data.groups.new("NOTINCAMERA")
+
+    # limpio grupos
+    for ob in bpy.data.objects:
+        if ob.name in bpy.data.groups["INCAMERA"].objects:
+            bpy.data.groups["INCAMERA"].objects.unlink(ob)
+        if ob.name in bpy.data.groups["NOTINCAMERA"].objects:
+            bpy.data.groups["NOTINCAMERA"].objects.unlink(ob)
+
+    # ordeno grupos
+    for ob in bpy.data.objects:
+        obs = False
+        if ob.type == "MESH":
+            tm = ob.to_mesh(bpy.context.scene, True, "RENDER")
+            for vert in tm.vertices:
+                cam = world_to_camera_view(
+                    bpy.context.scene,
+                    bpy.context.scene.camera,
+                    vert.co + ob.location)
+                if cam[0] >= -0 and cam[0] <= 1 and cam[1] >= 0 and cam[1] <= 1:
+                    obs = True
+            del(tm)
+        else:
+            obs = True
+        if obs:
+            bpy.data.groups["INCAMERA"].objects.link(ob)
+        else:
+            bpy.data.groups["NOTINCAMERA"].objects.link(ob)
+
+
+class RenderOnlyInCamera (Operator):
+    bl_idname = "group.group_in_out_camera"
+    bl_label = "Make a group for objects in outer camera"
+    bl_options = {"REGISTER", "UNDO"}
+
+    def execute(self, context):
+        DefRenderOnlyInCamera()
+        return {'FINISHED'}
+
+
+# ------------------------ DUPLICATE OBJECTS SYMMETRY ------------------------
+
+def duplicateSymmetrical(self, disconect):
+    for objeto in bpy.context.selected_objects:
+
+        bpy.ops.object.select_all(action='DESELECT')
+        objeto.select = 1
+        bpy.context.scene.objects.active = objeto
+        bpy.ops.object.duplicate(linked=1)
+        OBDUP = bpy.context.active_object
+        print(OBDUP)
+        OBDUP.driver_add("location")
+        OBDUP.animation_data.drivers[0].driver.expression = "-var"
+        OBDUP.animation_data.drivers[0].driver.variables.new()
+        OBDUP.animation_data.drivers[0].driver.variables[0].type = "TRANSFORMS"
+        OBDUP.animation_data.drivers[
+            0].driver.variables[
+                0].targets[
+            0].id = objeto
+        OBDUP.animation_data.drivers[
+            0].driver.variables[
+                0].targets[
+            0].transform_type = 'LOC_X'
+        OBDUP.animation_data.drivers[1].driver.expression = "var"
+        OBDUP.animation_data.drivers[1].driver.variables.new()
+        OBDUP.animation_data.drivers[1].driver.variables[0].type = "TRANSFORMS"
+        OBDUP.animation_data.drivers[
+            1].driver.variables[
+                0].targets[
+            0].id = objeto
+        OBDUP.animation_data.drivers[
+            1].driver.variables[
+                0].targets[
+            0].transform_type = 'LOC_Y'
+        OBDUP.animation_data.drivers[2].driver.expression = "var"
+        OBDUP.animation_data.drivers[2].driver.variables.new()
+        OBDUP.animation_data.drivers[2].driver.variables[0].type = "TRANSFORMS"
+        OBDUP.animation_data.drivers[
+            2].driver.variables[
+                0].targets[
+            0].id = objeto
+        OBDUP.animation_data.drivers[
+            2].driver.variables[
+                0].targets[
+            0].transform_type = 'LOC_Z'
+        OBDUP.driver_add("scale")
+        OBDUP.animation_data.drivers[3].driver.expression = "-var"
+        OBDUP.animation_data.drivers[3].driver.variables.new()
+        OBDUP.animation_data.drivers[3].driver.variables[0].type = "TRANSFORMS"
+        OBDUP.animation_data.drivers[
+            3].driver.variables[
+                0].targets[
+            0].id = objeto
+        OBDUP.animation_data.drivers[
+            3].driver.variables[
+                0].targets[
+            0].transform_type = 'SCALE_X'
+        OBDUP.animation_data.drivers[4].driver.expression = "var"
+        OBDUP.animation_data.drivers[4].driver.variables.new()
+        OBDUP.animation_data.drivers[4].driver.variables[0].type = "TRANSFORMS"
+        OBDUP.animation_data.drivers[
+            4].driver.variables[
+                0].targets[
+            0].id = objeto
+        OBDUP.animation_data.drivers[
+            4].driver.variables[
+                0].targets[
+            0].transform_type = 'SCALE_Y'
+        OBDUP.animation_data.drivers[5].driver.expression = "var"
+        OBDUP.animation_data.drivers[5].driver.variables.new()
+        OBDUP.animation_data.drivers[5].driver.variables[0].type = "TRANSFORMS"
+        OBDUP.animation_data.drivers[
+            5].driver.variables[
+                0].targets[
+            0].id = objeto
+        OBDUP.animation_data.drivers[
+            5].driver.variables[
+                0].targets[
+            0].transform_type = 'SCALE_Z'
+        OBDUP.driver_add("rotation_euler")
+        OBDUP.animation_data.drivers[6].driver.expression = "var"
+        OBDUP.animation_data.drivers[6].driver.variables.new()
+        OBDUP.animation_data.drivers[6].driver.variables[0].type = "TRANSFORMS"
+        OBDUP.animation_data.drivers[
+            6].driver.variables[
+                0].targets[
+            0].id = objeto
+        OBDUP.animation_data.drivers[
+            6].driver.variables[
+                0].targets[
+            0].transform_type = 'ROT_X'
+        OBDUP.animation_data.drivers[7].driver.expression = "-var"
+        OBDUP.animation_data.drivers[7].driver.variables.new()
+        OBDUP.animation_data.drivers[7].driver.variables[0].type = "TRANSFORMS"
+        OBDUP.animation_data.drivers[
+            7].driver.variables[
+                0].targets[
+            0].id = objeto
+        OBDUP.animation_data.drivers[
+            7].driver.variables[
+                0].targets[
+            0].transform_type = 'ROT_Y'
+        OBDUP.animation_data.drivers[8].driver.expression = "-var"
+        OBDUP.animation_data.drivers[8].driver.variables.new()
+        OBDUP.animation_data.drivers[8].driver.variables[0].type = "TRANSFORMS"
+        OBDUP.animation_data.drivers[
+            8].driver.variables[
+                0].targets[
+            0].id = objeto
+        OBDUP.animation_data.drivers[
+            8].driver.variables[
+                0].targets[
+            0].transform_type = 'ROT_Z'
+
+        if disconect is not True:
+            bpy.ops.object.make_single_user(obdata=True, object=True)
+            bpy.context.active_object.driver_remove("location")
+            bpy.context.active_object.driver_remove("rotation_euler")
+            bpy.context.active_object.driver_remove("scale")
+
+
+class oscDuplicateSymmetricalOp(Operator):
+    bl_idname = "object.duplicate_object_symmetry_osc"
+    bl_label = "Oscurart Duplicate Symmetrical"
+    bl_options = {"REGISTER", "UNDO"}
+
+    desconecta = BoolProperty(name="Keep Connection", default=True)
+
+    def execute(self, context):
+
+        duplicateSymmetrical(self, self.desconecta)
+
+        return {'FINISHED'}
+
+
+# ------------------------ OBJECTS TO GROUPS ------------------------
+
+def DefObjectToGroups():
+    scgr = bpy.data.groups.new(
+        "%s_MSH" %
+        (os.path.basename(bpy.data.filepath).replace(".blend", "")))
+    for ob in bpy.data.objects:
+        if ob.type == "MESH":
+            gr = bpy.data.groups.new(ob.name)
+            gr.objects.link(ob)
+            scgr.objects.link(ob)
+
+
+class ObjectsToGroups(Operator):
+    bl_idname = "object.objects_to_groups"
+    bl_label = "Objects to Groups"
+    bl_options = {"REGISTER", "UNDO"}
+
+    def execute(self, context):
+        DefObjectToGroups()
+        return {'FINISHED'}
diff --git a/oscurart_tools/oscurart_render.py b/oscurart_tools/oscurart_render.py
new file mode 100644
index 0000000000000000000000000000000000000000..a20aafee512178090ff74f7c5d792c018ac154b9
--- /dev/null
+++ b/oscurart_tools/oscurart_render.py
@@ -0,0 +1,399 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from bpy.types import (
+            Operator,
+            Panel,
+            )
+import os
+
+
+# -------------------------------- RENDER ALL SCENES ---------------------
+
+def defRenderAll(frametype, scenes):
+
+    activescene = bpy.context.scene
+    FC = bpy.context.scene.frame_current
+    FS = bpy.context.scene.frame_start
+    FE = bpy.context.scene.frame_end
+    print("---------------------")
+    types = {'MESH', 'META', 'CURVE'}
+
+    for ob in bpy.data.objects:
+        if ob.type in types:
+            if not len(ob.material_slots):
+                ob.data.materials.append(None)
+
+    slotlist = {ob: [sl.material for sl in ob.material_slots]
+                for ob in bpy.data.objects if ob.type in types if len(ob.material_slots)}
+
+    for scene in scenes:
+        renpath = scene.render.filepath
+
+        if frametype:
+            scene.frame_start = FC
+            scene.frame_end = FC
+            scene.frame_end = FC
+            scene.frame_start = FC
+
+        filename = os.path.basename(bpy.data.filepath.rpartition(".")[0])
+        uselayers = {layer: layer.use for layer in scene.render.layers}
+        for layer, usado in uselayers.items():
+            if usado:
+                for i in scene.render.layers:
+                    i.use = False
+                layer.use = 1
+                print("SCENE: %s" % scene.name)
+                print("LAYER: %s" % layer.name)
+                scene.render.filepath = os.path.join(
+                    os.path.dirname(renpath), filename, scene.name, layer.name, "%s_%s_%s" %
+                    (filename, scene.name, layer.name))
+                bpy.context.window.screen.scene = scene
+                bpy.ops.render.render(
+                    animation=True,
+                    write_still=True,
+                    layer=layer.name,
+                    scene=scene.name)
+                print("DONE")
+                print("---------------------")
+        for layer, usado in uselayers.items():
+            layer.use = usado
+        scene.render.filepath = renpath
+        for ob, slots in slotlist.items():
+            ob.data.materials.clear()
+            for slot in slots:
+                ob.data.materials.append(slot)
+        if frametype:
+            scene.frame_start = FS
+            scene.frame_end = FE
+            scene.frame_end = FE
+            scene.frame_start = FS
+
+    bpy.context.window.screen.scene = activescene
+
+
+class renderAll (Operator):
+    bl_idname = "render.render_all_scenes_osc"
+    bl_label = "Render All Scenes"
+
+    frametype = bpy.props.BoolProperty(default=False)
+
+    def execute(self, context):
+        defRenderAll(self.frametype, [scene for scene in bpy.data.scenes])
+        return {'FINISHED'}
+
+
+# --------------------------------RENDER SELECTED SCENES------------------
+
+class renderSelected (Operator):
+    bl_idname = "render.render_selected_scenes_osc"
+    bl_label = "Render Selected Scenes"
+
+    frametype = bpy.props.BoolProperty(default=False)
+
+    def execute(self, context):
+        defRenderAll(
+            self.frametype,
+            [sc for sc in bpy.data.scenes if sc.oscurart.use_render_scene])
+        return {'FINISHED'}
+
+
+# --------------------------------RENDER CURRENT SCENE--------------------
+
+class renderCurrent (Operator):
+    bl_idname = "render.render_current_scene_osc"
+    bl_label = "Render Current Scene"
+
+    frametype = bpy.props.BoolProperty(default=False)
+
+    def execute(self, context):
+
+        defRenderAll(self.frametype, [bpy.context.scene])
+
+        return {'FINISHED'}
+
+
+# --------------------------RENDER CROP----------------------
+
+def OscRenderCropFunc():
+
+    SCENENAME = os.path.split(bpy.data.filepath)[-1].partition(".")[0]
+    rcParts = bpy.context.scene.oscurart.rcPARTS
+    # don't divide by zero
+    PARTS = (rcParts if rcParts and rcParts > 0 else 1)
+    CHUNKYSIZE = 1 / PARTS
+    FILEPATH = bpy.context.scene.render.filepath
+    bpy.context.scene.render.use_border = True
+    bpy.context.scene.render.use_crop_to_border = True
+    for PART in range(PARTS):
+        bpy.context.scene.render.border_min_y = PART * CHUNKYSIZE
+        bpy.context.scene.render.border_max_y = (
+            PART * CHUNKYSIZE) + CHUNKYSIZE
+        bpy.context.scene.render.filepath = "%s_part%s" % (
+                                            os.path.join(FILEPATH,
+                                                         SCENENAME,
+                                                         bpy.context.scene.name,
+                                                         SCENENAME),
+                                            PART
+                                            )
+        bpy.ops.render.render(animation=False, write_still=True)
+
+    bpy.context.scene.render.filepath = FILEPATH
+
+
+class renderCrop (Operator):
+    bl_idname = "render.render_crop_osc"
+    bl_label = "Render Crop: Render!"
+
+    def execute(self, context):
+        OscRenderCropFunc()
+        return {'FINISHED'}
+
+
+# ---------------------------------- BROKEN FRAMES ---------------------
+
+class SumaFile(Operator):
+    bl_idname = "object.add_broken_file"
+    bl_label = "Add Broken Files"
+
+    def execute(self, context):
+        os.chdir(os.path.dirname(bpy.data.filepath))
+        absdir = os.path.join(
+            os.path.dirname(bpy.data.filepath),
+            bpy.context.scene.render.filepath.replace(r"//",
+                                                      ""))
+        for root, folder, files in os.walk(absdir):
+            for f in files:
+                if os.path.getsize(os.path.join(root, f)) < 10:
+                    print(f)
+                    i = bpy.context.scene.broken_files.add()
+                    i.filename = f
+                    i.fullpath = os.path.join(root, f)
+                    i.value = os.path.getsize(os.path.join(root, f))
+                    i.checkbox = True
+        return {'FINISHED'}
+
+
+class ClearFile(Operator):
+    bl_idname = "object.clear_broken_file"
+    bl_label = "Clear Broken Files"
+
+    def execute(self, context):
+        bpy.context.scene.broken_files.clear()
+        return {'FINISHED'}
+
+
+class DeleteFiles(Operator):
+    bl_idname = "object.delete_broken_file"
+    bl_label = "Delete Broken Files"
+
+    def execute(self, context):
+        for file in bpy.context.scene.broken_files:
+            if file.checkbox:
+                os.remove(file.fullpath)
+        bpy.context.scene.broken_files.clear()
+        return {'FINISHED'}
+
+
+class BrokenFramesPanel(Panel):
+    bl_label = "Oscurart Broken Render Files"
+    bl_idname = "OBJECT_PT_osc_broken_files"
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = "render"
+
+    def draw(self, context):
+        layout = self.layout
+        col = layout.column(align=1)
+
+        for i in bpy.context.scene.broken_files:
+            colrow = col.row(align=1)
+            colrow.prop(i, "filename")
+            colrow.prop(i, "value")
+            colrow.prop(i, "checkbox")
+
+        col = layout.column(align=1)
+        colrow = col.row(align=1)
+        colrow.operator("object.add_broken_file")
+        colrow.operator("object.clear_broken_file")
+        colrow = col.row(align=1)
+        colrow.operator("object.delete_broken_file")
+
+
+# --------------------------------COPY RENDER SETTINGS--------------------
+
+def defCopyRenderSettings(mode):
+
+    sc = bpy.context.scene
+    sceneslist = bpy.data.scenes[:]
+    sceneslist.remove(sc)
+
+    excludes = {
+        'name',
+        'objects',
+        'object_bases',
+        'has_multiple_engines',
+        'display_settings',
+        'broken_files',
+        'rna_type',
+        'frame_subframe',
+        'view_settings',
+        'tool_settings',
+        'render',
+        'user_clear',
+        'animation_data_create',
+        'collada_export',
+        'keying_sets',
+        'icon_props',
+        'image_settings',
+        'library',
+        'bake',
+        'active_layer',
+        'frame_current_final',
+        'sequence_editor_clear',
+        'rigidbody_world',
+        'unit_settings',
+        'orientations',
+        '__slots__',
+        'ray_cast',
+        'sequencer_colorspace_settings',
+        'ffmpeg',
+        'is_movie_format',
+        'frame_path',
+        'frame_set',
+        'network_render',
+        'animation_data_clear',
+        'is_nla_tweakmode',
+        'keying_sets_all',
+        'sequence_editor',
+        '__doc__',
+        'file_extension',
+        'users',
+        'node_tree',
+        'is_updated_data',
+        'bl_rna',
+        'is_library_indirect',
+        'cycles_curves',
+        'timeline_markers',
+        'statistics',
+        'use_shading_nodes',
+        'use_game_engine',
+        'sequence_editor_create',
+        'is_updated',
+        '__module__',
+        'update_tag',
+        'update',
+        'animation_data',
+        'cycles',
+        'copy',
+        'game_settings',
+        'layers',
+        '__weakref__',
+        'string',
+        'double',
+        'use_render_scene',
+        'engine',
+        'use_nodes',
+        'world'}
+
+    if mode == "render":
+        scenerenderdict = {}
+        scenedict = {}
+        sceneimagesettingdict = {}
+        for prop in dir(bpy.context.scene.render):
+            if prop not in excludes:
+                try:
+                    scenerenderdict[prop] = getattr(
+                        bpy.context.scene.render, prop)
+                except:
+                    print("%s does not exist." % (prop))
+
+        for prop in dir(bpy.context.scene):
+            if prop not in excludes:
+                try:
+                    scenedict[prop] = getattr(bpy.context.scene, prop)
+                except:
+                    print("%s does not exist." % (prop))
+
+        for prop in dir(bpy.context.scene.render.image_settings):
+            if prop not in excludes:
+                try:
+                    sceneimagesettingdict[prop] = getattr(
+                        bpy.context.scene.render.image_settings,
+                        prop)
+                except:
+                    print("%s does not exist." % (prop))
+
+        # render
+        for escena in sceneslist:
+            for prop, value in scenerenderdict.items():
+                try:
+                    setattr(escena.render, prop, value)
+                except:
+                    print("%s was not copied!" % (prop))
+                    pass
+        # scene
+        for escena in sceneslist:
+            for prop, value in scenedict.items():
+                try:
+                    setattr(escena, prop, value)
+                except:
+                    print("%s was not copied!" % (prop))
+                    pass
+        # imageSettings
+        for escena in sceneslist:
+            for prop, value in sceneimagesettingdict.items():
+                try:
+                    setattr(escena.render.image_settings, prop, value)
+                except:
+                    print("%s was not copied!" % (prop))
+                    pass
+
+    if mode == "cycles":
+        scenecyclesdict = {}
+        for prop in dir(bpy.context.scene.cycles):
+            if prop not in excludes:
+                try:
+                    scenecyclesdict[prop] = getattr(
+                        bpy.context.scene.cycles, prop)
+                except:
+                    print("%s does not exist." % (prop))
+        # cycles
+        for escena in sceneslist:
+            for prop, value in scenecyclesdict.items():
+                try:
+                    setattr(escena.cycles, prop, value)
+                except:
+                    print("%s was not copied!" % (prop))
+                    pass
+
+
+class copyRenderSettings(Operator):
+    bl_idname = "render.copy_render_settings_osc"
+    bl_label = "Copy Render Settings"
+
+    mode = bpy.props.StringProperty(default="")
+
+    def execute(self, context):
+
+        defCopyRenderSettings(self.mode)
+
+        return {'FINISHED'}
diff --git a/oscurart_tools/oscurart_shapes.py b/oscurart_tools/oscurart_shapes.py
new file mode 100644
index 0000000000000000000000000000000000000000..10bbd22e663d38ca1511e2c89973a294ff62000b
--- /dev/null
+++ b/oscurart_tools/oscurart_shapes.py
@@ -0,0 +1,469 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from bpy.types import Operator
+from bpy.props import (
+            BoolProperty,
+            FloatProperty,
+            )
+import math
+
+
+# ---------------------CREATE SHAPES----------------
+
+def DefSplitShapes(self, ACTIVESHAPE, LAYOUTCOMPAT):
+    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+
+    ACTOBJ = bpy.context.active_object
+    has_keys = hasattr(getattr(ACTOBJ.data, "shape_keys", None), "key_blocks")
+    if has_keys:
+        INDEX = ACTOBJ.active_shape_key_index
+
+        if LAYOUTCOMPAT:
+            for SHAPE in ACTOBJ.data.shape_keys.key_blocks:
+                if len(SHAPE.name) > 7:
+                    SHAPE.name = SHAPE.name[:8]
+
+        if ACTIVESHAPE:
+            ACTOBJ.active_shape_key_index = INDEX
+            AS = ACTOBJ.active_shape_key
+            AS.value = 1
+            SHAPE = ACTOBJ.shape_key_add(name=AS.name[:8] + "_L", from_mix=True)
+            SHAPE.vertex_group = "_L"
+            SHAPE2 = ACTOBJ.shape_key_add(name=AS.name[:8] + "_R", from_mix=True)
+            SHAPE2.vertex_group = "_R"
+            bpy.ops.object.shape_key_clear()
+        else:
+            for SHAPE in ACTOBJ.data.shape_keys.key_blocks[1:]:
+                SHAPE.value = 1
+                SHAPE1 = ACTOBJ.shape_key_add(
+                    name=SHAPE.name[:8] + "_L",
+                    from_mix=True)
+                SHAPE1.vertex_group = "_L"
+                SHAPE2 = ACTOBJ.shape_key_add(
+                    name=SHAPE.name[:8] + "_R",
+                    from_mix=True)
+                SHAPE2.vertex_group = "_R"
+                bpy.ops.object.shape_key_clear()
+            ACTOBJ.active_shape_key_index = INDEX
+
+    return has_keys
+
+
+class CreaShapes(Operator):
+    bl_idname = "mesh.split_lr_shapes_osc"
+    bl_label = "Split LR Shapes"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type in
+                {'MESH', 'SURFACE', 'CURVE'})
+
+    activeshape = BoolProperty(
+            name="Only Active Shape",
+            default=False
+            )
+    layoutcompat = BoolProperty(
+            name="Layout Compatible",
+            default=True
+            )
+
+    def execute(self, context):
+
+        is_done = DefSplitShapes(self, self.activeshape,
+                                 self.layoutcompat)
+        if not is_done:
+            self.report({'INFO'}, message="Active object doesn't have shape keys")
+            return {'CANCELLED'}
+
+        return {'FINISHED'}
+
+
+# ----------------------------SHAPES LAYOUT-----------------------
+
+class CreaShapesLayout(Operator):
+    bl_idname = "mesh.create_symmetrical_layout_osc"
+    bl_label = "Symmetrical Layout"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type in
+                {'MESH', 'SURFACE', 'CURVE'})
+
+    def execute(self, context):
+
+        SEL_OBJ = bpy.context.active_object
+        has_keys = hasattr(getattr(SEL_OBJ.data, "shape_keys", None), "key_blocks")
+        if has_keys:
+            LISTA_KEYS = bpy.context.active_object.data.shape_keys.key_blocks[1:]
+
+            EDITMODE = "bpy.ops.object.mode_set(mode='EDIT')"
+            OBJECTMODE = "bpy.ops.object.mode_set(mode='OBJECT')"
+            POSEMODE = "bpy.ops.object.mode_set(mode='POSE')"
+
+            amt = bpy.data.armatures.new("ArmatureData")
+            ob = bpy.data.objects.new("RIG_LAYOUT_" + SEL_OBJ.name, amt)
+
+            scn = bpy.context.scene
+            scn.objects.link(ob)
+            scn.objects.active = ob
+            ob.select = True
+
+            verticess = [(-1, 1, 0), (1, 1, 0), (1, -1, 0), (-1, -1, 0)]
+            edgess = [(0, 1), (1, 2), (2, 3), (3, 0)]
+            mesh = bpy.data.meshes.new("%s_data_container" % (SEL_OBJ))
+            object = bpy.data.objects.new("GRAPHIC_CONTAINER", mesh)
+            bpy.context.scene.objects.link(object)
+            mesh.from_pydata(verticess, edgess, [])
+
+            gx = 0
+            gy = 0
+
+            for keyblock in LISTA_KEYS:
+                if keyblock.name[-2:] != "_L":
+                    if keyblock.name[-2:] != "_R":
+
+                        scn.objects.active = ob
+                        eval(EDITMODE)
+
+                        bone = amt.edit_bones.new(keyblock.name)
+                        bone.head = (gx, 0, 0)
+                        bone.tail = (gx, 0, 1)
+
+                        bonectrl = amt.edit_bones.new(keyblock.name + "_CTRL")
+                        bonectrl.head = (gy, 0, 0)
+                        bonectrl.tail = (gy, 0, 0.2)
+
+                        ob.data.edit_bones[
+                            bonectrl.name].parent = ob.data.edit_bones[
+                                bone.name]
+                        bpy.context.scene.objects.active = ob
+
+                        for SIDE in ["L", "R"]:
+                            DR = SEL_OBJ.data.shape_keys.key_blocks[
+                                keyblock.name + "_" + SIDE].driver_add("value")
+                            if SIDE == "L":
+                                DR.driver.expression = "var+var_001"
+                            else:
+                                DR.driver.expression = "-var+var_001"
+                            VAR1 = DR.driver.variables.new()
+                            VAR2 = DR.driver.variables.new()
+
+                            VAR1.targets[0].id = ob
+                            VAR1.type = 'TRANSFORMS'
+                            VAR1.targets[0].bone_target = bonectrl.name
+                            VAR1.targets[0].transform_space = "LOCAL_SPACE"
+                            VAR1.targets[0].transform_type = "LOC_X"
+                            VAR2.targets[0].id = ob
+                            VAR2.type = 'TRANSFORMS'
+                            VAR2.targets[0].bone_target = bonectrl.name
+                            VAR2.targets[0].transform_space = "LOCAL_SPACE"
+                            VAR2.targets[0].transform_type = "LOC_Y"
+
+                        eval(POSEMODE)
+
+                        ob.pose.bones[keyblock.name].custom_shape = object
+                        ob.pose.bones[
+                            keyblock.name +
+                            "_CTRL"].custom_shape = object
+                        CNS = ob.pose.bones[
+                            keyblock.name +
+                            "_CTRL"].constraints.new(
+                                type='LIMIT_LOCATION')
+                        CNS.min_x = -1
+                        CNS.use_min_x = 1
+                        CNS.min_z = 0
+                        CNS.use_min_z = 1
+                        CNS.min_y = -1
+                        CNS.use_min_y = 1
+                        CNS.max_x = 1
+                        CNS.use_max_x = 1
+                        CNS.max_z = 0
+                        CNS.use_max_z = 1
+                        CNS.max_y = 1
+                        CNS.use_max_y = 1
+                        CNS.owner_space = "LOCAL"
+                        CNS.use_transform_limit = True
+
+                        eval(OBJECTMODE)
+
+                        bpy.ops.object.text_add(location=(gx, 0, 0))
+                        gx = gx + 2.2
+                        gy = gy + 2.2
+                        texto = bpy.context.object
+
+                        texto.data.body = keyblock.name
+                        texto.name = "TEXTO_" + keyblock.name
+
+                        texto.rotation_euler[0] = math.pi / 2
+                        texto.location.x = -1
+                        texto.location.z = -1
+                        texto.data.size = .2
+
+                        CNS = texto.constraints.new(type="COPY_LOCATION")
+                        CNS.target = ob
+                        CNS.subtarget = ob.pose.bones[keyblock.name].name
+                        CNS.use_offset = True
+        else:
+            self.report({'INFO'}, message="Active object doesn't have shape keys")
+            return {'CANCELLED'}
+
+        return {'FINISHED'}
+
+
+# ----------------------------CREATE LMR GROUPS-------------------
+
+def createLMRGroups(self, FACTORVG, ADDVG):
+    bpy.context.window.screen.scene.tool_settings.mesh_select_mode = (
+        True, False, False)
+
+    ACTOBJ = bpy.context.active_object
+    bpy.ops.object.mode_set(mode="EDIT", toggle=False)
+    bpy.ops.mesh.select_all(action='DESELECT')
+    bpy.ops.object.mode_set(mode="OBJECT")
+    GRUPOS = ["_L", "_R"]
+    MIRRORINDEX = 0
+
+    for LADO in GRUPOS:
+        if MIRRORINDEX == 0:
+            bpy.ops.object.vertex_group_add()
+            bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+            bpy.ops.mesh.select_all(action='SELECT')
+            bpy.ops.object.vertex_group_assign()
+            bpy.ops.mesh.select_all(action='DESELECT')
+            bpy.ops.object.mode_set(mode='WEIGHT_PAINT', toggle=False)
+            for VERTICE in ACTOBJ.data.vertices:
+                VERTICE.groups[-1].weight = (VERTICE.co[0] * FACTORVG) + ADDVG
+            ACTOBJ.vertex_groups[-1].name = LADO
+        else:
+            bpy.ops.object.vertex_group_add()
+            bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+            bpy.ops.mesh.select_all(action='SELECT')
+            bpy.ops.object.vertex_group_assign()
+            bpy.ops.mesh.select_all(action='DESELECT')
+            bpy.ops.object.mode_set(mode='WEIGHT_PAINT', toggle=False)
+            for VERTICE in ACTOBJ.data.vertices:
+                VERTICE.groups[-1].weight = (-VERTICE.co[0] * FACTORVG) + ADDVG
+            ACTOBJ.vertex_groups[-1].name = LADO
+        MIRRORINDEX += 1
+
+    ACTOBJ.vertex_groups.active_index = len(ACTOBJ.vertex_groups)
+
+
+class CreaGrupos(Operator):
+    bl_idname = "mesh.create_lmr_groups_osc"
+    bl_label = "Create Mix groups"
+    bl_description = "Create Mix groups"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    FACTORVG = FloatProperty(
+            name="Factor",
+            default=1,
+            min=0,
+            max=1000
+            )
+    ADDVG = FloatProperty(
+            name="Addition",
+            default=.5,
+            min=0,
+            max=1000
+            )
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type == 'MESH')
+
+    def execute(self, context):
+
+        createLMRGroups(self, self.FACTORVG, self.ADDVG)
+
+        return {'FINISHED'}
+
+
+# ------------------------ SHAPES LAYOUT SYMMETRICA ------------------------
+
+class CreateLayoutAsymmetrical(Operator):
+    bl_idname = "mesh.create_asymmetrical_layout_osc"
+    bl_label = "Asymmetrical Layout"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type in
+                {'MESH', 'SURFACE', 'CURVE'})
+
+    def execute(self, context):
+
+        SEL_OBJ = bpy.context.active_object
+
+        has_keys = hasattr(getattr(SEL_OBJ.data, "shape_keys", None), "key_blocks")
+        if has_keys:
+            LISTA_KEYS = bpy.context.active_object.data.shape_keys.key_blocks[1:]
+
+            EDITMODE = "bpy.ops.object.mode_set(mode='EDIT')"
+            OBJECTMODE = "bpy.ops.object.mode_set(mode='OBJECT')"
+            POSEMODE = "bpy.ops.object.mode_set(mode='POSE')"
+
+            amtas = bpy.data.armatures.new("ArmatureData")
+            obas = bpy.data.objects.new("RIG_LAYOUT_" + SEL_OBJ.name, amtas)
+
+            scn = bpy.context.scene
+            scn.objects.link(obas)
+            scn.objects.active = obas
+            obas.select = True
+
+            verticess = [(-.1, 1, 0), (.1, 1, 0), (.1, 0, 0), (-.1, 0, 0)]
+            edgess = [(0, 1), (1, 2), (2, 3), (3, 0)]
+            mesh = bpy.data.meshes.new("%s_data_container" % (SEL_OBJ))
+            object = bpy.data.objects.new("GRAPHIC_CONTAINER_AS", mesh)
+            bpy.context.scene.objects.link(object)
+            mesh.from_pydata(verticess, edgess, [])
+
+            eval(EDITMODE)
+            gx = 0
+            gy = 0
+
+            for keyblock in LISTA_KEYS:
+                if keyblock.name[-2:] != "_L":
+                    if keyblock.name[-2:] != "_R":
+                        scn.objects.active = obas
+                        eval(EDITMODE)
+                        bone = amtas.edit_bones.new(keyblock.name)
+                        bone.head = (gx, 0, 0)
+                        bone.tail = (gx, 0, 1)
+
+                        bonectrl = amtas.edit_bones.new(keyblock.name + "_CTRL")
+                        bonectrl.head = (gy, 0, 0)
+                        bonectrl.tail = (gy, 0, 0.2)
+
+                        obas.data.edit_bones[
+                            bonectrl.name].parent = obas.data.edit_bones[
+                                bone.name]
+                        bpy.context.scene.objects.active = obas
+
+                        bpy.ops.armature.select_all(action="DESELECT")
+
+                        DR1 = keyblock.driver_add("value")
+                        DR1.driver.expression = "var"
+                        VAR2 = DR1.driver.variables.new()
+                        VAR2.targets[0].id = obas
+                        VAR2.targets[0].bone_target = bonectrl.name
+                        VAR2.type = 'TRANSFORMS'
+                        VAR2.targets[0].transform_space = "LOCAL_SPACE"
+                        VAR2.targets[0].transform_type = "LOC_Y"
+
+                        eval(POSEMODE)
+
+                        obas.pose.bones[keyblock.name].custom_shape = object
+                        obas.pose.bones[
+                            keyblock.name +
+                            "_CTRL"].custom_shape = object
+
+                        bpy.data.objects[
+                            "RIG_LAYOUT_" +
+                            SEL_OBJ.name].data.bones.active = bpy.data.objects[
+                                "RIG_LAYOUT_" +
+                                SEL_OBJ.name].data.bones[
+                                    keyblock.name +
+                                    "_CTRL"]
+
+                        eval(POSEMODE)
+                        CNS = obas.pose.bones[
+                            keyblock.name +
+                            "_CTRL"].constraints.new(
+                                type='LIMIT_LOCATION')
+                        CNS.min_x = 0
+                        CNS.use_min_x = 1
+                        CNS.min_z = 0
+                        CNS.use_min_z = 1
+                        CNS.min_y = 0
+                        CNS.use_min_y = 1
+
+                        CNS.max_x = 0
+                        CNS.use_max_x = 1
+                        CNS.max_z = 0
+                        CNS.use_max_z = 1
+                        CNS.max_y = 1
+                        CNS.use_max_y = 1
+
+                        CNS.owner_space = "LOCAL"
+                        CNS.use_transform_limit = True
+
+                        eval(OBJECTMODE)
+
+                        bpy.ops.object.text_add(location=(0, 0, 0))
+                        gx = gx + 2.2
+                        gy = gy + 2.2
+                        texto = bpy.context.object
+                        texto.data.body = keyblock.name
+                        texto.name = "TEXTO_" + keyblock.name
+
+                        texto.rotation_euler[0] = math.pi / 2
+                        texto.location.x = -.15
+                        texto.location.z = -.15
+                        texto.data.size = .2
+
+                        CNS = texto.constraints.new(type="COPY_LOCATION")
+                        CNS.target = obas
+                        CNS.subtarget = obas.pose.bones[keyblock.name].name
+                        CNS.use_offset = True
+        else:
+            self.report({'INFO'}, message="Active object doesn't have shape keys")
+            return {'CANCELLED'}
+
+        return {'FINISHED'}
+
+
+# ---------------------------SHAPES TO OBJECTS------------------
+
+class ShapeToObjects(Operator):
+    bl_idname = "object.shape_key_to_objects_osc"
+    bl_label = "Shapes To Objects"
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.active_object is not None and
+                context.active_object.type in
+                {'MESH', 'SURFACE', 'CURVE'})
+
+    def execute(self, context):
+        OBJACT = bpy.context.active_object
+        has_keys = hasattr(getattr(OBJACT.data, "shape_keys", None), "key_blocks")
+        if has_keys:
+            for SHAPE in OBJACT.data.shape_keys.key_blocks[:]:
+                print(SHAPE.name)
+                bpy.ops.object.shape_key_clear()
+                SHAPE.value = 1
+                mesh = OBJACT.to_mesh(bpy.context.scene, True, 'PREVIEW')
+                object = bpy.data.objects.new(SHAPE.name, mesh)
+                bpy.context.scene.objects.link(object)
+        else:
+            self.report({'INFO'}, message="Active object doesn't have shape keys")
+            return {'CANCELLED'}
+
+        return {'FINISHED'}