diff --git a/add_advanced_objects_menu/__init__.py b/add_advanced_objects_menu/__init__.py
index 46a3dffc7e5ef3a48449c2d243c48d6ded0bf654..42a3344522573c3fac586735a9a3592ecbf47a4d 100644
--- a/add_advanced_objects_menu/__init__.py
+++ b/add_advanced_objects_menu/__init__.py
@@ -25,7 +25,7 @@
 bl_info = {
     "name": "Add Advanced Objects",
     "author": "Meta Androcto",
-    "version": (0, 1, 5),
+    "version": (0, 1, 6),
     "blender": (2, 78, 0),
     "location": "View3D > Add ",
     "description": "Add Object & Camera extras",
@@ -55,7 +55,6 @@ if "bpy" in locals():
     importlib.reload(arrange_on_curve)
     importlib.reload(mesh_easylattice)
 
-
 else:
     from . import add_light_template
     from . import scene_objects_bi
@@ -78,18 +77,18 @@ else:
 
 import bpy
 from bpy.types import (
-        Menu,
-        AddonPreferences,
-        PropertyGroup,
-        )
+    AddonPreferences,
+    Menu,
+    PropertyGroup,
+)
 from bpy.props import (
-        BoolProperty,
-        EnumProperty,
-        FloatProperty,
-        IntProperty,
-        StringProperty,
-        PointerProperty,
-        )
+    BoolProperty,
+    EnumProperty,
+    FloatProperty,
+    IntProperty,
+    StringProperty,
+    PointerProperty,
+)
 
 
 # Define the "Scenes" menu
@@ -204,15 +203,15 @@ class AdvancedObjPreferences(AddonPreferences):
     bl_idname = __name__
 
     show_menu_list = BoolProperty(
-            name="Menu List",
-            description="Show/Hide the Add Menu items",
-            default=False
-            )
+        name="Menu List",
+        description="Show/Hide the Add Menu items",
+        default=False
+    )
     show_panel_list = BoolProperty(
-            name="Panels List",
-            description="Show/Hide the Panel items",
-            default=False
-            )
+        name="Panels List",
+        description="Show/Hide the Panel items",
+        default=False
+    )
 
     def draw(self, context):
         layout = self.layout
@@ -315,214 +314,214 @@ class AdvancedObjProperties(PropertyGroup):
     # cubester
     # main properties
     cubester_check_audio = BoolProperty(
-            name="",
-            default=False
-            )
+        name="",
+        default=False
+    )
     cubester_audio_image = EnumProperty(
-            name="Input Type",
-            items=(("image", "Image",
-                    "Use an Image as input for generating Geometry", "IMAGE_COL", 0),
-                   ("audio", "Audio",
-                    "Use a Sound Strip as input for generating Geometry", "FILE_SOUND", 1))
-            )
+        name="Input Type",
+        items=(("image", "Image",
+                "Use an Image as input for generating Geometry", "IMAGE_COL", 0),
+               ("audio", "Audio",
+                "Use a Sound Strip as input for generating Geometry", "FILE_SOUND", 1))
+    )
     cubester_audio_file_length = IntProperty(
-            default=0
-            )
+        default=0
+    )
     # audio
     cubester_audio_path = StringProperty(
-            default="",
-            name="Audio File",
-            subtype="FILE_PATH",
-            update=find_audio_length
-            )
+        default="",
+        name="Audio File",
+        subtype="FILE_PATH",
+        update=find_audio_length
+    )
     cubester_audio_min_freq = IntProperty(
-            name="Minimum Frequency",
-            min=20, max=100000,
-            default=20
-            )
+        name="Minimum Frequency",
+        min=20, max=100000,
+        default=20
+    )
     cubester_audio_max_freq = IntProperty(
-            name="Maximum Frequency",
-            min=21, max=999999,
-            default=5000
-            )
+        name="Maximum Frequency",
+        min=21, max=999999,
+        default=5000
+    )
     cubester_audio_offset_type = EnumProperty(
-            name="Offset Type",
-            items=(("freq", "Frequency Offset", ""),
-                   ("frame", "Frame Offset", "")),
-            description="Type of offset per row of mesh"
-            )
+        name="Offset Type",
+        items=(("freq", "Frequency Offset", ""),
+               ("frame", "Frame Offset", "")),
+        description="Type of offset per row of mesh"
+    )
     cubester_audio_frame_offset = IntProperty(
-            name="Frame Offset",
-            min=0, max=10,
-            default=2
-            )
+        name="Frame Offset",
+        min=0, max=10,
+        default=2
+    )
     cubester_audio_block_layout = EnumProperty(
-            name="Block Layout",
-            items=(("rectangle", "Rectangular", ""),
-                  ("radial", "Radial", ""))
-            )
+        name="Block Layout",
+        items=(("rectangle", "Rectangular", ""),
+              ("radial", "Radial", ""))
+    )
     cubester_audio_width_blocks = IntProperty(
-            name="Width Block Count",
-            min=1, max=10000,
-            default=5
-            )
+        name="Width Block Count",
+        min=1, max=10000,
+        default=5
+    )
     cubester_audio_length_blocks = IntProperty(
-            name="Length Block Count",
-            min=1, max=10000,
-            default=50
-            )
+        name="Length Block Count",
+        min=1, max=10000,
+        default=50
+    )
     # image
     cubester_load_type = EnumProperty(
-            name="Image Input Type",
-            items=(("single", "Single Image", ""),
-                  ("multiple", "Image Sequence", ""))
-            )
+        name="Image Input Type",
+        items=(("single", "Single Image", ""),
+              ("multiple", "Image Sequence", ""))
+    )
     cubester_image = StringProperty(
-            default="",
-            name=""
-            )
+        default="",
+        name=""
+    )
     cubester_load_image = StringProperty(
-            default="",
-            name="Load Image",
-            subtype="FILE_PATH",
-            update=adjust_selected_image
-            )
+        default="",
+        name="Load Image",
+        subtype="FILE_PATH",
+        update=adjust_selected_image
+    )
     cubester_skip_images = IntProperty(
-            name="Image Step",
-            min=1, max=30,
-            default=1,
-            description="Step from image to image by this number"
-            )
+        name="Image Step",
+        min=1, max=30,
+        default=1,
+        description="Step from image to image by this number"
+    )
     cubester_max_images = IntProperty(
-            name="Max Number Of Images",
-            min=2, max=1000,
-            default=10,
-            description="Maximum number of images to be used"
-            )
+        name="Max Number Of Images",
+        min=2, max=1000,
+        default=10,
+        description="Maximum number of images to be used"
+    )
     cubester_frame_step = IntProperty(
-            name="Frame Step Size",
-            min=1, max=10,
-            default=4,
-            description="The number of frames each picture is used"
-            )
+        name="Frame Step Size",
+        min=1, max=10,
+        default=4,
+        description="The number of frames each picture is used"
+    )
     cubester_skip_pixels = IntProperty(
-            name="Skip # Pixels",
-            min=0, max=256,
-            default=64,
-            description="Skip this number of pixels before placing the next"
-            )
+        name="Skip # Pixels",
+        min=0, max=256,
+        default=64,
+        description="Skip this number of pixels before placing the next"
+    )
     cubester_mesh_style = EnumProperty(
-            name="Mesh Type",
-            items=(("blocks", "Blocks", ""),
-                   ("plane", "Plane", "")),
-            description="Compose mesh of multiple blocks or of a single plane"
-            )
+        name="Mesh Type",
+        items=(("blocks", "Blocks", ""),
+               ("plane", "Plane", "")),
+        description="Compose mesh of multiple blocks or of a single plane"
+    )
     cubester_block_style = EnumProperty(
-            name="Block Style",
-            items=(("size", "Vary Size", ""),
-                   ("position", "Vary Position", "")),
-            description="Vary Z-size of block, or vary Z-position"
-            )
+        name="Block Style",
+        items=(("size", "Vary Size", ""),
+               ("position", "Vary Position", "")),
+        description="Vary Z-size of block, or vary Z-position"
+    )
     cubester_height_scale = FloatProperty(
-            name="Height Scale",
-            subtype="DISTANCE",
-            min=0.1, max=2,
-            default=0.2
-            )
+        name="Height Scale",
+        subtype="DISTANCE",
+        min=0.1, max=2,
+        default=0.2
+    )
     cubester_invert = BoolProperty(
-            name="Invert Height",
-            default=False
-            )
+        name="Invert Height",
+        default=False
+    )
     # general adjustments
     cubester_size_per_hundred_pixels = FloatProperty(
-            name="Size Per 100 Blocks/Points",
-            subtype="DISTANCE",
-            min=0.001, max=5,
-            default=1
-            )
+        name="Size Per 100 Blocks/Points",
+        subtype="DISTANCE",
+        min=0.001, max=5,
+        default=1
+    )
     # material based stuff
     cubester_materials = EnumProperty(
-            name="Material",
-            items=(("vertex", "Vertex Colors", ""),
-                   ("image", "Image", "")),
-            description="Color with vertex colors, or uv unwrap and use an image"
-            )
+        name="Material",
+        items=(("vertex", "Vertex Colors", ""),
+               ("image", "Image", "")),
+        description="Color with vertex colors, or uv unwrap and use an image"
+    )
     cubester_use_image_color = BoolProperty(
-            name="Use Original Image Colors'?",
-            default=True,
-            description="Use original image colors, or replace with an another one"
-            )
+        name="Use Original Image Colors'?",
+        default=True,
+        description="Use original image colors, or replace with an another one"
+    )
     cubester_color_image = StringProperty(
-            default="",
-            name=""
-            )
+        default="",
+        name=""
+    )
     cubester_load_color_image = StringProperty(
-            default="",
-            name="Load Color Image",
-            subtype="FILE_PATH",
-            update=adjust_selected_color_image
-            )
+        default="",
+        name="Load Color Image",
+        subtype="FILE_PATH",
+        update=adjust_selected_color_image
+    )
     cubester_vertex_colors = {}
     # advanced
     cubester_advanced = BoolProperty(
-            name="Advanced Options",
-            default=False
-            )
+        name="Advanced Options",
+        default=False
+    )
     cubester_random_weights = BoolProperty(
-            name="Random Weights",
-            default=False
-            )
+        name="Random Weights",
+        default=False
+    )
     cubester_weight_r = FloatProperty(
-            name="Red",
-            subtype="FACTOR",
-            min=0.01, max=1.0,
-            default=0.25
-            )
+        name="Red",
+        subtype="FACTOR",
+        min=0.01, max=1.0,
+        default=0.25
+    )
     cubester_weight_g = FloatProperty(
-            name="Green",
-            subtype="FACTOR",
-            min=0.01, max=1.0,
-            default=0.25
-            )
+        name="Green",
+        subtype="FACTOR",
+        min=0.01, max=1.0,
+        default=0.25
+    )
     cubester_weight_b = FloatProperty(
-            name="Blue",
-            subtype="FACTOR",
-            min=0.01, max=1.0,
-            default=0.25
-            )
+        name="Blue",
+        subtype="FACTOR",
+        min=0.01, max=1.0,
+        default=0.25
+    )
     cubester_weight_a = FloatProperty(
-            name="Alpha",
-            subtype="FACTOR",
-            min=0.01, max=1.0,
-            default=0.25
-            )
+        name="Alpha",
+        subtype="FACTOR",
+        min=0.01, max=1.0,
+        default=0.25
+    )
 
     # arrange_on_curve
     arrange_c_use_selected = BoolProperty(
-            name="Use Selected",
-            description="Use the selected objects to duplicate",
-            default=True,
-            )
+        name="Use Selected",
+        description="Use the selected objects to duplicate",
+        default=True,
+    )
     arrange_c_obj_arranjar = StringProperty(
-            name=""
-            )
+        name=""
+    )
     arrange_c_select_type = EnumProperty(
-            name="Type",
-            description="Select object or group",
-            items=[
-                ('O', "Object", "Make duplicates of a specific object"),
-                ('G', "Group", "Make duplicates of the objects in a group"),
-            ],
-            default='O',
-            )
+        name="Type",
+        description="Select object or group",
+        items=[
+            ('O', "Object", "Make duplicates of a specific object"),
+            ('G', "Group", "Make duplicates of the objects in a group"),
+        ],
+        default='O',
+    )
 
 
 def register():
     bpy.utils.register_module(__name__)
 
     bpy.types.Scene.advanced_objects = PointerProperty(
-                                            type=AdvancedObjProperties
-                                            )
+        type=AdvancedObjProperties
+    )
 
     # Add "Extras" menu to the "Add" menu
     bpy.types.INFO_MT_add.append(menu)
@@ -543,10 +542,6 @@ def unregister():
     bpy.utils.unregister_module(__name__)
     del bpy.types.Scene.advanced_objects
 
-    # cleanup Easy Lattice Scene Property if it was created
-    if hasattr(bpy.types.Scene, "activelatticeobject"):
-        del bpy.types.Scene.activelatticeobject
-
 
 if __name__ == "__main__":
     register()
diff --git a/add_advanced_objects_menu/cubester.py b/add_advanced_objects_menu/cubester.py
index f1a8f5817804a39e9023464c2df1e3ecb55ab337..87322f4feb845e255dc9ac51743e23773745902f 100644
--- a/add_advanced_objects_menu/cubester.py
+++ b/add_advanced_objects_menu/cubester.py
@@ -25,28 +25,28 @@
 bl_info = {
     "name": "CubeSter",
     "author": "Jacob Morris",
-    "version": (0, 7, 1),
+    "version": (0, 7, 2),
     "blender": (2, 78, 0),
     "location": "View 3D > Toolbar > CubeSter",
     "description": "Takes image, image sequence, or audio file and converts it "
                    "into a height map based on pixel color and alpha values",
     "category": "Add Mesh"
-    }
+}
 
 import bpy
 import bmesh
 from bpy.types import (
-        Operator,
-        Panel,
-        )
+    Operator,
+    Panel,
+)
 
 import timeit
 from random import uniform
 from math import radians
 from os import (
-        path,
-        listdir,
-        )
+    path,
+    listdir,
+)
 
 
 # create block at center position x, y with block width 2 * hx and 2 * hy and height of h
@@ -146,18 +146,18 @@ def create_material(scene, ob, name):
 
         if adv_obj.cubester_materials == "image":
             mat.node_tree.links.new(
-                            nodes["Image Texture"].outputs[0],
-                            nodes["Diffuse BSDF"].inputs[0]
-                            )
+                nodes["Image Texture"].outputs[0],
+                nodes["Diffuse BSDF"].inputs[0]
+            )
             mat.node_tree.links.new(
-                            nodes["Texture Coordinate"].outputs[2],
-                            nodes["Image Texture"].inputs[0]
-                            )
+                nodes["Texture Coordinate"].outputs[2],
+                nodes["Image Texture"].inputs[0]
+            )
         else:
             mat.node_tree.links.new(
-                            nodes["Attribute"].outputs[0],
-                            nodes["Diffuse BSDF"].inputs[0]
-                            )
+                nodes["Attribute"].outputs[0],
+                nodes["Diffuse BSDF"].inputs[0]
+            )
     else:
         if adv_obj.cubester_materials == "image" or scene.render.engine != "BLENDER_RENDER":
             tex = bpy.data.textures.new("CubeSter_" + name, "IMAGE")
@@ -177,9 +177,11 @@ def create_mesh_from_audio(self, scene, verts, faces):
     audio_filepath = adv_obj.cubester_audio_path
     width = adv_obj.cubester_audio_width_blocks
     length = adv_obj.cubester_audio_length_blocks
-    size_per_hundred = adv_obj.cubester_size_per_hundred_pixels
 
+    size_per_hundred = adv_obj.cubester_size_per_hundred_pixels
     size = size_per_hundred / 100
+    # Note: used for compatibility with vertex colors changes
+    bl_version = bool(bpy.app.version >= (2, 79, 1))
 
     # create all blocks
     y = -(width / 2) * size + (size / 2)
@@ -212,7 +214,8 @@ def create_mesh_from_audio(self, scene, verts, faces):
             # go through each column, step by appropriate amount
             for column in range(0, picture.size[0] * 4, 4 + skip_x * 4):
                 r, g, b, a = get_pixel_values(picture, pixels, row, column)
-                vert_colors += [(r, g, b) for i in range(24)]
+                get_colors = (r, g, b, a) if bl_version else (r, g, b)
+                vert_colors += [get_colors for i in range(24)]
 
         bpy.ops.mesh.vertex_color_add()
 
@@ -244,7 +247,8 @@ def create_mesh_from_audio(self, scene, verts, faces):
                 for row in range(0, picture.size[1], skip_y + 1):
                     for column in range(0, picture.size[0] * 4, 4 + skip_x * 4):
                         r, g, b, a = get_pixel_values(picture, pixels, row, column)
-                        frame_colors += [(r, g, b) for i in range(24)]
+                        get_colors = (r, g, b, a) if bl_version else (r, g, b)
+                        frame_colors += [get_colors for i in range(24)]
 
                 frames_vert_colors.append(frame_colors)
 
@@ -354,6 +358,8 @@ def create_mesh_from_image(self, scene, verts, faces):
     adv_obj = scene.advanced_objects
     picture = bpy.data.images[adv_obj.cubester_image]
     pixels = list(picture.pixels)
+    # Note: used for compatibility with vertex colors changes
+    bl_version = bool(bpy.app.version >= (2, 79, 1))
 
     x_pixels = picture.size[0] / (adv_obj.cubester_skip_pixels + 1)
     y_pixels = picture.size[1] / (adv_obj.cubester_skip_pixels + 1)
@@ -367,7 +373,6 @@ def create_mesh_from_image(self, scene, verts, faces):
     y = -height / 2 + half_width
 
     vert_colors = []
-    weights = [uniform(0.0, 1.0) for i in range(4)]  # random weights
     rows = 0
 
     # go through each row of pixels stepping by adv_obj.cubester_skip_pixels + 1
@@ -377,16 +382,17 @@ def create_mesh_from_image(self, scene, verts, faces):
         # go through each column, step by appropriate amount
         for column in range(0, picture.size[0] * 4, 4 + adv_obj.cubester_skip_pixels * 4):
             r, g, b, a = get_pixel_values(picture, pixels, row, column)
+            get_colors = (r, g, b, a) if bl_version else (r, g, b)
             h = find_point_height(r, g, b, a, scene)
 
             # if not transparent
             if h != -1:
                 if adv_obj.cubester_mesh_style == "blocks":
                     create_block(x, y, half_width, h, verts, faces)
-                    vert_colors += [(r, g, b) for i in range(24)]
+                    vert_colors += [get_colors for i in range(24)]
                 else:
                     verts += [(x, y, h)]
-                    vert_colors += [(r, g, b) for i in range(4)]
+                    vert_colors += [get_colors for i in range(4)]
 
             x += step
         y += step
@@ -464,14 +470,15 @@ def create_mesh_from_image(self, scene, verts, faces):
             for row in range(0, picture.size[1], adv_obj.cubester_skip_pixels + 1):
                 for column in range(0, picture.size[0] * 4, 4 + adv_obj.cubester_skip_pixels * 4):
                     r, g, b, a = get_pixel_values(picture, pixels, row, column)
+                    get_colors = (r, g, b, a) if bl_version else (r, g, b)
                     h = find_point_height(r, g, b, a, scene)
 
                     if h != -1:
                         frame_heights.append(h)
                         if adv_obj.cubester_mesh_style == "blocks":
-                            frame_colors += [(r, g, b) for i in range(24)]
+                            frame_colors += [get_colors for i in range(24)]
                         else:
-                            frame_colors += [(r, g, b) for i in range(4)]
+                            frame_colors += [get_colors for i in range(4)]
 
             if adv_obj.cubester_mesh_style == "plane":
                 del vert_colors[len(vert_colors) - 4:len(vert_colors)]
@@ -482,24 +489,24 @@ def create_mesh_from_image(self, scene, verts, faces):
         # determine what data to use
         if adv_obj.cubester_materials == "vertex" or scene.render.engine == "BLENDER_ENGINE":
             adv_obj.cubester_vertex_colors[ob.name] = {
-                                    "type": "vertex", "frames": frames_vert_colors,
-                                    "frame_skip": adv_obj.cubester_frame_step,
-                                    "total_images": max_images
-                                    }
+                "type": "vertex", "frames": frames_vert_colors,
+                "frame_skip": adv_obj.cubester_frame_step,
+                "total_images": max_images
+            }
         else:
             adv_obj.cubester_vertex_colors[ob.name] = {
-                                    "type": "image", "frame_skip": scene.cubester_frame_step,
-                                    "total_images": max_images
-                                    }
+                "type": "image", "frame_skip": adv_obj.cubester_frame_step,
+                "total_images": max_images
+            }
             att = get_image_node(ob.data.materials[0])
             att.image_user.frame_duration = len(frames) * adv_obj.cubester_frame_step
 
         # animate mesh
         create_f_curves(
-                mesh, frames,
-                adv_obj.cubester_frame_step,
-                adv_obj.cubester_mesh_style
-                )
+            mesh, frames,
+            adv_obj.cubester_frame_step,
+            adv_obj.cubester_mesh_style
+        )
 
 
 # generate uv map for object
@@ -879,11 +886,12 @@ class CubeSterPanel(Panel):
 
 class CubeSter(Operator):
     bl_idname = "mesh.cubester"
-    bl_label = "Generate Mesh"
+    bl_label = "Generate CubeSter Mesh"
     bl_description = "Generate a mesh from an Image or Sound File"
     bl_options = {"REGISTER", "UNDO"}
 
     def execute(self, context):
+
         verts, faces = [], []
 
         start = timeit.default_timer()
@@ -901,7 +909,8 @@ class CubeSter(Operator):
                 return {"CANCELLED"}
         else:
             if (adv_obj.cubester_audio_path != "" and
-               path.isfile(adv_obj.cubester_audio_path) and adv_obj.cubester_check_audio is True):
+                    path.isfile(adv_obj.cubester_audio_path) and
+                    adv_obj.cubester_check_audio is True):
 
                 create_mesh_from_audio(self, scene, verts, faces)
                 created = adv_obj.cubester_audio_file_length
@@ -913,19 +922,21 @@ class CubeSter(Operator):
         stop = timeit.default_timer()
 
         if adv_obj.cubester_mesh_style == "blocks" or adv_obj.cubester_audio_image == "audio":
-            self.report({"INFO"},
-                        "CubeSter: {} blocks and {} frame(s) "
-                        "in {}s".format(str(int(len(verts) / 8)),
-                                        str(created),
-                                        str(round(stop - start, 4)))
-                        )
+            self.report(
+                {"INFO"},
+                "CubeSter: {} blocks and {} frame(s) "
+                "in {}s".format(str(int(len(verts) / 8)),
+                                str(created),
+                                str(round(stop - start, 4)))
+            )
         else:
-            self.report({"INFO"},
-                        "CubeSter: {} points and {} frame(s) "
-                        "in {}s" .format(str(len(verts)),
-                                         str(created),
-                                         str(round(stop - start, 4)))
-                        )
+            self.report(
+                {"INFO"},
+                "CubeSter: {} points and {} frame(s) "
+                "in {}s" .format(str(len(verts)),
+                                 str(created),
+                                 str(round(stop - start, 4)))
+            )
 
         return {"FINISHED"}
 
diff --git a/add_curve_ivygen.py b/add_curve_ivygen.py
index dd52310207cabc2840a7085eab22bb35fd927005..7a90b3b9d2e84255bb7fd7af04c267855e4aecd2 100644
--- a/add_curve_ivygen.py
+++ b/add_curve_ivygen.py
@@ -21,9 +21,9 @@
 bl_info = {
     "name": "IvyGen",
     "author": "testscreenings, PKHG, TrumanBlending",
-    "version": (0, 1, 2),
+    "version": (0, 1, 4),
     "blender": (2, 59, 0),
-    "location": "View3D > Add > Curve",
+    "location": "View3D > Tool Shelf > Create > Ivy Generator",
     "description": "Adds generated ivy to a mesh object starting "
                    "at the 3D cursor",
     "warning": "",
@@ -34,10 +34,16 @@ bl_info = {
 
 
 import bpy
+from bpy.types import (
+        Operator,
+        Panel,
+        PropertyGroup,
+        )
 from bpy.props import (
+        BoolProperty,
         FloatProperty,
         IntProperty,
-        BoolProperty,
+        PointerProperty,
         )
 from mathutils import (
         Vector,
@@ -191,7 +197,7 @@ def createIvyGeometry(IVY, growLeaves):
 
     if growLeaves:
         faceList = [[4 * i + l for l in range(4)] for i in
-                                                     range(len(vertList) // 4)]
+                    range(len(vertList) // 4)]
 
         # Generate the new leaf mesh and link
         me = bpy.data.meshes.new('IvyLeaf')
@@ -212,24 +218,6 @@ def createIvyGeometry(IVY, growLeaves):
         ob.parent = newCurve
 
 
-'''
-def computeBoundingSphere(ob):
-    # Get the mesh data
-    me = ob.data
-    # Intialise the center
-    center = Vector((0.0, 0.0, 0.0))
-    # Add all vertex coords
-    for v in me.vertices:
-        center += v.co
-    # Average over all verts
-    center /= len(me.vertices)
-    # Create the iterator and find its max
-    length_iter = ((center - v.co).length for v in me.vertices)
-    radius = max(length_iter)
-    return radius
-'''
-
-
 class IvyNode:
     """ The basic class used for each point on the ivy which is grown."""
     __slots__ = ('pos', 'primaryDir', 'adhesionVector', 'adhesionLength',
@@ -463,12 +451,204 @@ def check_mesh_faces(ob):
     return False
 
 
-class IvyGen(bpy.types.Operator):
+class IvyGen(Operator):
     bl_idname = "curve.ivy_gen"
     bl_label = "IvyGen"
     bl_description = "Generate Ivy on an Mesh Object"
     bl_options = {'REGISTER', 'UNDO'}
 
+    updateIvy = BoolProperty(
+            name="Update Ivy",
+            description="Update the Ivy location based on the cursor and Panel settings",
+            default=False
+            )
+    defaultIvy = BoolProperty(
+            name="Default Ivy",
+            options={"HIDDEN", "SKIP_SAVE"},
+            default=False
+            )
+
+    @classmethod
+    def poll(self, context):
+        # Check if there's an object and whether it's a mesh
+        ob = context.active_object
+        return ((ob is not None) and
+                (ob.type == 'MESH') and
+                (context.mode == 'OBJECT'))
+
+    def invoke(self, context, event):
+        self.updateIvy = True
+        return self.execute(context)
+
+    def execute(self, context):
+        # scene = context.scene
+        ivyProps = context.window_manager.ivy_gen_props
+
+        if not self.updateIvy:
+            return {'PASS_THROUGH'}
+
+        # assign the variables, check if it is default
+        # Note: update the values if window_manager props defaults are changed
+        randomSeed = ivyProps.randomSeed if not self.defaultIvy else 0
+        maxTime = ivyProps.maxTime if not self.defaultIvy else 0
+        maxIvyLength = ivyProps.maxIvyLength if not self.defaultIvy else 1.0
+        ivySize = ivyProps.ivySize if not self.defaultIvy else 0.02
+        maxFloatLength = ivyProps.maxFloatLength if not self.defaultIvy else 0.5
+        maxAdhesionDistance = ivyProps.maxAdhesionDistance if not self.defaultIvy else 1.0
+        primaryWeight = ivyProps.primaryWeight if not self.defaultIvy else 0.5
+        randomWeight = ivyProps.randomWeight if not self.defaultIvy else 0.2
+        gravityWeight = ivyProps.gravityWeight if not self.defaultIvy else 1.0
+        adhesionWeight = ivyProps.adhesionWeight if not self.defaultIvy else 0.1
+        branchingProbability = ivyProps.branchingProbability if not self.defaultIvy else 0.05
+        leafProbability = ivyProps.leafProbability if not self.defaultIvy else 0.35
+        ivyBranchSize = ivyProps.ivyBranchSize if not self.defaultIvy else 0.001
+        ivyLeafSize = ivyProps.ivyLeafSize if not self.defaultIvy else 0.02
+        growLeaves = ivyProps.growLeaves if not self.defaultIvy else True
+
+        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+
+        # Get the selected object
+        ob = context.active_object
+
+        # Check if the mesh has at least one polygon since some functions
+        # are expecting them in the object's data (see T51753)
+        check_face = check_mesh_faces(ob)
+        if check_face is False:
+            self.report({'WARNING'},
+                        "Mesh Object doesn't have at least one Face. "
+                        "Operation Cancelled")
+            return {"CANCELLED"}
+
+        # Compute bounding sphere radius
+        # radius = computeBoundingSphere(ob)  # Not needed anymore
+
+        # Get the seeding point
+        seedPoint = context.scene.cursor_location
+
+        # Fix the random seed
+        rand_seed(randomSeed)
+
+        # Make the new ivy
+        IVY = Ivy(
+            primaryWeight=primaryWeight,
+            randomWeight=randomWeight,
+            gravityWeight=gravityWeight,
+            adhesionWeight=adhesionWeight,
+            branchingProbability=branchingProbability,
+            leafProbability=leafProbability,
+            ivySize=ivySize,
+            ivyLeafSize=ivyLeafSize,
+            ivyBranchSize=ivyBranchSize,
+            maxFloatLength=maxFloatLength,
+            maxAdhesionDistance=maxAdhesionDistance
+            )
+        # Generate first root and node
+        IVY.seed(seedPoint)
+
+        checkTime = False
+        maxLength = maxIvyLength  # * radius
+
+        # If we need to check time set the flag
+        if maxTime != 0.0:
+            checkTime = True
+
+        t = time.time()
+        startPercent = 0.0
+        checkAliveIter = [True, ]
+
+        # Grow until 200 roots is reached or backup counter exceeds limit
+        while (any(checkAliveIter) and
+               (IVY.maxLength < maxLength) and
+               (not checkTime or (time.time() - t < maxTime))):
+            # Grow the ivy for this iteration
+            IVY.grow(ob)
+
+            # Print the proportion of ivy growth to console
+            if (IVY.maxLength / maxLength * 100) > 10 * startPercent // 10:
+                print('%0.2f%% of Ivy nodes have grown' %
+                                         (IVY.maxLength / maxLength * 100))
+                startPercent += 10
+                if IVY.maxLength / maxLength > 1:
+                    print("Halting Growth")
+
+            # Make an iterator to check if all are alive
+            checkAliveIter = (r.alive for r in IVY.ivyRoots)
+
+        # Create the curve and leaf geometry
+        createIvyGeometry(IVY, growLeaves)
+        print("Geometry Generation Complete")
+
+        print("Ivy generated in %0.2f s" % (time.time() - t))
+
+        self.updateIvy = False
+        self.defaultIvy = False
+
+        return {'FINISHED'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        layout.prop(self, "updateIvy", icon="FILE_REFRESH")
+
+
+class CURVE_PT_IvyGenPanel(Panel):
+    bl_label = "Ivy Generator"
+    bl_idname = "CURVE_PT_IvyGenPanel"
+    bl_space_type = "VIEW_3D"
+    bl_region_type = "TOOLS"
+    bl_category = "Create"
+    bl_context = 'objectmode'
+    bl_options = {"DEFAULT_CLOSED"}
+
+    def draw(self, context):
+        layout = self.layout
+        wm = context.window_manager
+        col = layout.column(align=True)
+
+        prop_new = col.operator("curve.ivy_gen", text="Add New Ivy", icon="OUTLINER_OB_CURVE")
+        prop_new.defaultIvy = False
+        prop_new.updateIvy = True
+
+        prop_def = col.operator("curve.ivy_gen", text="Add New Default Ivy", icon="CURVE_DATA")
+        prop_def.defaultIvy = True
+        prop_def.updateIvy = True
+
+        col = layout.column(align=True)
+        col.label("Generation Settings:")
+        col.prop(wm.ivy_gen_props, "randomSeed")
+        col.prop(wm.ivy_gen_props, "maxTime")
+
+        col = layout.column(align=True)
+        col.label("Size Settings:")
+        col.prop(wm.ivy_gen_props, "maxIvyLength")
+        col.prop(wm.ivy_gen_props, "ivySize")
+        col.prop(wm.ivy_gen_props, "maxFloatLength")
+        col.prop(wm.ivy_gen_props, "maxAdhesionDistance")
+
+        col = layout.column(align=True)
+        col.label("Weight Settings:")
+        col.prop(wm.ivy_gen_props, "primaryWeight")
+        col.prop(wm.ivy_gen_props, "randomWeight")
+        col.prop(wm.ivy_gen_props, "gravityWeight")
+        col.prop(wm.ivy_gen_props, "adhesionWeight")
+
+        col = layout.column(align=True)
+        col.label("Branch Settings:")
+        col.prop(wm.ivy_gen_props, "branchingProbability")
+        col.prop(wm.ivy_gen_props, "ivyBranchSize")
+
+        col = layout.column(align=True)
+        col.prop(wm.ivy_gen_props, "growLeaves")
+
+        if wm.ivy_gen_props.growLeaves:
+            col = layout.column(align=True)
+            col.label("Leaf Settings:")
+            col.prop(wm.ivy_gen_props, "ivyLeafSize")
+            col.prop(wm.ivy_gen_props, "leafProbability")
+
+
+class IvyGenProperties(PropertyGroup):
     maxIvyLength = FloatProperty(
             name="Max Ivy Length",
             description="Maximum ivy length in Blender Units",
@@ -551,7 +731,8 @@ class IvyGen(bpy.types.Operator):
                         "can live while floating",
             default=0.5,
             min=0.0,
-            soft_max=1.0)
+            soft_max=1.0
+            )
     maxAdhesionDistance = FloatProperty(
             name="Max Adhesion Length",
             description="The maximum distance that a branch "
@@ -580,168 +761,29 @@ class IvyGen(bpy.types.Operator):
             description="Grow leaves or not",
             default=True
             )
-    updateIvy = BoolProperty(
-            name="Update Ivy",
-            default=False
-            )
-
-    @classmethod
-    def poll(self, context):
-        # Check if there's an object and whether it's a mesh
-        ob = context.active_object
-        return ((ob is not None) and
-                (ob.type == 'MESH') and
-                (context.mode == 'OBJECT'))
-
-    def invoke(self, context, event):
-        self.updateIvy = True
-        return self.execute(context)
-
-    def execute(self, context):
-        if not self.updateIvy:
-            return {'PASS_THROUGH'}
-
-        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
-        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
-
-        # Get the selected object
-        ob = context.active_object
-
-        # Check if the mesh has at least one polygon since some functions
-        # are expecting them in the object's data (see T51753)
-        check_face = check_mesh_faces(ob)
-        if check_face is False:
-            self.report({'WARNING'},
-                        "Mesh Object doesn't have at least one Face. "
-                        "Operation Cancelled")
-            return {"CANCELLED"}
-
-        # Compute bounding sphere radius
-        # radius = computeBoundingSphere(ob)  # Not needed anymore
-
-        # Get the seeding point
-        seedPoint = context.scene.cursor_location
-
-        # Fix the random seed
-        rand_seed(self.randomSeed)
-
-        # Make the new ivy
-        IVY = Ivy(**self.as_keywords(ignore=('randomSeed', 'growLeaves',
-                                  'maxIvyLength', 'maxTime', 'updateIvy')))
-
-        # Generate first root and node
-        IVY.seed(seedPoint)
-
-        checkTime = False
-        maxLength = self.maxIvyLength  # * radius
-
-        # If we need to check time set the flag
-        if self.maxTime != 0.0:
-            checkTime = True
 
-        t = time.time()
-        startPercent = 0.0
-        checkAliveIter = [True, ]
-
-        # Grow until 200 roots is reached or backup counter exceeds limit
-        while (any(checkAliveIter) and
-               (IVY.maxLength < maxLength) and
-               (not checkTime or (time.time() - t < self.maxTime))):
-            # Grow the ivy for this iteration
-            IVY.grow(ob)
 
-            # Print the proportion of ivy growth to console
-            if (IVY.maxLength / maxLength * 100) > 10 * startPercent // 10:
-                print('%0.2f%% of Ivy nodes have grown' %
-                                         (IVY.maxLength / maxLength * 100))
-                startPercent += 10
-                if IVY.maxLength / maxLength > 1:
-                    print("Halting Growth")
-
-            # Make an iterator to check if all are alive
-            checkAliveIter = (r.alive for r in IVY.ivyRoots)
-
-        # Create the curve and leaf geometry
-        createIvyGeometry(IVY, self.growLeaves)
-        print("Geometry Generation Complete")
-
-        print("Ivy generated in %0.2f s" % (time.time() - t))
-
-        self.updateIvy = False
-
-        return {'FINISHED'}
-
-    def draw(self, context):
-        layout = self.layout
-
-        layout.prop(self, 'updateIvy', icon='CURVE_DATA')
-
-        properties = layout.operator('curve.ivy_gen', text="Add New Ivy")
-        properties.randomSeed = self.randomSeed
-        properties.maxTime = self.maxTime
-        properties.maxIvyLength = self.maxIvyLength
-        properties.ivySize = self.ivySize
-        properties.maxFloatLength = self.maxFloatLength
-        properties.maxAdhesionDistance = self.maxAdhesionDistance
-        properties.primaryWeight = self.primaryWeight
-        properties.randomWeight = self.randomWeight
-        properties.gravityWeight = self.gravityWeight
-        properties.adhesionWeight = self.adhesionWeight
-        properties.branchingProbability = self.branchingProbability
-        properties.leafProbability = self.leafProbability
-        properties.ivyBranchSize = self.ivyBranchSize
-        properties.ivyLeafSize = self.ivyLeafSize
-        properties.updateIvy = True
-
-        prop_def = layout.operator('curve.ivy_gen', text="Add New Default Ivy")
-        prop_def.updateIvy = True
-
-        layout.prop(self, 'growLeaves')
-
-        box = layout.box()
-        box.label("Generation Settings:")
-        box.prop(self, 'randomSeed')
-        box.prop(self, 'maxTime')
-
-        box = layout.box()
-        box.label("Size Settings:")
-        box.prop(self, 'maxIvyLength')
-        box.prop(self, 'ivySize')
-        box.prop(self, 'maxFloatLength')
-        box.prop(self, 'maxAdhesionDistance')
-
-        box = layout.box()
-        box.label("Weight Settings:")
-        box.prop(self, 'primaryWeight')
-        box.prop(self, 'randomWeight')
-        box.prop(self, 'gravityWeight')
-        box.prop(self, 'adhesionWeight')
-
-        box = layout.box()
-        box.label("Branch Settings:")
-        box.prop(self, 'branchingProbability')
-        box.prop(self, 'ivyBranchSize')
-
-        if self.growLeaves:
-            box = layout.box()
-            box.label("Leaf Settings:")
-            box.prop(self, 'ivyLeafSize')
-            box.prop(self, 'leafProbability')
-
-
-def menu_func(self, context):
-    self.layout.operator(IvyGen.bl_idname, text="Add Ivy to Mesh",
-                         icon='OUTLINER_DATA_CURVE').updateIvy = True
+classes = (
+    IvyGen,
+    IvyGenProperties,
+    CURVE_PT_IvyGenPanel
+)
 
 
 def register():
-    bpy.utils.register_module(__name__)
-    bpy.types.INFO_MT_curve_add.append(menu_func)
+    for cls in classes:
+        bpy.utils.register_class(cls)
+
+    bpy.types.WindowManager.ivy_gen_props = PointerProperty(
+            type=IvyGenProperties
+            )
 
 
 def unregister():
-    bpy.types.INFO_MT_curve_add.remove(menu_func)
-    bpy.utils.unregister_module(__name__)
+    del bpy.types.WindowManager.ivy_gen_props
+
+    for cls in reversed(classes):
+        bpy.utils.unregister_class(cls)
 
 
 if __name__ == "__main__":
diff --git a/ant_landscape/add_mesh_ant_landscape.py b/ant_landscape/add_mesh_ant_landscape.py
index 5d25cf2404d322e8c13675e55195de8640973a2b..6a36c42fd4e9e8ce042bf443b56477d33c9bdf09 100644
--- a/ant_landscape/add_mesh_ant_landscape.py
+++ b/ant_landscape/add_mesh_ant_landscape.py
@@ -586,6 +586,14 @@ class AntAddLandscape(bpy.types.Operator):
             description="Automatic refresh"
             )
 
+    @classmethod
+    def poll(self, context):
+        ob = context.object
+        if ob is not None:
+            if ob.mode == 'EDIT':
+                return False
+        return True
+
     def draw(self, context):
         draw_ant_refresh(self, context)
         draw_ant_main(self, context, generate=True)
diff --git a/ant_landscape/ant_functions.py b/ant_landscape/ant_functions.py
index 3b515933282d085e72439b5199c2171c0f123362..3c0f2c34f3cf5e5f75d8b2855fc126d44af3baed 100644
--- a/ant_landscape/ant_functions.py
+++ b/ant_landscape/ant_functions.py
@@ -193,7 +193,10 @@ class AntLandscapeRegenerate(bpy.types.Operator):
 
     @classmethod
     def poll(cls, context):
-        return bpy.context.active_object.ant_landscape
+        ob = bpy.context.active_object
+        if ob.mode == 'EDIT':
+            return False
+        return ob.ant_landscape
 
 
     def execute(self, context):
diff --git a/archipack/archipack_material.py b/archipack/archipack_material.py
index c226c7fbc6d485c8362f358b125bd23f5b2facea..22da496d73604d46a1f515de7f530ea93d636678 100644
--- a/archipack/archipack_material.py
+++ b/archipack/archipack_material.py
@@ -223,6 +223,8 @@ class MaterialSetManager():
             Store sets for each object type
         """
         self.objects = {}
+        # hold reference of dynamic enumerator
+        self.enums = {}
 
     def get_filename(self, object_type):
 
@@ -234,6 +236,7 @@ class MaterialSetManager():
 
     def cleanup(self):
         self.objects.clear()
+        self.enums.clear()
 
     def register_set(self, object_type, set_name, materials_names):
 
@@ -275,16 +278,20 @@ class MaterialSetManager():
             finally:
                 f.close()
 
-            for s_key in material_sets.keys():
+            s_keys = material_sets.keys()
+            for s_key in s_keys:
                 self.register_set(object_type, s_key, material_sets[s_key])
 
+            self.make_enum(object_type, s_keys)
+
     def save(self, object_type):
         # always save in user prefs
         filename = self.get_filename(object_type)
         # print("filename:%s" % filename)
         o_dict = self.objects[object_type]
         lines = []
-        for s_key in o_dict.keys():
+        s_keys = o_dict.keys()
+        for s_key in s_keys:
             for mat in o_dict[s_key]:
                 lines.append("{}##|##{}\n".format(s_key, mat))
         try:
@@ -296,6 +303,8 @@ class MaterialSetManager():
         finally:
             f.close()
 
+        self.make_enum(object_type, s_keys)
+
     def add(self, context, set_name):
         o = context.active_object
         if "archipack_material" in o:
@@ -311,9 +320,11 @@ class MaterialSetManager():
             d = o.archipack_material[0]
             object_type = d.category
             set_name = d.material
-            if set_name in self.objects[object_type].keys():
+            s_keys = self.objects[object_type].keys()
+            if set_name in s_keys:
                 self.objects[object_type].pop(set_name)
                 self.save(object_type)
+            self.make_enum(object_type, s_keys)
 
     def get_materials(self, object_type, set_name):
         if object_type not in self.objects.keys():
@@ -326,7 +337,13 @@ class MaterialSetManager():
             return None
         return self.objects[object_type][set_name]
 
-    def make_enum(self, object_type):
+    def make_enum(self, object_type, s_keys):
+        if len(s_keys) < 1:
+            self.enums[object_type] = [('DEFAULT', 'Default', '', 0)]
+        else:
+            self.enums[object_type] = [(s.upper(), s.capitalize(), '', i) for i, s in enumerate(s_keys)]
+
+    def get_enum(self, object_type):
 
         if object_type not in self.objects.keys():
             self.load(object_type)
@@ -334,19 +351,14 @@ class MaterialSetManager():
         if object_type not in self.objects.keys():
             self.objects[object_type] = {}
 
-        s_keys = self.objects[object_type].keys()
-
-        if len(s_keys) < 1:
-            return [('DEFAULT', 'Default', '', 0)]
-
-        return [(s.upper(), s.capitalize(), '', i) for i, s in enumerate(s_keys)]
+        return self.enums[object_type]
 
 
 def material_enum(self, context):
     global setman
     if setman is None:
         setman = MaterialSetManager()
-    return setman.make_enum(self.category)
+    return setman.get_enum(self.category)
 
 
 def update(self, context):
diff --git a/bone_selection_sets.py b/bone_selection_sets.py
index 46aa7f2524589a45efa09dcbf07f6210781ce316..686eb808a9a6d6f46229c57b34130b7d0ea63e0f 100644
--- a/bone_selection_sets.py
+++ b/bone_selection_sets.py
@@ -18,8 +18,8 @@
 
 bl_info = {
     "name": "Bone Selection Sets",
-    "author": "Inês Almeida, Antony Riakiotakis, Dan Eicher",
-    "version": (2, 0, 1),
+    "author": "Inês Almeida, Sybren A. Stüvel, Antony Riakiotakis, Dan Eicher",
+    "version": (2, 1, 1),
     "blender": (2, 75, 0),
     "location": "Properties > Object Data (Armature) > Selection Sets",
     "description": "List of Bone sets for easy selection while animating",
@@ -31,18 +31,18 @@ bl_info = {
 
 import bpy
 from bpy.types import (
-        Operator,
-        Menu,
-        Panel,
-        UIList,
-        PropertyGroup,
-        )
+    Operator,
+    Menu,
+    Panel,
+    UIList,
+    PropertyGroup,
+)
 from bpy.props import (
-        StringProperty,
-        IntProperty,
-        EnumProperty,
-        CollectionProperty,
-        )
+    StringProperty,
+    IntProperty,
+    EnumProperty,
+    CollectionProperty,
+)
 
 
 # Data Structure ##############################################################
@@ -68,6 +68,8 @@ class POSE_MT_selection_sets_specials(Menu):
 
         layout.operator("pose.selection_set_delete_all", icon='X')
         layout.operator("pose.selection_set_remove_bones", icon='X')
+        layout.operator("pose.selection_set_copy", icon='COPYDOWN')
+        layout.operator("pose.selection_set_paste", icon='PASTEDOWN')
 
 
 class POSE_PT_selection_sets(Panel):
@@ -128,21 +130,35 @@ class POSE_UL_selection_set(UIList):
         layout.prop(set, "name", text="", icon='GROUP_BONE', emboss=False)
 
 
-class POSE_MT_create_new_selection_set(Menu):
-    bl_idname = "POSE_MT_selection_set_create"
+class POSE_MT_selection_set_create(Menu):
     bl_label = "Choose Selection Set"
 
     def draw(self, context):
         layout = self.layout
         layout.operator("pose.selection_set_add_and_assign",
-            text="New Selection Set")
+                        text="New Selection Set")
+
+
+class POSE_MT_selection_sets(Menu):
+    bl_label = 'Select Selection Set'
+
+    @classmethod
+    def poll(cls, context):
+        return POSE_OT_selection_set_select.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+        layout.operator_context = 'EXEC_DEFAULT'
+        for idx, sel_set in enumerate(context.object.selection_sets):
+            props = layout.operator(POSE_OT_selection_set_select.bl_idname, text=sel_set.name)
+            props.selection_set_index = idx
 
 
 # Operators ###################################################################
 
 class PluginOperator(Operator):
     @classmethod
-    def poll(self, context):
+    def poll(cls, context):
         return (context.object and
                 context.object.type == 'ARMATURE' and
                 context.mode == 'POSE')
@@ -150,12 +166,11 @@ class PluginOperator(Operator):
 
 class NeedSelSetPluginOperator(PluginOperator):
     @classmethod
-    def poll(self, context):
-        if super().poll(context):
-            arm = context.object
-            return (arm.active_selection_set < len(arm.selection_sets) and
-                    arm.active_selection_set >= 0)
-        return False
+    def poll(cls, context):
+        if not super().poll(context):
+            return False
+        arm = context.object
+        return 0 <= arm.active_selection_set < len(arm.selection_sets)
 
 
 class POSE_OT_selection_set_delete_all(PluginOperator):
@@ -206,11 +221,11 @@ class POSE_OT_selection_set_move(NeedSelSetPluginOperator):
     )
 
     @classmethod
-    def poll(self, context):
-        if super().poll(context):
-            arm = context.object
-            return len(arm.selection_sets) > 1
-        return False
+    def poll(cls, context):
+        if not super().poll(context):
+            return False
+        arm = context.object
+        return len(arm.selection_sets) > 1
 
     def execute(self, context):
         arm = context.object
@@ -235,30 +250,12 @@ class POSE_OT_selection_set_add(PluginOperator):
 
     def execute(self, context):
         arm = context.object
-
-        new_sel_set = arm.selection_sets.add()
-
-        # naming
-        if "SelectionSet" not in arm.selection_sets:
-            new_sel_set.name = "SelectionSet"
-        else:
-            sorted_sets = []
-            for selset in arm.selection_sets:
-                if selset.name.startswith("SelectionSet."):
-                    index = selset.name[13:]
-                    if index.isdigit():
-                        sorted_sets.append(index)
-            sorted_sets = sorted(sorted_sets)
-            min_index = 1
-            for num in sorted_sets:
-                num = int(num)
-                if min_index < num:
-                    break
-                min_index = num + 1
-            new_sel_set.name = "SelectionSet.{:03d}".format(min_index)
+        sel_sets = arm.selection_sets
+        new_sel_set = sel_sets.add()
+        new_sel_set.name = uniqify("SelectionSet", sel_sets.keys())
 
         # select newly created set
-        arm.active_selection_set = len(arm.selection_sets) - 1
+        arm.active_selection_set = len(sel_sets) - 1
 
         return {'FINISHED'}
 
@@ -293,7 +290,7 @@ class POSE_OT_selection_set_assign(PluginOperator):
 
         if not (arm.active_selection_set < len(arm.selection_sets)):
             bpy.ops.wm.call_menu("INVOKE_DEFAULT",
-                name="POSE_MT_selection_set_create")
+                                 name="POSE_MT_selection_set_create")
         else:
             bpy.ops.pose.selection_set_assign('EXEC_DEFAULT')
 
@@ -337,12 +334,22 @@ class POSE_OT_selection_set_select(NeedSelSetPluginOperator):
     bl_description = "Add Selection Set bones to current selection"
     bl_options = {'UNDO', 'REGISTER'}
 
+    selection_set_index = IntProperty(
+        name='Selection Set Index',
+        default=-1,
+        description='Which Selection Set to select; -1 uses the active Selection Set')
+
     def execute(self, context):
         arm = context.object
-        act_sel_set = arm.selection_sets[arm.active_selection_set]
+
+        if self.selection_set_index == -1:
+            idx = arm.active_selection_set
+        else:
+            idx = self.selection_set_index
+        sel_set = arm.selection_sets[idx]
 
         for bone in context.visible_pose_bones:
-            if bone.name in act_sel_set.bone_ids:
+            if bone.name in sel_set.bone_ids:
                 bone.bone.select = True
 
         return {'FINISHED'}
@@ -377,11 +384,44 @@ class POSE_OT_selection_set_add_and_assign(PluginOperator):
         return {'FINISHED'}
 
 
+class POSE_OT_selection_set_copy(NeedSelSetPluginOperator):
+    bl_idname = "pose.selection_set_copy"
+    bl_label = "Copy Selection Set to Clipboard"
+    bl_description = "Converts the Selection Set to JSON and places it on the clipboard"
+    bl_options = {'UNDO', 'REGISTER'}
+
+    def execute(self, context):
+        context.window_manager.clipboard = to_json(context)
+        self.report({'INFO'}, 'Copied Selection Set to Clipboard')
+        return {'FINISHED'}
+
+
+class POSE_OT_selection_set_paste(PluginOperator):
+    bl_idname = "pose.selection_set_paste"
+    bl_label = "Paste Selection Set from Clipboard"
+    bl_description = "Adds a new Selection Set from copied JSON on the clipboard"
+    bl_options = {'UNDO', 'REGISTER'}
+
+    def execute(self, context):
+        import json
+
+        try:
+            from_json(context, context.window_manager.clipboard)
+        except (json.JSONDecodeError, KeyError):
+            self.report({'ERROR'}, 'The clipboard does not contain a Selection Set')
+        else:
+            # Select the pasted Selection Set.
+            context.object.active_selection_set = len(context.object.selection_sets) - 1
+
+        return {'FINISHED'}
+
+
 # Registry ####################################################################
 
 classes = (
-    POSE_MT_create_new_selection_set,
+    POSE_MT_selection_set_create,
     POSE_MT_selection_sets_specials,
+    POSE_MT_selection_sets,
     POSE_PT_selection_sets,
     POSE_UL_selection_set,
     SelectionEntry,
@@ -396,23 +436,111 @@ classes = (
     POSE_OT_selection_set_select,
     POSE_OT_selection_set_deselect,
     POSE_OT_selection_set_add_and_assign,
+    POSE_OT_selection_set_copy,
+    POSE_OT_selection_set_paste,
 )
 
 
+def add_sss_button(self, context):
+    self.layout.menu('POSE_MT_selection_sets')
+
+
+def to_json(context) -> str:
+    """Convert the active bone selection set of the current rig to JSON."""
+    import json
+
+    arm = context.object
+    active_idx = arm.active_selection_set
+    sel_set = arm.selection_sets[active_idx]
+
+    return json.dumps({
+        'name': sel_set.name,
+        'bones': [bone_id.name for bone_id in sel_set.bone_ids]
+    })
+
+
+def from_json(context, as_json: str):
+    """Add the single bone selection set from JSON to the current rig."""
+    import json
+
+    sel_set = json.loads(as_json)
+
+    sel_sets = context.object.selection_sets
+    new_sel_set = sel_sets.add()
+    new_sel_set.name = uniqify(sel_set['name'], sel_sets.keys())
+
+    for bone_name in sel_set['bones']:
+        bone_id = new_sel_set.bone_ids.add()
+        bone_id.name = bone_name
+
+
+def uniqify(name: str, other_names: list) -> str:
+    """Return a unique name with .xxx suffix if necessary.
+
+    >>> uniqify('hey', ['there'])
+    'hey'
+    >>> uniqify('hey', ['hey.001', 'hey.005'])
+    'hey'
+    >>> uniqify('hey', ['hey', 'hey.001', 'hey.005'])
+    'hey.002'
+    >>> uniqify('hey', ['hey', 'hey.005', 'hey.001'])
+    'hey.002'
+    >>> uniqify('hey', ['hey', 'hey.005', 'hey.001', 'hey.left'])
+    'hey.002'
+    >>> uniqify('hey', ['hey', 'hey.001', 'hey.002'])
+    'hey.003'
+
+    It also works with a dict_keys object:
+    >>> uniqify('hey', {'hey': 1, 'hey.005': 1, 'hey.001': 1}.keys())
+    'hey.002'
+    """
+
+    if name not in other_names:
+        return name
+
+    # Construct the list of numbers already in use.
+    offset = len(name) + 1
+    others = (n[offset:] for n in other_names
+              if n.startswith(name + '.'))
+    numbers = sorted(int(suffix) for suffix in others
+                     if suffix.isdigit())
+
+    # Find the first unused number.
+    min_index = 1
+    for num in numbers:
+        if min_index < num:
+            break
+        min_index = num + 1
+    return "{}.{:03d}".format(name, min_index)
+
+
+# store keymaps here to access after registration
+addon_keymaps = []
+
+
 def register():
     for cls in classes:
         bpy.utils.register_class(cls)
 
     bpy.types.Object.selection_sets = CollectionProperty(
-            type=SelectionSet,
-            name="Selection Sets",
-            description="List of groups of bones for easy selection"
-            )
+        type=SelectionSet,
+        name="Selection Sets",
+        description="List of groups of bones for easy selection"
+    )
     bpy.types.Object.active_selection_set = IntProperty(
-            name="Active Selection Set",
-            description="Index of the currently active selection set",
-            default=0
-            )
+        name="Active Selection Set",
+        description="Index of the currently active selection set",
+        default=0
+    )
+
+    wm = bpy.context.window_manager
+    km = wm.keyconfigs.addon.keymaps.new(name='Pose')
+
+    kmi = km.keymap_items.new('wm.call_menu', 'W', 'PRESS', alt=True, shift=True)
+    kmi.properties.name = 'POSE_MT_selection_sets'
+    addon_keymaps.append((km, kmi))
+
+    bpy.types.VIEW3D_MT_select_pose.append(add_sss_button)
 
 
 def unregister():
@@ -422,6 +550,14 @@ def unregister():
     del bpy.types.Object.selection_sets
     del bpy.types.Object.active_selection_set
 
+    # handle the keymap
+    for km, kmi in addon_keymaps:
+        km.keymap_items.remove(kmi)
+    addon_keymaps.clear()
+
 
 if __name__ == "__main__":
+    import doctest
+
+    doctest.testmod()
     register()
diff --git a/camera_turnaround.py b/camera_turnaround.py
index d1a27e98c2e0952e026106683808591d49c6694a..6a6e710f5efcdd884defaf3e6fcda5862664899e 100644
--- a/camera_turnaround.py
+++ b/camera_turnaround.py
@@ -21,7 +21,7 @@ bl_info = {
     "author": "Antonio Vazquez (antonioya)",
     "version": (0, 2, 5),
     "blender": (2, 68, 0),
-    "location": "View3D > Toolshelf > Turnaround camera",
+    "location": "View3D > Toolshelf > Animation Tab > Turnaround Camera",
     "description": "Add a camera rotation around selected object",
     "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
                 "Scripts/Animation/TurnaroundCamera",
@@ -58,7 +58,7 @@ class RunAction(Operator):
         scene = context.scene
         turn_camera = scene.turn_camera
         selectobject = context.active_object
-        camera = bpy.data.objects[bpy.context.scene.camera.name]
+        camera = context.scene.camera
         savedcursor = bpy.context.scene.cursor_location.copy()  # cursor position
         savedframe = scene.frame_current
         if turn_camera.use_cursor is False:
@@ -68,7 +68,7 @@ class RunAction(Operator):
         # Create empty and parent
         # -------------------------
         bpy.ops.object.empty_add(type='PLAIN_AXES')
-        myempty = bpy.data.objects[bpy.context.active_object.name]
+        myempty = context.active_object
 
         myempty.location = selectobject.location
         savedstate = myempty.matrix_world
@@ -89,7 +89,7 @@ class RunAction(Operator):
         # -------------------------
         bpy.ops.object.select_all(False)
         myempty.select = True
-        bpy.context.scene.objects.active = myempty
+        context.scene.objects.active = myempty
         # save current configuration
         savedinterpolation = context.user_preferences.edit.keyframe_new_interpolation_type
         # change interpolation mode
@@ -97,7 +97,7 @@ class RunAction(Operator):
         # create first frame
         myempty.rotation_euler = (0, 0, 0)
         myempty.empty_draw_size = 0.1
-        bpy.context.scene.frame_set(scene.frame_start)
+        context.scene.frame_set(scene.frame_start)
         myempty.keyframe_insert(data_path='rotation_euler', frame=scene.frame_start)
 
         # Clear the Camera Animations if the option is checked
diff --git a/depsgraph_debug.py b/depsgraph_debug.py
index 9e4c67f017dccaef16ceb3120a37dc429caa10d2..438d48858c49dc61bb3d1133e0b1e7f5f65081d3 100644
--- a/depsgraph_debug.py
+++ b/depsgraph_debug.py
@@ -40,8 +40,8 @@ def _get_depsgraph(context):
     if bpy.app.version < (2, 80, 0,):
         return scene.depsgraph
     else:
-        scene_layer = scene.view_layers.active
-        return scene_layer.depsgraph
+        view_layer = context.view_layer
+        return view_layer.depsgraph
 
 
 ###############################################################################
diff --git a/development_iskeyfree.py b/development_iskeyfree.py
index 0408a648ecfe4ab5a2d800552b428a5253760177..7851afeeaa9d501c7c55942dbaaf30129621003c 100644
--- a/development_iskeyfree.py
+++ b/development_iskeyfree.py
@@ -21,33 +21,33 @@
 bl_info = {
     "name": "Is key Free",
     "author": "Antonio Vazquez (antonioya)",
-    "version": (1, 0, 2),
+    "version": (1, 1, 1),
     "blender": (2, 6, 9),
     "location": "Text Editor > Props Shelf (Ctrl/t > IsKeyFree Tools",
-    "description": "Find free shortcuts and inform of used keys",
+    "description": "Find free shortcuts, inform about used and print a key list",
     "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6"
                 "/Py/Scripts/Development/IsKeyFree",
-    "category": "Development"}
+    "category": "Development"
+}
 
 import bpy
 from bpy.props import (
-        StringProperty,
-        BoolProperty,
-        EnumProperty,
-        PointerProperty,
-        )
+    BoolProperty,
+    EnumProperty,
+    StringProperty,
+    PointerProperty,
+)
 from bpy.types import (
-        Operator,
-        Panel,
-        PropertyGroup,
-        )
+    Operator,
+    Panel,
+    PropertyGroup,
+)
 
 
 # ------------------------------------------------------
 # Class to find keymaps
 # ------------------------------------------------------
 
-
 class MyChecker():
     lastfind = None
     lastkey = None
@@ -191,16 +191,11 @@ mychecker = MyChecker()  # Global class handler
 # ------------------------------------------------------
 # Button: Class for search button
 # ------------------------------------------------------
-
-
 class RunActionCheck(Operator):
     bl_idname = "iskeyfree.action_check"
     bl_label = ""
     bl_description = "Verify if the selected shortcut is free"
 
-    # ------------------------------
-    # Execute
-    # ------------------------------
     # noinspection PyUnusedLocal
     def execute(self, context):
         scene = context.scene.is_keyfree
@@ -239,6 +234,8 @@ class UIControlPanel(Panel):
         row = layout.row()
         row.prop(scene, "numpad")
 
+        layout.operator("iskeyfree.run_export_keys", icon="FILE_TEXT")
+
         global mychecker
         mylist = mychecker.getlist()
         oldcontext = None
@@ -270,8 +267,6 @@ class UIControlPanel(Panel):
 # ------------------------------------------------------
 # Update key (special values) event handler
 # ------------------------------------------------------
-
-
 # noinspection PyUnusedLocal
 def update_data(self, context):
     scene = context.scene.is_keyfree
@@ -281,230 +276,320 @@ def update_data(self, context):
 
 class IskeyFreeProperties(PropertyGroup):
     data = StringProperty(
-                    name="Key", maxlen=32,
-                    description="Shortcut to verify"
-                    )
+        name="Key", maxlen=32,
+        description="Shortcut to verify"
+    )
     use_crtl = BoolProperty(
-                    name="Ctrl",
-                    description="Ctrl key used in shortcut",
-                    default=False
-                    )
+        name="Ctrl",
+        description="Ctrl key used in shortcut",
+        default=False
+    )
     use_alt = BoolProperty(
-                    name="Alt",
-                    description="Alt key used in shortcut",
-                    default=False
-                    )
+        name="Alt",
+        description="Alt key used in shortcut",
+        default=False
+    )
     use_shift = BoolProperty(
-                    name="Shift",
-                    description="Shift key used in shortcut",
-                    default=False
-                    )
+        name="Shift",
+        description="Shift key used in shortcut",
+        default=False
+    )
     use_oskey = BoolProperty(
-                    name="OsKey",
-                    description="Operating system key used in shortcut",
-                    default=False
-                    )
+        name="OsKey",
+        description="Operating system key used in shortcut",
+        default=False
+    )
     numpad = EnumProperty(
-                    items=(('NONE', "Select key", ""),
-                       ("LEFTMOUSE", "LEFTMOUSE", ""),
-                       ("MIDDLEMOUSE", "MIDDLEMOUSE", ""),
-                       ("RIGHTMOUSE", "RIGHTMOUSE", ""),
-                       ("BUTTON4MOUSE", "BUTTON4MOUSE", ""),
-                       ("BUTTON5MOUSE", "BUTTON5MOUSE", ""),
-                       ("BUTTON6MOUSE", "BUTTON6MOUSE", ""),
-                       ("BUTTON7MOUSE", "BUTTON7MOUSE", ""),
-                       ("ACTIONMOUSE", "ACTIONMOUSE", ""),
-                       ("SELECTMOUSE", "SELECTMOUSE", ""),
-                       ("MOUSEMOVE", "MOUSEMOVE", ""),
-                       ("INBETWEEN_MOUSEMOVE", "INBETWEEN_MOUSEMOVE", ""),
-                       ("TRACKPADPAN", "TRACKPADPAN", ""),
-                       ("TRACKPADZOOM", "TRACKPADZOOM", ""),
-                       ("MOUSEROTATE", "MOUSEROTATE", ""),
-                       ("WHEELUPMOUSE", "WHEELUPMOUSE", ""),
-                       ("WHEELDOWNMOUSE", "WHEELDOWNMOUSE", ""),
-                       ("WHEELINMOUSE", "WHEELINMOUSE", ""),
-                       ("WHEELOUTMOUSE", "WHEELOUTMOUSE", ""),
-                       ("EVT_TWEAK_L", "EVT_TWEAK_L", ""),
-                       ("EVT_TWEAK_M", "EVT_TWEAK_M", ""),
-                       ("EVT_TWEAK_R", "EVT_TWEAK_R", ""),
-                       ("EVT_TWEAK_A", "EVT_TWEAK_A", ""),
-                       ("EVT_TWEAK_S", "EVT_TWEAK_S", ""),
-                       ("A", "A", ""),
-                       ("B", "B", ""),
-                       ("C", "C", ""),
-                       ("D", "D", ""),
-                       ("E", "E", ""),
-                       ("F", "F", ""),
-                       ("G", "G", ""),
-                       ("H", "H", ""),
-                       ("I", "I", ""),
-                       ("J", "J", ""),
-                       ("K", "K", ""),
-                       ("L", "L", ""),
-                       ("M", "M", ""),
-                       ("N", "N", ""),
-                       ("O", "O", ""),
-                       ("P", "P", ""),
-                       ("Q", "Q", ""),
-                       ("R", "R", ""),
-                       ("S", "S", ""),
-                       ("T", "T", ""),
-                       ("U", "U", ""),
-                       ("V", "V", ""),
-                       ("W", "W", ""),
-                       ("X", "X", ""),
-                       ("Y", "Y", ""),
-                       ("Z", "Z", ""),
-                       ("ZERO", "ZERO", ""),
-                       ("ONE", "ONE", ""),
-                       ("TWO", "TWO", ""),
-                       ("THREE", "THREE", ""),
-                       ("FOUR", "FOUR", ""),
-                       ("FIVE", "FIVE", ""),
-                       ("SIX", "SIX", ""),
-                       ("SEVEN", "SEVEN", ""),
-                       ("EIGHT", "EIGHT", ""),
-                       ("NINE", "NINE", ""),
-                       ("LEFT_CTRL", "LEFT_CTRL", ""),
-                       ("LEFT_ALT", "LEFT_ALT", ""),
-                       ("LEFT_SHIFT", "LEFT_SHIFT", ""),
-                       ("RIGHT_ALT", "RIGHT_ALT", ""),
-                       ("RIGHT_CTRL", "RIGHT_CTRL", ""),
-                       ("RIGHT_SHIFT", "RIGHT_SHIFT", ""),
-                       ("OSKEY", "OSKEY", ""),
-                       ("GRLESS", "GRLESS", ""),
-                       ("ESC", "ESC", ""),
-                       ("TAB", "TAB", ""),
-                       ("RET", "RET", ""),
-                       ("SPACE", "SPACE", ""),
-                       ("LINE_FEED", "LINE_FEED", ""),
-                       ("BACK_SPACE", "BACK_SPACE", ""),
-                       ("DEL", "DEL", ""),
-                       ("SEMI_COLON", "SEMI_COLON", ""),
-                       ("PERIOD", "PERIOD", ""),
-                       ("COMMA", "COMMA", ""),
-                       ("QUOTE", "QUOTE", ""),
-                       ("ACCENT_GRAVE", "ACCENT_GRAVE", ""),
-                       ("MINUS", "MINUS", ""),
-                       ("SLASH", "SLASH", ""),
-                       ("BACK_SLASH", "BACK_SLASH", ""),
-                       ("EQUAL", "EQUAL", ""),
-                       ("LEFT_BRACKET", "LEFT_BRACKET", ""),
-                       ("RIGHT_BRACKET", "RIGHT_BRACKET", ""),
-                       ("LEFT_ARROW", "LEFT_ARROW", ""),
-                       ("DOWN_ARROW", "DOWN_ARROW", ""),
-                       ("RIGHT_ARROW", "RIGHT_ARROW", ""),
-                       ("UP_ARROW", "UP_ARROW", ""),
-                       ("NUMPAD_1", "NUMPAD_1", ""),
-                       ("NUMPAD_2", "NUMPAD_2", ""),
-                       ("NUMPAD_3", "NUMPAD_3", ""),
-                       ("NUMPAD_4", "NUMPAD_4", ""),
-                       ("NUMPAD_5", "NUMPAD_5", ""),
-                       ("NUMPAD_6", "NUMPAD_6", ""),
-                       ("NUMPAD_7", "NUMPAD_7", ""),
-                       ("NUMPAD_8", "NUMPAD_8", ""),
-                       ("NUMPAD_9", "NUMPAD_9", ""),
-                       ("NUMPAD_0", "NUMPAD_0", ""),
-                       ("NUMPAD_PERIOD", "NUMPAD_PERIOD", ""),
-                       ("NUMPAD_SLASH", "NUMPAD_SLASH", ""),
-                       ("NUMPAD_ASTERIX", "NUMPAD_ASTERIX", ""),
-                       ("NUMPAD_MINUS", "NUMPAD_MINUS", ""),
-                       ("NUMPAD_ENTER", "NUMPAD_ENTER", ""),
-                       ("NUMPAD_PLUS", "NUMPAD_PLUS", ""),
-                       ("F1", "F1", ""),
-                       ("F2", "F2", ""),
-                       ("F3", "F3", ""),
-                       ("F4", "F4", ""),
-                       ("F5", "F5", ""),
-                       ("F6", "F6", ""),
-                       ("F7", "F7", ""),
-                       ("F8", "F8", ""),
-                       ("F9", "F9", ""),
-                       ("F10", "F10", ""),
-                       ("F11", "F11", ""),
-                       ("F12", "F12", ""),
-                       ("F13", "F13", ""),
-                       ("F14", "F14", ""),
-                       ("F15", "F15", ""),
-                       ("F16", "F16", ""),
-                       ("F17", "F17", ""),
-                       ("F18", "F18", ""),
-                       ("F19", "F19", ""),
-                       ("PAUSE", "PAUSE", ""),
-                       ("INSERT", "INSERT", ""),
-                       ("HOME", "HOME", ""),
-                       ("PAGE_UP", "PAGE_UP", ""),
-                       ("PAGE_DOWN", "PAGE_DOWN", ""),
-                       ("END", "END", ""),
-                       ("MEDIA_PLAY", "MEDIA_PLAY", ""),
-                       ("MEDIA_STOP", "MEDIA_STOP", ""),
-                       ("MEDIA_FIRST", "MEDIA_FIRST", ""),
-                       ("MEDIA_LAST", "MEDIA_LAST", ""),
-                       ("TEXTINPUT", "TEXTINPUT", ""),
-                       ("WINDOW_DEACTIVATE", "WINDOW_DEACTIVATE", ""),
-                       ("TIMER", "TIMER", ""),
-                       ("TIMER0", "TIMER0", ""),
-                       ("TIMER1", "TIMER1", ""),
-                       ("TIMER2", "TIMER2", ""),
-                       ("TIMER_JOBS", "TIMER_JOBS", ""),
-                       ("TIMER_AUTOSAVE", "TIMER_AUTOSAVE", ""),
-                       ("TIMER_REPORT", "TIMER_REPORT", ""),
-                       ("TIMERREGION", "TIMERREGION", ""),
-                       ("NDOF_MOTION", "NDOF_MOTION", ""),
-                       ("NDOF_BUTTON_MENU", "NDOF_BUTTON_MENU", ""),
-                       ("NDOF_BUTTON_FIT", "NDOF_BUTTON_FIT", ""),
-                       ("NDOF_BUTTON_TOP", "NDOF_BUTTON_TOP", ""),
-                       ("NDOF_BUTTON_BOTTOM", "NDOF_BUTTON_BOTTOM", ""),
-                       ("NDOF_BUTTON_LEFT", "NDOF_BUTTON_LEFT", ""),
-                       ("NDOF_BUTTON_RIGHT", "NDOF_BUTTON_RIGHT", ""),
-                       ("NDOF_BUTTON_FRONT", "NDOF_BUTTON_FRONT", ""),
-                       ("NDOF_BUTTON_BACK", "NDOF_BUTTON_BACK", ""),
-                       ("NDOF_BUTTON_ISO1", "NDOF_BUTTON_ISO1", ""),
-                       ("NDOF_BUTTON_ISO2", "NDOF_BUTTON_ISO2", ""),
-                       ("NDOF_BUTTON_ROLL_CW", "NDOF_BUTTON_ROLL_CW", ""),
-                       ("NDOF_BUTTON_ROLL_CCW", "NDOF_BUTTON_ROLL_CCW", ""),
-                       ("NDOF_BUTTON_SPIN_CW", "NDOF_BUTTON_SPIN_CW", ""),
-                       ("NDOF_BUTTON_SPIN_CCW", "NDOF_BUTTON_SPIN_CCW", ""),
-                       ("NDOF_BUTTON_TILT_CW", "NDOF_BUTTON_TILT_CW", ""),
-                       ("NDOF_BUTTON_TILT_CCW", "NDOF_BUTTON_TILT_CCW", ""),
-                       ("NDOF_BUTTON_ROTATE", "NDOF_BUTTON_ROTATE", ""),
-                       ("NDOF_BUTTON_PANZOOM", "NDOF_BUTTON_PANZOOM", ""),
-                       ("NDOF_BUTTON_DOMINANT", "NDOF_BUTTON_DOMINANT", ""),
-                       ("NDOF_BUTTON_PLUS", "NDOF_BUTTON_PLUS", ""),
-                       ("NDOF_BUTTON_MINUS", "NDOF_BUTTON_MINUS", ""),
-                       ("NDOF_BUTTON_ESC", "NDOF_BUTTON_ESC", ""),
-                       ("NDOF_BUTTON_ALT", "NDOF_BUTTON_ALT", ""),
-                       ("NDOF_BUTTON_SHIFT", "NDOF_BUTTON_SHIFT", ""),
-                       ("NDOF_BUTTON_CTRL", "NDOF_BUTTON_CTRL", ""),
-                       ("NDOF_BUTTON_1", "NDOF_BUTTON_1", ""),
-                       ("NDOF_BUTTON_2", "NDOF_BUTTON_2", ""),
-                       ("NDOF_BUTTON_3", "NDOF_BUTTON_3", ""),
-                       ("NDOF_BUTTON_4", "NDOF_BUTTON_4", ""),
-                       ("NDOF_BUTTON_5", "NDOF_BUTTON_5", ""),
-                       ("NDOF_BUTTON_6", "NDOF_BUTTON_6", ""),
-                       ("NDOF_BUTTON_7", "NDOF_BUTTON_7", ""),
-                       ("NDOF_BUTTON_8", "NDOF_BUTTON_8", ""),
-                       ("NDOF_BUTTON_9", "NDOF_BUTTON_9", ""),
-                       ("NDOF_BUTTON_10", "NDOF_BUTTON_10", ""),
-                       ("NDOF_BUTTON_A", "NDOF_BUTTON_A", ""),
-                       ("NDOF_BUTTON_B", "NDOF_BUTTON_B", ""),
-                       ("NDOF_BUTTON_C", "NDOF_BUTTON_C", "")
-                    ),
-                    name="Quick Type",
-                    description="Enter key code in find text",
-                    update=update_data
-                    )
+        items=(
+            ('NONE', "Select key", ""),
+            ("LEFTMOUSE", "LEFTMOUSE", ""),
+            ("MIDDLEMOUSE", "MIDDLEMOUSE", ""),
+            ("RIGHTMOUSE", "RIGHTMOUSE", ""),
+            ("BUTTON4MOUSE", "BUTTON4MOUSE", ""),
+            ("BUTTON5MOUSE", "BUTTON5MOUSE", ""),
+            ("BUTTON6MOUSE", "BUTTON6MOUSE", ""),
+            ("BUTTON7MOUSE", "BUTTON7MOUSE", ""),
+            ("ACTIONMOUSE", "ACTIONMOUSE", ""),
+            ("SELECTMOUSE", "SELECTMOUSE", ""),
+            ("MOUSEMOVE", "MOUSEMOVE", ""),
+            ("INBETWEEN_MOUSEMOVE", "INBETWEEN_MOUSEMOVE", ""),
+            ("TRACKPADPAN", "TRACKPADPAN", ""),
+            ("TRACKPADZOOM", "TRACKPADZOOM", ""),
+            ("MOUSEROTATE", "MOUSEROTATE", ""),
+            ("WHEELUPMOUSE", "WHEELUPMOUSE", ""),
+            ("WHEELDOWNMOUSE", "WHEELDOWNMOUSE", ""),
+            ("WHEELINMOUSE", "WHEELINMOUSE", ""),
+            ("WHEELOUTMOUSE", "WHEELOUTMOUSE", ""),
+            ("EVT_TWEAK_L", "EVT_TWEAK_L", ""),
+            ("EVT_TWEAK_M", "EVT_TWEAK_M", ""),
+            ("EVT_TWEAK_R", "EVT_TWEAK_R", ""),
+            ("EVT_TWEAK_A", "EVT_TWEAK_A", ""),
+            ("EVT_TWEAK_S", "EVT_TWEAK_S", ""),
+            ("A", "A", ""),
+            ("B", "B", ""),
+            ("C", "C", ""),
+            ("D", "D", ""),
+            ("E", "E", ""),
+            ("F", "F", ""),
+            ("G", "G", ""),
+            ("H", "H", ""),
+            ("I", "I", ""),
+            ("J", "J", ""),
+            ("K", "K", ""),
+            ("L", "L", ""),
+            ("M", "M", ""),
+            ("N", "N", ""),
+            ("O", "O", ""),
+            ("P", "P", ""),
+            ("Q", "Q", ""),
+            ("R", "R", ""),
+            ("S", "S", ""),
+            ("T", "T", ""),
+            ("U", "U", ""),
+            ("V", "V", ""),
+            ("W", "W", ""),
+            ("X", "X", ""),
+            ("Y", "Y", ""),
+            ("Z", "Z", ""),
+            ("ZERO", "ZERO", ""),
+            ("ONE", "ONE", ""),
+            ("TWO", "TWO", ""),
+            ("THREE", "THREE", ""),
+            ("FOUR", "FOUR", ""),
+            ("FIVE", "FIVE", ""),
+            ("SIX", "SIX", ""),
+            ("SEVEN", "SEVEN", ""),
+            ("EIGHT", "EIGHT", ""),
+            ("NINE", "NINE", ""),
+            ("LEFT_CTRL", "LEFT_CTRL", ""),
+            ("LEFT_ALT", "LEFT_ALT", ""),
+            ("LEFT_SHIFT", "LEFT_SHIFT", ""),
+            ("RIGHT_ALT", "RIGHT_ALT", ""),
+            ("RIGHT_CTRL", "RIGHT_CTRL", ""),
+            ("RIGHT_SHIFT", "RIGHT_SHIFT", ""),
+            ("OSKEY", "OSKEY", ""),
+            ("GRLESS", "GRLESS", ""),
+            ("ESC", "ESC", ""),
+            ("TAB", "TAB", ""),
+            ("RET", "RET", ""),
+            ("SPACE", "SPACE", ""),
+            ("LINE_FEED", "LINE_FEED", ""),
+            ("BACK_SPACE", "BACK_SPACE", ""),
+            ("DEL", "DEL", ""),
+            ("SEMI_COLON", "SEMI_COLON", ""),
+            ("PERIOD", "PERIOD", ""),
+            ("COMMA", "COMMA", ""),
+            ("QUOTE", "QUOTE", ""),
+            ("ACCENT_GRAVE", "ACCENT_GRAVE", ""),
+            ("MINUS", "MINUS", ""),
+            ("SLASH", "SLASH", ""),
+            ("BACK_SLASH", "BACK_SLASH", ""),
+            ("EQUAL", "EQUAL", ""),
+            ("LEFT_BRACKET", "LEFT_BRACKET", ""),
+            ("RIGHT_BRACKET", "RIGHT_BRACKET", ""),
+            ("LEFT_ARROW", "LEFT_ARROW", ""),
+            ("DOWN_ARROW", "DOWN_ARROW", ""),
+            ("RIGHT_ARROW", "RIGHT_ARROW", ""),
+            ("UP_ARROW", "UP_ARROW", ""),
+            ("NUMPAD_1", "NUMPAD_1", ""),
+            ("NUMPAD_2", "NUMPAD_2", ""),
+            ("NUMPAD_3", "NUMPAD_3", ""),
+            ("NUMPAD_4", "NUMPAD_4", ""),
+            ("NUMPAD_5", "NUMPAD_5", ""),
+            ("NUMPAD_6", "NUMPAD_6", ""),
+            ("NUMPAD_7", "NUMPAD_7", ""),
+            ("NUMPAD_8", "NUMPAD_8", ""),
+            ("NUMPAD_9", "NUMPAD_9", ""),
+            ("NUMPAD_0", "NUMPAD_0", ""),
+            ("NUMPAD_PERIOD", "NUMPAD_PERIOD", ""),
+            ("NUMPAD_SLASH", "NUMPAD_SLASH", ""),
+            ("NUMPAD_ASTERIX", "NUMPAD_ASTERIX", ""),
+            ("NUMPAD_MINUS", "NUMPAD_MINUS", ""),
+            ("NUMPAD_ENTER", "NUMPAD_ENTER", ""),
+            ("NUMPAD_PLUS", "NUMPAD_PLUS", ""),
+            ("F1", "F1", ""),
+            ("F2", "F2", ""),
+            ("F3", "F3", ""),
+            ("F4", "F4", ""),
+            ("F5", "F5", ""),
+            ("F6", "F6", ""),
+            ("F7", "F7", ""),
+            ("F8", "F8", ""),
+            ("F9", "F9", ""),
+            ("F10", "F10", ""),
+            ("F11", "F11", ""),
+            ("F12", "F12", ""),
+            ("F13", "F13", ""),
+            ("F14", "F14", ""),
+            ("F15", "F15", ""),
+            ("F16", "F16", ""),
+            ("F17", "F17", ""),
+            ("F18", "F18", ""),
+            ("F19", "F19", ""),
+            ("PAUSE", "PAUSE", ""),
+            ("INSERT", "INSERT", ""),
+            ("HOME", "HOME", ""),
+            ("PAGE_UP", "PAGE_UP", ""),
+            ("PAGE_DOWN", "PAGE_DOWN", ""),
+            ("END", "END", ""),
+            ("MEDIA_PLAY", "MEDIA_PLAY", ""),
+            ("MEDIA_STOP", "MEDIA_STOP", ""),
+            ("MEDIA_FIRST", "MEDIA_FIRST", ""),
+            ("MEDIA_LAST", "MEDIA_LAST", ""),
+            ("TEXTINPUT", "TEXTINPUT", ""),
+            ("WINDOW_DEACTIVATE", "WINDOW_DEACTIVATE", ""),
+            ("TIMER", "TIMER", ""),
+            ("TIMER0", "TIMER0", ""),
+            ("TIMER1", "TIMER1", ""),
+            ("TIMER2", "TIMER2", ""),
+            ("TIMER_JOBS", "TIMER_JOBS", ""),
+            ("TIMER_AUTOSAVE", "TIMER_AUTOSAVE", ""),
+            ("TIMER_REPORT", "TIMER_REPORT", ""),
+            ("TIMERREGION", "TIMERREGION", ""),
+            ("NDOF_MOTION", "NDOF_MOTION", ""),
+            ("NDOF_BUTTON_MENU", "NDOF_BUTTON_MENU", ""),
+            ("NDOF_BUTTON_FIT", "NDOF_BUTTON_FIT", ""),
+            ("NDOF_BUTTON_TOP", "NDOF_BUTTON_TOP", ""),
+            ("NDOF_BUTTON_BOTTOM", "NDOF_BUTTON_BOTTOM", ""),
+            ("NDOF_BUTTON_LEFT", "NDOF_BUTTON_LEFT", ""),
+            ("NDOF_BUTTON_RIGHT", "NDOF_BUTTON_RIGHT", ""),
+            ("NDOF_BUTTON_FRONT", "NDOF_BUTTON_FRONT", ""),
+            ("NDOF_BUTTON_BACK", "NDOF_BUTTON_BACK", ""),
+            ("NDOF_BUTTON_ISO1", "NDOF_BUTTON_ISO1", ""),
+            ("NDOF_BUTTON_ISO2", "NDOF_BUTTON_ISO2", ""),
+            ("NDOF_BUTTON_ROLL_CW", "NDOF_BUTTON_ROLL_CW", ""),
+            ("NDOF_BUTTON_ROLL_CCW", "NDOF_BUTTON_ROLL_CCW", ""),
+            ("NDOF_BUTTON_SPIN_CW", "NDOF_BUTTON_SPIN_CW", ""),
+            ("NDOF_BUTTON_SPIN_CCW", "NDOF_BUTTON_SPIN_CCW", ""),
+            ("NDOF_BUTTON_TILT_CW", "NDOF_BUTTON_TILT_CW", ""),
+            ("NDOF_BUTTON_TILT_CCW", "NDOF_BUTTON_TILT_CCW", ""),
+            ("NDOF_BUTTON_ROTATE", "NDOF_BUTTON_ROTATE", ""),
+            ("NDOF_BUTTON_PANZOOM", "NDOF_BUTTON_PANZOOM", ""),
+            ("NDOF_BUTTON_DOMINANT", "NDOF_BUTTON_DOMINANT", ""),
+            ("NDOF_BUTTON_PLUS", "NDOF_BUTTON_PLUS", ""),
+            ("NDOF_BUTTON_MINUS", "NDOF_BUTTON_MINUS", ""),
+            ("NDOF_BUTTON_ESC", "NDOF_BUTTON_ESC", ""),
+            ("NDOF_BUTTON_ALT", "NDOF_BUTTON_ALT", ""),
+            ("NDOF_BUTTON_SHIFT", "NDOF_BUTTON_SHIFT", ""),
+            ("NDOF_BUTTON_CTRL", "NDOF_BUTTON_CTRL", ""),
+            ("NDOF_BUTTON_1", "NDOF_BUTTON_1", ""),
+            ("NDOF_BUTTON_2", "NDOF_BUTTON_2", ""),
+            ("NDOF_BUTTON_3", "NDOF_BUTTON_3", ""),
+            ("NDOF_BUTTON_4", "NDOF_BUTTON_4", ""),
+            ("NDOF_BUTTON_5", "NDOF_BUTTON_5", ""),
+            ("NDOF_BUTTON_6", "NDOF_BUTTON_6", ""),
+            ("NDOF_BUTTON_7", "NDOF_BUTTON_7", ""),
+            ("NDOF_BUTTON_8", "NDOF_BUTTON_8", ""),
+            ("NDOF_BUTTON_9", "NDOF_BUTTON_9", ""),
+            ("NDOF_BUTTON_10", "NDOF_BUTTON_10", ""),
+            ("NDOF_BUTTON_A", "NDOF_BUTTON_A", ""),
+            ("NDOF_BUTTON_B", "NDOF_BUTTON_B", ""),
+            ("NDOF_BUTTON_C", "NDOF_BUTTON_C", "")
+        ),
+        name="Quick Type",
+        description="Enter key code in find text",
+        update=update_data
+    )
+
+
+class IsKeyFreeRunExportKeys(Operator):
+    bl_idname = "iskeyfree.run_export_keys"
+    bl_label = "List all Shortcuts"
+    bl_description = ("List all existing shortcuts in a text block\n"
+                      "The newly generated list will be made active in the Text Editor\n"
+                      "To access the previous ones, select them from the Header dropdown")
+
+    def all_shortcuts_name(self, context):
+        new_name, def_name, ext = "", "All_Shortcuts", ".txt"
+        suffix = 1
+        try:
+            # first slap a simple linear count + 1 for numeric suffix, if it fails
+            # harvest for the rightmost numbers and append the max value
+            list_txt = []
+            data_txt = bpy.data.texts
+            list_txt = [txt.name for txt in data_txt if txt.name.startswith("All_Shortcuts")]
+            new_name = "{}_{}{}".format(def_name, len(list_txt) + 1, ext)
+
+            if new_name in list_txt:
+                from re import findall
+                test_num = [findall("\d+", words) for words in list_txt]
+                suffix += max([int(l[-1]) for l in test_num])
+                new_name = "{}_{}{}".format(def_name, suffix, ext)
+            return new_name
+        except:
+            return None
+
+    def execute(self, context):
+        wm = bpy.context.window_manager
+        from collections import defaultdict
+        mykeys = defaultdict(list)
+        file_name = self.all_shortcuts_name(context) or "All_Shortcut.txt"
+        start_note = "# Note: Some of the shortcuts entries don't have a name. Mostly Modal stuff\n"
+        col_width, col_shortcuts = 2, 2
+
+        for ctx_type, keyboardmap in wm.keyconfigs.user.keymaps.items():
+            for myitem in keyboardmap.keymap_items:
+                padding = len(myitem.name)
+                col_width = padding + 2 if padding > col_width else col_width
+
+                short_type = myitem.type if myitem.type else "UNKNOWN"
+                is_ctrl = " Ctrl" if myitem.ctrl is True else ""
+                is_alt = " Alt" if myitem.alt is True else ""
+                is_shift = " Shift" if myitem.shift is True else ""
+                is_oskey = " OsKey" if myitem.oskey is True else ""
+                short_cuts = "{}{}{}{}{}".format(short_type, is_ctrl, is_alt, is_shift, is_oskey)
+
+                t = (
+                    myitem.name if myitem.name else "No Name",
+                    short_cuts,
+                )
+                mykeys[ctx_type].append(t)
+                padding_s = len(short_cuts) + 2
+                col_shortcuts = padding_s if padding_s > col_shortcuts else col_shortcuts
+
+        max_line = col_shortcuts + col_width + 4
+        textblock = bpy.data.texts.new(file_name)
+        total = sum([len(mykeys[ctxs]) for ctxs in mykeys])
+        textblock.write('# %d Total Shortcuts\n\n' % total)
+        textblock.write(start_note)
+
+        for ctx in mykeys:
+            textblock.write("\n[%s]\nEntries: %s\n\n" % (ctx, len(mykeys[ctx])))
+            line_k = sorted(mykeys[ctx])
+            for keys in line_k:
+                add_ticks = "-" * (max_line - (len(keys[0]) + len(keys[1])))
+                entries = "{ticks} {entry}".format(ticks=add_ticks, entry=keys[1])
+                textblock.write("{name} {entry}\n".format(name=keys[0], entry=entries))
+
+            textblock.write("\n\n")
+
+        # try to set the created text block to active
+        if context.area.type in {"TEXT_EDITOR"}:
+            bpy.context.space_data.text = bpy.data.texts[file_name]
+
+        self.report({'INFO'}, "See %s textblock" % file_name)
+
+        return {"FINISHED"}
 
 
 # -----------------------------------------------------
 # Registration
 # ------------------------------------------------------
+classes = (
+    IskeyFreeProperties,
+    RunActionCheck,
+    UIControlPanel,
+    IsKeyFreeRunExportKeys,
+)
+
 
 def register():
-    bpy.utils.register_module(__name__)
+    for cls in classes:
+        bpy.utils.register_class(cls)
     bpy.types.Scene.is_keyfree = PointerProperty(type=IskeyFreeProperties)
 
 
 def unregister():
-    bpy.utils.unregister_module(__name__)
+    for cls in classes:
+        bpy.utils.unregister_class(cls)
     del bpy.types.Scene.is_keyfree
diff --git a/development_ui_classes.py b/development_ui_classes.py
index 18b692f42358096e42f344a99f75dbd764ba65e0..f03b7bb50b8a9737f7a40f3e545ab94c31262570 100644
--- a/development_ui_classes.py
+++ b/development_ui_classes.py
@@ -21,7 +21,7 @@
 bl_info = {
     "name": "UI Classes Overview",
     "author": "lijenstina",
-    "version": (1, 0, 1),
+    "version": (1, 0, 2),
     "blender": (2, 78, 0),
     "location": "Text Editor > Properties",
     "description": "Print the UI classes in a text-block",
@@ -33,15 +33,15 @@ bl_info = {
 
 import bpy
 from bpy.types import (
-        Operator,
-        Panel,
-        PropertyGroup,
-        )
+    Operator,
+    Panel,
+    PropertyGroup,
+)
 from bpy.props import (
-        BoolProperty,
-        EnumProperty,
-        PointerProperty,
-        )
+    BoolProperty,
+    EnumProperty,
+    PointerProperty,
+)
 
 
 class TEXT_PT_ui_cheat_sheet(Panel):
@@ -128,7 +128,10 @@ class TEXT_OT_ui_cheat_sheet(Operator):
                 textblock.write(('\n' if not searchable else '').join(sorted(op_string_ui[cls_name])))
                 textblock.write(close_line)
 
-            context.space_data.text = bpy.data.texts[file_name]
+            # try to set the created text block to active
+            if context.area.type in {"TEXT_EDITOR"}:
+                bpy.context.space_data.text = bpy.data.texts[file_name]
+
             self.report({'INFO'}, "See %s textblock" % file_name)
 
             return {'FINISHED'}
@@ -152,21 +155,21 @@ class text_ui_cheat_props(PropertyGroup):
                ('Header', "Headers", "Print Header UI types"),
                ),
         default='all',
-        )
+    )
     searchable = BoolProperty(
         name="Format searchable",
         description="Generate the list as Python dictionary,\n"
                     "using the format Class: Path",
         default=False
-        )
+    )
 
 
 # Register
 classes = (
-        TEXT_OT_ui_cheat_sheet,
-        TEXT_PT_ui_cheat_sheet,
-        text_ui_cheat_props
-        )
+    TEXT_OT_ui_cheat_sheet,
+    TEXT_PT_ui_cheat_sheet,
+    text_ui_cheat_props
+)
 
 
 def register():
diff --git a/io_export_after_effects.py b/io_export_after_effects.py
index aafa8ecbb429435508b1b444740e397c00885a29..4a5c6b9282bb90ef6c72baacce6a5407f8fdb518 100644
--- a/io_export_after_effects.py
+++ b/io_export_after_effects.py
@@ -23,8 +23,8 @@ bl_info = {
     "description": "Export cameras, selected objects & camera solution "
         "3D Markers to Adobe After Effects CS3 and above",
     "author": "Bartek Skorupa",
-    "version": (0, 64),
-    "blender": (2, 69, 0),
+    "version": (0, 65),
+    "blender": (2, 79, 0),
     "location": "File > Export > Adobe After Effects (.jsx)",
     "warning": "",
     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
@@ -150,7 +150,7 @@ def convert_name(name):
 
 # get object's blender's location rotation and scale and return AE's Position, Rotation/Orientation and scale
 # this function will be called for every object for every frame
-def convert_transform_matrix(matrix, width, height, aspect, x_rot_correction=False):
+def convert_transform_matrix(matrix, width, height, aspect, x_rot_correction=False, ae_size=100.0):
 
     # get blender transform data for ob
     b_loc = matrix.to_translation()
@@ -159,9 +159,9 @@ def convert_transform_matrix(matrix, width, height, aspect, x_rot_correction=Fal
 
     # convert to AE Position Rotation and Scale
     # Axes in AE are different. AE's X is blender's X, AE's Y is negative Blender's Z, AE's Z is Blender's Y
-    x = (b_loc.x * 100.0) / aspect + width / 2.0  # calculate AE's X position
-    y = (-b_loc.z * 100.0) + (height / 2.0)  # calculate AE's Y position
-    z = b_loc.y * 100.0  # calculate AE's Z position
+    x = (b_loc.x * ae_size) / aspect + width / 2.0  # calculate AE's X position
+    y = (-b_loc.z * ae_size) + (height / 2.0)  # calculate AE's Y position
+    z = b_loc.y * ae_size  # calculate AE's Z position
     # Convert rotations to match AE's orientation.
     rx = degrees(b_rot.x)  # if not x_rot_correction - AE's X orientation = blender's X rotation if 'ZYX' euler.
     ry = -degrees(b_rot.y)  # AE's Y orientation is negative blender's Y rotation if 'ZYX' euler
@@ -240,7 +240,7 @@ def convert_lens(camera, width, height, aspect):
 
 
 # jsx script for AE creation
-def write_jsx_file(file, data, selection, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles):
+def write_jsx_file(file, data, selection, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles, ae_size):
 
     print("\n---------------------------\n- Export to After Effects -\n---------------------------")
     # store the current frame to restore it at the end of export
@@ -382,7 +382,7 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
                             # bundles are in camera space. Transpose to world space
                             matrix = Matrix.Translation(cam.matrix_basis.copy() * track.bundle)
                             # convert the position into AE space
-                            ae_transform = convert_transform_matrix(matrix, data['width'], data['height'], data['aspect'], x_rot_correction=False)
+                            ae_transform = convert_transform_matrix(matrix, data['width'], data['height'], data['aspect'], False, ae_size)
                             js_data['bundles_cam'][name_ae]['position'] += '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2])
 
     # get all keyframes for each object and store in dico
@@ -407,7 +407,7 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
             # get cam name
             name_ae = active_cam_name
             # convert cam transform properties to AE space
-            ae_transform = convert_transform_matrix(active_cam.matrix_world.copy(), data['width'], data['height'], data['aspect'], x_rot_correction=True)
+            ae_transform = convert_transform_matrix(active_cam.matrix_world.copy(), data['width'], data['height'], data['aspect'], True, ae_size)
             # convert Blender's lens to AE's zoom in pixels
             zoom = convert_lens(active_cam, data['width'], data['height'], data['aspect'])
             # store all values in dico
@@ -437,7 +437,7 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
                     # get cam name
                     name_ae = selection['cameras'][i][1]
                     # convert cam transform properties to AE space
-                    ae_transform = convert_transform_matrix(cam[0].matrix_world.copy(), data['width'], data['height'], data['aspect'], x_rot_correction=True)
+                    ae_transform = convert_transform_matrix(cam[0].matrix_world.copy(), data['width'], data['height'], data['aspect'], True, ae_size)
                     # convert Blender's lens to AE's zoom in pixels
                     zoom = convert_lens(cam[0], data['width'], data['height'], data['aspect'])
                     # store all values in dico
@@ -475,7 +475,7 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
                 name_ae = selection['lights'][i][1]
                 type = selection['lights'][i][0].data.type
                 # convert ob transform properties to AE space
-                ae_transform = convert_transform_matrix(ob[0].matrix_world.copy(), data['width'], data['height'], data['aspect'], x_rot_correction=True)
+                ae_transform = convert_transform_matrix(ob[0].matrix_world.copy(), data['width'], data['height'], data['aspect'], True, ae_size)
                 color = ob[0].data.color
                 # store all values in dico
                 position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2])
@@ -522,7 +522,7 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
                 # get object name
                 name_ae = selection['nulls'][i][1]
                 # convert ob transform properties to AE space
-                ae_transform = convert_transform_matrix(ob[0].matrix_world.copy(), data['width'], data['height'], data['aspect'], x_rot_correction=True)
+                ae_transform = convert_transform_matrix(ob[0].matrix_world.copy(), data['width'], data['height'], data['aspect'], True, ae_size)
                 # store all values in dico
                 position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2])
                 orientation = '[%f,%f,%f],' % (ae_transform[3], ae_transform[4], ae_transform[5])
@@ -676,10 +676,10 @@ def write_jsx_file(file, data, selection, include_animation, include_active_cam,
 ##########################################
 
 
-def main(file, context, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles):
+def main(file, context, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles, ae_size):
     data = get_comp_data(context)
     selection = get_selected(context)
-    write_jsx_file(file, data, selection, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles)
+    write_jsx_file(file, data, selection, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles, ae_size)
     print ("\nExport to After Effects Completed")
     return {'FINISHED'}
 
@@ -688,7 +688,7 @@ def main(file, context, include_animation, include_active_cam, include_selected_
 ##########################################
 
 from bpy_extras.io_utils import ExportHelper
-from bpy.props import StringProperty, BoolProperty
+from bpy.props import StringProperty, BoolProperty, FloatProperty
 
 
 class ExportJsx(bpy.types.Operator, ExportHelper):
@@ -728,11 +728,18 @@ class ExportJsx(bpy.types.Operator, ExportHelper):
 #            description="Include 3D Markers of Object Motion Solution for selected cameras",
 #            default=True,
 #            )
+    ae_size = FloatProperty(
+            name="AE Size",
+            description="Size of AE Composition (pixels per 1BU)",
+            default=100.0,
+            )
 
     def draw(self, context):
         layout = self.layout
 
         box = layout.box()
+        box.label('Size fo AE Comp (pixels per 1 BU)')
+        box.prop(self, 'ae_size')
         box.label('Animation:')
         box.prop(self, 'include_animation')
         box.label('Include Cameras and Objects:')
@@ -752,7 +759,7 @@ class ExportJsx(bpy.types.Operator, ExportHelper):
         return ok
 
     def execute(self, context):
-        return main(self.filepath, context, self.include_animation, self.include_active_cam, self.include_selected_cams, self.include_selected_objects, self.include_cam_bundles)
+        return main(self.filepath, context, self.include_animation, self.include_active_cam, self.include_selected_cams, self.include_selected_objects, self.include_cam_bundles, self.ae_size)
 
 
 def menu_func(self, context):
diff --git a/io_scene_fbx/__init__.py b/io_scene_fbx/__init__.py
index 943df0b43a3a5db1af9966be45af6b13edccc102..9611cb1f2600fa3c84c2dde7747b8a22a4f7d468 100644
--- a/io_scene_fbx/__init__.py
+++ b/io_scene_fbx/__init__.py
@@ -21,7 +21,7 @@
 bl_info = {
     "name": "FBX format",
     "author": "Campbell Barton, Bastien Montagne, Jens Restemeier",
-    "version": (3, 8, 4),
+    "version": (3, 9, 1),
     "blender": (2, 79, 1),
     "location": "File > Import-Export",
     "description": "FBX IO meshes, UV's, vertex colors, materials, textures, cameras, lamps and actions",
diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py
index 58bd4586b5f9594a1222ae96fd208f7ea03a6e32..b75a8977cb759357798a6947b6e4a325963956fc 100644
--- a/io_scene_fbx/export_fbx_bin.py
+++ b/io_scene_fbx/export_fbx_bin.py
@@ -1896,8 +1896,9 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No
                                ACNW(ob_obj.key, 'LCL_SCALING', force_key, force_sek, scale))
         p_rots[ob_obj] = rot
 
-    animdata_shapes = OrderedDict()
     force_key = (simplify_fac == 0.0)
+
+    animdata_shapes = OrderedDict()
     for me, (me_key, _shapes_key, shapes) in scene_data.data_deformers_shape.items():
         # Ignore absolute shape keys for now!
         if not me.shape_keys.use_relative:
@@ -1908,6 +1909,12 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No
             acnode.add_group(me_key, shape.name, shape.name, (shape.name,))
             animdata_shapes[channel_key] = (acnode, me, shape)
 
+    animdata_cameras = OrderedDict()
+    for cam_obj, cam_key in scene_data.data_cameras.items():
+        cam = cam_obj.bdata.data
+        acnode = AnimationCurveNodeWrapper(cam_key, 'CAMERA_FOCAL', force_key, force_sek, (cam.lens,))
+        animdata_cameras[cam_key] = (acnode, cam)
+
     currframe = f_start
     while currframe <= f_end:
         real_currframe = currframe - f_start if start_zero else currframe
@@ -1927,6 +1934,8 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No
             ob_obj.dupli_list_clear()
         for anim_shape, me, shape in animdata_shapes.values():
             anim_shape.add_keyframe(real_currframe, (shape.value * 100.0,))
+        for anim_camera, camera in animdata_cameras.values():
+            anim_camera.add_keyframe(real_currframe, (camera.lens,))
         currframe += bake_step
 
     scene.frame_set(back_currframe, 0.0)
@@ -1958,6 +1967,18 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No
                     anim_data = animations[elem_key] = ("dummy_unused_key", OrderedDict())
                 anim_data[1][fbx_group] = (group_key, group, fbx_gname)
 
+    # And cameras' lens keys.
+    for cam_key, (anim_camera, camera) in animdata_cameras.items():
+        final_keys = OrderedDict()
+        anim_camera.simplify(simplify_fac, bake_step, force_keep)
+        if not anim_camera:
+            continue
+        for elem_key, group_key, group, fbx_group, fbx_gname in anim_camera.get_final_data(scene, ref_id, force_keep):
+                anim_data = animations.get(elem_key)
+                if anim_data is None:
+                    anim_data = animations[elem_key] = ("dummy_unused_key", OrderedDict())
+                anim_data[1][fbx_group] = (group_key, group, fbx_gname)
+
     astack_key = get_blender_anim_stack_key(scene, ref_id)
     alayer_key = get_blender_anim_layer_key(scene, ref_id)
     name = (get_blenderID_name(ref_id) if ref_id else scene.name).encode()
@@ -2194,8 +2215,11 @@ def fbx_data_from_scene(scene, settings):
                     if mod.show_render:
                         use_org_data = False
             if not use_org_data:
-                tmp_me = ob.to_mesh(scene, apply_modifiers=True,
-                                    settings='RENDER' if settings.use_mesh_modifiers_render else 'PREVIEW')
+                tmp_me = ob.to_mesh(
+                    scene,
+                    apply_modifiers=settings.use_mesh_modifiers,
+                    settings='RENDER' if settings.use_mesh_modifiers_render else 'PREVIEW',
+                )
                 data_meshes[ob_obj] = (get_blenderID_key(tmp_me), tmp_me, True)
             # Re-enable temporary disabled modifiers.
             for mod, show_render in tmp_mods:
diff --git a/io_scene_fbx/fbx_utils.py b/io_scene_fbx/fbx_utils.py
index 16a8256f3dd2f86ab367cf03819260484662b5a4..82e17fe2e03919e691c57f930f2c5e83501ad90e 100644
--- a/io_scene_fbx/fbx_utils.py
+++ b/io_scene_fbx/fbx_utils.py
@@ -94,6 +94,7 @@ FBX_LIGHT_DECAY_TYPES = {
     'CONSTANT': 0,                   # None.
     'INVERSE_LINEAR': 1,             # Linear.
     'INVERSE_SQUARE': 2,             # Quadratic.
+    'INVERSE_COEFFICIENTS': 2,       # Quadratic...
     'CUSTOM_CURVE': 2,               # Quadratic.
     'LINEAR_QUADRATIC_WEIGHTED': 2,  # Quadratic.
 }
@@ -728,6 +729,7 @@ class AnimationCurveNodeWrapper:
         'LCL_ROTATION': ("Lcl Rotation", "R", ("X", "Y", "Z")),
         'LCL_SCALING': ("Lcl Scaling", "S", ("X", "Y", "Z")),
         'SHAPE_KEY': ("DeformPercent", "DeformPercent", ("DeformPercent",)),
+        'CAMERA_FOCAL': ("FocalLength", "FocalLength", ("FocalLength",)),
     }
 
     def __init__(self, elem_key, kind, force_keying, force_startend_keying, default_values=...):
diff --git a/io_scene_fbx/import_fbx.py b/io_scene_fbx/import_fbx.py
index 4757d2ef791ad40f36bb42d93b415752ce4f08c4..446be0ffa64772ecb57050089c1ea0159ab3c1ab 100644
--- a/io_scene_fbx/import_fbx.py
+++ b/io_scene_fbx/import_fbx.py
@@ -64,6 +64,18 @@ MAT_CONVERT_LAMP = fbx_utils.MAT_CONVERT_LAMP.inverted()
 MAT_CONVERT_CAMERA = fbx_utils.MAT_CONVERT_CAMERA.inverted()
 
 
+def validate_blend_names(name):
+    assert(type(name) == bytes)
+    # Blender typically does not accept names over 63 bytes...
+    if len(name) > 63:
+        import hashlib
+        h = hashlib.sha1(name).hexdigest()
+        return name[:55].decode('utf-8', 'replace') + "_" + h[:7]
+    else:
+        # We use 'replace' even though FBX 'specs' say it should always be utf8, see T53841.
+        return name.decode('utf-8', 'replace')
+
+
 def elem_find_first(elem, id_search, default=None):
     for fbx_item in elem.elems:
         if fbx_item.id == id_search:
@@ -82,7 +94,7 @@ def elem_find_first_string(elem, id_search):
     if fbx_item is not None and fbx_item.props:  # Do not error on complete empty properties (see T45291).
         assert(len(fbx_item.props) == 1)
         assert(fbx_item.props_type[0] == data_types.STRING)
-        return fbx_item.props[0].decode('utf-8')
+        return fbx_item.props[0].decode('utf-8', 'replace')
     return None
 
 
@@ -124,14 +136,14 @@ def elem_name_ensure_class(elem, clss=...):
     elem_name, elem_class = elem_split_name_class(elem)
     if clss is not ...:
         assert(elem_class == clss)
-    return elem_name.decode('utf-8')
+    return validate_blend_names(elem_name)
 
 
 def elem_name_ensure_classes(elem, clss=...):
     elem_name, elem_class = elem_split_name_class(elem)
     if clss is not ...:
         assert(elem_class in clss)
-    return elem_name.decode('utf-8')
+    return validate_blend_names(elem_name)
 
 
 def elem_split_name_class_nodeattr(elem):
@@ -308,13 +320,14 @@ def blen_read_custom_properties(fbx_obj, blen_obj, settings):
                     # Special case for 3DS Max user properties:
                     assert(fbx_prop.props[1] == b'KString')
                     assert(fbx_prop.props_type[4] == data_types.STRING)
-                    items = fbx_prop.props[4].decode('utf-8')
+                    items = fbx_prop.props[4].decode('utf-8', 'replace')
                     for item in items.split('\r\n'):
                         if item:
                             prop_name, prop_value = item.split('=', 1)
-                            blen_obj[prop_name.strip()] = prop_value.strip()
+                            prop_name = validate_blend_names(prop_name.strip().encode('utf-8'))
+                            blen_obj[prop_name] = prop_value.strip()
                 else:
-                    prop_name = fbx_prop.props[0].decode('utf-8')
+                    prop_name = validate_blend_names(fbx_prop.props[0])
                     prop_type = fbx_prop.props[1]
                     if prop_type in {b'Vector', b'Vector3D', b'Color', b'ColorRGB'}:
                         assert(fbx_prop.props_type[4:7] == bytes((data_types.FLOAT64,)) * 3)
@@ -330,7 +343,7 @@ def blen_read_custom_properties(fbx_obj, blen_obj, settings):
                         blen_obj[prop_name] = fbx_prop.props[4]
                     elif prop_type == b'KString':
                         assert(fbx_prop.props_type[4] == data_types.STRING)
-                        blen_obj[prop_name] = fbx_prop.props[4].decode('utf-8')
+                        blen_obj[prop_name] = fbx_prop.props[4].decode('utf-8', 'replace')
                     elif prop_type in {b'Number', b'double', b'Double'}:
                         assert(fbx_prop.props_type[4] == data_types.FLOAT64)
                         blen_obj[prop_name] = fbx_prop.props[4]
@@ -344,13 +357,13 @@ def blen_read_custom_properties(fbx_obj, blen_obj, settings):
                         assert(fbx_prop.props_type[4:6] == bytes((data_types.INT32, data_types.STRING)))
                         val = fbx_prop.props[4]
                         if settings.use_custom_props_enum_as_string and fbx_prop.props[5]:
-                            enum_items = fbx_prop.props[5].decode('utf-8').split('~')
+                            enum_items = fbx_prop.props[5].decode('utf-8', 'replace').split('~')
                             assert(val >= 0 and val < len(enum_items))
                             blen_obj[prop_name] = enum_items[val]
                         else:
                             blen_obj[prop_name] = val
                     else:
-                        print ("WARNING: User property type '%s' is not supported" % prop_type.decode('utf-8'))
+                        print ("WARNING: User property type '%s' is not supported" % prop_type.decode('utf-8', 'replace'))
 
 
 def blen_read_object_transform_do(transform_data):
@@ -544,7 +557,7 @@ def blen_read_animations_action_item(action, item, cnodes, fps, anim_offset):
     'Bake' loc/rot/scale into the action,
     taking any pre_ and post_ matrix into account to transform from fbx into blender space.
     """
-    from bpy.types import Object, PoseBone, ShapeKey, Material
+    from bpy.types import Object, PoseBone, ShapeKey, Material, Camera
     from itertools import chain
 
     fbx_curves = []
@@ -564,6 +577,8 @@ def blen_read_animations_action_item(action, item, cnodes, fps, anim_offset):
         props = [("diffuse_color", 3, grpname or "Diffuse Color")]
     elif isinstance(item, ShapeKey):
         props = [(item.path_from_id("value"), 1, "Key")]
+    elif isinstance(item, Camera):
+        props = [(item.path_from_id("lens"), 1, "Camera")]
     else:  # Object or PoseBone:
         if item.is_bone:
             bl_obj = item.bl_obj.pose.bones[item.bl_bone]
@@ -611,6 +626,17 @@ def blen_read_animations_action_item(action, item, cnodes, fps, anim_offset):
             for fc, v in zip(blen_curves, (value,)):
                 fc.keyframe_points.insert(frame, v, {'NEEDED', 'FAST'}).interpolation = 'LINEAR'
 
+    elif isinstance(item, Camera):
+        for frame, values in blen_read_animations_curves_iter(fbx_curves, anim_offset, 0, fps):
+            value = 0.0
+            for v, (fbxprop, channel, _fbx_acdata) in values:
+                assert(fbxprop == b'FocalLength')
+                assert(channel == 0)
+                value = v
+
+            for fc, v in zip(blen_curves, (value,)):
+                fc.keyframe_points.insert(frame, v, {'NEEDED', 'FAST'}).interpolation = 'LINEAR'
+
     else:  # Object or PoseBone:
         if item.is_bone:
             bl_obj = item.bl_obj.pose.bones[item.bl_bone]
@@ -673,7 +699,7 @@ def blen_read_animations(fbx_tmpl_astack, fbx_tmpl_alayer, stacks, scene, anim_o
     Only the first found action is linked to objects, more complex setups are not handled,
     it's up to user to reproduce them!
     """
-    from bpy.types import ShapeKey, Material
+    from bpy.types import ShapeKey, Material, Camera
 
     actions = {}
     for as_uuid, ((fbx_asdata, _blen_data), alayers) in stacks.items():
@@ -685,6 +711,8 @@ def blen_read_animations(fbx_tmpl_astack, fbx_tmpl_alayer, stacks, scene, anim_o
                     id_data = item
                 elif isinstance(item, ShapeKey):
                     id_data = item.id_data
+                elif isinstance(item, Camera):
+                    id_data = item
                 else:
                     id_data = item.bl_obj
                     # XXX Ignore rigged mesh animations - those are a nightmare to handle, see note about it in
@@ -715,7 +743,7 @@ def blen_read_animations(fbx_tmpl_astack, fbx_tmpl_alayer, stacks, scene, anim_o
 
 def blen_read_geom_layerinfo(fbx_layer):
     return (
-        elem_find_first_string(fbx_layer, b'Name'),
+        validate_blend_names(elem_find_first_string_as_bytes(fbx_layer, b'Name')),
         elem_find_first_string_as_bytes(fbx_layer, b'MappingInformationType'),
         elem_find_first_string_as_bytes(fbx_layer, b'ReferenceInformationType'),
         )
@@ -1270,18 +1298,17 @@ def blen_read_shape(fbx_tmpl, fbx_sdata, fbx_bcdata, meshes, scene):
 
         if me.shape_keys is None:
             objects[0].shape_key_add(name="Basis", from_mix=False)
-        objects[0].shape_key_add(name=elem_name_utf8, from_mix=False)
+        kb = objects[0].shape_key_add(name=elem_name_utf8, from_mix=False)
         me.shape_keys.use_relative = True  # Should already be set as such.
 
-        kb = me.shape_keys.key_blocks[elem_name_utf8]
         for idx, co in vcos:
             kb.data[idx].co[:] = co
         kb.value = weight
 
         # Add vgroup if necessary.
         if create_vg:
-            add_vgroup_to_objects(indices, vgweights, elem_name_utf8, objects)
-            kb.vertex_group = elem_name_utf8
+            vgoups = add_vgroup_to_objects(indices, vgweights, kb.name, objects)
+            kb.vertex_group = kb.name
 
         keyblocks.append(kb)
 
@@ -2825,6 +2852,13 @@ def load(operator, context, filepath="",
                         if keyblocks is None:
                             continue
                         items += [(kb, lnk_prop) for kb in keyblocks]
+                    elif lnk_prop == b'FocalLength':  # Camera lens.
+                        from bpy.types import Camera
+                        fbx_item = fbx_table_nodes.get(n_uuid, None)
+                        if fbx_item is None or not isinstance(fbx_item[1], Camera):
+                            continue
+                        cam = fbx_item[1]
+                        items.append((cam, lnk_prop))
                     elif lnk_prop == b'DiffuseColor':
                         from bpy.types import Material
                         fbx_item = fbx_table_nodes.get(n_uuid, None)
@@ -2861,7 +2895,11 @@ def load(operator, context, filepath="",
                         continue
                     # Note this is an infamous simplification of the compound props stuff,
                     # seems to be standard naming but we'll probably have to be smarter to handle more exotic files?
-                    channel = {b'd|X': 0, b'd|Y': 1, b'd|Z': 2, b'd|DeformPercent': 0}.get(acn_ctype.props[3], None)
+                    channel = {
+                        b'd|X': 0, b'd|Y': 1, b'd|Z': 2,
+                        b'd|DeformPercent': 0,
+                        b'd|FocalLength': 0
+                    }.get(acn_ctype.props[3], None)
                     if channel is None:
                         continue
                     curvenodes[acn_uuid][ac_uuid] = (fbx_acitem, channel)
diff --git a/io_scene_fbx/json2fbx.py b/io_scene_fbx/json2fbx.py
index dc4c5bccdf0f81364c4b889fcc8b23ec226e89bb..579b45a79414e48338e91e94e7a77da7e02491da 100755
--- a/io_scene_fbx/json2fbx.py
+++ b/io_scene_fbx/json2fbx.py
@@ -108,9 +108,9 @@ def parse_json_rec(fbx_root, json_node):
         elif dt == "d":
             e.add_float64_array(d)
         elif dt == "b":
-            e.add_byte_array(d)
-        elif dt == "c":
             e.add_bool_array(d)
+        elif dt == "c":
+            e.add_byte_array(d)
 
     if name == "FBXVersion":
         assert(data_types == "I")
diff --git a/io_scene_obj/import_obj.py b/io_scene_obj/import_obj.py
index 7ca22160872e1cf47dfeba762db60d2f61ed7377..f3e16fcfb59e829561fc87740ece2ccc59734cf2 100644
--- a/io_scene_obj/import_obj.py
+++ b/io_scene_obj/import_obj.py
@@ -109,7 +109,7 @@ def create_materials(filepath, relpath,
 
         curr_token = []
         for token in img_data[:-1]:
-            if token.startswith(b'-'):
+            if token.startswith(b'-') and token[1:].isalpha():
                 if curr_token:
                     map_options[curr_token[0]] = curr_token[1:]
                 curr_token[:] = []
diff --git a/materials_library_vx/__init__.py b/materials_library_vx/__init__.py
index 9a8b47f9ec270efbea4747410ac00938e89589e6..071318627dea0cc223da94b93dec1566734fcfad 100644
--- a/materials_library_vx/__init__.py
+++ b/materials_library_vx/__init__.py
@@ -21,7 +21,7 @@
 bl_info = {
   "name": "Material Library",
   "author": "Mackraken (mackraken2023@hotmail.com)",
-  "version": (0, 5, 7),
+  "version": (0, 5, 8),
   "blender": (2, 7, 8),
   "api": 60995,
   "location": "Properties > Material",
@@ -114,7 +114,7 @@ def check_index(collection, index):
 
 def send_command(cmd, output="sendmat.py"):
     bin = winpath(bpy.app.binary_path)
-    scriptpath = winpath(os.path.join(matlib_path, output))
+    scriptpath = winpath(os.path.join(bpy.app.tempdir, output))
 
     with open(scriptpath, "w") as f:
       f.write(cmd)
@@ -484,11 +484,8 @@ if mat:
 #        self.current_library.materials[self.mat_index].category = cat
       #remove mat from any category
       else:
-        matnode = xml.find("material", mat.name, lib)
-        if matnode:
-          xml.deleteNode(matnode)
         mat.category = ""
-        self.current_library.materials[self.mat_index].category = ""
+        self.all_materials[self.mat_index].category = ""
     else:
       return "WARNING", "Select a material"
 
@@ -741,8 +738,7 @@ bpy.ops.wm.save_mainfile(filepath="%s", check_existing=False, compress=True)'''
 # Scene.matlib = PointerProperty(type = matlibProperties)
 
 ### MENUS
-class matlibLibsMenu(Menu):
-  bl_idname = "matlib.libs_menu"
+class MATLIB_MT_LibsMenu(Menu):
   bl_label = "Libraries Menu"
 
   def draw(self, context):
@@ -752,8 +748,7 @@ class matlibLibsMenu(Menu):
     for i, lib in enumerate(libs):
       layout.operator("matlib.operator", text=lib.shortname).cmd="lib"+str(i)
 
-class matlibCatsMenu(Menu):
-  bl_idname = "matlib.cats_menu"
+class MATLIB_MT_CatsMenu(Menu):
   bl_label = "Categories Menu"
 
   def draw(self, context):
@@ -779,7 +774,7 @@ class matlibCatsMenu(Menu):
 
 
 
-class MatlibAdd(Operator):
+class MATLIB_OT_add(Operator):
   """Add active material to library"""
   bl_idname = "matlib.add"
   bl_label = "Add active material"
@@ -797,7 +792,7 @@ class MatlibAdd(Operator):
       self.report({success[0]}, success[1])
     return {'FINISHED'}
 
-class MatlibRemove(Operator):
+class MATLIB_OT_remove(Operator):
   """Remove material from library"""
   bl_idname = "matlib.remove"
   bl_label = "Remove material from library"
@@ -815,7 +810,7 @@ class MatlibRemove(Operator):
       self.report({success[0]}, success[1])
     return {'FINISHED'}
 
-class MatlibReload(Operator):
+class MATLIB_OT_remove(Operator):
   """Reload library"""
   bl_idname = "matlib.reload"
   bl_label = "Reload library"
@@ -836,7 +831,7 @@ class MatlibReload(Operator):
     return {'FINISHED'}
 
 
-class MatlibApply(Operator):
+class MATLIB_OT_apply(Operator):
   """Apply selected material"""
   bl_idname = "matlib.apply"
   bl_label = "Apply material"
@@ -858,7 +853,7 @@ class MatlibApply(Operator):
     return {'FINISHED'}
 
 
-class MatlibPreview(Operator):
+class MATLIB_OT_preview(Operator):
   """Preview selected material"""
   bl_idname = "matlib.preview"
   bl_label = "Preview selected material"
@@ -880,7 +875,7 @@ class MatlibPreview(Operator):
     return {'FINISHED'}
 
 
-class MatlibFlush(Operator):
+class MATLIB_OT_flush(Operator):
   """Flush unused materials"""
   bl_idname = "matlib.flush"
   bl_label = "Flush unused materials"
@@ -917,7 +912,7 @@ class MatlibFlush(Operator):
     return {'FINISHED'}
 
 
-class matlibOperator(Operator):
+class MATLIB_OT_operator(Operator):
   """Add, Remove, Reload, Apply, Preview, Clean Material"""
   bl_label = "New"
   bl_idname = "matlib.operator"
@@ -1118,7 +1113,7 @@ for mat in mats:
     return {'FINISHED'}
 
 
-class matlibvxPanel(Panel):
+class MATLIB_PT_vxPanel(Panel):
   bl_label = "Material Library VX"
   bl_space_type = "PROPERTIES"
   bl_region_type = "WINDOW"
@@ -1144,7 +1139,7 @@ class matlibvxPanel(Panel):
     else:
       text = "Select a Library"
 
-    row.menu("matlib.libs_menu",text=text)
+    row.menu("MATLIB_MT_LibsMenu",text=text)
     row.operator("matlib.operator", icon="ZOOMIN", text="").cmd = "LIBRARY_ADD"
     if matlib.active_material:
       row.label(matlib.active_material.category)
@@ -1175,7 +1170,7 @@ class matlibvxPanel(Panel):
     row = layout.row(align=True)
     text = "All"
     if matlib.current_category: text = matlib.current_category
-    row.menu("matlib.cats_menu",text=text)
+    row.menu("MATLIB_MT_CatsMenu",text=text)
     row.prop(matlib, "filter", icon="FILTER", text="")
     row.operator("matlib.operator", icon="FILE_PARENT", text="").cmd="FILTER_SET"
     row.operator("matlib.operator", icon="ZOOMIN", text="").cmd="FILTER_ADD"
@@ -1198,7 +1193,7 @@ class matlibvxPanel(Panel):
 #      else:
 #        row.label("Library not found!.")
 
-#classes = [matlibvxPanel, matlibOperator, matlibLibsMenu, matlibCatsMenu]
+#classes = [MATLIB_PT_vxPanel, MATLIB_OT_operator, MATLIB_MT_LibsMenu, MATLIB_MT_CatsMenu]
 #print(bpy.context.scene)
 
 
diff --git a/materials_utils/__init__.py b/materials_utils/__init__.py
index c768d77048be6653485686c58c47f92c1fef3094..ea85a104177c9e079a3b1c805c3afbb06083f680 100644
--- a/materials_utils/__init__.py
+++ b/materials_utils/__init__.py
@@ -26,7 +26,7 @@
 bl_info = {
     "name": "Materials Utils Specials",
     "author": "Community",
-    "version": (1, 0, 3),
+    "version": (1, 0, 5),
     "blender": (2, 77, 0),
     "location": "Materials Properties Specials > Shift Q",
     "description": "Materials Utils and Convertors",
@@ -34,7 +34,7 @@ bl_info = {
     "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
                 "Scripts/3D_interaction/Materials_Utils",
     "category": "Material"
-    }
+}
 
 if "bpy" in locals():
     import importlib
@@ -51,27 +51,35 @@ else:
 import bpy
 import os
 from os import (
-        path as os_path,
-        access as os_access,
-        remove as os_remove,
-        )
+    path as os_path,
+    access as os_access,
+    remove as os_remove,
+)
 from bpy.props import (
-        StringProperty,
-        BoolProperty,
-        EnumProperty,
-        PointerProperty,
-        )
+    BoolProperty,
+    CollectionProperty,
+    EnumProperty,
+    IntProperty,
+    StringProperty,
+    PointerProperty,
+)
 from bpy.types import (
-        Menu,
-        Operator,
-        Panel,
-        AddonPreferences,
-        PropertyGroup,
-        )
+    AddonPreferences,
+    Menu,
+    Operator,
+    Panel,
+    PropertyGroup,
+    UIList,
+)
 from .warning_messages_utils import (
-        warning_messages,
-        c_data_has_materials,
-        )
+    warning_messages,
+    c_data_has_materials,
+    c_obj_data_has_materials,
+)
+
+# Globals
+UNDO_MESSAGE = "*Only Undo is available*"
+COLUMN_SPLIT = 20
 
 
 # Functions
@@ -146,7 +154,7 @@ def replace_material(m1, m2, all_objects=False, update_selection=False, operator
                     if m.material == matorg:
                         m.material = matrep
                         # don't break the loop as the material can be
-                        # ref'd more than once
+                        # referenced more than once
 
                         # Indicate which objects were affected
                         if update_selection:
@@ -169,7 +177,7 @@ def select_material_by_name(find_mat_name):
     if find_mat is None:
         return
 
-    # check for editmode
+    # check for edit mode
     editmode = False
 
     scn = bpy.context.scene
@@ -200,7 +208,7 @@ def select_material_by_name(find_mat_name):
             else:
                 ob.select = False
     else:
-        # it's editmode, so select the polygons
+        # it's edit mode, so select the polygons
         ob = actob
         ms = ob.material_slots
 
@@ -227,7 +235,7 @@ def select_material_by_name(find_mat_name):
 
 def mat_to_texface(operator=None):
     # assigns the first image in each material to the polygons in the active
-    # uvlayer for all selected objects
+    # uv layer for all selected objects
 
     # check for editmode
     editmode = False
@@ -282,7 +290,7 @@ def mat_to_texface(operator=None):
                 bpy.ops.mesh.uv_texture_add()
                 scn.objects.active = actob
 
-            # get active uvlayer
+            # get active uv layer
             for t in me.uv_textures:
                 if t.active:
                     uvtex = t.data
@@ -316,7 +324,7 @@ def assignmatslots(ob, matlist):
     scn.objects.active = ob
 
     for s in ob.material_slots:
-        bpy.ops.object.material_slot_remove()
+        remove_material_slot()
 
     # re-add them and assign material
     if matlist:
@@ -330,7 +338,7 @@ def assignmatslots(ob, matlist):
                 # to face indices, mat tries to get an '' as mat index
                 pass
 
-    # restore active object:
+    # restore active object
     scn.objects.active = ob_active
 
 
@@ -352,65 +360,97 @@ def cleanmatslots(operator=None):
     objs = bpy.context.selected_editable_objects
     # collect all object names for warning_messages
     message_a = []
-    # Flag if there are non MESH objects selected
-    mixed_obj = False
+    # Flags if there are non MESH objects selected
+    mixed_obj, mixed_obj_slot = False, False
 
     for ob in objs:
-        if ob.type == 'MESH':
-            mats = ob.material_slots.keys()
-
-            # if mats is empty then mats[faceindex] will be out of range
-            if mats:
-                # check the polygons on the mesh to build a list of used materials
-                usedMatIndex = []  # we'll store used materials indices here
-                faceMats = []
-                me = ob.data
-                for f in me.polygons:
-                    # get the material index for this face...
-                    faceindex = f.material_index
-
-                    # indices will be lost: Store face mat use by name
-                    currentfacemat = mats[faceindex]
-                    faceMats.append(currentfacemat)
-
-                    # check if index is already listed as used or not
-                    found = False
-                    for m in usedMatIndex:
-                        if m == faceindex:
-                            found = True
-                            # break
-
-                    if found is False:
-                        # add this index to the list
-                        usedMatIndex.append(faceindex)
-
-                # re-assign the used mats to the mesh and leave out the unused
-                ml = []
-                mnames = []
-                for u in usedMatIndex:
-                    ml.append(mats[u])
-                    # we'll need a list of names to get the face indices...
-                    mnames.append(mats[u])
-
-                assignmatslots(ob, ml)
-
-                # restore face indices:
-                i = 0
-                for f in me.polygons:
-                    matindex = mnames.index(faceMats[i])
-                    f.material_index = matindex
-                    i += 1
-            else:
-                message_a.append(getattr(ob, "name", "NO NAME"))
-                continue
-        else:
+        if ob.type != 'MESH':
+            mat_empty = []
             message_a.append(getattr(ob, "name", "NO NAME"))
             if mixed_obj is False:
                 mixed_obj = True
+
+            # at least try to remove empty material slots
+            if ob.type in {'CURVE', 'SURFACE', 'FONT', 'META'}:
+                mats = ob.material_slots
+                mat_empty = [i for i, slot in enumerate(mats) if not slot.material]
+
+                if not mat_empty:
+                    continue
+
+                if mixed_obj_slot is False:
+                    mixed_obj_slot = True
+
+                # Ctx - copy the context for operator override
+                Ctx = bpy.context.copy()
+                # for this operator it needs only the active object replaced
+                Ctx['object'] = ob
+
+                for index in mat_empty:
+                    try:
+                        ob.active_material_index = index
+                        bpy.ops.object.material_slot_remove(Ctx)
+                    except:
+                        continue
+            continue
+
+        mats = ob.material_slots.keys()
+        maxindex = len(mats) - 1  # indices start from zero
+
+        # if mats is empty then mats[faceindex] will be out of range
+        if not mats:
+            message_a.append(getattr(ob, "name", "NO NAME"))
             continue
 
+        # check the polygons on the mesh to build a list of used materials
+        usedMatIndex = []   # we'll store used materials indices here
+        faceMats = []
+        badIndices = set()  # collect face indices that are out material slot's range
+        me = ob.data
+        for f in me.polygons:
+            # get the material index for this face...
+            faceindex = f.material_index
+            # check if the mats[faceindex] is not out of range
+            if faceindex > maxindex:
+                badIndices.add(faceindex)
+                continue
+
+            # indices will be lost: Store face mat use by name
+            currentfacemat = mats[faceindex]
+            faceMats.append(currentfacemat)
+
+            # check if index is already listed as used or not
+            found = False
+            for m in usedMatIndex:
+                if m == faceindex:
+                    found = True
+
+            if found is False:
+                # add this index to the list
+                usedMatIndex.append(faceindex)
+
+        # re-assign the used mats to the mesh and leave out the unused
+        ml = []
+        mnames = []
+        for u in usedMatIndex:
+            if u not in badIndices:
+                ml.append(mats[u])
+                # we'll need a list of names to get the face indices...
+                mnames.append(mats[u])
+
+        assignmatslots(ob, ml)
+
+        # restore face indices:
+        i = 0
+        for f in me.polygons:
+            if i not in badIndices:
+                matindex = mnames.index(faceMats[i])
+                f.material_index = matindex
+                i += 1
+
     if message_a and operator:
-        warn_mess = ('C_OB_MIX_NO_MAT' if mixed_obj is True else 'C_OB_NO_MAT')
+        warn_s = 'C_OB_MIX_NO_MAT' if mixed_obj is True else 'C_OB_NO_MAT'
+        warn_mess = 'C_OB_MIX_SLOT_MAT' if mixed_obj_slot else warn_s
         warning_messages(operator, warn_mess, message_a)
 
     if actob:
@@ -426,12 +466,11 @@ def cleanmatslots(operator=None):
 def assign_mat_mesh_edit(matname="Default", operator=None):
     actob = bpy.context.active_object
     found = False
-    for m in bpy.data.materials:
-        if m.name == matname:
-            target = m
-            found = True
-            break
-    if not found:
+
+    # check if material exists, if it doesn't then create it
+    target = bpy.data.materials.get(matname)
+
+    if not target:
         target = bpy.data.materials.new(matname)
 
     if (actob.type in {'MESH'} and actob.mode in {'EDIT'}):
@@ -447,8 +486,8 @@ def assign_mat_mesh_edit(matname="Default", operator=None):
                 break
             i += 1
 
+        # the material is not attached to the object
         if not found:
-            # the material is not attached to the object
             actob.data.materials.append(target)
 
         # is selected ?
@@ -472,7 +511,7 @@ def assign_mat_mesh_edit(matname="Default", operator=None):
 
 
 def assign_mat(matname="Default", operator=None):
-    # get active object so we can restore it later
+    # get the active object so we can restore it later
     actob = bpy.context.active_object
 
     # is active object selected ?
@@ -480,19 +519,15 @@ def assign_mat(matname="Default", operator=None):
     actob.select = True
 
     # check if material exists, if it doesn't then create it
-    found = False
-    for m in bpy.data.materials:
-        if m.name == matname:
-            target = m
-            found = True
-            break
+    target = bpy.data.materials.get(matname)
 
-    if not found:
+    if not target:
         target = bpy.data.materials.new(matname)
 
-    # if objectmode then set all polygons
+    # if object mode then set all polygons
     editmode = False
     allpolygons = True
+
     if actob.mode == 'EDIT':
         editmode = True
         allpolygons = False
@@ -596,7 +631,7 @@ def check_texture(img, mat):
 
 
 def texface_to_mat(operator=None):
-    # editmode check here!
+    # edit mode check here!
     editmode = False
     ob = bpy.context.object
     if ob.mode == 'EDIT':
@@ -604,7 +639,6 @@ def texface_to_mat(operator=None):
         bpy.ops.object.mode_set()
 
     for ob in bpy.context.selected_editable_objects:
-
         faceindex = []
         unique_images = []
         # collect object names for warning messages
@@ -668,27 +702,30 @@ def remove_materials(operator=None, setting="SLOT"):
     actob = bpy.context.active_object
     actob_name = getattr(actob, "name", "NO NAME")
 
-    if actob:
-        if not included_object_types(actob.type):
-            if operator:
-                warning_messages(operator, 'OB_CANT_MAT', actob_name)
-        else:
-            if (hasattr(actob.data, "materials") and
-               len(actob.data.materials) > 0):
-                if setting == "SLOT":
-                    bpy.ops.object.material_slot_remove()
-                elif setting == "ALL":
-                    for mat in actob.data.materials:
-                        try:
-                            bpy.ops.object.material_slot_remove()
-                        except:
-                            pass
-
-                if operator:
-                    warn_mess = ('R_ACT_MAT_ALL' if setting == "ALL" else 'R_ACT_MAT')
-                    warning_messages(operator, warn_mess, actob_name)
-            elif operator:
-                warning_messages(operator, 'R_OB_NO_MAT', actob_name)
+    if not actob:
+        return
+
+    if not included_object_types(actob.type):
+        if operator:
+            warning_messages(operator, 'OB_CANT_MAT', actob_name)
+        return
+
+    if (hasattr(actob.data, "materials") and len(actob.data.materials) > 0):
+        if setting == "SLOT":
+            remove_material_slot()
+        elif setting == "ALL":
+            for mat in actob.data.materials:
+                try:
+                    remove_material_slot()
+                except:
+                    pass
+
+        if operator:
+            warn_mess = 'R_ACT_MAT_ALL' if setting == "ALL" else 'R_ACT_MAT'
+            warning_messages(operator, warn_mess, actob_name)
+
+    elif operator:
+        warning_messages(operator, 'R_OB_NO_MAT', actob_name)
 
 
 def remove_materials_all(operator=None):
@@ -700,11 +737,10 @@ def remove_materials_all(operator=None):
         if not included_object_types(ob.type):
             continue
         else:
-            # code from blender stackexchange (by CoDEmanX)
+            # code from blender stack exchange (by CoDEmanX)
             ob.active_material_index = 0
 
-            if (hasattr(ob.data, "materials") and
-               len(ob.material_slots) >= 1):
+            if (hasattr(ob.data, "materials") and len(ob.material_slots) >= 1):
                 mat_count = True
 
             # Ctx - copy the context for operator override
@@ -740,9 +776,10 @@ class VIEW3D_OT_show_mat_preview(Operator):
 
     @classmethod
     def poll(cls, context):
-        return (context.active_object is not None and
-                context.object.active_material is not None and
-                included_object_types(context.object.type))
+        obj = context.active_object
+        return (obj is not None and
+                obj.active_material is not None and
+                included_object_types(obj.type))
 
     def invoke(self, context, event):
         self.is_not_undo = True
@@ -753,89 +790,107 @@ class VIEW3D_OT_show_mat_preview(Operator):
         ob = context.active_object
         prw_size = size_preview()
 
-        if self.is_not_undo is True:
-            if ob and hasattr(ob, "active_material"):
-                mat = ob.active_material
-                is_opaque = (True if (ob and hasattr(ob, "show_transparent") and
-                             ob.show_transparent is True)
-                             else False)
-                is_opaque_bi = (True if (mat and hasattr(mat, "use_transparency") and
-                                mat.use_transparency is True)
-                                else False)
-                is_mesh = (True if ob.type == 'MESH' else False)
-
-                if size_type_is_preview():
-                    layout.template_ID_preview(ob, "active_material", new="material.new",
-                                               rows=prw_size['Width'], cols=prw_size['Height'])
-                else:
-                    layout.template_ID(ob, "active_material", new="material.new")
-                layout.separator()
-
-                if c_render_engine("Both"):
-                    layout.prop(mat, "use_nodes", icon='NODETREE')
-
-                if c_need_of_viewport_colors():
-                    color_txt = ("Viewport Color:" if c_render_engine("Cycles") else "Diffuse")
-                    spec_txt = ("Viewport Specular:" if c_render_engine("Cycles") else "Specular")
-                    col = layout.column(align=True)
-                    col.label(color_txt)
-                    col.prop(mat, "diffuse_color", text="")
-                    if c_render_engine("BI"):
-                        # Blender Render
-                        col.prop(mat, "diffuse_intensity", text="Intensity")
-                    col.separator()
-
-                    col.label(spec_txt)
-                    col.prop(mat, "specular_color", text="")
-                    col.prop(mat, "specular_hardness")
-
-                    if (c_render_engine("BI") and not c_context_use_nodes()):
-                        # Blender Render
-                        col.separator()
-                        col.prop(mat, "use_transparency")
-                        col.separator()
-                        if is_opaque_bi:
-                            col.prop(mat, "transparency_method", text="")
-                            col.separator()
-                            col.prop(mat, "alpha")
-                    elif (c_render_engine("Cycles") and is_mesh):
-                        # Cycles
-                        col.separator()
-                        col.prop(ob, "show_transparent", text="Transparency")
-                        if is_opaque:
-                            col.separator()
-                            col.prop(mat, "alpha")
-                    layout.separator()
-                else:
-                    other_render = ("*Unavailable with this Renderer*" if not c_render_engine("Both")
-                                    else "*Unavailable in this Context*")
-                    no_col_label = ("*Only available in Solid Shading*" if c_render_engine("Cycles")
-                                    else other_render)
-                    layout.label(no_col_label, icon="INFO")
+        if self.is_not_undo is False:
+            layout.label(text=UNDO_MESSAGE, icon="INFO")
+            return
+
+        if not (ob and hasattr(ob, "active_material")):
+            layout.label(text="No Active Object or Active Material", icon="INFO")
+            return
+
+        mat = ob.active_material
+        is_opaque = (
+            True if (ob and hasattr(ob, "show_transparent") and
+            ob.show_transparent is True) else False
+        )
+        is_opaque_bi = (
+            True if (mat and hasattr(mat, "use_transparency") and
+            mat.use_transparency is True) else False
+        )
+        is_mesh = True if ob.type == 'MESH' else False
+
+        if size_type_is_preview():
+            layout.template_ID_preview(ob, "active_material", new="material.new",
+                                       rows=prw_size['Width'], cols=prw_size['Height'])
         else:
-            layout.label(text="**Only Undo is available**", icon="INFO")
+            layout.template_ID(ob, "active_material", new="material.new")
+        layout.separator()
+
+        if c_render_engine("Both"):
+            layout.prop(mat, "use_nodes", icon='NODETREE')
+
+        if not c_need_of_viewport_colors():
+            other_render = (
+                "*Unavailable with this Renderer*" if not c_render_engine("Both") else
+                "*Unavailable in this Context*"
+            )
+            no_col_label = (
+                "*Only available in Solid Shading*" if c_render_engine("Cycles") else
+                other_render
+            )
+            layout.label(no_col_label, icon="INFO")
+            return
+
+        color_txt = "Viewport Color:" if c_render_engine("Cycles") else "Diffuse"
+        spec_txt = "Viewport Specular:" if c_render_engine("Cycles") else "Specular"
+        col = layout.column(align=True)
+        col.label(color_txt)
+        col.prop(mat, "diffuse_color", text="")
+
+        if c_render_engine("BI"):
+            # Blender Render
+            col.prop(mat, "diffuse_intensity", text="Intensity")
+        col.separator()
+
+        col.label(spec_txt)
+        col.prop(mat, "specular_color", text="")
+        col.prop(mat, "specular_hardness")
+
+        if (c_render_engine("BI") and not c_context_use_nodes()):
+            # Blender Render
+            col.separator()
+            col.prop(mat, "use_transparency")
+            col.separator()
+            if is_opaque_bi:
+                col.prop(mat, "transparency_method", text="")
+                col.separator()
+                col.prop(mat, "alpha")
+        elif (c_render_engine("Cycles") and is_mesh):
+            # Cycles
+            col.separator()
+            col.prop(ob, "show_transparent", text="Transparency")
+            if is_opaque:
+                col.separator()
+                col.prop(mat, "alpha")
+                col.separator()
+                col.label("Viewport Alpha:")
+                col.prop(mat.game_settings, "alpha_blend", text="")
+        layout.separator()
 
     def check(self, context):
         return self.is_not_undo
 
     def execute(self, context):
         self.is_not_undo = False
+
         return {'FINISHED'}
 
 
 class VIEW3D_OT_copy_material_to_selected(Operator):
     bl_idname = "view3d.copy_material_to_selected"
     bl_label = "Copy Materials to others"
-    bl_description = ("Copy Material From Active to Selected objects \n"
+    bl_description = ("Copy Material From Active to Selected objects\n"
+                      "In case of multiple materials, only the first slot is assigned\n"
                       "Works on Object's Data linked Materials")
     bl_options = {'REGISTER', 'UNDO'}
 
     @classmethod
     def poll(cls, context):
+        obj = context.active_object
         return (c_data_has_materials() and
-                context.active_object is not None and
-                included_object_types(context.active_object.type) and
-                context.object.active_material is not None and
+                obj is not None and
+                included_object_types(obj.type) and
+                obj.active_material is not None and
                 context.selected_editable_objects)
 
     def execute(self, context):
@@ -853,6 +908,7 @@ class VIEW3D_OT_copy_material_to_selected(Operator):
                 return {'CANCELLED'}
 
         warning_messages(self, warn_mess)
+
         return {'FINISHED'}
 
 
@@ -872,13 +928,14 @@ class VIEW3D_OT_texface_to_material(Operator):
         return context.window_manager.invoke_confirm(self, event)
 
     def execute(self, context):
-        if context.selected_editable_objects:
-            texface_to_mat(self)
-            return {'FINISHED'}
-        else:
+        if not context.selected_editable_objects:
             warning_messages(self, 'TEX_MAT_NO_SL')
             return {'CANCELLED'}
 
+        texface_to_mat(self)
+
+        return {'FINISHED'}
+
 
 class VIEW3D_OT_set_new_material_name(Operator):
     bl_idname = "view3d.set_new_material_name"
@@ -901,6 +958,7 @@ class VIEW3D_OT_set_new_material_name(Operator):
         layout.prop(scene, "use_tweak")
 
     def execute(self, context):
+
         return {'FINISHED'}
 
 
@@ -908,34 +966,61 @@ class VIEW3D_OT_assign_material(Operator):
     bl_idname = "view3d.assign_material"
     bl_label = "Assign Material"
     bl_description = "Assign a material to the selection"
+    bl_property = "matname"
     bl_options = {'REGISTER', 'UNDO'}
 
     is_existing = BoolProperty(
         name="Is it a new Material",
         options={'HIDDEN'},
         default=True,
-        )
+    )
     matname = StringProperty(
         name="Material Name",
         description="Name of the Material to Assign",
         options={'HIDDEN'},
         default="Material_New",
         maxlen=128,
-        )
+    )
+    is_not_undo = False     # prevent drawing props on undo
 
     @classmethod
     def poll(cls, context):
         return context.active_object is not None
 
     def invoke(self, context, event):
-        return self.execute(context)
+        self.is_not_undo = True
+
+        if not self.is_existing or use_mat_menu_type() not in {'POPUP'}:
+            return self.execute(context)
+
+        materials_lists_fill_names(context, refresh=True, is_object=False)
+        return context.window_manager.invoke_props_dialog(self, width=400, height=200)
+
+    def check(self, context):
+        return self.is_not_undo
+
+    def draw(self, context):
+        draw_ui_list_popups(self, context, obj_data=False)
 
     def execute(self, context):
         actob = context.active_object
-        mn = self.matname
         scene = context.scene.mat_specials
+        mn = self.matname
         tweak = scene.use_tweak
 
+        if use_mat_menu_type() == 'POPUP' and self.is_existing:
+            mats_col = context.scene.mat_specials_mats
+            len_mats = len(mats_col)
+            mat_index = scene.index_mat
+
+            if not (len_mats > 0 and mat_index is not None and mat_index <= len_mats):
+                self.report({'WARNING'},
+                            "No Materials in the Scene. Please use the Add New option")
+                return {"CANCELLED"}
+
+            mats_up = mats_col[mat_index].name
+            mn = mats_up
+
         if not self.is_existing:
             new_name = check_mat_name_unique(scene.set_material_name)
             mn = new_name
@@ -951,6 +1036,8 @@ class VIEW3D_OT_assign_material(Operator):
         mat_to_texface()
         self.is_not_undo = False
 
+        activate_mat_slot(actob, mn)
+
         if tweak and not self.is_existing:
             try:
                 bpy.ops.view3d.show_mat_preview('INVOKE_DEFAULT')
@@ -976,6 +1063,7 @@ class VIEW3D_OT_clean_material_slots(Operator):
 
     def execute(self, context):
         cleanmatslots(self)
+
         return {'FINISHED'}
 
 
@@ -993,18 +1081,19 @@ class VIEW3D_OT_material_to_texface(Operator):
                 context.active_object is not None)
 
     def execute(self, context):
-        if context.selected_editable_objects:
-            mat_to_texface(self)
-            return {'FINISHED'}
-        else:
+        if not context.selected_editable_objects:
             warning_messages(self, "MAT_TEX_NO_SL")
             return {'CANCELLED'}
 
+        mat_to_texface(self)
+
+        return {'FINISHED'}
+
 
 class VIEW3D_OT_material_remove_slot(Operator):
     bl_idname = "view3d.material_remove_slot"
     bl_label = "Remove Active Slot (Active Object)"
-    bl_description = ("Remove active material slot from active object\n"
+    bl_description = ("Remove active material slot from active object \n"
                       "Can't be used in Edit Mode")
     bl_options = {'REGISTER', 'UNDO'}
 
@@ -1013,21 +1102,22 @@ class VIEW3D_OT_material_remove_slot(Operator):
         # materials can't be removed in Edit mode
         return (c_data_has_materials() and
                 context.active_object is not None and
-                not context.object.mode == 'EDIT')
+                not context.active_object.mode == 'EDIT')
 
     def execute(self, context):
-        if context.selected_editable_objects:
-            remove_materials(self, "SLOT")
-            return {'FINISHED'}
-        else:
+        if not context.selected_editable_objects:
             warning_messages(self, 'R_NO_SL_MAT')
             return {'CANCELLED'}
 
+        remove_materials(self, "SLOT")
+
+        return {'FINISHED'}
+
 
 class VIEW3D_OT_material_remove_object(Operator):
     bl_idname = "view3d.material_remove_object"
     bl_label = "Remove all Slots (Active Object)"
-    bl_description = ("Remove all material slots from active object\n"
+    bl_description = ("Remove all material slots from active object \n"
                       "Can't be used in Edit Mode")
     bl_options = {'REGISTER', 'UNDO'}
 
@@ -1036,16 +1126,17 @@ class VIEW3D_OT_material_remove_object(Operator):
         # materials can't be removed in Edit mode
         return (c_data_has_materials() and
                 context.active_object is not None and
-                not context.object.mode == 'EDIT')
+                not context.active_object.mode == 'EDIT')
 
     def execute(self, context):
-        if context.selected_editable_objects:
-            remove_materials(self, "ALL")
-            return {'FINISHED'}
-        else:
+        if not context.selected_editable_objects:
             warning_messages(self, 'R_NO_SL_MAT')
             return {'CANCELLED'}
 
+        remove_materials(self, "ALL")
+
+        return {'FINISHED'}
+
 
 class VIEW3D_OT_material_remove_all(Operator):
     bl_idname = "view3d.material_remove_all"
@@ -1059,19 +1150,20 @@ class VIEW3D_OT_material_remove_all(Operator):
         # materials can't be removed in Edit mode
         return (c_data_has_materials() and
                 context.active_object is not None and
-                not context.object.mode == 'EDIT')
+                not context.active_object.mode == 'EDIT')
 
     def invoke(self, context, event):
         return context.window_manager.invoke_confirm(self, event)
 
     def execute(self, context):
-        if context.selected_editable_objects:
-            remove_materials_all(self)
-            return {'FINISHED'}
-        else:
+        if not context.selected_editable_objects:
             warning_messages(self, 'R_NO_SL_MAT')
             return {'CANCELLED'}
 
+        remove_materials_all(self)
+
+        return {'FINISHED'}
+
 
 class VIEW3D_OT_select_material_by_name(Operator):
     bl_idname = "view3d.select_material_by_name"
@@ -1080,20 +1172,59 @@ class VIEW3D_OT_select_material_by_name(Operator):
     bl_options = {'REGISTER', 'UNDO'}
 
     matname = StringProperty(
-            name='Material Name',
-            description='Name of Material to Select',
-            maxlen=63,
-            )
+        name="Material Name",
+        description="Name of Material to Select",
+        maxlen=63,
+    )
+    is_not_undo = False
+    is_edit = False
 
     @classmethod
     def poll(cls, context):
+        obj = context.active_object
         return (c_data_has_materials() and
-                context.active_object is not None)
+                obj is not None and obj.mode in {"OBJECT", "EDIT"})
+
+    def invoke(self, context, event):
+        self.is_not_undo = True
+
+        if use_mat_menu_type() not in {'POPUP'}:
+            return self.execute(context)
+
+        obj = context.active_object
+        self.is_edit = bool(obj.mode == 'EDIT')
+        materials_lists_fill_names(context, refresh=True, is_object=self.is_edit)
+
+        return context.window_manager.invoke_props_dialog(self, width=400, height=200)
+
+    def check(self, context):
+        return self.is_not_undo
+
+    def draw(self, context):
+        draw_ui_list_popups(self, context, obj_data=self.is_edit)
 
     def execute(self, context):
-        mn = self.matname
+        if use_mat_menu_type() == 'POPUP':
+            mats_col = context.scene.mat_specials_mats
+            scene = context.scene.mat_specials
+            len_mats = len(mats_col)
+            mat_index = scene.index_mat
+
+            if not (len_mats > 0 and mat_index is not None and mat_index <= len_mats):
+                self.report({'WARNING'},
+                            "No materials found. Operation Cancelled")
+                return {"CANCELLED"}
+
+            mats_up = mats_col[mat_index].name
+            mn = mats_up
+        else:
+            mn = self.matname
+
         select_material_by_name(mn)
-        warning_messages(self, 'SL_MAT_BY_NAME', mn)
+        message = 'SL_MAT_EDIT_BY_NAME' if self.is_edit else 'SL_MAT_BY_NAME'
+        warning_messages(self, message, mn)
+        self.is_not_undo = False
+
         return {'FINISHED'}
 
 
@@ -1104,25 +1235,26 @@ class VIEW3D_OT_replace_material(Operator):
     bl_options = {'REGISTER', 'UNDO'}
 
     matorg = StringProperty(
-            name="Original",
-            description="Material to replace",
-            maxlen=63,
-            )
+        name="Original",
+        description="Material to replace",
+        maxlen=63,
+    )
     matrep = StringProperty(
-            name="Replacement",
-            description="Replacement material",
-            maxlen=63,
-            )
+        name="Replacement",
+        description="Replacement material",
+        maxlen=63,
+    )
     all_objects = BoolProperty(
-            name="All objects",
-            description="Replace for all objects in this blend file",
-            default=True,
-            )
+        name="All objects",
+        description="If enabled, replace for all objects in this blend file\n"
+                    "If disabled, only selected objects will be affected",
+        default=False,
+    )
     update_selection = BoolProperty(
-            name="Update Selection",
-            description="Select affected objects and deselect unaffected",
-            default=True,
-            )
+        name="Update Selection",
+        description="Select affected objects and deselect unaffected",
+        default=True,
+    )
 
     @classmethod
     def poll(cls, context):
@@ -1139,9 +1271,12 @@ class VIEW3D_OT_replace_material(Operator):
         return context.window_manager.invoke_props_dialog(self)
 
     def execute(self, context):
-        replace_material(self.matorg, self.matrep, self.all_objects,
-                         self.update_selection, self)
+        replace_material(
+            self.matorg, self.matrep, self.all_objects,
+            self.update_selection, self
+        )
         self.matorg, self.matrep = "", ""
+
         return {'FINISHED'}
 
 
@@ -1152,22 +1287,22 @@ class VIEW3D_OT_fake_user_set(Operator):
     bl_options = {'REGISTER', 'UNDO'}
 
     fake_user = EnumProperty(
-            name="Fake User",
-            description="Turn fake user on or off",
-            items=(('ON', "On", "Enable fake user"), ('OFF', "Off", "Disable fake user")),
-            default='ON',
-            )
+        name="Fake User",
+        description="Turn fake user on or off",
+        items=(('ON', "On", "Enable fake user"), ('OFF', "Off", "Disable fake user")),
+        default='ON',
+    )
     materials = EnumProperty(
-            name="Materials",
-            description="Chose what objects and materials to affect",
-            items=(('ACTIVE', "Active object", "Materials of active object only"),
-                   ('SELECTED', "Selected objects", "Materials of selected objects"),
-                   ('SCENE', "Scene objects", "Materials of objects in current scene"),
-                   ('USED', "Used", "All materials used by objects"),
-                   ('UNUSED', "Unused", "Currently unused materials"),
-                   ('ALL', "All", "All materials in this blend file")),
-            default='UNUSED',
-            )
+        name="Materials",
+        description="Chose what objects and materials to affect",
+        items=(('ACTIVE', "Active object", "Materials of active object only"),
+               ('SELECTED', "Selected objects", "Materials of selected objects"),
+               ('SCENE', "Scene objects", "Materials of objects in current scene"),
+               ('USED', "Used", "All materials used by objects"),
+               ('UNUSED', "Unused", "Currently unused materials"),
+               ('ALL', "All", "All materials in this blend file")),
+        default='UNUSED',
+    )
 
     @classmethod
     def poll(cls, context):
@@ -1183,6 +1318,7 @@ class VIEW3D_OT_fake_user_set(Operator):
 
     def execute(self, context):
         fake_user_set(self.fake_user, self.materials, self)
+
         return {'FINISHED'}
 
 
@@ -1196,15 +1332,15 @@ class MATERIAL_OT_set_transparent_back_side(Operator):
     @classmethod
     def poll(cls, context):
         obj = context.active_object
-        if (not obj):
+        if not obj:
             return False
         mat = obj.active_material
-        if (not mat):
+        if not mat:
             return False
-        if (mat.node_tree):
+        if mat.node_tree:
             if (len(mat.node_tree.nodes) == 0):
                 return True
-        if (not mat.use_nodes):
+        if not mat.use_nodes:
             return True
         return False
 
@@ -1246,7 +1382,7 @@ class MATERIAL_OT_move_slot_top(Operator):
     @classmethod
     def poll(cls, context):
         obj = context.active_object
-        if (not obj):
+        if not obj:
             return False
         if (len(obj.material_slots) <= 2):
             return False
@@ -1276,7 +1412,7 @@ class MATERIAL_OT_move_slot_bottom(Operator):
     @classmethod
     def poll(cls, context):
         obj = context.active_object
-        if (not obj):
+        if not obj:
             return False
         if (len(obj.material_slots) <= 2):
             return False
@@ -1306,15 +1442,14 @@ class MATERIAL_OT_link_to_base_names(Operator):
     bl_options = {'REGISTER', 'UNDO'}
 
     mat_keep = StringProperty(
-                name="Material to keep",
-                default="",
-                )
+        name="Material to keep",
+        default="",
+    )
     is_auto = BoolProperty(
-                name="Auto Rename/Replace",
-                description=("Automatically Replace names "
-                             "by stripping numerical suffix"),
-                default=False,
-               )
+        name="Auto Rename/Replace",
+        description="Automatically Replace names by stripping numerical suffix",
+        default=False,
+    )
     mat_error = []          # collect mat for warning messages
     is_not_undo = False     # prevent drawing props on undo
     check_no_name = True    # check if no name is passed
@@ -1325,16 +1460,18 @@ class MATERIAL_OT_link_to_base_names(Operator):
 
     def draw(self, context):
         layout = self.layout
-        if self.is_not_undo is True:
-            boxee = layout.box()
-            boxee.prop_search(self, "mat_keep", bpy.data, "materials")
-            boxee.enabled = not self.is_auto
-            layout.separator()
-
-            boxs = layout.box()
-            boxs.prop(self, "is_auto", text="Auto Rename/Replace", icon="SYNTAX_ON")
-        else:
-            layout.label(text="**Only Undo is available**", icon="INFO")
+
+        if self.is_not_undo is False:
+            layout.label(text=UNDO_MESSAGE, icon="INFO")
+            return
+
+        boxee = layout.box()
+        boxee.prop_search(self, "mat_keep", bpy.data, "materials")
+        boxee.enabled = not self.is_auto
+        layout.separator()
+
+        boxs = layout.box()
+        boxs.prop(self, "is_auto", text="Auto Rename/Replace", icon="SYNTAX_ON")
 
     def invoke(self, context, event):
         self.is_not_undo = True
@@ -1430,13 +1567,14 @@ class MATERIAL_OT_link_to_base_names(Operator):
             warning_messages(self, 'MAT_LINK_ERROR', self.mat_error, 'MAT')
 
         self.is_not_undo = False
+
         return {'FINISHED'}
 
 
 class MATERIAL_OT_check_converter_path(Operator):
     bl_idname = "material.check_converter_path"
     bl_label = "Check Converters images/data save path"
-    bl_description = "Check if the given path is writeable (has OS writing privileges)"
+    bl_description = "Check if the given path is writable (has OS writing privileges)"
     bl_options = {'REGISTER', 'INTERNAL'}
 
     def check_valid_path(self, context):
@@ -1447,24 +1585,24 @@ class MATERIAL_OT_check_converter_path(Operator):
             warning_messages(self, "DIR_PATH_EMPTY", override=True)
             return False
 
-        if os_path.exists(paths):
-            if os_access(paths, os.W_OK | os.X_OK):
-                try:
-                    path_test = os_path.join(paths, "XYfoobartestXY.txt")
-                    with open(path_test, 'w') as f:
-                        f.closed
-                    os_remove(path_test)
-                    return True
-                except (OSError, IOError):
-                    warning_messages(self, 'DIR_PATH_W_ERROR', override=True)
-                    return False
-            else:
-                warning_messages(self, 'DIR_PATH_A_ERROR', override=True)
-                return False
-        else:
+        if not os_path.exists(paths):
             warning_messages(self, 'DIR_PATH_N_ERROR', override=True)
             return False
 
+        if not os_access(paths, os.W_OK | os.X_OK):
+            warning_messages(self, 'DIR_PATH_A_ERROR', override=True)
+            return False
+
+        try:
+            path_test = os_path.join(paths, "XYfoobartestXY.txt")
+            with open(path_test, 'w') as f:
+                f.closed
+            os_remove(path_test)
+            return True
+        except (OSError, IOError):
+            warning_messages(self, 'DIR_PATH_W_ERROR', override=True)
+            return False
+
         return True
 
     def execute(self, context):
@@ -1476,6 +1614,67 @@ class MATERIAL_OT_check_converter_path(Operator):
         return {'FINISHED'}
 
 
+# Material selections pop-up
+
+class VIEW3D_UL_assign_material_popup_ui(UIList):
+
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+        self.use_filter_show = True
+
+        col = layout.column(align=True)
+        col.alignment = "LEFT"
+        mat = bpy.data.materials.get(item.name, None)
+        if not mat:
+            col.label(text="{} - is not available".format(item.name), icon="ERROR")
+        else:
+            split = col.split(percentage=0.75, align=True)
+            row = split.row(align=True)
+            row.label(text=item.name, translate=False, icon="MATERIAL_DATA")
+            subrow = split.row(align=True)
+            subrow.alignment = "RIGHT"
+            subrow.label(text="", icon="PINNED" if item.mat_fake_user else "BLANK1")
+            subrow = split.row(align=True)
+            subrow.alignment = "RIGHT"
+            subrow.label(text="", icon="LINK_BLEND" if item.mat_lib else "BLANK1")
+
+
+def draw_ui_list_popups(self, context, obj_data=False):
+    layout = self.layout
+
+    if not self.is_not_undo:
+        layout.label(text=UNDO_MESSAGE, icon="INFO")
+        return
+
+    matlen = len(context.scene.mat_specials_mats)
+    matdata = "in Object's Data" if obj_data else "in Data"
+    matgramma = "Material" if matlen == 1 else "Materials"
+    matcount = "No" if matlen < 1 else matlen
+
+    box = layout.box()
+    col = box.column(align=True)
+    col.label(text="{} {} {}".format(matcount, matgramma, matdata),
+              icon="INFO")
+    sub_split = col.split(percentage=0.7, align=True)
+    sub_box_1 = sub_split.box()
+    sub_box_1.label("Name")
+    sub_split_2 = sub_split.split(percentage=0.5, align=True)
+    sub_box_2 = sub_split_2.box()
+    sub_box_2.label("Fake")
+    sub_box_3 = sub_split_2.box()
+    sub_box_3.label("Lib")
+
+    col.template_list(
+        "VIEW3D_UL_assign_material_popup_ui",
+        'mat_specials',
+        context.scene,
+        'mat_specials_mats',
+        context.scene.mat_specials,
+        'index_mat',
+        rows=10
+    )
+    return
+
+
 # Menu classes
 
 class VIEW3D_MT_assign_material(Menu):
@@ -1485,26 +1684,45 @@ class VIEW3D_MT_assign_material(Menu):
         layout = self.layout
         layout.operator_context = 'INVOKE_REGION_WIN'
 
-        if c_data_has_materials():
-            # no materials
-            for material_name in bpy.data.materials.keys():
-                mats = layout.operator("view3d.assign_material",
-                                text=material_name,
-                                icon='MATERIAL_DATA')
-                mats.matname = material_name
-                mats.is_existing = True
-            use_separator(self, context)
-
         if (not context.active_object):
             # info why the add material is innactive
             layout.label(text="*No active Object in the Scene*", icon="INFO")
             use_separator(self, context)
+
         mat_prop_name = context.scene.mat_specials.set_material_name
-        add_new = layout.operator("view3d.assign_material",
-                                  text="Add New", icon='ZOOMIN')
+        add_new = layout.operator(
+                        "view3d.assign_material",
+                        text="Add New", icon='ZOOMIN'
+                        )
         add_new.matname = mat_prop_name
         add_new.is_existing = False
 
+        if use_mat_menu_type() != 'POPUP':
+            use_separator(self, context)
+
+        if c_data_has_materials():
+            mat_entry = layout.column()
+
+            if use_mat_menu_type() == 'POPUP':
+                matp = mat_entry.operator(
+                            "view3d.assign_material",
+                            icon='MATERIAL_DATA'
+                            )
+                matp.is_existing = True
+            elif use_mat_menu_type() == 'COLUMNS':
+                get_col_size = switch_to_column()
+                mat_entry = layout.column_flow(columns=get_col_size)
+
+            if use_mat_menu_type() in {'COLUMNS', 'STANDARD'}:
+                for material_name in bpy.data.materials.keys():
+                    mats = mat_entry.operator(
+                                "view3d.assign_material",
+                                text=material_name,
+                                icon='MATERIAL_DATA'
+                                )
+                    mats.matname = material_name
+                    mats.is_existing = True
+
 
 class VIEW3D_MT_select_material(Menu):
     bl_label = "Select by Material"
@@ -1512,28 +1730,58 @@ class VIEW3D_MT_select_material(Menu):
     def draw(self, context):
         layout = self.layout
         layout.operator_context = 'INVOKE_REGION_WIN'
-        ob = context.object
+        obj = context.active_object
+        has_users = False
+        col = layout.column()
+
+        if not c_data_has_materials():
+            layout.label(text="*No Materials in the Data*", icon="INFO")
+            return
+        elif not obj:
+            layout.label(text="*No Active Object*", icon="INFO")
+            return
+        elif obj.mode == "EDIT" and not c_obj_data_has_materials(obj):
+            layout.label(text="*No Materials in the Object's Data*", icon="INFO")
+            return
+        elif use_mat_menu_type() == 'POPUP':
+            col.operator(
+                "view3d.select_material_by_name",
+                text="Select by Material",
+                icon='HAND',
+            )
+            return
 
-        if (not c_data_has_materials()):
-            layout.label(text="*No Materials in the data*", icon="INFO")
-        elif (not ob):
-            layout.label(text="*No Objects to select*", icon="INFO")
+        if obj.mode == 'OBJECT':
+            if use_mat_menu_type() == 'COLUMNS':
+                get_col_size = switch_to_column(is_edit=False)
+                col = layout.column_flow(columns=get_col_size)
+            # show all used materials in entire blend file
+            for material_name, material in bpy.data.materials.items():
+                if material.users > 0:
+                    has_users = True
+                    col.operator(
+                        "view3d.select_material_by_name",
+                        text=material_name,
+                        icon='MATERIAL_DATA',
+                    ).matname = material_name
+            if not has_users:
+                layout.label(text="*No users for Materials in the data*", icon="INFO")
+                return
+        elif obj.mode == 'EDIT':
+            if use_mat_menu_type() == 'COLUMNS':
+                get_col_size = switch_to_column(is_edit=True)
+                col = layout.column_flow(columns=get_col_size)
+            # show only the materials on this object
+            mats = obj.material_slots.keys()
+            for m in mats:
+                if m not in "":  # skip empty slots
+                    col.operator(
+                        "view3d.select_material_by_name",
+                        text=m,
+                        icon='MATERIAL_DATA'
+                    ).matname = m
         else:
-            if ob.mode == 'OBJECT':
-                # show all used materials in entire blend file
-                for material_name, material in bpy.data.materials.items():
-                    if (material.users > 0):
-                        layout.operator("view3d.select_material_by_name",
-                                        text=material_name,
-                                        icon='MATERIAL_DATA',
-                                        ).matname = material_name
-            elif ob.mode == 'EDIT':
-                # show only the materials on this object
-                mats = ob.material_slots.keys()
-                for m in mats:
-                    layout.operator("view3d.select_material_by_name",
-                                    text=m,
-                                    icon='MATERIAL_DATA').matname = m
+            layout.label(text="*Works only in Object and Edit mode*", icon="INFO")
 
 
 class VIEW3D_MT_remove_material(Menu):
@@ -1543,24 +1791,35 @@ class VIEW3D_MT_remove_material(Menu):
         layout = self.layout
         layout.operator_context = 'INVOKE_REGION_WIN'
 
-        layout.operator("view3d.clean_material_slots",
-                        text="Clean Material Slots",
-                        icon='COLOR_BLUE')
-        use_separator(self, context)
+        if context.mode in {'PAINT_TEXTURE'}:
+            layout.label(
+                text="Removing materials can lead to loss of painting data",
+                icon="INFO"
+            )
+            use_separator(self, context)
 
-        if not c_render_engine("Lux"):
-            layout.operator("view3d.material_remove_slot", icon='COLOR_GREEN')
-            layout.operator("view3d.material_remove_object", icon='COLOR_RED')
+        layout.operator(
+            "view3d.clean_material_slots",
+            text="Clean Material Slots",
+            icon='COLOR_BLUE'
+        )
+        use_separator(self, context)
 
-            if use_remove_mat_all():
-                use_separator(self, context)
-                layout.operator("view3d.material_remove_all",
-                                text="Remove Material Slots "
-                                "(All Selected Objects)",
-                                icon='CANCEL')
-        else:
+        if c_render_engine("Lux"):
             layout.label(text="Sorry, other Menu functions are", icon="INFO")
             layout.label(text="unvailable with Lux Renderer")
+            return
+
+        layout.operator("view3d.material_remove_slot", icon='COLOR_GREEN')
+        layout.operator("view3d.material_remove_object", icon='COLOR_RED')
+
+        if use_remove_mat_all():
+            use_separator(self, context)
+            layout.operator(
+                "view3d.material_remove_all",
+                text="Remove Material Slots (All Selected Objects)",
+                icon='CANCEL'
+            )
 
 
 class VIEW3D_MT_master_material(Menu):
@@ -1574,8 +1833,13 @@ class VIEW3D_MT_master_material(Menu):
             layout.operator("view3d.show_mat_preview", icon="VISIBLE_IPO_ON")
             use_separator(self, context)
 
-        layout.menu("VIEW3D_MT_assign_material", icon='ZOOMIN')
-        layout.menu("VIEW3D_MT_select_material", icon='HAND')
+        if use_mat_menu_type() == 'POPUP':
+            VIEW3D_MT_assign_material.draw(self, context)
+            use_separator(self, context)
+            VIEW3D_MT_select_material.draw(self, context)
+        else:
+            layout.menu("VIEW3D_MT_assign_material", icon='ZOOMIN')
+            layout.menu("VIEW3D_MT_select_material", icon='HAND')
         use_separator(self, context)
 
         layout.operator("view3d.copy_material_to_selected", icon="COPY_ID")
@@ -1665,8 +1929,15 @@ def menu_func(self, context):
     layout.operator_context = 'INVOKE_REGION_WIN'
 
     use_separator(self, context)
-    layout.menu("VIEW3D_MT_assign_material", icon='ZOOMIN')
-    layout.menu("VIEW3D_MT_select_material", icon='HAND')
+    if use_mat_menu_type() == 'POPUP':
+        VIEW3D_MT_assign_material.draw(self, context)
+        use_separator(self, context)
+        VIEW3D_MT_select_material.draw(self, context)
+    else:
+        layout.menu("VIEW3D_MT_assign_material", icon='ZOOMIN')
+        layout.menu("VIEW3D_MT_select_material", icon='HAND')
+    use_separator(self, context)
+
     layout.operator("view3d.replace_material",
                     text='Replace Material',
                     icon='ARROW_LEFTRIGHT')
@@ -1741,11 +2012,15 @@ class MATERIAL_PT_scenemassive(Panel):
     def poll(cls, context):
         return (enable_converters() is True and converter_type('BI_CONV'))
 
+    def draw_header(self, context):
+        layout = self.layout
+        help_panel_header(layout, menu_type="HELP_MT_biconvert")
+
     def draw(self, context):
         layout = self.layout
         sc = context.scene
-        row = layout.row()
-        box = row.box()
+        col = layout.column(align=True)
+        box = col.box()
 
         split = box.box().split(0.5)
         split.operator("ml.refresh",
@@ -1757,14 +2032,9 @@ class MATERIAL_PT_scenemassive(Panel):
                                   icon='MATERIAL')
         ml_restore.switcher = False
         ml_restore.renderer = "BI"
-
-        box = layout.box()
-        row = box.row()
         row.menu("scenemassive.opt", text="Advanced Options", icon='SCRIPTWIN')
-        row.menu("HELP_MT_biconvert",
-                 text="Usage Information Guide", icon="INFO")
 
-        box = layout.box()
+        box = col.box()
         box.label("Save Directory")
         split = box.split(0.85)
         split.prop(sc.mat_specials, "conv_path", text="", icon="RENDER_RESULT")
@@ -1783,28 +2053,32 @@ class MATERIAL_PT_xps_convert(Panel):
     def poll(cls, context):
         return (enable_converters() is True and converter_type('CYC_CONV'))
 
+    def draw_header(self, context):
+        layout = self.layout
+        help_panel_header(layout, menu_type="help.nodeconvert")
+
     def draw(self, context):
         layout = self.layout
-        row = layout.row()
-        box = row.box()
+        col = layout.column(align=True)
+        box = col.box()
 
-        box.label(text="Multi Image Support (Imports)")
+        box.label(text="Multi Image Support (Imports)", icon="INFO")
         split = box.box().split(0.5)
-        split.operator("xps_tools.convert_to_cycles_all",
-                       text="Convert All to Nodes", icon="TEXTURE")
-        split.operator("xps_tools.convert_to_cycles_selected",
-                       text="Convert Selected to Nodes", icon="TEXTURE")
+        split.operator(
+            "xps_tools.convert_to_cycles_all",
+            text="Convert All to Nodes", icon="TEXTURE"
+        )
+        split.operator(
+            "xps_tools.convert_to_cycles_selected",
+            text="Convert Selected to Nodes", icon="TEXTURE"
+        )
 
-        box = layout.box()
-        row = box.row()
-        ml_restore = row.operator("ml.restore", text="To BI Nodes ON",
+        box = col.box()
+        ml_restore = box.operator("ml.restore", text="To BI Nodes ON",
                                   icon='MATERIAL')
         ml_restore.switcher = True
         ml_restore.renderer = "BI"
 
-        row.menu("help.nodeconvert",
-                 text="Usage Information Guide", icon="INFO")
-
 
 # Converters Help #
 
@@ -1826,12 +2100,12 @@ class MATERIAL_MT_biconv_help(Menu):
         layout.label(text="Select the texture loaded in the image node")
         layout.label(text="Press Ctrl/T to create the image nodes")
         layout.label(text="In the Node Editor, Select the Diffuse Node")
-        layout.label(text="Enable Node Wrangler addon", icon="NODETREE")
+        layout.label(text="Enable Node Wrangler add-on", icon="NODETREE")
         layout.label(text="If Unconnected or No Image Node Error:", icon="MOD_EXPLODE")
         use_separator(self, context)
         layout.label(text="Extract Alpha: the images have to have alpha channel")
         layout.label(text="The default path is the folder where the current .blend is")
-        layout.label(text="During Baking, the script will check writting privileges")
+        layout.label(text="During Baking, the script will check writing privileges")
         layout.label(text="Set the save path for extracting images with full access")
         layout.label(text="May Require Run As Administrator on Windows OS", icon="ERROR")
         layout.label(text="Converts Bi Textures to Image Files:", icon="MOD_EXPLODE")
@@ -1861,7 +2135,7 @@ class MATERIAL_MT_nodeconv_help(Menu):
         layout.label(text="Select the texture loaded in the image node")
         layout.label(text="Press Ctrl/T to create the image nodes")
         layout.label(text="In the Node Editor, Select the Diffuse Node")
-        layout.label(text="Enable Node Wrangler addon", icon="NODETREE")
+        layout.label(text="Enable Node Wrangler add-on", icon="NODETREE")
         layout.label(text="If Unconnected or No Image Node Error:", icon="MOD_EXPLODE")
         use_separator(self, context)
         layout.label(text="For Specular Nodes, Image color influence has to be enabled")
@@ -1869,7 +2143,7 @@ class MATERIAL_MT_nodeconv_help(Menu):
         layout.label(text="The Converter report can point out to some failures")
         layout.label(text="Not all Files will produce good results", icon="ERROR")
         layout.label(text="fbx, .dae, .obj, .3ds, .xna and more")
-        layout.label(text="**Supports Imported Files**:", icon="IMPORT")
+        layout.label(text="*Supports Imported Files*:", icon="IMPORT")
         use_separator(self, context)
         layout.label(text="For some file types")
         layout.label(text="Supports Alpha, Normals, Specular and Diffuse")
@@ -1880,7 +2154,7 @@ class MATERIAL_MT_nodeconv_help(Menu):
 
 
 # Make Report
-class material_converter_report(Operator):
+class MATERIAL_OT_converter_report(Operator):
     bl_idname = "mat_converter.reports"
     bl_label = "Material Converter Report"
     bl_description = "Report about done Material Conversions"
@@ -1901,208 +2175,309 @@ class material_converter_report(Operator):
         return context.window_manager.invoke_props_dialog(self, width=500)
 
     def execute(self, context):
+
         return {'FINISHED'}
 
 
 # Scene Properties
+class material_specials_scene_mats(PropertyGroup):
+    name = StringProperty()
+    mat_lib = BoolProperty(
+        default=False
+    )
+    mat_fake_user = BoolProperty(
+        default=False
+    )
+
+
 class material_specials_scene_props(PropertyGroup):
     conv_path = StringProperty(
-            name="Save Directory",
-            description=("Path to save images during conversion \n"
-                         "Default is the location of the blend file"),
-            default="//",
-            subtype='DIR_PATH',
-            )
+        name="Save Directory",
+        description="Path to save images during conversion\n"
+                    "Default is the location of the blend file",
+        default="//",
+        subtype='DIR_PATH'
+    )
     EXTRACT_ALPHA = BoolProperty(
-            attr="EXTRACT_ALPHA",
-            default=False,
-            description=("Extract Alpha channel from non-procedural images \n"
-                         "Don't use this option if the image doesn't have Alpha"),
-            )
+        attr="EXTRACT_ALPHA",
+        default=False,
+        description="Extract Alpha channel from non-procedural images\n"
+                    "Don't use this option if the image doesn't have Alpha"
+    )
     SET_FAKE_USER = BoolProperty(
-            attr="SET_FAKE_USER",
-            default=False,
-            description="Set fake user on unused images, so they can be kept in the .blend",
-            )
+        attr="SET_FAKE_USER",
+        default=False,
+        description="Set fake user on unused images, so they can be kept in the .blend"
+    )
     EXTRACT_PTEX = BoolProperty(
-            attr="EXTRACT_PTEX",
-            default=False,
-            description="Extract procedural images and bake them to jpeg",
-            )
+        attr="EXTRACT_PTEX",
+        default=False,
+        description="Extract procedural images and bake them to jpeg"
+    )
     EXTRACT_OW = BoolProperty(
-            attr="Overwrite",
-            default=False,
-            description="Extract textures again instead of re-using priorly extracted textures",
-            )
+        attr="Overwrite",
+        default=False,
+        description="Extract textures again instead of re-using previously extracted textures"
+    )
     SCULPT_PAINT = BoolProperty(
-            attr="SCULPT_PAINT",
-            default=False,
-            description=("Conversion geared towards sculpting and painting.\n"
-                         "Creates a diffuse, glossy mixed with layer weight. \n"
-                         "Image nodes are not connected"),
-            )
+        attr="SCULPT_PAINT",
+        default=False,
+        description="Conversion geared towards sculpting and painting.\n"
+                    "Creates a diffuse, glossy mixed with layer weight.\n"
+                    "Image nodes are not connected"
+    )
     UV_UNWRAP = BoolProperty(
-            attr="UV_UNWRAP",
-            default=False,
-            description=("Use automatical Angle based UV Unwrap of the active Object"),
-            )
+        attr="UV_UNWRAP",
+        default=False,
+        description="Use automatic Angle based UV Unwrap for the Active Object"
+    )
     enable_report = BoolProperty(
-            attr="enable_report",
-            default=False,
-            description=("Enable Converter Report in the UI"),
-            )
+        attr="enable_report",
+        default=False,
+        description="Enable Converter Report in the UI"
+    )
     img_bake_size = EnumProperty(
-            name="Bake Image Size",
-            description="Set the resolution size of baked images \n",
-            items=(('512', "Set : 512 x 512", "Bake Resolution 512 x 512"),
-                   ('1024', "Set : 1024 x 1024", "Bake Resolution 1024 x 1024"),
-                   ('2048', "Set : 2048 x 2048", "Bake Resolution 2048 x 2048")),
-            default='1024',
-            )
+        name="Bake Image Size",
+        description="Set the resolution size of baked images \n",
+        items=(
+            ('512', "Set : 512 x 512", "Bake Resolution 512 x 512"),
+            ('1024', "Set : 1024 x 1024", "Bake Resolution 1024 x 1024"),
+            ('2048', "Set : 2048 x 2048", "Bake Resolution 2048 x 2048")
+        ),
+        default='1024'
+    )
     set_material_name = StringProperty(
-            name="New Material name",
-            description="What Base name pattern to use for a new created Material\n"
-                        "It is appended by an automatic numeric pattern depending\n"
-                        "on the number of Scene's materials containing the Base",
-            default="Material_New",
-            maxlen=128,
-            )
+        name="New Material name",
+        description="What Base name pattern to use for a new created Material\n"
+                    "It is appended by an automatic numeric pattern depending\n"
+                    "on the number of Scene's materials containing the Base",
+        default="Material_New",
+        maxlen=128
+    )
     use_tweak = BoolProperty(
         name="Tweak Settings",
         description="Open Preview Active Material after new Material creation",
-        default=False,
-        )
+        default=False
+    )
+    index_mat = IntProperty(
+        name="index",
+        options={"HIDDEN"}
+    )
 
 
-# Addon Preferences
+# Add-on Preferences
 class VIEW3D_MT_material_utils_pref(AddonPreferences):
     bl_idname = __name__
 
     show_warnings = BoolProperty(
-            name="Enable Warning messages",
-            default=False,
-            description="Show warning messages \n"
-                        "when an action is executed or failed.\n \n"
-                        "Advisable if you don't know how the tool works",
-            )
+        name="Enable Warning messages",
+        default=False,
+        description="Show warning messages when an action is executed or failed"
+    )
     show_remove_mat = BoolProperty(
-            name="Enable Remove all Materials",
-            default=False,
-            description="Enable Remove all Materials for all Selected Objects\n\n"
-                        "Use with care - if you want to keep materials after\n"
-                        "closing or reloading Blender, Set Fake User for them",
-            )
+        name="Enable Remove all Materials",
+        default=False,
+        description="Enable Remove all Materials for all Selected Objects\n\n"
+                    "Use with care - if you want to keep materials after\n"
+                    "closing or reloading Blender, Set Fake User for them"
+    )
     show_mat_preview = BoolProperty(
-            name="Enable Material Preview",
-            default=True,
-            description="Material Preview of the Active Object \n"
-                        "Contains the preview of the active Material, \n"
-                        "Use nodes, Color, Specular and Transparency \n"
-                        "settings depending on the Context and Preferences",
-            )
+        name="Enable Material Preview",
+        default=True,
+        description="Material Preview of the Active Object\n"
+                    "Contains the preview of the active Material,\n"
+                    "Use nodes, Color, Specular and Transparency\n"
+                    "settings depending on the Context and Preferences"
+    )
     set_cleanmatslots = BoolProperty(
-            name="Enable Auto Clean",
-            default=True,
-            description="Enable Automatic Removal of unused Material Slots \n"
-                        "called together with the Assign Material menu option. \n \n"
-                        "Apart from preference and the cases when it affects \n"
-                        "adding materials, enabling it can have some \n"
-                        "performance impact on very dense meshes",
-            )
+        name="Enable Auto Clean",
+        default=True,
+        description="Enable Automatic Removal of unused Material Slots\n"
+                    "called together with the Assign Material menu option.\n"
+                    "Apart from preference and the cases when it affects\n"
+                    "adding materials, enabling it can have some\n"
+                    "performance impact on very dense meshes"
+    )
     show_separators = BoolProperty(
-            name="Use Separators in the menus",
-            default=True,
-            description="Use separators in the menus, a trade-off between \n"
-                        "readability vs. using more space for displaying items",
-            )
+        name="Use Separators in the menus",
+        default=True,
+        description="Use separators in the menus, a trade-off between\n"
+                    "readability vs. using more space for displaying items"
+    )
     show_converters = BoolProperty(
-            name="Enable Converters",
-            default=False,
-            description="Enable Material Converters",
-            )
+        name="Enable Converters",
+        default=False,
+        description="Enable Material Converters"
+    )
     set_preview_size = EnumProperty(
-            name="Preview Menu Size",
-            description="Set the preview menu size \n"
-                        "depending on the number of materials \n"
-                        "in the scene (width and height)",
-            items=(('2x2', "Size 2x2", "Width 2 Height 2"),
-                   ('2x3', "Size 2x3", "Width 3 Height 2"),
-                   ('3x3', "Size 3x3", "Width 3 Height 3"),
-                   ('3x4', "Size 3x4", "Width 4 Height 3"),
-                   ('4x4', "Size 4x4", "Width 4 Height 4"),
-                   ('5x5', "Size 5x5", "Width 5 Height 5"),
-                   ('6x6', "Size 6x6", "Width 6 Height 6"),
-                   ('0x0', "List", "Display as a List")),
-            default='3x3',
-            )
+        name="Preview Menu Size",
+        description="Set the preview menu size\n"
+                    "depending on the number of materials\n"
+                    "in the scene (width and height)",
+        items=(
+            ('2x2', "Size 2x2", "Width 2 Height 2"),
+            ('2x3', "Size 2x3", "Width 3 Height 2"),
+            ('3x3', "Size 3x3", "Width 3 Height 3"),
+            ('3x4', "Size 3x4", "Width 4 Height 3"),
+            ('4x4', "Size 4x4", "Width 4 Height 4"),
+            ('5x5', "Size 5x5", "Width 5 Height 5"),
+            ('6x6', "Size 6x6", "Width 6 Height 6"),
+            ('0x0', "List", "Display as a List")
+        ),
+        default='3x3'
+    )
     set_preview_type = EnumProperty(
-            name="Preview Menu Type",
-            description="Set the the Preview menu type",
-            items=(('LIST', "Classic",
-                    "Display as a Classic List like in Blender Propreties.\n"
-                    "Preview of Active Material is not available"),
-                   ('PREVIEW', "Preview Display",
-                    "Display as a preview of Thumbnails\n"
-                    "It can have some performance issues with scenes containing a lot of materials\n"
-                    "Preview of Active Material is available")),
-            default='PREVIEW',
-            )
+        name="Preview Menu Type",
+        description="Set the the Preview menu type",
+        items=(
+            ('LIST', "Classic",
+            "Display as a Classic List like in Blender Properties.\n"
+            "Preview of Active Material is not available\n\n"
+            "Note: Choosing a different material from the list will replace the active one"),
+            ('PREVIEW', "Preview Display",
+            "Display as a preview of Thumbnails\n"
+            "It can have some performance issues with scenes containing a lot of materials\n"
+            "Preview of Active Material is available\n\n"
+            "Note: Choosing a different material from the list will replace the active one")
+        ),
+        default='PREVIEW'
+    )
     set_experimental_type = EnumProperty(
-            name="Experimental Features",
-            description="Set the Type of converters enabled",
-            items=(('ALL', "All Converters",
-                    "Enable all Converters"),
-                   ('CYC_CONV', "BI and Cycles Nodes",
-                    "Enable Cycles related Convert"),
-                   ('BI_CONV', "BI To Cycles",
-                    "Enable Blender Internal related Converters")),
-            default='ALL',
-            )
+        name="Experimental Features",
+        description="Set the type of converters enabled",
+        items=(
+            ('ALL', "All Converters",
+            "Enable all Converters"),
+            ('CYC_CONV', "BI and Cycles Nodes",
+            "Enable Cycles related Convert"),
+            ('BI_CONV', "BI To Cycles",
+            "Enable Blender Internal related Converters")
+        ),
+        default='ALL',
+    )
+    set_add_material_menu = EnumProperty(
+        name="Add Material Menu",
+        description="Set the type of Add Material menu",
+        items=(
+            ('STANDARD', "Standard Menu",
+            "Material entries in the menu are bellow each other"),
+            ('COLUMNS', "Column Menu",
+            "Material entries are placed in column blocks"),
+            ('POPUP', "Pop up Menu",
+            "Material entries are placed in a scrollable list inside a pop-up menu")
+        ),
+        default='POPUP'
+    )
 
     def draw(self, context):
         layout = self.layout
         sc = context.scene
 
-        box = layout.box()
+        col_m = layout.column(align=True)
+
+        box = col_m.box()
         box.label("Save Directory")
         split = box.split(0.85)
         split.prop(sc.mat_specials, "conv_path", text="", icon="RENDER_RESULT")
-        split.operator("material.check_converter_path",
-                       text="", icon="EXTERNAL_DATA")
-
-        box = layout.box()
+        split.operator(
+            "material.check_converter_path",
+            text="", icon="EXTERNAL_DATA"
+        )
+        box = col_m.box()
         split = box.split(align=True)
 
-        col = split.column()
+        col = split.column(align=True)
         col.prop(self, "show_warnings")
         col.prop(self, "show_remove_mat")
-
-        col = split.column()
-        col.alignment = 'RIGHT'
         col.prop(self, "set_cleanmatslots")
         col.prop(self, "show_separators")
 
-        boxie = box.box()
-        split = boxie.split(percentage=0.3)
+        col = split.column(align=True)
+        col.label("Apply / Select Material mode:")
+        col.prop(self, "set_add_material_menu", expand=True)
+
+        box = col_m.box()
+        size_split = 0.3 if self.show_mat_preview else 1.0
+        split = box.split(percentage=size_split, align=True)
         split.prop(self, "show_mat_preview")
+
         if self.show_mat_preview:
-            rowsy = split.row(align=True)
-            rowsy.enabled = True if self.show_mat_preview else False
-            rowsy.prop(self, "set_preview_type", expand=True)
-            rowsa = boxie.row(align=True)
-            rowsa.enabled = True if self.set_preview_type in {'PREVIEW'} else False
-            rowsa.prop(self, "set_preview_size", expand=True)
-
-        boxif = box.box()
-        split = boxif.split(percentage=0.3)
+            subsplit = split.split(percentage=0.7, align=True)
+            row = subsplit.row(align=True)
+            row.prop(self, "set_preview_type", expand=True)
+
+            subrow = subsplit.row(align=True)
+            subrow.enabled = True if self.set_preview_type in {'PREVIEW'} else False
+            subrow.prop(self, "set_preview_size", text="")
+
+        box = col_m.box()
+        size_split = 0.3 if self.show_converters else 1.0
+        split = box.split(percentage=size_split, align=True)
         split.prop(self, "show_converters")
+
         if self.show_converters:
-            rowe = split.row(align=True)
-            rowe.prop(self, "set_experimental_type", expand=True)
+            row = split.row(align=True)
+            row.prop(self, "set_experimental_type", expand=True)
 
 
 # utility functions:
 
+def help_panel_header(layout, menu_type="VIEW3D_MT_master_material"):
+    layout.separator()
+    box = layout.box()
+    box.scale_y = 0.5
+    box.menu(menu_type, text="", icon="INFO")
+    layout.separator()
+
+
+def activate_mat_slot(actob, matname):
+    mats = actob.material_slots
+    for i, m in enumerate(mats):
+        if m.name == matname:
+            # make slot active
+            actob.active_material_index = i
+            break
+
+
+def materials_lists_fill_names(context, refresh=False, is_object=False):
+    mats_list = context.scene.mat_specials_mats
+    if refresh:
+        for key in mats_list.keys():
+            index = mats_list.find(key)
+            if index != -1:
+                mats_list.remove(index)
+
+    obj = context.active_object
+    mat_collection = []
+    if (is_object and obj):
+        mat_collection = [
+                slot.material for slot in obj.material_slots if
+                slot.material
+                ]
+    else:
+        mat_collection = bpy.data.materials
+
+    for mat in mat_collection:
+        if mat.name not in mats_list.keys() or refresh:
+            prop = mats_list.add()
+            prop.name = mat.name
+            prop.mat_lib = bool(mat.library)
+            prop.mat_fake_user = mat.use_fake_user
+
+
+def switch_to_column(is_edit=False):
+    obj = bpy.context.active_object
+    collect = obj.material_slots if is_edit else bpy.data.materials
+    col_size = int(round(len(collect) / COLUMN_SPLIT))
+
+    return col_size if col_size > 0 else 1
+
+
+def remove_material_slot():
+    if bpy.ops.object.material_slot_remove.poll():
+        bpy.ops.object.material_slot_remove()
+
+
 def check_mat_name_unique(name_id="Material_new"):
     # check if the new name pattern is in materials' data
     name_list = []
@@ -2229,6 +2604,13 @@ def use_remove_mat_all():
     return bool(show_rmv_mat)
 
 
+def use_mat_menu_type():
+    pref = return_preferences()
+    use_menu_mat = pref.set_add_material_menu
+
+    return use_menu_mat
+
+
 def use_mat_preview():
     pref = return_preferences()
     show_mat_prw = pref.show_mat_preview
@@ -2283,8 +2665,12 @@ def register():
 
     # Register Scene Properties
     bpy.types.Scene.mat_specials = PointerProperty(
-                                        type=material_specials_scene_props
-                                        )
+        type=material_specials_scene_props
+    )
+    bpy.types.Scene.mat_specials_mats = CollectionProperty(
+        name="Material name",
+        type=material_specials_scene_mats
+    )
 
     kc = bpy.context.window_manager.keyconfigs.addon
     if kc:
@@ -2310,6 +2696,7 @@ def unregister():
     bpy.types.MATERIAL_MT_specials.remove(menu_func)
 
     del bpy.types.Scene.mat_specials
+    del bpy.types.Scene.mat_specials_mats
 
     bpy.utils.unregister_module(__name__)
 
diff --git a/materials_utils/material_converter.py b/materials_utils/material_converter.py
index dfde5c50f1b92c1b573efb7ba3a6b469333b7ffa..bf52bec1de3f5b73e8f3665c5065f2cb5dc32a49 100644
--- a/materials_utils/material_converter.py
+++ b/materials_utils/material_converter.py
@@ -1,14 +1,15 @@
 # -*- coding: utf-8 -*-
 
 import bpy
+import math
 from mathutils import Vector
 from bpy.types import Operator
 from .warning_messages_utils import (
-        warning_messages,
-        c_is_cycles_addon_enabled,
-        c_data_has_materials,
-        collect_report,
-        )
+    warning_messages,
+    c_is_cycles_addon_enabled,
+    c_data_has_materials,
+    collect_report,
+)
 
 # -----------------------------------------------------------------------------
 # Globals
@@ -665,7 +666,7 @@ def makeCyclesFromBI(cmat):
 
     # Make Diffuse and Output nodes
     mainShader = makeMainShader(TreeNodes)
-    mainShader.inputs['Roughness'].default_value = cmat.specular_intensity
+    mainShader.inputs['Roughness'].default_value = math.sqrt(max(cmat.specular_intensity, 0.0))
     mainDiffuse = mainShader
     materialOutput = makeMaterialOutput(TreeNodes)
     links.new(mainShader.outputs['BSDF'], materialOutput.inputs['Surface'])
@@ -752,6 +753,7 @@ class material_convert_all(Operator):
 
     def execute(self, context):
         AutoNode(False, self)
+
         return {'FINISHED'}
 
 
@@ -766,13 +768,12 @@ class material_convert_selected(Operator):
     def poll(cls, context):
         return (bpy.data.filepath != "" and c_data_has_materials() and
                 c_is_cycles_addon_enabled() and
-                bool(next((obj for obj in context.selected_objects if obj.type == 'MESH'),
-                         None)
-                    )
+                bool(next((obj for obj in context.selected_objects if obj.type == 'MESH'), None))
                 )
 
     def execute(self, context):
         AutoNode(True, self)
+
         return {'FINISHED'}
 
 
diff --git a/materials_utils/materials_cycles_converter.py b/materials_utils/materials_cycles_converter.py
index c9dd994dbe374205bf2b523f3295fab6b21672fc..13e1e1ec2ad06542960b09a3d44d4605412ae471 100644
--- a/materials_utils/materials_cycles_converter.py
+++ b/materials_utils/materials_cycles_converter.py
@@ -6,18 +6,18 @@ import bpy
 from os import path as os_path
 from bpy.types import Operator
 from math import (
-        log2, ceil,
-        )
+    log2, ceil, sqrt,
+)
 from bpy.props import (
-        BoolProperty,
-        EnumProperty,
-        )
+    BoolProperty,
+    EnumProperty,
+)
 from .warning_messages_utils import (
-        warning_messages,
-        c_is_cycles_addon_enabled,
-        c_data_has_materials,
-        collect_report,
-        )
+    warning_messages,
+    c_is_cycles_addon_enabled,
+    c_data_has_materials,
+    collect_report,
+)
 
 # -----------------------------------------------------------------------------
 # Globals
@@ -130,7 +130,7 @@ def BakingText(tex, mode, tex_type=None):
     img = bpy.data.images.get("TMP_BAKING")
     img.file_format = ("JPEG" if not mode == "ALPHA" else "PNG")
 
-    # switch temporarly to 'IMAGE EDITOR', other approaches are not reliable
+    # switch temporarily to 'IMAGE EDITOR', other approaches are not reliable
     check_area = False
     store_area = bpy.context.area.type
     collect_report("INFO: Temporarly switching context to Image Editor")
@@ -267,8 +267,7 @@ def AutoNode(active=False, operator=None):
             for n in TreeNodes.nodes:
                 TreeNodes.nodes.remove(n)
 
-            # Starting point is diffuse BSDF and output material
-            # and a Color Ramp node
+            # Starting point is diffuse BSDF and output material and a Color Ramp node
             shader = TreeNodes.nodes.new('ShaderNodeBsdfDiffuse')
             shader.location = 10, 10
             shader_val = TreeNodes.nodes.new('ShaderNodeValToRGB')
@@ -382,7 +381,7 @@ def AutoNode(active=False, operator=None):
             else:
                 # Create Clay Material (Diffuse, Glossy, Layer Weight)
                 shader.inputs['Color'].default_value = PAINT_SC_COLOR
-                shader.inputs['Roughness'].default_value = 0.9
+                shader.inputs['Roughness'].default_value = 0.9486
 
                 # remove Color Ramp and links from the default shader and reroute
                 try:
@@ -416,10 +415,10 @@ def AutoNode(active=False, operator=None):
                     shader.inputs['Roughness'].default_value = cmat.specular_intensity
 
                 if shader.type == 'ShaderNodeBsdfGlossy':
-                    shader.inputs['Roughness'].default_value = 1 - cmat.raytrace_mirror.gloss_factor
+                    shader.inputs['Roughness'].default_value = sqrt(max(1 - cmat.raytrace_mirror.gloss_factor, 0.0))
 
                 if shader.type == 'ShaderNodeBsdfGlass':
-                    shader.inputs['Roughness'].default_value = 1 - cmat.raytrace_mirror.gloss_factor
+                    shader.inputs['Roughness'].default_value = sqrt(max(1 - cmat.raytrace_mirror.gloss_factor, 0.0))
                     shader.inputs['IOR'].default_value = cmat.raytrace_transparency.ior
 
                 if shader.type == 'ShaderNodeEmission':
@@ -848,6 +847,21 @@ def create_mix_node(TreeNodes, links, nodes, loc, start, median_point, row, fram
     return mix_node
 
 
+def unwrap_active_object(context):
+    enable_unwrap = context.scene.mat_specials.UV_UNWRAP
+    if enable_unwrap:
+        obj_name = getattr(context.active_object, "name", "UNNAMED OBJECT")
+        try:
+            # it's possible that the active object would fail UV Unwrap
+            bpy.ops.object.editmode_toggle()
+            bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.001)
+            bpy.ops.object.editmode_toggle()
+            collect_report("INFO: UV Unwrapping active object {}".format(obj_name))
+        except:
+            collect_report("ERROR: UV Unwrapping failed for "
+                           "active object {}".format(obj_name))
+
+
 # -----------------------------------------------------------------------------
 # Operator Classes
 
@@ -866,10 +880,8 @@ class mllock(Operator):
         TreeNodes = cmat.node_tree
         for n in TreeNodes.nodes:
             if n.type == 'ShaderNodeOutputMaterial':
-                if n.label == 'Locked':
-                    n.label = ''
-                else:
-                    n.label = 'Locked'
+                n.label = "" if n.label == "Locked" else "Locked"
+
         return {'FINISHED'}
 
 
@@ -882,28 +894,17 @@ class mlrefresh(Operator):
 
     @classmethod
     def poll(cls, context):
-        return (bpy.data.filepath != ""and c_is_cycles_addon_enabled() and
+        return (bpy.data.filepath != "" and c_is_cycles_addon_enabled() and
                 c_data_has_materials())
 
     def execute(self, context):
         AutoNodeInitiate(False, self)
 
         if CHECK_AUTONODE is True:
-            enable_unwrap = bpy.context.scene.mat_specials.UV_UNWRAP
-            if enable_unwrap:
-                obj_name = getattr(context.active_object, "name", "UNNAMED OBJECT")
-                try:
-                    # it's possible to the active object would fail UV Unwrap
-                    bpy.ops.object.editmode_toggle()
-                    bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.001)
-                    bpy.ops.object.editmode_toggle()
-                    collect_report("INFO: UV Unwrapping active object "
-                                   "{}".format(obj_name))
-                except:
-                    collect_report("ERROR: UV Unwrapping failed for "
-                                   "active object {}".format(obj_name))
+            unwrap_active_object(context)
 
         collect_report("Conversion finished !", False, True)
+
         return {'FINISHED'}
 
 
@@ -922,20 +923,10 @@ class mlrefresh_active(Operator):
     def execute(self, context):
         AutoNodeInitiate(True, self)
         if CHECK_AUTONODE is True:
-            obj_name = getattr(context.active_object, "name", "UNNAMED OBJECT")
-            enable_unwrap = bpy.context.scene.mat_specials.UV_UNWRAP
-            if enable_unwrap:
-                try:
-                    # you can already guess it, what could happen here
-                    bpy.ops.object.editmode_toggle()
-                    bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.001)
-                    bpy.ops.object.editmode_toggle()
-                    collect_report("INFO: UV Unwrapping object {}".format(obj_name))
-                except:
-                    collect_report("ERROR: UV Unwrapping failed for "
-                                   "object {}".format(obj_name))
+            unwrap_active_object(context)
 
         collect_report("Conversion finished !", False, True)
+
         return {'FINISHED'}
 
 
@@ -947,27 +938,28 @@ class mlrestore(Operator):
     bl_options = {'REGISTER', 'UNDO'}
 
     switcher = BoolProperty(
-            name="Use Nodes",
-            description="When restoring, switch Use Nodes On/Off",
-            default=True
-            )
+        name="Use Nodes",
+        description="When restoring, switch Use Nodes On/Off",
+        default=True
+    )
     renderer = EnumProperty(
-            name="Renderer",
-            description="Choose Cycles or Blender Internal",
-            items=(('CYCLES', "Cycles", "Switch to Cycles"),
-                   ('BI', "Blender Internal", "Switch to Blender Internal")),
-            default='CYCLES',
-            )
+        name="Renderer",
+        description="Choose Cycles or Blender Internal",
+        items=(
+            ('CYCLES', "Cycles", "Switch to Cycles"),
+            ('BI', "Blender Internal", "Switch to Blender Internal")
+        ),
+        default='CYCLES',
+    )
 
     @classmethod
     def poll(cls, context):
         return c_is_cycles_addon_enabled()
 
     def execute(self, context):
-        if self.switcher:
-            AutoNodeSwitch(self.renderer, "ON", self)
-        else:
-            AutoNodeSwitch(self.renderer, "OFF", self)
+        switch = "ON" if self.switcher else "OFF"
+        AutoNodeSwitch(self.renderer, switch, self)
+
         return {'FINISHED'}
 
 
diff --git a/materials_utils/texture_rename.py b/materials_utils/texture_rename.py
index c803295eb6008d08bb78916528e31a1e0dfa792b..585a3a7d90cdd90b11a8e85e7e0628598891f5b9 100644
--- a/materials_utils/texture_rename.py
+++ b/materials_utils/texture_rename.py
@@ -3,31 +3,41 @@
 
 import bpy
 from bpy.types import (
-        Operator,
-        Panel,
-        )
-from bpy.props import StringProperty
+    Operator,
+    Panel,
+)
+from bpy.props import (
+    BoolProperty,
+    StringProperty,
+)
 from .warning_messages_utils import (
-        warning_messages,
-        c_data_has_images,
-        )
+    warning_messages,
+    c_data_has_images,
+)
 
 
 class TEXTURE_OT_patern_rename(Operator):
     bl_idname = "texture.patern_rename"
     bl_label = "Texture Renamer"
     bl_description = ("Replace the Texture names pattern with the attached Image ones\n"
-                      "Works on all Textures (Including Brushes) \n \n"
-                      "The First field - the name pattern to replace \n"
-                      "The Second - searches for existing names \n")
+                      "Works on all Textures (Including Brushes)\n"
+                      "The First field - the name pattern to replace\n"
+                      "The Second - search for existing names")
     bl_options = {'REGISTER', 'UNDO'}
 
     def_name = "Texture"    # default name
     is_not_undo = False     # prevent drawing props on undo
+
     named = StringProperty(
-                name="Search for name",
-                default=def_name
-                )
+        name="Search for name",
+        description="Enter the name pattern or choose the one from the dropdown list below",
+        default=def_name
+    )
+    replace_all = BoolProperty(
+        name="Replace all",
+        description="Replace all the Textures in the data with the names of the images attached",
+        default=False
+    )
 
     @classmethod
     def poll(cls, context):
@@ -35,28 +45,35 @@ class TEXTURE_OT_patern_rename(Operator):
 
     def draw(self, context):
         layout = self.layout
-        if self.is_not_undo is True:
-            box = layout.box()
-            box.prop(self, "named", text="Name pattern", icon="SYNTAX_ON")
-            layout.separator()
+        if not self.is_not_undo:
+            layout.label(text="*Only Undo is available*", icon="INFO")
+            return
+
+        layout.prop(self, "replace_all")
 
-            box = layout.box()
-            box.prop_search(self, "named", bpy.data, "textures")
-        else:
-            layout.label(text="**Only Undo is available**", icon="INFO")
+        box = layout.box()
+        box.enabled = not self.replace_all
+        box.prop(self, "named", text="Name pattern", icon="SYNTAX_ON")
+
+        box = layout.box()
+        box.enabled = not self.replace_all
+        box.prop_search(self, "named", bpy.data, "textures")
 
     def invoke(self, context, event):
         self.is_not_undo = True
         return context.window_manager.invoke_props_dialog(self)
 
+    def check(self, context):
+        return self.is_not_undo
+
     def execute(self, context):
         errors = []     # collect texture names without images attached
-        tex_count = 0   # check if there is textures at all
+        tex_count = len(bpy.data.textures)
 
         for texture in bpy.data.textures:
             try:
-                if texture and self.named in texture.name and texture.type in {"IMAGE"}:
-                    tex_count += 1
+                is_allowed = self.named in texture.name if not self.replace_all else True
+                if texture and is_allowed and texture.type in {"IMAGE"}:
                     textname = ""
                     img = (bpy.data.textures[texture.name].image if bpy.data.textures[texture.name] else None)
                     if not img:
@@ -67,7 +84,7 @@ class TEXTURE_OT_patern_rename(Operator):
                         else:
                             break
                     texture.name = textname
-                if texture.type != "IMAGE":  # rename specific textures as clouds, environnement map,...
+                if texture.type != "IMAGE":  # rename specific textures as clouds, environment map...
                     texture.name = texture.type.lower()
             except:
                 continue
@@ -86,7 +103,6 @@ class TEXTURE_OT_patern_rename(Operator):
 
 
 class TEXTURE_PT_rename_panel(Panel):
-    # Creates a Panel in the scene context of the properties editor
     bl_label = "Texture Rename"
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
@@ -98,13 +114,13 @@ class TEXTURE_PT_rename_panel(Panel):
 
 
 def register():
-    bpy.utils.register_module(__name__)
-    pass
+    bpy.utils.register_class(TEXTURE_OT_patern_rename)
+    bpy.utils.register_class(TEXTURE_PT_rename_panel)
 
 
 def unregister():
-    bpy.utils.unregister_module(__name__)
-    pass
+    bpy.utils.unregister_class(TEXTURE_PT_rename_panel)
+    bpy.utils.unregister_class(TEXTURE_OT_patern_rename)
 
 
 if __name__ == "__main__":
diff --git a/materials_utils/warning_messages_utils.py b/materials_utils/warning_messages_utils.py
index 2e5f3b695cc46da17fb5aae30136a7daccb7fa69..00f4a719c7bd56ff4cd9c344c9abbcb52a823435 100644
--- a/materials_utils/warning_messages_utils.py
+++ b/materials_utils/warning_messages_utils.py
@@ -21,7 +21,7 @@ def warning_messages(operator=None, warn='DEFAULT', object_name="", is_mat=None,
     # a list of strings can be passed and concatenated in obj_name too
     # is_mat a switch to change to materials or textures for obj_name('MAT','TEX', 'FILE', None)
     # fake - optional string that can be passed
-    # MAX_COUNT - max members of an list to be displayed
+    # MAX_COUNT - max members of an list to be displayed in UI report
     # override - important messages that should be enabled, no matter the setting
 
     # pass the show_warnings bool to enable/disable them
@@ -72,6 +72,8 @@ def warning_messages(operator=None, warn='DEFAULT', object_name="", is_mat=None,
                                          "not cleaned"),
             'C_OB_MIX_NO_MAT': "{}{}".format(obj_name, "No Materials or an Object type that "
                                              "can't have Materials (Clean Material Slots)"),
+            'C_OB_MIX_SLOT_MAT': "{}{}".format(obj_name, "No Materials or only empty Slots are removed  "
+                                                "(Clean Material Slots)"),
             'R_OB_NO_MAT': "{}{}".format(obj_name, "No Materials. Nothing to remove"),
             'R_OB_FAIL_MAT': "{}{}".format(obj_name, "Failed to remove materials - (Operator Error)"),
             'R_NO_SL_MAT': "No Selection. Material slots are not removed",
@@ -79,6 +81,7 @@ def warning_messages(operator=None, warn='DEFAULT', object_name="", is_mat=None,
             'R_ALL_NO_MAT': "Object(s) have no materials to remove",
             'R_ACT_MAT': "{}{}".format(obj_name, "Removed active Material"),
             'R_ACT_MAT_ALL': "{}{}".format(obj_name, "Removed all Material from the Object"),
+            'SL_MAT_EDIT_BY_NAME': "{}{}{}".format("Geometry with the Material ", obj_name, "been selected"),
             'SL_MAT_BY_NAME': "{}{}{}".format("Objects with the Material ", obj_name, "been selected"),
             'OB_CANT_MAT': "{}{}".format(obj_name, "Object type that can't have Materials"),
             'REP_MAT_NONE': "Replace Material: No materials replaced",
@@ -123,17 +126,18 @@ def warning_messages(operator=None, warn='DEFAULT', object_name="", is_mat=None,
         operator.report({'INFO'}, message[warn])
 
         if obj_size_big is True:
-            print("\n** MATERIAL SPECIALS **: \n Full list for the Info message is: \n",
-                  ", ".join(object_name), "\n")
+            print("\n[Materials Utils Specials]:\nFull list for the Info message is:\n\n",
+                  " ".join(names + "," + "\n" * ((i + 1) % 10 == 0) for i, names in enumerate(object_name)),
+                  "\n")
 
-    # restore settings if overriden
+    # restore settings if overridden
     if override:
         addon.preferences.show_warnings = get_warn
 
 
 def collect_report(collection="", is_start=False, is_final=False):
     # collection passes a string for appending to COLLECT_REPORT global
-    # is_final swithes to the final report with the operator in __init__
+    # is_final switches to the final report with the operator in __init__
     global COLLECT_REPORT
     scene = bpy.context.scene.mat_specials
     use_report = scene.enable_report
@@ -164,20 +168,14 @@ def c_data_has_materials():
     return (len(bpy.data.materials) > 0)
 
 
+def c_obj_data_has_materials(obj):
+    # check for material presence in object's data
+    matlen = 0
+    if obj:
+        matlen = len(obj.data.materials)
+    return (matlen > 0)
+
+
 def c_data_has_images():
     # check for image presence in data
     return (len(bpy.data.images) > 0)
-
-
-def register():
-    bpy.utils.register_module(__name__)
-    pass
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
-    pass
-
-
-if __name__ == "__main__":
-    register()
diff --git a/measureit/__init__.py b/measureit/__init__.py
index 489e0a9e6651bd9e5b840868181f251c375afd50..b5791bbfdfd18e1ff1d8e5e27b4421ec290c96e4 100644
--- a/measureit/__init__.py
+++ b/measureit/__init__.py
@@ -29,7 +29,7 @@ bl_info = {
     "name": "MeasureIt",
     "author": "Antonio Vazquez (antonioya)",
     "location": "View3D > Tools Panel /Properties panel",
-    "version": (1, 7, 0),
+    "version": (1, 7, 1),
     "blender": (2, 7, 4),
     "description": "Tools for measuring objects.",
     "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/"
@@ -37,8 +37,6 @@ bl_info = {
     "category": "3D View"
 }
 
-import sys
-import os
 
 # ----------------------------------------------
 # Import modules
diff --git a/measureit/measureit_geometry.py b/measureit/measureit_geometry.py
index 8b0b837103ca865b6e1ca7a1341b22ca0d7f9c1b..1617ed5ad8681b16028a91df4606e8c94e5dc5fa 100644
--- a/measureit/measureit_geometry.py
+++ b/measureit/measureit_geometry.py
@@ -75,7 +75,7 @@ def draw_segments(context, myobj, op, region, rv3d):
         # --------------------
         # Loop
         # --------------------
-        for idx in range(0, op.measureit_num):
+        for idx in range(op.measureit_num):
             ms = op.measureit_segments[idx]
             if ovr is False:
                 fsize = ms.glfont_size
@@ -557,7 +557,7 @@ def draw_segments(context, myobj, op, region, rv3d):
                         p_02a = None
                         p_02b = None
                         # draw the arc
-                        for i in range(0, int(n_step)):
+                        for i in range(int(n_step)):
                             p2 = mat_trans2 * mat_rot1 * mat_trans1 * p1
                             p1_ = (p1[0] + vi[0], p1[1] + vi[1], p1[2] + vi[2])
                             # First Point
@@ -606,7 +606,7 @@ def draw_segments(context, myobj, op, region, rv3d):
                         for face in ms.measureit_faces:
                             myvertices = []
                             for v in face.measureit_index:
-                                myvertices.extend([v.glidx])
+                                myvertices.append(v.glidx)
 
                             area = get_area_and_paint(myvertices, myobj, obverts, region, rv3d)
                             tot += area
@@ -668,7 +668,7 @@ def get_area_and_paint(myvertices, myobj, obverts, region, rv3d):
             bm = from_edit_mesh(myobj.data)
             myv = []
             for v in bm.verts:
-                myv.extend([v.co])
+                myv.append(v.co)
             tris = mesh_utils.ngon_tessellate(myv, myvertices)
 
         for t in tris:
@@ -750,7 +750,7 @@ def get_group_sum(myobj, tag):
         scale = bpy.context.scene.unit_settings.scale_length
         tot = 0.0
         obverts = get_mesh_vertices(myobj)
-        for idx in range(0, mp.measureit_num):
+        for idx in range(mp.measureit_num):
             ms = mp.measureit_segments[idx]
             if (ms.gltype == 1 or ms.gltype == 12 or
                 ms.gltype == 13 or ms.gltype == 14) and ms.gltot != '99' \
diff --git a/measureit/measureit_main.py b/measureit/measureit_main.py
index 89a48799a438c74350a379b889f77a23cbf747d6..c85de95d7a6823bc7ea13eb31004aa9dea4bee2b 100644
--- a/measureit/measureit_main.py
+++ b/measureit/measureit_main.py
@@ -408,7 +408,7 @@ class MeasureitEditPanel(Panel):
                     row = box.row(True)
                     row.operator("measureit.expandallsegmentbutton", text="Expand all", icon="ZOOMIN")
                     row.operator("measureit.collapseallsegmentbutton", text="Collapse all", icon="ZOOMOUT")
-                    for idx in range(0, mp.measureit_num):
+                    for idx in range(mp.measureit_num):
                         if mp.measureit_segments[idx].glfree is False:
                             add_item(box, idx, mp.measureit_segments[idx])
 
@@ -426,7 +426,7 @@ class MeasureitEditPanel(Panel):
                     myobj = context.object
                     obverts = get_mesh_vertices(myobj)
                     viewtot = False
-                    for idx in range(0, mp.measureit_num):
+                    for idx in range(mp.measureit_num):
                         ms = mp.measureit_segments[idx]
                         if (ms.gltype == 1 or ms.gltype == 12
                             or ms.gltype == 13 or ms.gltype == 14) and ms.gltot != '99' \
@@ -472,7 +472,7 @@ class MeasureitEditPanel(Panel):
                         box = layout.box()
                         box.label("Totals", icon='SOLO_ON')
                         final = 0
-                        for idx in range(0, len(tot)):
+                        for idx in range(len(tot)):
                             if ac[idx] is True:
                                 final += tot[idx]
                                 tx_dist = format_distance(fmt, units, tot[idx])
@@ -1030,7 +1030,7 @@ class AddSegmentOrtoButton(Operator):
                     mainobject.MeasureGenerator.add()
 
                 mp = mainobject.MeasureGenerator[0]
-                for x in range(0, len(mylist)):
+                for x in range(len(mylist)):
                     # -----------------------
                     # Only if not exist
                     # -----------------------
@@ -1658,7 +1658,7 @@ class DeleteAllSumButton(Operator):
         if context.object is not None:
             if 'MeasureGenerator' in context.object:
                 mp = context.object.MeasureGenerator[0]
-                for idx in range(0, mp.measureit_num):
+                for idx in range(mp.measureit_num):
                     ms = mp.measureit_segments[idx]
                     ms.gltot = '99'
 
@@ -2011,19 +2011,22 @@ def draw_main(context):
         rv3d = context.space_data.region_quadviews[i]
 
     scene = bpy.context.scene
-    # Get visible layers
+    local_view = context.area.spaces.active.local_view is not None
     layers = []
-    if bpy.context.space_data.lock_camera_and_layers is True:
-        for x in range(0, 20):
-            if bpy.context.scene.layers[x] is True:
-                layers.extend([x])
-    else:
-        for x in range(20):
-            if bpy.context.space_data.layers[x] is True:
-                layers.extend([x])
+    if local_view is False:
+        # Get visible layers
+        if bpy.context.space_data.lock_camera_and_layers is True:
+            for x in range(20):
+                if bpy.context.scene.layers[x] is True:
+                    layers.append(x)
+        else:
+            # Lock disabled, use view dependent visible layers
+            for x in range(20):
+                if bpy.context.space_data.layers[x] is True:
+                    layers.append(x)
 
     # Display selected or all
-    if scene.measureit_gl_ghost is False:
+    if scene.measureit_gl_ghost is False or local_view is True:
         objlist = context.selected_objects
     else:
         objlist = context.scene.objects
@@ -2036,13 +2039,18 @@ def draw_main(context):
     for myobj in objlist:
         if myobj.hide is False:
             if 'MeasureGenerator' in myobj:
-                # verify visible layer
-                for x in range(0, 20):
-                    if myobj.layers[x] is True:
-                        if x in layers:
+                if local_view is False:
+                    # verify visible layer
+                    for x in range(20):
+                        if myobj.layers[x] is True and x in layers:
                             op = myobj.MeasureGenerator[0]
                             draw_segments(context, myobj, op, region, rv3d)
-                        break
+                            break
+                else:
+                    # Layer check not needed here, selected objects are not
+                    # added to context.selected_objects if in disabled layers
+                    op = myobj.MeasureGenerator[0]
+                    draw_segments(context, myobj, op, region, rv3d)
     # ---------------------------------------
     # Generate all OpenGL calls for debug
     # ---------------------------------------
@@ -2120,7 +2128,7 @@ def get_selected_vertex(myobject):
     tv = len(bm.verts)
     for v in bm.verts:
         if v.select:
-            mylist.extend([v.index])
+            mylist.append(v.index)
 
     if flag is True:
         bpy.ops.object.editmode_toggle()
@@ -2154,7 +2162,7 @@ def get_selected_vertex_history(myobject):
 
     bm = from_edit_mesh(myobject.data)
     for v in bm.select_history:
-        mylist.extend([v.index])
+        mylist.append(v.index)
 
     if flag is True:
         bpy.ops.object.editmode_toggle()
@@ -2185,8 +2193,8 @@ def get_smart_selected(myobject):
     bm = from_edit_mesh(myobject.data)
     for e in bm.edges:
         if e.select is True:
-            mylist.extend([e.verts[0].index])
-            mylist.extend([e.verts[1].index])
+            mylist.append(e.verts[0].index)
+            mylist.append(e.verts[1].index)
 
     if flag is True:
         bpy.ops.object.editmode_toggle()
@@ -2216,12 +2224,12 @@ def get_selected_faces(myobject):
 
     bm = from_edit_mesh(myobject.data)
     for e in bm.faces:
-        myface = []
+        myfaces = []
         if e.select is True:
-            for i in range(0, len(e.verts)):
-                myface.extend([e.verts[i].index])
+            for i in range(len(e.verts)):
+                myfaces.append(e.verts[i].index)
 
-            mylist.extend([myface])
+            mylist.extend([myfaces])
 
     if flag is True:
         bpy.ops.object.editmode_toggle()
diff --git a/measureit/measureit_render.py b/measureit/measureit_render.py
index eb04c92de4e5ef61753f59119c5d8c04d74b58ac..d5eb64301e3eb12755138f8862daa44797a34567 100644
--- a/measureit/measureit_render.py
+++ b/measureit/measureit_render.py
@@ -56,9 +56,9 @@ def render_main(self, context, animation=False):
         # Get visible layers
         layers = []
         scene = context.scene
-        for x in range(0, 20):
+        for x in range(20):
             if scene.layers[x] is True:
-                layers.extend([x])
+                layers.append(x)
 
         # Get object list
         objlist = context.scene.objects
@@ -124,8 +124,8 @@ def render_main(self, context, animation=False):
         # --------------------------------
         # Loop for all tiles
         # --------------------------------
-        for row in range(0, row_num):
-            for col in range(0, col_num):
+        for row in range(row_num):
+            for col in range(col_num):
                 buffer = bgl.Buffer(bgl.GL_FLOAT, width * height * 4)
                 bgl.glDisable(bgl.GL_SCISSOR_TEST)  # if remove this line, get blender screenshot not image
                 bgl.glViewport(0, 0, tile_x, tile_y)
@@ -170,7 +170,7 @@ def render_main(self, context, animation=False):
                     if myobj.hide is False:
                         if 'MeasureGenerator' in myobj:
                             # verify visible layer
-                            for x in range(0, 20):
+                            for x in range(20):
                                 if myobj.layers[x] is True:
                                     if x in layers:
                                         op = myobj.MeasureGenerator[0]
@@ -216,7 +216,7 @@ def render_main(self, context, animation=False):
                 # --------------------------------
                 bgl.glFinish()
                 bgl.glReadPixels(0, 0, width, height, bgl.GL_RGBA, bgl.GL_FLOAT, buffer)  # read image data
-                for y in range(0, tile_y):
+                for y in range(tile_y):
                     # final image pixels position
                     p1 = (y * width * 4) + (row * tile_y * width * 4) + (col * tile_x * 4)
                     p2 = p1 + (tile_x * 4)
diff --git a/mesh_carver.py b/mesh_carver.py
index aa388a1580f979e24714690f9b64df70d5646abc..16308aa4e7c423c832da3ab6381532f95cf74998 100644
--- a/mesh_carver.py
+++ b/mesh_carver.py
@@ -21,37 +21,44 @@ bl_info = {
     "name": "Carver MT",
     "category": "Object",
     "author": "Pixivore, Cedric LEPILLER, Ted Milker",
-    "version": (1, 1, 7),
-    "blender": (2, 77, 0),
+    "version": (1, 1, 8),
+    "blender": (2, 79, 2),
     "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
                 "Scripts/Modeling/Carver",
     "description": "Multiple tools to carve or to create objects",
-    }
+}
 
 import bpy
 import bgl
 import blf
 import math
-import mathutils
 import sys
 import random
 import bmesh
+from mathutils import (
+    Color,
+    Euler,
+    Matrix,
+    Vector,
+    Quaternion,
+)
 import bpy_extras
 from bpy.props import (
-        BoolProperty,
-        EnumProperty,
-        IntProperty,
-        StringProperty,
-        )
+    BoolProperty,
+    IntProperty,
+    PointerProperty,
+    StringProperty,
+)
 from bpy_extras import view3d_utils
 from bpy_extras.view3d_utils import (
-        region_2d_to_vector_3d,
-        region_2d_to_location_3d,
-        )
+    region_2d_to_vector_3d,
+    region_2d_to_location_3d,
+)
+
 
 Profils = [
     ("CTP_4882",
-     mathutils.Vector((2.61824, -5.56469, 0)),
+      Vector((2.61824, -5.56469, 0)),
      [(-1.156501, 0.799282, 0.032334),
       (-0.967583, 0.838861, 0.032334),
       (-1.10386, 0.846403, 0.032334),
@@ -108,7 +115,7 @@ Profils = [
       [38, 39, 47], [34, 32, 35], [39, 46, 47], [43, 34, 35], [35, 38, 47], [47, 42, 35], [32, 33, 35],
       [42, 40, 43], [36, 37, 39], [42, 43, 35], [44, 45, 47], [46, 44, 47]]),
     ("CTP_8354",
-     mathutils.Vector((-0.06267, -2.43829, -0.0)),
+     Vector((-0.06267, -2.43829, -0.0)),
      [(-0.534254, -1.0, 0.032334),
       (-1.0, -0.534254, 0.032334),
       (-0.654798, -0.98413, 0.032334),
@@ -212,7 +219,7 @@ Profils = [
       [48, 71, 80, 47], [67, 37, 38, 83], [82, 83, 87, 86], [81, 82, 86, 85], [80, 81, 85, 84], [47, 80, 84, 46],
       [83, 38, 39, 87]]),
     ("CTP_5585",
-     mathutils.Vector((5.0114, -2.4281, 0.0)),
+     Vector((5.0114, -2.4281, 0.0)),
      [(-0.490711, -1.0, 0.032334),
       (-1.0, -0.490711, 0.032334),
       (1.0, -0.490711, 0.032334),
@@ -233,7 +240,7 @@ Profils = [
      [[11, 12, 13, 14], [9, 8, 4, 1], [10, 9, 1, 0], [11, 10, 0, 3], [12, 11, 3, 2], [13, 12, 2, 7],
       [14, 13, 7, 6], [15, 14, 6, 5], [8, 15, 5, 4], [9, 10, 15, 8], [10, 11, 14, 15]]),
     ("CTP_6960",
-     mathutils.Vector((-0.11417, 2.48371, -0.0)),
+     Vector((-0.11417, 2.48371, -0.0)),
      [(0.0, 1.0, 0.016827),
       (-0.382683, 0.92388, 0.016827),
       (-0.707107, 0.707107, 0.016827),
@@ -271,7 +278,7 @@ Profils = [
       [6, 22, 21, 5], [14, 30, 29, 13], [7, 23, 22, 6], [15, 31, 30, 14], [8, 24, 23, 7], [1, 17, 16, 0],
       [0, 16, 31, 15], [9, 25, 24, 8], [2, 18, 17, 1], [10, 26, 25, 9]]),
     ("CTP_5359",
-     mathutils.Vector((5.50446, 2.41669, -0.0)),
+     Vector((5.50446, 2.41669, -0.0)),
      [(0.0, 0.714247, 0.023261),
       (-0.382683, 0.659879, 0.023261),
       (-0.707107, 0.505049, 0.023261),
@@ -309,7 +316,7 @@ Profils = [
       [6, 22, 21, 5], [14, 30, 29, 13], [7, 23, 22, 6], [15, 31, 30, 14], [8, 24, 23, 7], [1, 17, 16, 0],
       [0, 16, 31, 15], [9, 25, 24, 8], [2, 18, 17, 1], [10, 26, 25, 9]]),
     ("CTP_5424",
-     mathutils.Vector((2.61824, 2.34147, 0.0)),
+     Vector((2.61824, 2.34147, 0.0)),
      [(1.0, -1.0, 0.032334),
       (-1.0, 1.0, 0.032334),
       (1.0, 1.0, 0.032334),
@@ -328,7 +335,7 @@ Profils = [
      [[3, 0, 2], [10, 9, 2], [2, 1, 4], [2, 4, 13], [5, 3, 2], [6, 5, 2], [2, 13, 12], [2, 12, 11], [7, 6, 2],
       [8, 7, 2], [2, 11, 10], [9, 8, 2]]),
     ("CTP_3774",
-     mathutils.Vector((2.61824, -2.52425, 0.0)),
+     Vector((2.61824, -2.52425, 0.0)),
      [(1.0, 0.0, 0.020045),
       (-1.0, 0.0, 0.020045),
       (0.31903, -0.664947, 0.020045),
@@ -367,7 +374,7 @@ Profils = [
       [11, 30, 9, 12], [17, 16, 27, 26], [14, 17, 26, 24], [24, 25, 0, 14], [15, 13, 27, 16], [9, 30, 23, 4],
       [31, 29, 7, 18], [28, 31, 18, 21], [30, 28, 21, 23]]),
     ("CTP_4473",
-     mathutils.Vector((7.31539, 0.0, 0.0)),
+     Vector((7.31539, 0.0, 0.0)),
      [(0.24549, -1.0, 0.022454),
       (-0.24549, -1.0, 0.022454),
       (-0.24549, 1.0, 0.022454),
@@ -383,7 +390,7 @@ Profils = [
       ],
      [[8, 3, 2, 10], [0, 9, 11, 1], [4, 8, 9, 5], [8, 10, 11, 9], [10, 7, 6, 11]]),
     ("CTP_4003",
-     mathutils.Vector((4.91276, 0.0, 0.0)),
+     Vector((4.91276, 0.0, 0.0)),
      [(-1.0, -1.0, 0.026945),
       (1.0, -1.0, 0.026945),
       (-1.0, 1.0, 0.026945),
@@ -424,7 +431,7 @@ Profils = [
       [23, 25, 31, 29], [24, 23, 29, 30], [25, 22, 28, 31], [26, 22, 15, 20], [10, 27, 33, 5], [31, 28, 3, 11],
       [33, 30, 13, 14], [29, 31, 11, 12], [5, 33, 14, 1], [30, 29, 12, 13], [32, 28, 22, 26]]),
     ("CTP_3430",
-     mathutils.Vector((2.61824, 0.0, 0.0)),
+     Vector((2.61824, 0.0, 0.0)),
      [(-1.0, -1.0, 0.032334),
       (1.0, -1.0, 0.032334),
       (-1.0, 1.0, 0.032334),
@@ -432,7 +439,7 @@ Profils = [
       ],
      [[0, 1, 3, 2]]),
     ("CTP_7175",
-     mathutils.Vector((0.0, 0.0, 0.0)),
+     Vector((0.0, 0.0, 0.0)),
      [(-1.0, -1.0, 0.032334),
       (1.0, -1.0, 0.032334),
       (-1.0, 1.0, 0.032334),
@@ -464,33 +471,33 @@ class CarverPrefs(bpy.types.AddonPreferences):
     bl_idname = __name__
 
     Enable_Tab_01 = BoolProperty(
-            name="Info",
-            description="Some general information and settings about the add-on",
-            default=False
-            )
+        name="Info",
+        description="Some general information and settings about the add-on",
+        default=False
+    )
     Enable_Tab_02 = BoolProperty(
-            name="Hotkeys",
-            description="List of the shortcuts used during carving",
-            default=False
-            )
+        name="Hotkeys",
+        description="List of the shortcuts used during carving",
+        default=False
+    )
     bpy.types.Scene.Key_Create = StringProperty(
-            name="Object creation",
-            description="Object creation",
-            maxlen=1,
-            default="C"
-            )
+        name="Object creation",
+        description="Object creation",
+        maxlen=1,
+        default="C"
+    )
     bpy.types.Scene.Key_Update = StringProperty(
-            name="Auto Bevel Update",
-            description="Auto Bevel Update",
-            maxlen=1,
-            default="A",
-            )
+        name="Auto Bevel Update",
+        description="Auto Bevel Update",
+        maxlen=1,
+        default="A",
+    )
     bpy.types.Scene.Key_Bool = StringProperty(
-            name="Boolean type",
-            description="Boolean operation type",
-            maxlen=1,
-            default="T",
-            )
+        name="Boolean type",
+        description="Boolean operation type",
+        maxlen=1,
+        default="T",
+    )
     bpy.types.Scene.Key_Brush = StringProperty(
             name="Brush Mode",
             description="Brush Mode",
@@ -498,167 +505,150 @@ class CarverPrefs(bpy.types.AddonPreferences):
             default="B",
             )
     bpy.types.Scene.Key_Help = StringProperty(
-            name="Help display",
-            description="Help display",
-            maxlen=1,
-            default="H",
-            )
+        name="Help display",
+        description="Help display",
+        maxlen=1,
+        default="H",
+    )
     bpy.types.Scene.Key_Instant = StringProperty(
-            name="Instantiate",
-            description="Instantiate object",
-            maxlen=1,
-            default="I",
-            )
+        name="Instantiate",
+        description="Instantiate object",
+        maxlen=1,
+        default="I",
+    )
     bpy.types.Scene.Key_Close = StringProperty(
-            name="Close polygonal shape",
-            description="Close polygonal shape",
-            maxlen=1,
-            default="X",
-            )
+        name="Close polygonal shape",
+        description="Close polygonal shape",
+        maxlen=1,
+        default="X",
+    )
     bpy.types.Scene.Key_Apply = StringProperty(
-            name="Apply operation",
-            description="Apply operation",
-            maxlen=1,
-            default="Q",
-            )
+        name="Apply operation",
+        description="Apply operation",
+        maxlen=1,
+        default="Q",
+    )
     bpy.types.Scene.Key_Scale = StringProperty(
-            name="Scale object",
-            description="Scale object",
-            maxlen=1,
-            default="S",
-            )
+        name="Scale object",
+        description="Scale object",
+        maxlen=1,
+        default="S",
+    )
     bpy.types.Scene.Key_Gapy = StringProperty(
-            name="Gap rows",
-            description="Scale gap between columns",
-            maxlen=1,
-            default="J",
-            )
+        name="Gap rows",
+        description="Scale gap between columns",
+        maxlen=1,
+        default="J",
+    )
     bpy.types.Scene.Key_Gapx = StringProperty(
-            name="Gap columns",
-            description="Scale gap between columns",
-            maxlen=1,
-            default="U",
-            )
+        name="Gap columns",
+        description="Scale gap between columns",
+        maxlen=1,
+        default="U",
+    )
     bpy.types.Scene.Key_Depth = StringProperty(
-            name="Depth",
-            description="Cursor depth or solidify pattern",
-            maxlen=1,
-            default="D",
-            )
+        name="Depth",
+        description="Cursor depth or solidify pattern",
+        maxlen=1,
+        default="D",
+    )
     bpy.types.Scene.Key_BrushDepth = StringProperty(
-            name="Brush Depth",
-            description="Brush depth",
-            maxlen=1,
-            default="C",
-            )
+        name="Brush Depth",
+        description="Brush depth",
+        maxlen=1,
+        default="C",
+    )
     bpy.types.Scene.Key_Subadd = StringProperty(
-            name="Add subdivision",
-            description="Add subdivision",
-            maxlen=1,
-            default="X",
-            )
+        name="Add subdivision",
+        description="Add subdivision",
+        maxlen=1,
+        default="X",
+    )
     bpy.types.Scene.Key_Subrem = StringProperty(
-            name="Remove subdivision",
-            description="Remove subdivision",
-            maxlen=1,
-            default="W",
-            )
+        name="Remove subdivision",
+        description="Remove subdivision",
+        maxlen=1,
+        default="W",
+    )
     bpy.types.Scene.Key_Randrot = StringProperty(
-            name="Random rotation",
-            description="Random rotation",
-            maxlen=1,
-            default="R",
-            )
-    bpy.types.Scene.Key_Solver = StringProperty(
-            name="Solver",
-            description="Switch between Carve and BMesh Boolean solver\n"
-                        "depending on a specific use case",
-            maxlen=1,
-            default="V",
-            )
+        name="Random rotation",
+        description="Random rotation",
+        maxlen=1,
+        default="R",
+    )
     bpy.types.Scene.ProfilePrefix = StringProperty(
-            name="Profile prefix",
-            description="Prefix to look for profiles with",
-            default="Carver_Profile-"
-            )
-    bpy.types.Scene.CarverSolver = EnumProperty(
-            name="Boolean Solver",
-            description="Boolean solver to use by default\n",
-            default="CARVE",
-            items=(
-                ('CARVE', 'Carve', "Carve solver, as the legacy one, can handle\n"
-                                   "basic coplanar but can often fail with\n"
-                                   "non-closed geometry"),
-                ('BMESH', 'BMesh', "BMesh solver is faster, but cannot handle\n"
-                                   "coplanar and self-intersecting geometry")
-                )
-            )
+        name="Profile prefix",
+        description="Prefix to look for profiles with",
+        default="Carver_Profile-"
+    )
 
     def draw(self, context):
         scene = context.scene
         layout = self.layout
 
-        layout.prop(self, "Enable_Tab_01", text="Info and Settings", icon="QUESTION")
+        icon_1 = "TRIA_RIGHT" if not self.Enable_Tab_01 else "TRIA_DOWN"
+        box = layout.box()
+        box.prop(self, "Enable_Tab_01", text="Info and Settings", emboss=False, icon=icon_1)
         if self.Enable_Tab_01:
-            layout.label(text="Carver Operator:", icon="LAYER_ACTIVE")
-            layout.label(text="Select a Mesh Object and press [CTRL]+[SHIFT]+[X] to carve",
+            box.label(text="Carver Operator:", icon="LAYER_ACTIVE")
+            box.label(text="Select a Mesh Object and press [CTRL]+[SHIFT]+[X] to carve",
                          icon="LAYER_USED")
-            layout.label(text="To finish carving press [ESC] or [RIGHT CLICK]",
+            box.label(text="To finish carving press [ESC] or [RIGHT CLICK]",
                          icon="LAYER_USED")
+            box.prop(scene, "ProfilePrefix", text="Profile prefix")
 
-            layout.prop(scene, "ProfilePrefix", text="Profile prefix")
-            layout.prop(scene, "CarverSolver", text="Solver")
-
-        layout.prop(self, "Enable_Tab_02", text="Keys", icon="KEYINGSET")
+        icon_2 = "TRIA_RIGHT" if not self.Enable_Tab_02 else "TRIA_DOWN"
+        box = layout.box()
+        box.prop(self, "Enable_Tab_02", text="Keys", emboss=False, icon=icon_2)
         if self.Enable_Tab_02:
-            split = layout.split()
-            col = split.column()
+            split = box.split(align=True)
+            box = split.box()
+            col = box.column(align=True)
             col.label("Object Creation:")
             col.prop(scene, "Key_Create", text="")
             col.label("Auto bevel update:")
             col.prop(scene, "Key_Update", text="")
             col.label("Boolean operation type:")
             col.prop(scene, "Key_Bool", text="")
-            col.label("Solver:")
-            col.prop(scene, "Key_Solver", text="")
+            col.label("Brush Depth:")
+            col.prop(scene, "Key_BrushDepth", text="")
 
-            col = split.column()
+            box = split.box()
+            col = box.column(align=True)
             col.label("Brush Mode:")
             col.prop(scene, "Key_Brush", text="")
             col.label("Help display:")
             col.prop(scene, "Key_Help", text="")
             col.label("Instantiate object:")
             col.prop(scene, "Key_Instant", text="")
-            col.label("Brush Depth:")
-            col.prop(scene, "Key_BrushDepth", text="")
+            col.label("Random rotation:")
+            col.prop(scene, "Key_Randrot", text="")
 
-            col = split.column()
+            box = split.box()
+            col = box.column(align=True)
             col.label("Close polygonal shape:")
             col.prop(scene, "Key_Close", text="")
             col.label("Apply operation:")
             col.prop(scene, "Key_Apply", text="")
             col.label("Scale object:")
             col.prop(scene, "Key_Scale", text="")
+            col.label("Subdiv add:")
+            col.prop(scene, "Key_Subadd", text="")
 
-            col = split.column()
+            box = split.box()
+            col = box.column(align=True)
             col.label("Gap rows:")
             col.prop(scene, "Key_Gapy", text="")
             col.label("Gap columns:")
             col.prop(scene, "Key_Gapx", text="")
             col.label("Depth / Solidify:")
             col.prop(scene, "Key_Depth", text="")
-
-            col = split.column()
-            col.label("Subdiv add:")
-            col.prop(scene, "Key_Subadd", text="")
             col.label("Subdiv Remove:")
             col.prop(scene, "Key_Subrem", text="")
-            col.label("Random rotation:")
-            col.prop(scene, "Key_Randrot", text="")
 
 
 # Draw Text (Center position)
-def DrawCenterText(text, xt, yt, Size, Color, self):
+def DrawCenterText(text, xt, yt, Size, colors, self):
     font_id = 0
     # Offset Shadow
     Sshadow_x = 2
@@ -670,16 +660,16 @@ def DrawCenterText(text, xt, yt, Size, Color, self):
 
     blf.draw(font_id, text)
     blf.position(font_id, xt - blf.dimensions(font_id, text)[0] / 2, yt, 0)
-    if Color is not None:
-        mColor = mathutils.Color((Color[0], Color[1], Color[2]))
-        bgl.glColor4f(mColor.r, mColor.g, mColor.b, 1.0)
+    if colors is not None:
+        mcolor = Color((colors[0], colors[1], colors[2]))
+        bgl.glColor4f(mcolor.r, mcolor.g, mcolor.b, 1.0)
     else:
         bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
     blf.draw(font_id, text)
 
 
 # Draw text (Left position)
-def DrawLeftText(text, xt, yt, Size, Color, self):
+def DrawLeftText(text, xt, yt, Size, colors, self):
     font_id = 0
     # Offset Shadow
     Sshadow_x = 2
@@ -690,16 +680,16 @@ def DrawLeftText(text, xt, yt, Size, Color, self):
     bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
     blf.draw(font_id, text)
     blf.position(font_id, xt, yt, 0)
-    if Color is not None:
-        mColor = mathutils.Color((Color[0], Color[1], Color[2]))
-        bgl.glColor4f(mColor.r, mColor.g, mColor.b, 1.0)
+    if colors is not None:
+        mcolor = Color((colors[0], colors[1], colors[2]))
+        bgl.glColor4f(mcolor.r, mcolor.g, mcolor.b, 1.0)
     else:
         bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
     blf.draw(font_id, text)
 
 
 # Draw text (Right position)
-def DrawRightText(text, xt, yt, Size, Color, self):
+def DrawRightText(text, xt, yt, Size, colors, self):
     font_id = 0
     # Offset Shadow
     Sshadow_x = 2
@@ -710,9 +700,9 @@ def DrawRightText(text, xt, yt, Size, Color, self):
     bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
     blf.draw(font_id, text)
     blf.position(font_id, xt - blf.dimensions(font_id, text)[0], yt, 0)
-    if Color is not None:
-        mColor = mathutils.Color((Color[0], Color[1], Color[2]))
-        bgl.glColor4f(mColor.r, mColor.g, mColor.b, 1.0)
+    if colors is not None:
+        mcolor = Color((colors[0], colors[1], colors[2]))
+        bgl.glColor4f(mcolor.r, mcolor.g, mcolor.b, 1.0)
     else:
         bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
     blf.draw(font_id, text)
@@ -743,28 +733,18 @@ def draw_callback_px(self, context):
         BooleanMode = "Create"
     else:
         if self.ObjectMode or self.ProfileMode:
-            if self.BoolOps == DIFFERENCE:
-                BooleanType = "Difference) [T]"
-            else:
-                BooleanType = "Union) [T]"
-
-            if self.ObjectMode:
-                BooleanMode = "Object Brush (" + BooleanType
-            else:
-                BooleanMode = "Profil Brush (" + BooleanType
+            BooleanType = "Difference) [T]" if self.BoolOps == DIFFERENCE else "Union) [T]"
+            BooleanMode = \
+                "Object Brush (" + BooleanType if self.ObjectMode else "Profil Brush (" + BooleanType
         else:
-            if (self.shift is False) and (self.ForceRebool is False):
-                BooleanMode = "Difference"
-            else:
-                BooleanMode = "Rebool"
+            BooleanMode = \
+                "Difference" if (self.shift is False) and (self.ForceRebool is False) else "Rebool"
 
     UIColor = (0.992, 0.5518, 0.0, 1.0)
 
     # Display boolean mode
-    if region.width >= 850:
-        DrawCenterText(BooleanMode, xt, yt, 40, UIColor, self)
-    else:
-        DrawCenterText(BooleanMode, xt, yt, 20, UIColor, self)
+    text_size = 40 if region.width >= 850 else 20
+    DrawCenterText(BooleanMode, xt, yt, text_size, UIColor, self)
 
     # Separator (Line)
     LineWidth = 75
@@ -790,12 +770,11 @@ def draw_callback_px(self, context):
     # Variables according to screen size
     IFontSize = 12
     yInterval = 20
-    xCmd = 0
     yCmd = yt - 30
+
     if region.width >= 850:
         IFontSize = 18
         yInterval = 25
-        xCmd = 100
 
     # Color
     Color0 = None
@@ -816,11 +795,9 @@ def draw_callback_px(self, context):
 
         # Depth Cursor
         TypeStr = "Cursor Depth [" + context.scene.Key_Depth + "] : "
-        if self.snapCursor:
-            BoolStr = "(ON)"
-        else:
-            BoolStr = "(OFF)"
+        BoolStr = "(ON)" if self.snapCursor else "(OFF)"
         OpsStr = TypeStr + BoolStr
+
         TotalWidth = blf.dimensions(font_id, OpsStr)[0]
         xLeft = region.width / 2 - TotalWidth / 2
         xLeftP = xLeft + blf.dimensions(font_id, TypeStr)[0]
@@ -830,11 +807,9 @@ def draw_callback_px(self, context):
         if self.CreateMode is False:
             # Apply Booleans
             TypeStr = "Apply Operations [" + context.scene.Key_Apply + "] : "
-            if self.DontApply:
-                BoolStr = "(OFF)"
-            else:
-                BoolStr = "(ON)"
+            BoolStr = "(OFF)" if self.DontApply else "(ON)"
             OpsStr = TypeStr + BoolStr
+
             TotalWidth = blf.dimensions(font_id, OpsStr)[0]
             xLeft = region.width / 2 - TotalWidth / 2
             xLeftP = xLeft + blf.dimensions(font_id, TypeStr)[0]
@@ -843,11 +818,9 @@ def draw_callback_px(self, context):
 
             # Auto update for bevel
             TypeStr = "Bevel Update [" + context.scene.Key_Update + "] : "
-            if self.Auto_BevelUpdate:
-                BoolStr = "(ON)"
-            else:
-                BoolStr = "(OFF)"
+            BoolStr = "(ON)" if self.Auto_BevelUpdate else "(OFF)"
             OpsStr = TypeStr + BoolStr
+
             TotalWidth = blf.dimensions(font_id, OpsStr)[0]
             xLeft = region.width / 2 - TotalWidth / 2
             xLeftP = xLeft + blf.dimensions(font_id, TypeStr)[0]
@@ -856,10 +829,7 @@ def draw_callback_px(self, context):
 
         # Subdivisions
         if self.CutMode == CIRCLE:
-            if self.CreateMode is False:
-                y = yCmd - yInterval * 4
-            else:
-                y = yCmd - yInterval * 2
+            y = yCmd - yInterval * 4 if self.CreateMode is False else yCmd - yInterval * 2
             TypeStr = "Subdivisions [" + context.scene.Key_Subrem + "][" + context.scene.Key_Subadd + "] : "
             BoolStr = str((int(360 / self.stepAngle[self.step])))
             OpsStr = TypeStr + BoolStr
@@ -872,11 +842,9 @@ def draw_callback_px(self, context):
     else:
         # INSTANTIATE:
         TypeStr = "Instantiate [" + context.scene.Key_Instant + "] : "
-        if self.Instantiate:
-            BoolStr = "(ON)"
-        else:
-            BoolStr = "(OFF)"
+        BoolStr = "(ON)" if self.Instantiate else "(OFF)"
         OpsStr = TypeStr + BoolStr
+
         blf.size(font_id, IFontSize, 72)
         TotalWidth = blf.dimensions(font_id, OpsStr)[0]
         xLeft = region.width / 2 - TotalWidth / 2
@@ -887,11 +855,9 @@ def draw_callback_px(self, context):
         # RANDOM ROTATION:
         if self.alt:
             TypeStr = "Random Rotation [" + context.scene.Key_Randrot + "] : "
-            if self.RandomRotation:
-                BoolStr = "(ON)"
-            else:
-                BoolStr = "(OFF)"
+            BoolStr = "(ON)" if self.RandomRotation else "(OFF)"
             OpsStr = TypeStr + BoolStr
+
             blf.size(font_id, IFontSize, 72)
             TotalWidth = blf.dimensions(font_id, OpsStr)[0]
             xLeft = region.width / 2 - TotalWidth / 2
@@ -911,42 +877,38 @@ def draw_callback_px(self, context):
             TotalWidth = blf.dimensions(font_id, OpsStr)[0]
             xLeft = region.width / 2 - TotalWidth / 2
             xLeftP = xLeft + blf.dimensions(font_id, TypeStr)[0]
-            if self.alt:
-                DrawLeftText(TypeStr, xLeft, yCmd - yInterval * 2, IFontSize, Color0, self)
-                DrawLeftText(BoolStr, xLeftP, yCmd - yInterval * 2, IFontSize, Color1, self)
-            else:
-                DrawLeftText(TypeStr, xLeft, yCmd - yInterval, IFontSize, Color0, self)
-                DrawLeftText(BoolStr, xLeftP, yCmd - yInterval, IFontSize, Color1, self)
+
+            self_alt_y = 2 if self.alt else 1
+            DrawLeftText(TypeStr, xLeft, yCmd - yInterval * self_alt_y, IFontSize, Color0, self)
+            DrawLeftText(BoolStr, xLeftP, yCmd - yInterval * self_alt_y, IFontSize, Color1, self)
 
         # BRUSH DEPTH:
         if (self.ObjectMode):
             TypeStr = "Carve Depth [" + context.scene.Key_Depth + "] : "
             BoolStr = str(round(self.ObjectBrush.data.vertices[0].co.z, 2))
             OpsStr = TypeStr + BoolStr
+
             blf.size(font_id, IFontSize, 72)
             TotalWidth = blf.dimensions(font_id, OpsStr)[0]
             xLeft = region.width / 2 - TotalWidth / 2
             xLeftP = xLeft + blf.dimensions(font_id, TypeStr)[0]
-            if self.alt:
-                DrawLeftText(TypeStr, xLeft, yCmd - yInterval * 2, IFontSize, Color0, self)
-                DrawLeftText(BoolStr, xLeftP, yCmd - yInterval * 2, IFontSize, Color1, self)
-            else:
-                DrawLeftText(TypeStr, xLeft, yCmd - yInterval, IFontSize, Color0, self)
-                DrawLeftText(BoolStr, xLeftP, yCmd - yInterval, IFontSize, Color1, self)
+
+            self_alt_y = 2 if self.alt else 1
+            DrawLeftText(TypeStr, xLeft, yCmd - yInterval * self_alt_y, IFontSize, Color0, self)
+            DrawLeftText(BoolStr, xLeftP, yCmd - yInterval * self_alt_y, IFontSize, Color1, self)
 
             TypeStr = "Brush Depth [" + context.scene.Key_BrushDepth + "] : "
             BoolStr = str(round(self.BrushDepthOffset, 2))
             OpsStr = TypeStr + BoolStr
+
             blf.size(font_id, IFontSize, 72)
             TotalWidth = blf.dimensions(font_id, OpsStr)[0]
             xLeft = region.width / 2 - TotalWidth / 2
             xLeftP = xLeft + blf.dimensions(font_id, TypeStr)[0]
-            if self.alt:
-                DrawLeftText(TypeStr, xLeft, yCmd - yInterval * 3, IFontSize, Color0, self)
-                DrawLeftText(BoolStr, xLeftP, yCmd - yInterval * 3, IFontSize, Color1, self)
-            else:
-                DrawLeftText(TypeStr, xLeft, yCmd - yInterval * 2, IFontSize, Color0, self)
-                DrawLeftText(BoolStr, xLeftP, yCmd - yInterval * 2, IFontSize, Color1, self)
+
+            self_alt_y = 3 if self.alt else 2
+            DrawLeftText(TypeStr, xLeft, yCmd - yInterval * self_alt_y, IFontSize, Color0, self)
+            DrawLeftText(BoolStr, xLeftP, yCmd - yInterval * self_alt_y, IFontSize, Color1, self)
 
     bgl.glEnable(bgl.GL_BLEND)
     if region.width >= 850:
@@ -969,21 +931,23 @@ def draw_callback_px(self, context):
             if self.ObjectMode or self.ProfileMode:
                 if self.ProfileMode:
                     DrawLeftText("[" + context.scene.Key_Brush + "]", xHelp, yHelp +
-                                 Help_Interval * 2, Help_FontSize, UIColor, self)
+                                Help_Interval * 2, Help_FontSize, UIColor, self)
                     DrawLeftText(": Object Mode", 150 + t_panel_width, yHelp +
-                                 Help_Interval * 2, Help_FontSize, None, self)
+                                Help_Interval * 2, Help_FontSize, None, self)
                 else:
                     DrawLeftText("[" + context.scene.Key_Brush + "]", xHelp, yHelp +
-                                 Help_Interval * 2, Help_FontSize, UIColor, self)
-                    DrawLeftText(": Return", 150 + t_panel_width, yHelp + Help_Interval * 2, Help_FontSize, None, self)
+                                Help_Interval * 2, Help_FontSize, UIColor, self)
+                    DrawLeftText(": Return", 150 + t_panel_width, yHelp +
+                                Help_Interval * 2, Help_FontSize, None, self)
             else:
                 DrawLeftText("[" + context.scene.Key_Brush + "]", xHelp, yHelp +
-                             Help_Interval * 2, Help_FontSize, UIColor, self)
+                            Help_Interval * 2, Help_FontSize, UIColor, self)
                 DrawLeftText(": Profil Brush", 150 + t_panel_width, yHelp +
-                             Help_Interval * 2, Help_FontSize, None, self)
-                DrawLeftText("[Ctrl + LMB]", xHelp, yHelp - Help_Interval * 6, Help_FontSize, UIColor, self)
+                            Help_Interval * 2, Help_FontSize, None, self)
+                DrawLeftText("[Ctrl + LMB]", xHelp, yHelp - Help_Interval * 6,
+                            Help_FontSize, UIColor, self)
                 DrawLeftText(": Move Cursor", 150 + t_panel_width, yHelp -
-                             Help_Interval * 6, Help_FontSize, None, self)
+                            Help_Interval * 6, Help_FontSize, None, self)
 
             if (self.ObjectMode is False) and (self.ProfileMode is False):
                 if self.CreateMode is False:
@@ -994,235 +958,225 @@ def draw_callback_px(self, context):
                 else:
                     DrawLeftText("[" + context.scene.Key_Create + "]", xHelp,
                                  yHelp + Help_Interval, Help_FontSize, UIColor, self)
-                    DrawLeftText(": Cut", 150 + t_panel_width, yHelp + Help_Interval, Help_FontSize, None, self)
+                    DrawLeftText(": Cut", 150 + t_panel_width, yHelp + Help_Interval,
+                                Help_FontSize, None, self)
 
                 if self.CutMode == RECTANGLE:
                     DrawLeftText("MouseMove", xHelp, yHelp, Help_FontSize, UIColor, self)
                     DrawLeftText("[Alt]", xHelp, yHelp - Help_Interval, Help_FontSize, UIColor, self)
-                    DrawLeftText("[" + context.scene.Key_Solver + "]",
-                                xHelp, yHelp - Help_Interval * 2, Help_FontSize, UIColor, self)
                     DrawLeftText(": Dimension", 150 + t_panel_width, yHelp, Help_FontSize, None, self)
-                    DrawLeftText(": Move all", 150 + t_panel_width, yHelp - Help_Interval, Help_FontSize, None, self)
-                    DrawLeftText(": Solver [" + context.scene.CarverSolver + "]", 150 + t_panel_width,
-                                yHelp - Help_Interval * 2, Help_FontSize, None, self)
+                    DrawLeftText(": Move all", 150 + t_panel_width, yHelp - Help_Interval,
+                                Help_FontSize, None, self)
 
                 if self.CutMode == CIRCLE:
                     DrawLeftText("MouseMove", xHelp, yHelp, Help_FontSize, UIColor, self)
                     DrawLeftText("[Alt]", xHelp, yHelp - Help_Interval, Help_FontSize, UIColor, self)
                     DrawLeftText("[" + context.scene.Key_Subrem + "] [" + context.scene.Key_Subadd + "]",
-                                 xHelp, yHelp - Help_Interval * 2, Help_FontSize, UIColor, self)
+                                xHelp, yHelp - Help_Interval * 2, Help_FontSize, UIColor, self)
                     DrawLeftText("[Ctrl]", xHelp, yHelp - Help_Interval * 3, Help_FontSize, UIColor, self)
-                    DrawLeftText("[" + context.scene.Key_Solver + "]",
-                                xHelp, yHelp - Help_Interval * 4, Help_FontSize, UIColor, self)
                     DrawLeftText(": Rotation and Radius", 150 + t_panel_width, yHelp, Help_FontSize, None, self)
-                    DrawLeftText(": Move all", 150 + t_panel_width, yHelp - Help_Interval, Help_FontSize, None, self)
+                    DrawLeftText(": Move all", 150 + t_panel_width, yHelp - Help_Interval,
+                                Help_FontSize, None, self)
                     DrawLeftText(": Subdivision", 150 + t_panel_width, yHelp -
-                                 Help_Interval * 2, Help_FontSize, None, self)
+                                Help_Interval * 2, Help_FontSize, None, self)
                     DrawLeftText(": Incremental rotation", 150 + t_panel_width,
-                                 yHelp - Help_Interval * 3, Help_FontSize, None, self)
-                    DrawLeftText(": Solver [" + context.scene.CarverSolver + "]",
-                                150 + t_panel_width, yHelp - Help_Interval * 4, Help_FontSize, None, self)
+                                yHelp - Help_Interval * 3, Help_FontSize, None, self)
 
                 if self.CutMode == LINE:
                     DrawLeftText("MouseMove", xHelp, yHelp, Help_FontSize, UIColor, self)
                     DrawLeftText("[Alt]", xHelp, yHelp - Help_Interval, Help_FontSize, UIColor, self)
                     DrawLeftText("[Space]", xHelp, yHelp - Help_Interval * 2, Help_FontSize, UIColor, self)
                     DrawLeftText("[Ctrl]", xHelp, yHelp - Help_Interval * 3, Help_FontSize, UIColor, self)
-                    DrawLeftText("[" + context.scene.Key_Solver + "]",
-                                xHelp, yHelp - Help_Interval * 4, Help_FontSize, UIColor, self)
                     DrawLeftText(": Dimension", 150 + t_panel_width, yHelp, Help_FontSize, None, self)
-                    DrawLeftText(": Move all", 150 + t_panel_width, yHelp - Help_Interval, Help_FontSize, None, self)
+                    DrawLeftText(": Move all", 150 + t_panel_width, yHelp - Help_Interval,
+                                Help_FontSize, None, self)
                     DrawLeftText(": Validate", 150 + t_panel_width, yHelp -
                                  Help_Interval * 2, Help_FontSize, None, self)
                     DrawLeftText(": Incremental", 150 + t_panel_width, yHelp -
-                                 Help_Interval * 3, Help_FontSize, None, self)
-                    DrawLeftText(": Solver [" + context.scene.CarverSolver + "]",
-                                150 + t_panel_width, yHelp - Help_Interval * 4, Help_FontSize, None, self)
+                                Help_Interval * 3, Help_FontSize, None, self)
                     if self.CreateMode:
                         DrawLeftText("[" + context.scene.Key_Subadd + "]", xHelp, yHelp -
-                                     Help_Interval * 4, Help_FontSize, UIColor, self)
+                                    Help_Interval * 4, Help_FontSize, UIColor, self)
                         DrawLeftText(": Close geometry", 150 + t_panel_width, yHelp -
-                                     Help_Interval * 4, Help_FontSize, None, self)
+                                    Help_Interval * 4, Help_FontSize, None, self)
             else:
                 DrawLeftText("[Space]", xHelp, yHelp + Help_Interval, Help_FontSize, UIColor, self)
-                DrawLeftText(": Difference", 150 + t_panel_width, yHelp + Help_Interval, Help_FontSize, None, self)
+                DrawLeftText(": Difference", 150 + t_panel_width, yHelp + Help_Interval,
+                            Help_FontSize, None, self)
                 DrawLeftText("[Shift][Space]", xHelp, yHelp, Help_FontSize, UIColor, self)
                 DrawLeftText(": Rebool", 150 + t_panel_width, yHelp, Help_FontSize, None, self)
                 DrawLeftText("[Alt][Space]", xHelp, yHelp - Help_Interval, Help_FontSize, UIColor, self)
-                DrawLeftText(": Duplicate", 150 + t_panel_width, yHelp - Help_Interval, Help_FontSize, None, self)
+                DrawLeftText(": Duplicate", 150 + t_panel_width, yHelp - Help_Interval,
+                            Help_FontSize, None, self)
                 DrawLeftText("[" + context.scene.Key_Scale + "]", xHelp, yHelp -
-                             Help_Interval * 2, Help_FontSize, UIColor, self)
-                DrawLeftText(": Scale", 150 + t_panel_width, yHelp - Help_Interval * 2, Help_FontSize, None, self)
+                            Help_Interval * 2, Help_FontSize, UIColor, self)
+                DrawLeftText(": Scale", 150 + t_panel_width, yHelp - Help_Interval * 2,
+                            Help_FontSize, None, self)
                 DrawLeftText("[LMB][Move]", xHelp, yHelp - Help_Interval * 3, Help_FontSize, UIColor, self)
-                DrawLeftText(": Rotation", 150 + t_panel_width, yHelp - Help_Interval * 3, Help_FontSize, None, self)
-                DrawLeftText("[Ctrl][LMB][Move]", xHelp, yHelp - Help_Interval * 4, Help_FontSize, UIColor, self)
-                DrawLeftText(": Step Angle", 150 + t_panel_width, yHelp - Help_Interval * 4, Help_FontSize, None, self)
+                DrawLeftText(": Rotation", 150 + t_panel_width, yHelp - Help_Interval * 3,
+                            Help_FontSize, None, self)
+                DrawLeftText("[Ctrl][LMB][Move]", xHelp, yHelp - Help_Interval * 4,
+                            Help_FontSize, UIColor, self)
+                DrawLeftText(": Step Angle", 150 + t_panel_width, yHelp - Help_Interval * 4,
+                            Help_FontSize, None, self)
                 if self.ProfileMode:
                     DrawLeftText("[" + context.scene.Key_Subadd + "][" + context.scene.Key_Subrem + "]",
-                                 xHelp, yHelp - Help_Interval * 5, Help_FontSize, UIColor, self)
+                                xHelp, yHelp - Help_Interval * 5, Help_FontSize, UIColor, self)
                     DrawLeftText(": Previous or Next Profile", 150 + t_panel_width,
                                  yHelp - Help_Interval * 5, Help_FontSize, None, self)
                 DrawLeftText("[ARROWS]", xHelp, yHelp - Help_Interval * 6, Help_FontSize, UIColor, self)
                 DrawLeftText(": Create / Delete rows or columns", 150 + t_panel_width,
-                             yHelp - Help_Interval * 6, Help_FontSize, None, self)
+                            yHelp - Help_Interval * 6, Help_FontSize, None, self)
                 DrawLeftText("[" + context.scene.Key_Gapy + "][" + context.scene.Key_Gapx + "]",
                              xHelp, yHelp - Help_Interval * 7, Help_FontSize, UIColor, self)
                 DrawLeftText(": Gap between rows or columns", 150 + t_panel_width,
-                             yHelp - Help_Interval * 7, Help_FontSize, None, self)
-                DrawLeftText("[" + context.scene.Key_Solver + "]",
-                            xHelp, yHelp - Help_Interval * 8, Help_FontSize, UIColor, self)
-                DrawLeftText(": Solver [" + context.scene.CarverSolver + "]",
-                            150 + t_panel_width, yHelp - Help_Interval * 8, Help_FontSize, None, self)
+                            yHelp - Help_Interval * 7, Help_FontSize, None, self)
 
-    # Opengl Initialise
+    # Opengl Initialize
     bgl.glEnable(bgl.GL_BLEND)
     bgl.glColor4f(0.512, 0.919, 0.04, 1.0)
     bgl.glLineWidth(2)
 
-    # if context.space_data.region_3d.is_perspective is False:
-    if 1:
-        bgl.glEnable(bgl.GL_POINT_SMOOTH)
-
-        bgl.glPointSize(6)
+    bgl.glEnable(bgl.GL_POINT_SMOOTH)
+    bgl.glPointSize(6)
 
-        if self.ProfileMode:
-            xrect = region.width - t_panel_width - 80
-            yrect = 80
-            bgl.glColor4f(0.0, 0.0, 0.0, 0.3)
-            bgl.glRecti(xrect, yrect, xrect + 60, yrect - 60)
-
-            faces = self.Profils[self.nProfil][3]
-            vertices = self.Profils[self.nProfil][2]
-            WidthProfil = 50
-            location = mathutils.Vector((region.width - t_panel_width - WidthProfil, 50, 0))
-            ProfilScale = 20.0
-            bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 0.7)
-            for f in faces:
-                if len(f) == 4:
-                    bgl.glBegin(bgl.GL_QUADS)
-                    bgl.glVertex3f(vertices[f[0]][0] * ProfilScale + location.x, vertices[f[0]][1] *
-                                   ProfilScale + location.y, vertices[f[0]][2] * ProfilScale + location.z)
-                    bgl.glVertex3f(vertices[f[1]][0] * ProfilScale + location.x, vertices[f[1]][1] *
-                                   ProfilScale + location.y, vertices[f[1]][2] * ProfilScale + location.z)
-                    bgl.glVertex3f(vertices[f[2]][0] * ProfilScale + location.x, vertices[f[2]][1] *
-                                   ProfilScale + location.y, vertices[f[2]][2] * ProfilScale + location.z)
-                    bgl.glVertex3f(vertices[f[3]][0] * ProfilScale + location.x, vertices[f[3]][1] *
-                                   ProfilScale + location.y, vertices[f[3]][2] * ProfilScale + location.z)
-                    bgl.glEnd()
-                if len(f) == 3:
-                    bgl.glBegin(bgl.GL_TRIANGLES)
-                    bgl.glVertex3f(vertices[f[0]][0] * ProfilScale + location.x, vertices[f[0]][1] *
-                                   ProfilScale + location.y, vertices[f[0]][2] * ProfilScale + location.z)
-                    bgl.glVertex3f(vertices[f[1]][0] * ProfilScale + location.x, vertices[f[1]][1] *
-                                   ProfilScale + location.y, vertices[f[1]][2] * ProfilScale + location.z)
-                    bgl.glVertex3f(vertices[f[2]][0] * ProfilScale + location.x, vertices[f[2]][1] *
-                                   ProfilScale + location.y, vertices[f[2]][2] * ProfilScale + location.z)
-                    bgl.glEnd()
-
-        if self.bDone:
-            if len(self.mouse_path) > 1:
-                x0 = self.mouse_path[0][0]
-                y0 = self.mouse_path[0][1]
-                x1 = self.mouse_path[1][0]
-                y1 = self.mouse_path[1][1]
-
-            # Cut Line
-            if self.CutMode == LINE:
-                if (self.shift) or (self.CreateMode and self.Closed):
-                    bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 0.5)
-
-                    bgl.glBegin(bgl.GL_POLYGON)
-                    for x, y in self.mouse_path:
-                        bgl.glVertex2i(x + self.xpos, y + self.ypos)
-                    bgl.glEnd()
-
-                bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 1.0)
-                bgl.glBegin(bgl.GL_LINE_STRIP)
-                for x, y in self.mouse_path:
-                    bgl.glVertex2i(x + self.xpos, y + self.ypos)
+    if self.ProfileMode:
+        xrect = region.width - t_panel_width - 80
+        yrect = 80
+        bgl.glColor4f(0.0, 0.0, 0.0, 0.3)
+        bgl.glRecti(xrect, yrect, xrect + 60, yrect - 60)
+
+        faces = self.Profils[self.nProfil][3]
+        vertices = self.Profils[self.nProfil][2]
+        WidthProfil = 50
+        location = Vector((region.width - t_panel_width - WidthProfil, 50, 0))
+        ProfilScale = 20.0
+        bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 0.7)
+        for f in faces:
+            if len(f) == 4:
+                bgl.glBegin(bgl.GL_QUADS)
+                bgl.glVertex3f(vertices[f[0]][0] * ProfilScale + location.x, vertices[f[0]][1] *
+                               ProfilScale + location.y, vertices[f[0]][2] * ProfilScale + location.z)
+                bgl.glVertex3f(vertices[f[1]][0] * ProfilScale + location.x, vertices[f[1]][1] *
+                               ProfilScale + location.y, vertices[f[1]][2] * ProfilScale + location.z)
+                bgl.glVertex3f(vertices[f[2]][0] * ProfilScale + location.x, vertices[f[2]][1] *
+                               ProfilScale + location.y, vertices[f[2]][2] * ProfilScale + location.z)
+                bgl.glVertex3f(vertices[f[3]][0] * ProfilScale + location.x, vertices[f[3]][1] *
+                               ProfilScale + location.y, vertices[f[3]][2] * ProfilScale + location.z)
                 bgl.glEnd()
-                if (self.CreateMode is False) or (self.CreateMode and self.Closed):
-                    bgl.glBegin(bgl.GL_LINE_STRIP)
-                    bgl.glVertex2i(self.mouse_path[len(self.mouse_path) - 1][0] + self.xpos,
-                                   self.mouse_path[len(self.mouse_path) - 1][1] + self.ypos)
-                    bgl.glVertex2i(self.mouse_path[0][0] + self.xpos, self.mouse_path[0][1] + self.ypos)
-                    bgl.glEnd()
-
-                bgl.glPointSize(6)
-                bgl.glBegin(bgl.GL_POINTS)
-                for x, y in self.mouse_path:
-                    bgl.glVertex2i(x + self.xpos, y + self.ypos)
+            if len(f) == 3:
+                bgl.glBegin(bgl.GL_TRIANGLES)
+                bgl.glVertex3f(vertices[f[0]][0] * ProfilScale + location.x, vertices[f[0]][1] *
+                               ProfilScale + location.y, vertices[f[0]][2] * ProfilScale + location.z)
+                bgl.glVertex3f(vertices[f[1]][0] * ProfilScale + location.x, vertices[f[1]][1] *
+                               ProfilScale + location.y, vertices[f[1]][2] * ProfilScale + location.z)
+                bgl.glVertex3f(vertices[f[2]][0] * ProfilScale + location.x, vertices[f[2]][1] *
+                               ProfilScale + location.y, vertices[f[2]][2] * ProfilScale + location.z)
                 bgl.glEnd()
 
-            # Cut rectangle
-            if self.CutMode == RECTANGLE:
+    if self.bDone:
+        if len(self.mouse_path) > 1:
+            x0 = self.mouse_path[0][0]
+            y0 = self.mouse_path[0][1]
+            x1 = self.mouse_path[1][0]
+            y1 = self.mouse_path[1][1]
+
+        # Cut Line
+        if self.CutMode == LINE:
+            if (self.shift) or (self.CreateMode and self.Closed):
                 bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 0.5)
 
-                # if SHIFT, fill primitive
-                if self.shift or self.CreateMode:
-                    bgl.glBegin(bgl.GL_QUADS)
-                    bgl.glVertex2i(x0 + self.xpos, y0 + self.ypos)
-                    bgl.glVertex2i(x1 + self.xpos, y0 + self.ypos)
-                    bgl.glVertex2i(x1 + self.xpos, y1 + self.ypos)
-                    bgl.glVertex2i(x0 + self.xpos, y1 + self.ypos)
-                    bgl.glEnd()
+                bgl.glBegin(bgl.GL_POLYGON)
+                for x, y in self.mouse_path:
+                    bgl.glVertex2i(x + self.xpos, y + self.ypos)
+                bgl.glEnd()
 
+            bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 1.0)
+            bgl.glBegin(bgl.GL_LINE_STRIP)
+            for x, y in self.mouse_path:
+                bgl.glVertex2i(x + self.xpos, y + self.ypos)
+            bgl.glEnd()
+            if (self.CreateMode is False) or (self.CreateMode and self.Closed):
                 bgl.glBegin(bgl.GL_LINE_STRIP)
-                bgl.glVertex2i(x0 + self.xpos, y0 + self.ypos)
-                bgl.glVertex2i(x1 + self.xpos, y0 + self.ypos)
-                bgl.glVertex2i(x1 + self.xpos, y1 + self.ypos)
-                bgl.glVertex2i(x0 + self.xpos, y1 + self.ypos)
-                bgl.glVertex2i(x0 + self.xpos, y0 + self.ypos)
+                bgl.glVertex2i(self.mouse_path[len(self.mouse_path) - 1][0] + self.xpos,
+                               self.mouse_path[len(self.mouse_path) - 1][1] + self.ypos)
+                bgl.glVertex2i(self.mouse_path[0][0] + self.xpos, self.mouse_path[0][1] + self.ypos)
                 bgl.glEnd()
-                bgl.glPointSize(6)
 
-                bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 1.0)
-                bgl.glBegin(bgl.GL_POINTS)
+            bgl.glPointSize(6)
+            bgl.glBegin(bgl.GL_POINTS)
+            for x, y in self.mouse_path:
+                bgl.glVertex2i(x + self.xpos, y + self.ypos)
+            bgl.glEnd()
+
+        # Cut rectangle
+        if self.CutMode == RECTANGLE:
+            bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 0.5)
+
+            # if SHIFT, fill primitive
+            if self.shift or self.CreateMode:
+                bgl.glBegin(bgl.GL_QUADS)
                 bgl.glVertex2i(x0 + self.xpos, y0 + self.ypos)
                 bgl.glVertex2i(x1 + self.xpos, y0 + self.ypos)
                 bgl.glVertex2i(x1 + self.xpos, y1 + self.ypos)
                 bgl.glVertex2i(x0 + self.xpos, y1 + self.ypos)
                 bgl.glEnd()
 
-            # Circle Cut
-            if self.CutMode == CIRCLE:
-                DEG2RAD = 3.14159 / 180
-                v0 = mathutils.Vector((self.mouse_path[0][0], self.mouse_path[0][1], 0))
-                v1 = mathutils.Vector((self.mouse_path[1][0], self.mouse_path[1][1], 0))
-                v0 -= v1
-                radius = self.mouse_path[1][0] - self.mouse_path[0][0]
-                DEG2RAD = 3.14159 / (180.0 / self.stepAngle[self.step])
-                if self.ctrl:
-                    self.stepR = (self.mouse_path[1][1] - self.mouse_path[0][1]) / 25
-                    shift = (3.14159 / (360.0 / 60.0)) * int(self.stepR)
-                else:
-                    shift = (self.mouse_path[1][1] - self.mouse_path[0][1]) / 50
-
-                if self.shift or self.CreateMode:
-                    bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 0.5)
-                    bgl.glBegin(bgl.GL_TRIANGLE_FAN)
-                    bgl.glVertex2f(x0 + self.xpos, y0 + self.ypos)
-                    for i in range(0, int(360 / self.stepAngle[self.step])):
-                        degInRad = i * DEG2RAD
-                        bgl.glVertex2f(x0 + self.xpos + math.cos(degInRad + shift) * radius,
-                                       y0 + self.ypos + math.sin(degInRad + shift) * radius)
-                    bgl.glVertex2f(x0 + self.xpos + math.cos(0 + shift) * radius,
-                                   y0 + self.ypos + math.sin(0 + shift) * radius)
-                    bgl.glEnd()
-
-                bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 1.0)
-                bgl.glBegin(bgl.GL_LINE_LOOP)
+            bgl.glBegin(bgl.GL_LINE_STRIP)
+            bgl.glVertex2i(x0 + self.xpos, y0 + self.ypos)
+            bgl.glVertex2i(x1 + self.xpos, y0 + self.ypos)
+            bgl.glVertex2i(x1 + self.xpos, y1 + self.ypos)
+            bgl.glVertex2i(x0 + self.xpos, y1 + self.ypos)
+            bgl.glVertex2i(x0 + self.xpos, y0 + self.ypos)
+            bgl.glEnd()
+            bgl.glPointSize(6)
+
+            bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 1.0)
+            bgl.glBegin(bgl.GL_POINTS)
+            bgl.glVertex2i(x0 + self.xpos, y0 + self.ypos)
+            bgl.glVertex2i(x1 + self.xpos, y0 + self.ypos)
+            bgl.glVertex2i(x1 + self.xpos, y1 + self.ypos)
+            bgl.glVertex2i(x0 + self.xpos, y1 + self.ypos)
+            bgl.glEnd()
+
+        # Circle Cut
+        if self.CutMode == CIRCLE:
+            DEG2RAD = 3.14159 / 180
+            v0 = Vector((self.mouse_path[0][0], self.mouse_path[0][1], 0))
+            v1 = Vector((self.mouse_path[1][0], self.mouse_path[1][1], 0))
+            v0 -= v1
+            radius = self.mouse_path[1][0] - self.mouse_path[0][0]
+            DEG2RAD = 3.14159 / (180.0 / self.stepAngle[self.step])
+            if self.ctrl:
+                self.stepR = (self.mouse_path[1][1] - self.mouse_path[0][1]) / 25
+                shift = (3.14159 / (360.0 / 60.0)) * int(self.stepR)
+            else:
+                shift = (self.mouse_path[1][1] - self.mouse_path[0][1]) / 50
+
+            if self.shift or self.CreateMode:
+                bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 0.5)
+                bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+                bgl.glVertex2f(x0 + self.xpos, y0 + self.ypos)
                 for i in range(0, int(360 / self.stepAngle[self.step])):
                     degInRad = i * DEG2RAD
                     bgl.glVertex2f(x0 + self.xpos + math.cos(degInRad + shift) * radius,
                                    y0 + self.ypos + math.sin(degInRad + shift) * radius)
+                bgl.glVertex2f(x0 + self.xpos + math.cos(0 + shift) * radius,
+                               y0 + self.ypos + math.sin(0 + shift) * radius)
                 bgl.glEnd()
 
+            bgl.glColor4f(UIColor[0], UIColor[1], UIColor[2], 1.0)
+            bgl.glBegin(bgl.GL_LINE_LOOP)
+            for i in range(0, int(360 / self.stepAngle[self.step])):
+                degInRad = i * DEG2RAD
+                bgl.glVertex2f(x0 + self.xpos + math.cos(degInRad + shift) * radius,
+                               y0 + self.ypos + math.sin(degInRad + shift) * radius)
+            bgl.glEnd()
+
     if self.ObjectMode or self.ProfileMode:
         if self.ShowCursor:
             region = context.region
             rv3d = context.space_data.region_3d
-            view_width = context.region.width
 
             if self.ObjectMode:
                 ob = self.ObjectBrush
@@ -1233,7 +1187,7 @@ def draw_callback_px(self, context):
             # 50% alpha, 2 pixel width line
             bgl.glEnable(bgl.GL_BLEND)
 
-            bbox = [mat * mathutils.Vector(b) for b in ob.bound_box]
+            bbox = [mat * Vector(b) for b in ob.bound_box]
 
             if self.shift:
                 bgl.glLineWidth(4)
@@ -1260,12 +1214,12 @@ def draw_callback_px(self, context):
             # Object display
             if self.qRot is not None:
                 ob.location = self.CurLoc
-                v = mathutils.Vector()
+                v = Vector()
                 v.x = v.y = 0.0
                 v.z = self.BrushDepthOffset
                 ob.location += self.qRot * v
 
-                e = mathutils.Euler()
+                e = Euler()
                 e.x = 0.0
                 e.y = 0.0
                 e.z = self.aRotZ / 25.0
@@ -1319,10 +1273,10 @@ def isect_line_plane_v3(p0, p1, p_co, p_no, epsilon=1e-6):
         # The segment is parallel to plane
         return None
 
+
 # ----------------------
 # generic math functions
 
-
 def add_v3v3(v0, v1):
     return (
         v0[0] + v1[0],
@@ -1358,21 +1312,19 @@ def mul_v3_fl(v0, f):
         v0[2] * f,
     )
 
-# Cut Square
-
 
+# Cut Square
 def CreateCutSquare(self, context):
     FAR_LIMIT = 10000.0
 
     # New mesh
     me = bpy.data.meshes.new('CMT_Square')
-
     # New object
     ob = bpy.data.objects.new('CMT_Square', me)
     # Save new object
     self.CurrentObj = ob
-    # Scene informations
-    scene = context.scene
+
+    # Scene information
     region = context.region
     rv3d = context.region_data
     coord = self.mouse_path[0][0], self.mouse_path[0][1]
@@ -1382,14 +1334,10 @@ def CreateCutSquare(self, context):
     if self.snapCursor:
         PlanePoint = context.scene.cursor_location
     else:
-        if self.OpsObj is not None:
-            PlanePoint = self.OpsObj.location
-        else:
-            PlanePoint = mathutils.Vector((0.0, 0.0, 0.0))
+        PlanePoint = self.OpsObj.location if self.OpsObj is not None else Vector((0.0, 0.0, 0.0))
 
     PlaneNormal = depthLocation
     PlaneNormalised = PlaneNormal.normalized()
-    d = -PlanePoint.x * PlaneNormalised.x - PlanePoint.y * PlaneNormalised.y - PlanePoint.z * PlaneNormalised.z
 
     # Link object to scene
     context.scene.objects.link(ob)
@@ -1448,20 +1396,15 @@ def CreateCutLine(self, context):
     ob = bpy.data.objects.new('CMT_Line', me)
     self.CurrentObj = ob
 
-    scene = context.scene
     region = context.region
     rv3d = context.region_data
     coord = self.mouse_path[0][0], self.mouse_path[0][1]
     depthLocation = region_2d_to_vector_3d(region, rv3d, coord)
     self.ViewVector = depthLocation
-    if self.snapCursor:
-        PlanePoint = context.scene.cursor_location
-    else:
-        PlanePoint = mathutils.Vector((0.0, 0.0, 0.0))
 
+    PlanePoint = context.scene.cursor_location if self.snapCursor else Vector((0.0, 0.0, 0.0))
     PlaneNormal = depthLocation
     PlaneNormalised = PlaneNormal.normalized()
-    d = -PlanePoint.x * PlaneNormalised.x - PlanePoint.y * PlaneNormalised.y - PlanePoint.z * PlaneNormalised.z
 
     context.scene.objects.link(ob)
 
@@ -1473,8 +1416,9 @@ def CreateCutLine(self, context):
 
     bLine = False
 
-    if (len(self.mouse_path) == 2) or ((len(self.mouse_path) <= 3) and (self.mouse_path[1] == self.mouse_path[2])):
-        PlanePoint = mathutils.Vector((0.0, 0.0, 0.0))
+    if (len(self.mouse_path) == 2) or ((len(self.mouse_path) <= 3) and
+            (self.mouse_path[1] == self.mouse_path[2])):
+        PlanePoint = Vector((0.0, 0.0, 0.0))
         PlaneNormal = depthLocation
         PlaneNormalised = PlaneNormal.normalized()
         # Force rebool
@@ -1496,7 +1440,6 @@ def CreateCutLine(self, context):
                 Index += 1
                 if NbVertices == 1:
                     t_v0 = t_bm.verts.new(loc0)
-                    t_init = t_v0
                     LocInit = loc0
                     t_bm.verts.index_update()
                 else:
@@ -1504,7 +1447,6 @@ def CreateCutLine(self, context):
                     t_edges = t_bm.edges.new([t_v0, t_v1])
                     NbVertices = 1
                     t_v0 = t_v1
-
     else:
         for x, y in self.mouse_path:
             v0 = x + self.xpos, y + self.ypos
@@ -1518,7 +1460,6 @@ def CreateCutLine(self, context):
             NbVertices += 1
             if NbVertices == 1:
                 t_v0 = t_bm.verts.new(loc0)
-                t_init = t_v0
                 LocInit = loc0
                 t_bm.verts.index_update()
                 FacesList.append(t_v0)
@@ -1554,20 +1495,15 @@ def CreateCutCircle(self, context):
     ob = bpy.data.objects.new('CMT_Circle', me)
     self.CurrentObj = ob
 
-    scene = context.scene
     region = context.region
     rv3d = context.region_data
     coord = self.mouse_path[0][0], self.mouse_path[0][1]
     depthLocation = region_2d_to_vector_3d(region, rv3d, coord)
     self.ViewVector = depthLocation
-    if self.snapCursor:
-        PlanePoint = context.scene.cursor_location
-    else:
-        PlanePoint = mathutils.Vector((0.0, 0.0, 0.0))
 
+    PlanePoint = context.scene.cursor_location if self.snapCursor else Vector((0.0, 0.0, 0.0))
     PlaneNormal = depthLocation
     PlaneNormalised = PlaneNormal.normalized()
-    d = -PlanePoint.x * PlaneNormalised.x - PlanePoint.y * PlaneNormalised.y - PlanePoint.z * PlaneNormalised.z
 
     context.scene.objects.link(ob)
 
@@ -1576,11 +1512,9 @@ def CreateCutCircle(self, context):
 
     x0 = self.mouse_path[0][0]
     y0 = self.mouse_path[0][1]
-    x1 = self.mouse_path[1][0]
-    y1 = self.mouse_path[1][1]
 
-    v0 = mathutils.Vector((self.mouse_path[0][0], self.mouse_path[0][1], 0))
-    v1 = mathutils.Vector((self.mouse_path[1][0], self.mouse_path[1][1], 0))
+    v0 = Vector((self.mouse_path[0][0], self.mouse_path[0][1], 0))
+    v1 = Vector((self.mouse_path[1][0], self.mouse_path[1][1], 0))
     v0 -= v1
     radius = self.mouse_path[1][0] - self.mouse_path[0][0]
     DEG2RAD = math.pi / (180.0 / self.stepAngle[self.step])
@@ -1594,7 +1528,8 @@ def CreateCutCircle(self, context):
     FacesList = []
     for i in range(0, int(360.0 / self.stepAngle[self.step])):
         degInRad = i * DEG2RAD
-        v0 = x0 + self.xpos + math.cos(degInRad + shift) * radius, y0 + self.ypos + math.sin(degInRad + shift) * radius
+        v0 = x0 + self.xpos + math.cos(degInRad + shift) * radius, \
+                y0 + self.ypos + math.sin(degInRad + shift) * radius
         vec = region_2d_to_vector_3d(region, rv3d, v0)
         loc0 = region_2d_to_location_3d(region, rv3d, v0, vec)
 
@@ -1607,7 +1542,6 @@ def CreateCutCircle(self, context):
         FacesList.append(t_v0)
 
     t_bm.verts.index_update()
-
     t_face = t_bm.faces.new(FacesList)
 
     t_bm.to_mesh(me)
@@ -1699,9 +1633,8 @@ def update_bevel(context):
         obj.select = True
     context.scene.objects.active = active
 
-# Create bevel
-
 
+# Create bevel
 def CreateBevel(context, CurrentObject):
     # Save active object
     SavActive = context.active_object
@@ -1752,7 +1685,7 @@ def CreateBevel(context, CurrentObject):
     context.object.data.use_auto_smooth = True
     context.object.data.auto_smooth_angle = 1.0471975
 
-    # Remet l'objet actif par défaut
+    # Restore the active object
     context.scene.objects.active = SavActive
 
 
@@ -1767,7 +1700,6 @@ def Picking(context, event):
     # get the ray from the viewport and mouse
     view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
     ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
-
     ray_target = ray_origin + view_vector
 
     def visible_objects_and_duplis():
@@ -1794,8 +1726,7 @@ def Picking(context, event):
         success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj)
         if success:
             return location, normal, face_index
-        else:
-            return None, None, None
+        return None, None, None
 
     # cast rays and find the closest object
     best_length_squared = -1.0
@@ -1820,7 +1751,6 @@ def Picking(context, event):
 
 
 def CreatePrimitive(self, _AngleStep, _radius):
-    CLRaw = []
     Angle = 0.0
     self.NbPointsInPrimitive = 0
     while(Angle < 360.0):
@@ -1838,7 +1768,7 @@ def CreatePrimitive(self, _AngleStep, _radius):
 def MoveCursor(qRot, location, self):
     if qRot is not None:
         self.CLR_C.clear()
-        vc = mathutils.Vector()
+        vc = Vector()
         idx = 0
         for i in range(int(len(self.CircleListRaw) / 3)):
             vc.x = self.CircleListRaw[idx * 3] * self.CRadius
@@ -1855,12 +1785,12 @@ def RBenVe(Object, Dir):
     ObjectV = Object.normalized()
     DirV = Dir.normalized()
     cosTheta = ObjectV.dot(DirV)
-    rotationAxis = mathutils.Vector((0.0, 0.0, 0.0))
+    rotationAxis = Vector((0.0, 0.0, 0.0))
     if (cosTheta < -1 + 0.001):
-        v = mathutils.Vector((0.0, 1.0, 0.0))
+        v = Vector((0.0, 1.0, 0.0))
         rotationAxis = ObjectV.cross(v)
         rotationAxis = rotationAxis.normalized()
-        q = mathutils.Quaternion()
+        q = Quaternion()
         q.w = 0.0
         q.x = rotationAxis.x
         q.y = rotationAxis.y
@@ -1869,7 +1799,7 @@ def RBenVe(Object, Dir):
     rotationAxis = ObjectV.cross(DirV)
     s = math.sqrt((1.0 + cosTheta) * 2.0)
     invs = 1 / s
-    q = mathutils.Quaternion()
+    q = Quaternion()
     q.w = s * 0.5
     q.x = rotationAxis.x * invs
     q.y = rotationAxis.y * invs
@@ -1878,7 +1808,6 @@ def RBenVe(Object, Dir):
 
 
 def Pick(context, event, self, ray_max=10000.0):
-    scene = context.scene
     region = context.region
     rv3d = context.region_data
     coord = event.mouse_region_x, event.mouse_region_y
@@ -1893,8 +1822,7 @@ def Pick(context, event, self, ray_max=10000.0):
         success, hit, normal, face_index = obj.ray_cast(ray_origin_obj, ray_target_obj)
         if success:
             return hit, normal, face_index
-        else:
-            return None, None, None
+        return None, None, None
 
     best_length_squared = ray_max * ray_max
     best_obj = None
@@ -1914,8 +1842,8 @@ def Pick(context, event, self, ray_max=10000.0):
 
     if best_obj is not None:
         return hits, ns, fs, rotation
-    else:
-        return None, None, None
+
+    return None, None, None
 
 
 def SelectObject(self, copyobj):
@@ -1939,7 +1867,7 @@ def UndoAdd(self, type, OpsObj):
         return
     if type != "DUPLICATE":
         ob = OpsObj
-        # Creation du mesh de 'sauvegarde'
+        # Create the 'backup' mesh
         bm = bmesh.new()
         bm.from_mesh(ob.data)
 
@@ -2011,7 +1939,7 @@ def duplicateObject(self):
     ob_new = bpy.context.active_object
 
     ob_new.location = self.CurLoc
-    v = mathutils.Vector()
+    v = Vector()
     v.x = v.y = 0.0
     v.z = self.BrushDepthOffset
     ob_new.location += self.qRot * v
@@ -2021,7 +1949,7 @@ def duplicateObject(self):
     if self.ProfileMode:
         ob_new.scale = self.ProfileBrush.scale
 
-    e = mathutils.Euler()
+    e = Euler()
     e.x = e.y = 0.0
     e.z = self.aRotZ / 25.0
 
@@ -2075,7 +2003,10 @@ def update_grid(self, context):
 
     # Get the data from the profils or the object
     if self.ProfileMode:
-        brush = bpy.data.objects.new(self.Profils[self.nProfil][0], bpy.data.meshes[self.Profils[self.nProfil][0]])
+        brush = bpy.data.objects.new(
+                    self.Profils[self.nProfil][0],
+                    bpy.data.meshes[self.Profils[self.nProfil][0]]
+                    )
         obj = bpy.data.objects["CT_Profil"]
         obfaces = brush.data.polygons
         obverts = brush.data.vertices
@@ -2107,7 +2038,7 @@ def update_grid(self, context):
 
         # Add random rotation
         if (self.RandomRotation) and not (self.GridScaleX or self.GridScaleY):
-            rotmat = mathutils.Matrix.Rotation(math.radians(360 * random.random()), 4, 'Z')
+            rotmat = Matrix.Rotation(math.radians(360 * random.random()), 4, 'Z')
             for v in obverts:
                 v.co = v.co * rotmat
 
@@ -2124,47 +2055,25 @@ def update_grid(self, context):
     mymesh.update(calc_edges=True)
     # Update data
     obj.data = mymesh
-    # Make the the object the active one to remove double
+    # Make the object active to remove doubles
     context.scene.objects.active = obj
 
 
-def boolean_difference():
+def boolean_operation(bool_type="DIFFERENCE"):
     ActiveObj = bpy.context.active_object
+    sel_index = 0 if bpy.context.selected_objects[0] != bpy.context.active_object else 1
 
-    if bpy.context.selected_objects[0] != bpy.context.active_object:
-        bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY")
-        BoolMod = ActiveObj.modifiers.new("CT_" + bpy.context.selected_objects[0].name, "BOOLEAN")
-        BoolMod.object = bpy.context.selected_objects[0]
-        BoolMod.operation = "DIFFERENCE"
-        BoolMod.solver = bpy.context.scene.CarverSolver
-        bpy.context.selected_objects[0].draw_type = 'WIRE'
-    else:
-        BoolMod = ActiveObj.modifiers.new("CT_" + bpy.context.selected_objects[1].name, "BOOLEAN")
-        BoolMod.object = bpy.context.selected_objects[1]
-        BoolMod.operation = "DIFFERENCE"
-        BoolMod.solver = bpy.context.scene.CarverSolver
-        bpy.context.selected_objects[1].draw_type = 'WIRE'
-
-
-def boolean_union():
-    ActiveObj = bpy.context.active_object
-
-    if bpy.context.selected_objects[0] != bpy.context.active_object:
-        BoolMod = ActiveObj.modifiers.new("CT_" + bpy.context.selected_objects[0].name, "BOOLEAN")
-        BoolMod.object = bpy.context.selected_objects[0]
-        BoolMod.operation = "UNION"
-        bpy.context.selected_objects[0].draw_type = 'WIRE'
-    else:
-        BoolMod = ActiveObj.modifiers.new("CT_" + bpy.context.selected_objects[1].name, "BOOLEAN")
-        BoolMod.object = bpy.context.selected_objects[1]
-        BoolMod.operation = "UNION"
-        bpy.context.selected_objects[1].draw_type = 'WIRE'
+    bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY")
+    BoolMod = ActiveObj.modifiers.new(
+                    "CT_" + bpy.context.selected_objects[sel_index].name,
+                    "BOOLEAN"
+                    )
+    BoolMod.object = bpy.context.selected_objects[sel_index]
+    BoolMod.operation = bool_type
+    bpy.context.selected_objects[sel_index].draw_type = 'WIRE'
 
 
 def Rebool(context, self):
-    SelObj_Name = []
-    BoolObj = []
-
     LastObj = context.active_object
 
     Brush = context.selected_objects[0]
@@ -2204,12 +2113,10 @@ def Rebool(context, self):
 
     m = LastObjectCreated.modifiers.new("CT_INTERSECT", "BOOLEAN")
     m.operation = "INTERSECT"
-    m.solver = context.scene.CarverSolver
     m.object = Brush
 
     m = obj.modifiers.new("CT_DIFFERENCE", "BOOLEAN")
     m.operation = "DIFFERENCE"
-    m.solver = context.scene.CarverSolver
     m.object = Brush
 
     for mb in LastObj.modifiers:
@@ -2262,14 +2169,14 @@ def createMeshFromData(self):
 
     if "CT_Profil" not in bpy.data.objects:
         ob = bpy.data.objects.new("CT_Profil", bpy.data.meshes[self.Profils[self.nProfil][0]])
-        ob.location = mathutils.Vector((0.0, 0.0, 0.0))
+        ob.location = Vector((0.0, 0.0, 0.0))
 
         # Link object to scene and make active
         scn = bpy.context.scene
         scn.objects.link(ob)
         scn.objects.active = ob
         ob.select = True
-        ob.location = mathutils.Vector((10000.0, 0.0, 0.0))
+        ob.location = Vector((10000.0, 0.0, 0.0))
         ob.draw_type = "WIRE"
 
         self.SolidifyPossible = True
@@ -2277,25 +2184,38 @@ def createMeshFromData(self):
         bpy.data.objects["CT_Profil"].data = bpy.data.meshes[self.Profils[self.nProfil][0]]
 
 
+def Selection_Save_Restore(self):
+    if "CT_Profil" in bpy.data.objects:
+        Selection_Save(self)
+        bpy.ops.object.select_all(action='DESELECT')
+        bpy.data.objects["CT_Profil"].select = True
+        bpy.context.scene.objects.active = bpy.data.objects["CT_Profil"]
+        if bpy.data.objects["CT_Profil"] in self.SavSel:
+            self.SavSel.remove(bpy.data.objects["CT_Profil"])
+        bpy.ops.object.delete(use_global=False)
+        Selection_Restore(self)
+
+
 def Selection_Save(self):
+    obj_name = getattr(bpy.context.active_object, "name", None)
     self.SavSel = bpy.context.selected_objects.copy()
-    self.Sav_ac = bpy.context.active_object
+    self.Sav_ac = obj_name
 
 
 def Selection_Restore(self):
     for o in self.SavSel:
         o.select = True
-    bpy.context.scene.objects.active = self.Sav_ac
+    if self.Sav_ac:
+        bpy.context.scene.objects.active = bpy.data.objects.get(self.Sav_ac, None)
 
 
 # Modal Operator
 class Carver(bpy.types.Operator):
     bl_idname = "object.carver"
     bl_label = "Carver"
-    bl_description = "Cut or create in object mode"
+    bl_description = "Cut or create Meshes in Object mode"
     bl_options = {'REGISTER', 'UNDO'}
 
-    # --------------------------------------------------------------------------------------------------
     @classmethod
     def poll(cls, context):
         ob = None
@@ -2306,14 +2226,12 @@ class Carver(bpy.types.Operator):
             (ob and ob.type == 'MESH' and context.mode == 'OBJECT') or
             (context.mode == 'OBJECT' and ob is None) or
             (context.mode == 'EDIT_MESH'))
-    # --------------------------------------------------------------------------------------------------
 
-    # --------------------------------------------------------------------------------------------------
     def modal(self, context, event):
         PI = 3.14156
-
         region_types = {'WINDOW', 'UI'}
         win = context.window
+
         for area in win.screen.areas:
             if area.type in ('VIEW_3D'):
                 for region in area.regions:
@@ -2327,14 +2245,10 @@ class Carver(bpy.types.Operator):
             return {'PASS_THROUGH'}
         try:
             # [Shift]
-            self.shift = False
-            if event.shift:
-                self.shift = True
+            self.shift = True if event.shift else False
 
             # [Ctrl]
-            self.ctrl = False
-            if event.ctrl:
-                self.ctrl = True
+            self.ctrl = True if event.ctrl else False
 
             # [Alt]
             self.alt = False
@@ -2349,7 +2263,7 @@ class Carver(bpy.types.Operator):
                 self.alt = True
             # [Alt] release
             if self.InitPosition and self.alt is False:
-                # Update coordonnee
+                # Update coordinates
                 for i in range(0, len(self.mouse_path)):
                     l = list(self.mouse_path[i])
                     l[0] += self.xpos
@@ -2417,15 +2331,14 @@ class Carver(bpy.types.Operator):
                                 self.CreateGeometry()
                                 bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
                                 # Cursor Snap
-                                context.scene.DepthCursor = self.snapCursor
+                                context.scene.mesh_carver.DepthCursor = self.snapCursor
                                 # Object Instantiate
-                                context.scene.OInstanciate = self.Instantiate
+                                context.scene.mesh_carver.OInstanciate = self.Instantiate
                                 # Random rotation
-                                context.scene.ORandom = self.RandomRotation
+                                context.scene.mesh_carver.ORandom = self.RandomRotation
 
                                 return {'FINISHED'}
                             else:
-                                # Cut
                                 self.Cut()
                                 UndoListUpdate(self)
 
@@ -2459,28 +2372,13 @@ class Carver(bpy.types.Operator):
                             self.BrushSolidify = False
                             self.CList = self.OB_List
 
-                            if "CT_Profil" in bpy.data.objects:
-                                Selection_Save(self)
-                                bpy.ops.object.select_all(action='DESELECT')
-                                bpy.data.objects["CT_Profil"].select = True
-                                context.scene.objects.active = bpy.data.objects["CT_Profil"]
-                                bpy.ops.object.delete(use_global=False)
-                                Selection_Restore(self)
-
-                            context.scene.nProfile = self.nProfil
-
+                            Selection_Save_Restore(self)
+                            context.scene.mesh_carver.nProfile = self.nProfil
                         else:
                             self.ObjectMode = False
                     else:
                         self.BrushSolidify = False
-
-                        if "CT_Profil" in bpy.data.objects:
-                            Selection_Save(self)
-                            bpy.ops.object.select_all(action='DESELECT')
-                            bpy.data.objects["CT_Profil"].select = True
-                            context.scene.objects.active = bpy.data.objects["CT_Profil"]
-                            bpy.ops.object.delete(use_global=False)
-                            Selection_Restore(self)
+                        Selection_Save_Restore(self)
 
                 if self.ProfileMode:
                     createMeshFromData(self)
@@ -2496,7 +2394,6 @@ class Carver(bpy.types.Operator):
 
                     bpy.ops.object.modifier_add(type='SOLIDIFY')
                     context.object.modifiers["Solidify"].name = "CT_SOLIDIFY"
-
                     context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1
 
                     Selection_Restore(self)
@@ -2525,7 +2422,6 @@ class Carver(bpy.types.Operator):
 
                                 Selection_Restore(self)
                         else:
-
                             if self.Solidify_Active_Start:
                                 Selection_Save(self)
                                 self.BrushSolidify = True
@@ -2556,12 +2452,6 @@ class Carver(bpy.types.Operator):
             if event.type == context.scene.Key_Apply and event.value == 'PRESS':
                 self.DontApply = not self.DontApply
 
-            if event.type == context.scene.Key_Solver and event.value == 'PRESS':
-                if context.scene.CarverSolver == "CARVE":
-                    context.scene.CarverSolver = "BMESH"
-                else:
-                    context.scene.CarverSolver = "CARVE"
-
             # Scale object
             if event.type == context.scene.Key_Scale and event.value == 'PRESS':
                 if self.ObjectScale is False:
@@ -2731,7 +2621,6 @@ class Carver(bpy.types.Operator):
                                     self.ProfileBrush.scale.x -= float(self.ascale) / 150.0
                                     self.ProfileBrush.scale.y -= float(self.ascale) / 150.0
                                     self.ProfileBrush.scale.z -= float(self.ascale) / 150.0
-
                         else:
                             if self.LMB:
                                 if self.ctrl:
@@ -2746,10 +2635,9 @@ class Carver(bpy.types.Operator):
                                 vBack = Pick(context, event, self)
                                 if vBack[0] is not None:
                                     self.ShowCursor = True
-                                    NormalObject = mathutils.Vector((0.0, 0.0, 1.0))
+                                    NormalObject = Vector((0.0, 0.0, 1.0))
                                     qR = RBenVe(NormalObject, vBack[1])
                                     self.qRot = vBack[3] * qR
-                                    Pos = vBack[0]
                                     MoveCursor(qR, vBack[0], self)
                                     self.SavCurLoc = vBack[0]
                                     if self.ctrl:
@@ -2758,13 +2646,13 @@ class Carver(bpy.types.Operator):
                                             yEcart = abs(self.SavMousePos.y - self.SavCurLoc.y)
                                             zEcart = abs(self.SavMousePos.z - self.SavCurLoc.z)
                                             if (xEcart > yEcart) and (xEcart > zEcart):
-                                                self.CurLoc = mathutils.Vector(
+                                                self.CurLoc = Vector(
                                                     (vBack[0].x, self.SavMousePos.y, self.SavMousePos.z))
                                             if (yEcart > xEcart) and (yEcart > zEcart):
-                                                self.CurLoc = mathutils.Vector(
+                                                self.CurLoc = Vector(
                                                     (self.SavMousePos.x, vBack[0].y, self.SavMousePos.z))
                                             if (zEcart > xEcart) and (zEcart > yEcart):
-                                                self.CurLoc = mathutils.Vector(
+                                                self.CurLoc = Vector(
                                                     (self.SavMousePos.x, self.SavMousePos.y, vBack[0].z))
                                             else:
                                                 self.CurLoc = vBack[0]
@@ -2807,7 +2695,7 @@ class Carver(bpy.types.Operator):
                     if self.LMB is False:
                         vBack = Pick(context, event, self)
                         if vBack[0] is not None:
-                            NormalObject = mathutils.Vector((0.0, 0.0, 1.0))
+                            NormalObject = Vector((0.0, 0.0, 1.0))
                             self.aqR = RBenVe(NormalObject, vBack[1])
                             self.qRot = vBack[3] * self.aqR
                         self.am = event.mouse_region_x, event.mouse_region_y
@@ -2871,13 +2759,13 @@ class Carver(bpy.types.Operator):
                                 self.CreateGeometry()
                                 bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
                                 # Depth Cursor
-                                context.scene.DepthCursor = self.snapCursor
+                                context.scene.mesh_carver.DepthCursor = self.snapCursor
                                 # Instantiate object
-                                context.scene.OInstanciate = self.Instantiate
+                                context.scene.mesh_carver.OInstanciate = self.Instantiate
                                 # Random rotation
-                                context.scene.ORandom = self.RandomRotation
+                                context.scene.mesh_carver.ORandom = self.RandomRotation
                                 # Apply operation
-                                context.scene.DontApply = self.DontApply
+                                context.scene.mesh_carver.DontApply = self.DontApply
 
                                 # if Object mode, set intiale state
                                 if self.ObjectBrush is not None:
@@ -2900,14 +2788,12 @@ class Carver(bpy.types.Operator):
 
                                     Selection_Restore(self)
 
-                                    context.scene.nProfile = self.nProfil
+                                    context.scene.mesh_carver.nProfile = self.nProfil
 
                                 return {'FINISHED'}
                             else:
-                                # Cut
                                 self.Cut()
                                 UndoListUpdate(self)
-
                         else:
                             # Line
                             self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))
@@ -2941,17 +2827,16 @@ class Carver(bpy.types.Operator):
                     else:
                         if self.step > 0:
                             self.step -= 1
-
             # Quit
             elif event.type in {'RIGHTMOUSE', 'ESC'}:
                 # Depth Cursor
-                context.scene.DepthCursor = self.snapCursor
+                context.scene.mesh_carver.DepthCursor = self.snapCursor
                 # Instantiate object
-                context.scene.OInstanciate = self.Instantiate
+                context.scene.mesh_carver.OInstanciate = self.Instantiate
                 # Random Rotation
-                context.scene.ORandom = self.RandomRotation
+                context.scene.mesh_carver.ORandom = self.RandomRotation
                 # Apply boolean operation
-                context.scene.DontApply = self.DontApply
+                context.scene.mesh_carver.DontApply = self.DontApply
 
                 # Reset Object
                 if self.ObjectBrush is not None:
@@ -2971,24 +2856,16 @@ class Carver(bpy.types.Operator):
                     context.scene.objects.active = self.ObjectBrush
 
                     bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY")
-
                     bpy.ops.object.select_all(action='TOGGLE')
 
                     Selection_Restore(self)
 
-                if "CT_Profil" in bpy.data.objects:
-                    Selection_Save(self)
-                    bpy.ops.object.select_all(action='DESELECT')
-                    bpy.data.objects["CT_Profil"].select = True
-                    context.scene.objects.active = bpy.data.objects["CT_Profil"]
-                    bpy.ops.object.delete(use_global=False)
-                    Selection_Restore(self)
-
+                Selection_Save_Restore(self)
                 context.scene.objects.active = self.CurrentActive
-
-                context.scene.nProfile = self.nProfil
+                context.scene.mesh_carver.nProfile = self.nProfil
 
                 bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
+
                 # Remove Copy Object Brush
                 if bpy.data.objects.get("CarverBrushCopy") is not None:
                     brush = bpy.data.objects["CarverBrushCopy"]
@@ -3003,7 +2880,6 @@ class Carver(bpy.types.Operator):
 
         except:
             print("\n[Carver MT ERROR]\n")
-
             import traceback
             traceback.print_exc()
 
@@ -3016,242 +2892,246 @@ class Carver(bpy.types.Operator):
 
             return {'FINISHED'}
 
-    # --------------------------------------------------------------------------------------------------
+    def cancel(self, context):
+        # Note: used to prevent memory leaks on quiting Blender while the modal operator
+        # is still running, gets called on return {"CANCELLED"}
+        bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
 
-    # --------------------------------------------------------------------------------------------------
     def invoke(self, context, event):
-        if context.area.type == 'VIEW_3D':
-            if context.mode == 'EDIT_MESH':
-                bpy.ops.object.mode_set(mode='OBJECT')
-
-            win = context.window
-
-            # Get default patterns
-            self.Profils = []
-            for p in Profils:
-                self.Profils.append((p[0], p[1], p[2], p[3]))
+        if context.area.type != 'VIEW_3D':
+            self.report({'WARNING'},
+                        "View3D not found or not currently active. Operation Cancelled")
+            return {'CANCELLED'}
 
-            for o in context.scene.objects:
-                if not o.name.startswith(context.scene.ProfilePrefix):
-                    continue
+        if context.mode == 'EDIT_MESH':
+            bpy.ops.object.mode_set(mode='OBJECT')
 
-                # In-scene profiles may have changed, remove them to refresh
-                for m in bpy.data.meshes:
-                    if m.name.startswith(context.scene.ProfilePrefix):
-                        bpy.data.meshes.remove(m)
+        # test if some other object types are selected that are not meshes
+        test_selection = True
+        for obj in context.selected_objects:
+            if obj.type != "MESH":
+                test_selection = False
+                break
+        if not test_selection:
+            self.report({'WARNING'},
+                        "Some selected objects are not of the Mesh type. Operation Cancelled")
+            return {"CANCELLED"}
+
+        # Get default patterns
+        self.Profils = []
+        for p in Profils:
+            self.Profils.append((p[0], p[1], p[2], p[3]))
+
+        for o in context.scene.objects:
+            if not o.name.startswith(context.scene.ProfilePrefix):
+                continue
+
+            # In-scene profiles may have changed, remove them to refresh
+            for m in bpy.data.meshes:
+                if m.name.startswith(context.scene.ProfilePrefix):
+                    bpy.data.meshes.remove(m)
+
+            vertices = []
+            for v in o.data.vertices:
+                vertices.append((v.co.x, v.co.y, v.co.z))
+
+            faces = []
+            for f in o.data.polygons:
+                face = []
+                for v in f.vertices:
+                    face.append(v)
+
+                faces.append(face)
+
+            self.Profils.append(
+                (o.name,
+                Vector((o.location.x, o.location.y, o.location.z)),
+                vertices, faces)
+            )
 
-                vertices = []
-                for v in o.data.vertices:
-                    vertices.append((v.co.x, v.co.y, v.co.z))
+        self.nProfil = context.scene.mesh_carver.nProfile
+        self.MaxProfil = len(self.Profils)
 
-                faces = []
-                for f in o.data.polygons:
-                    face = []
+        # reset selected profile if last profile exceeds length of array
+        if self.nProfil >= self.MaxProfil:
+            self.nProfil = context.scene.mesh_carver.nProfile = 0
 
-                    for v in f.vertices:
-                        face.append(v)
+        # Save selection
+        self.CurrentSelection = context.selected_objects.copy()
+        self.CurrentActive = context.active_object
+        self.SavSel = context.selected_objects.copy()
+        self.Sav_ac = None
 
-                    faces.append(face)
+        args = (self, context)
 
-                self.Profils.append(
-                            (o.name,
-                            mathutils.Vector((o.location.x, o.location.y, o.location.z)),
-                            vertices, faces)
-                            )
+        self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
 
-            self.nProfil = context.scene.nProfile
-            self.MaxProfil = len(self.Profils)
+        self.mouse_path = [(0, 0), (0, 0)]
 
-            # reset selected profile if last profile exceeds length of array
-            if self.nProfil >= self.MaxProfil:
-                self.nProfil = context.scene.nProfile = 0
+        self.shift = False
+        self.ctrl = False
+        self.alt = False
+        self.bDone = False
 
-            # Save selection
-            self.CurrentSelection = context.selected_objects.copy()
-            self.CurrentActive = context.active_object
-            self.SavSel = context.selected_objects.copy()
-            self.Sav_ac = None
+        self.DontApply = context.scene.mesh_carver.DontApply
+        self.Auto_BevelUpdate = True
 
-            args = (self, context)
+        # Cut type (Rectangle, Circle, Line)
+        self.CutMode = 0
+        self.BoolOps = DIFFERENCE
 
-            self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
+        # Circle variables
+        self.stepAngle = [2, 4, 5, 6, 9, 10, 15, 20, 30, 40, 45, 60, 72, 90]
+        self.step = 4
+        self.stepRotation = 0
 
-            self.mouse_path = [(0, 0), (0, 0)]
+        # Primitives Position
+        self.xpos = 0
+        self.ypos = 0
+        self.InitPosition = False
 
-            self.shift = False
-            self.ctrl = False
-            self.alt = False
+        # Line Increment
+        self.Increment = 15
+        # Close polygonal shape
+        self.Closed = False
 
-            self.bDone = False
+        # Depth Cursor
+        self.snapCursor = context.scene.mesh_carver.DepthCursor
 
-            self.DontApply = context.scene.DontApply
-            self.Auto_BevelUpdate = True
+        # Help
+        self.AskHelp = False
 
-            # Cut type (Rectangle, Circle, Line)
-            self.CutMode = 0
-            self.BoolOps = DIFFERENCE
+        # Working object
+        self.OpsObj = context.active_object
 
-            # Circle variables
-            self.stepAngle = [2, 4, 5, 6, 9, 10, 15, 20, 30, 40, 45, 60, 72, 90]
-            self.step = 4
-            self.stepRotation = 0
+        # Create mode
+        self.CreateMode = False
+        self.ExclusiveCreateMode = False
+        if len(context.selected_objects) == 0:
+            self.ExclusiveCreateMode = True
+            self.CreateMode = True
 
-            # Primitives Position
-            self.xpos = 0
-            self.ypos = 0
-            self.InitPosition = False
+        # Rebool forced (cut line)
+        self.ForceRebool = False
 
-            # Line Increment
-            self.Increment = 15
-            # Close polygonal shape
-            self.Closed = False
-
-            # Depth Cursor
-            self.snapCursor = context.scene.DepthCursor
-
-            # Help
-            self.AskHelp = False
-
-            # Working object
-            self.OpsObj = context.active_object
-
-            # Create mode
-            self.CreateMode = False
-            self.ExclusiveCreateMode = False
-            if len(context.selected_objects) == 0:
-                self.ExclusiveCreateMode = True
-                self.CreateMode = True
-
-            # Rebool forced (cut line)
-            self.ForceRebool = False
-
-            self.ViewVector = mathutils.Vector()
-
-            self.CurrentObj = None
-
-            # Brush
-            self.BrushSolidify = False
-            self.WidthSolidify = False
-            self.CarveDepth = False
-            self.BrushDepth = False
-            self.BrushDepthOffset = 0.0
-
-            self.ObjectScale = False
-
-            self.CircleListRaw = []
-            self.CLR_C = []
-            self.CurLoc = mathutils.Vector((0.0, 0.0, 0.0))
-            self.SavCurLoc = mathutils.Vector((0.0, 0.0, 0.0))
-            self.CRadius = 1.0
-            CreatePrimitive(self, 10.0, 1.0)
-            self.VertsList = []
-            self.FacesList = []
-
-            self.am = -1, -1
-            self.SavMousePos = None
-            self.xSavMouse = 0
-
-            self.ascale = 0
-            self.aRotZ = 0
-            self.nRotZ = 0
-            self.aqR = None
-            self.qRot = None
-
-            self.RandomRotation = context.scene.ORandom
-
-            self.ShowCursor = True
-
-            self.ObjectMode = False
-            self.ProfileMode = False
-            self.Instantiate = context.scene.OInstanciate
-
-            self.ProfileBrush = None
-            self.ObjectBrush = None
-            self.InitBrushPosition = None
-            self.InitBrushScale = None
-            self.InitBrushQRotation = None
-            self.InitBrushERotation = None
-            self.InitBrushARotation = None
-
-            self.ObjectBrush_DT = "WIRE"
-            self.XRay = False
-
-            # Grid mesh
-            self.nbcol = 1
-            self.nbrow = 1
-            self.gapx = 0
-            self.gapy = 0
-            self.scale_x = 1
-            self.scale_y = 1
-
-            self.GridScaleX = False
-            self.GridScaleY = False
-
-            if len(context.selected_objects) > 1:
-                self.ObjectBrush = context.active_object
-
-                # Copy the brush object
-                ob = bpy.data.objects.new("CarverBrushCopy", context.object.data.copy())
-                ob.location = self.ObjectBrush.location
-                scene = context.scene
-                scene.objects.link(ob)
-                scene.update()
-
-                # Get default variables
-                self.InitBrushPosition = self.ObjectBrush.location.copy()
-                self.InitBrushScale = self.ObjectBrush.scale.copy()
-                self.InitBrushQRotation = self.ObjectBrush.rotation_quaternion.copy()
-                self.InitBrushERotation = self.ObjectBrush.rotation_euler.copy()
-                self.ObjectBrush_DT = self.ObjectBrush.draw_type
-                self.XRay = self.ObjectBrush.show_x_ray
-                # Test if flat object
-                z = self.ObjectBrush.data.vertices[0].co.z
-                ErrorMarge = 0.01
-                self.Solidify_Active_Start = True
-                for v in self.ObjectBrush.data.vertices:
-                    if abs(v.co.z - z) > ErrorMarge:
-                        self.Solidify_Active_Start = False
-                        break
-                self.SolidifyPossible = False
-
-            self.CList = []
-            self.OPList = []
-            self.RList = []
-            self.OB_List = []
-
-            for ent in context.selected_objects:
-                if ent != self.ObjectBrush:
-                    self.OB_List.append(ent)
-
-            # Left button
-            self.LMB = False
-
-            # Undo Variables
-            self.undo_index = 0
-            self.undo_limit = context.user_preferences.edit.undo_steps
-            self.undo_list = []
-
-            # Boolean operations type
-            self.BooleanType = 0
-
-            self.UList = []
-            self.UList_Index = -1
-            self.UndoOps = []
-
-            context.window_manager.modal_handler_add(self)
-            return {'RUNNING_MODAL'}
-        else:
-            self.report({'WARNING'}, "View3D not found, cannot run operator")
-            return {'CANCELLED'}
-    # --------------------------------------------------------------------------------------------------
+        self.ViewVector = Vector()
+        self.CurrentObj = None
+
+        # Brush
+        self.BrushSolidify = False
+        self.WidthSolidify = False
+        self.CarveDepth = False
+        self.BrushDepth = False
+        self.BrushDepthOffset = 0.0
+
+        self.ObjectScale = False
+
+        self.CircleListRaw = []
+        self.CLR_C = []
+        self.CurLoc = Vector((0.0, 0.0, 0.0))
+        self.SavCurLoc = Vector((0.0, 0.0, 0.0))
+        self.CRadius = 1.0
+        CreatePrimitive(self, 10.0, 1.0)
+        self.VertsList = []
+        self.FacesList = []
+
+        self.am = -1, -1
+        self.SavMousePos = None
+        self.xSavMouse = 0
+
+        self.ascale = 0
+        self.aRotZ = 0
+        self.nRotZ = 0
+        self.aqR = None
+        self.qRot = None
+
+        self.RandomRotation = context.scene.mesh_carver.ORandom
+
+        self.ShowCursor = True
+        self.ObjectMode = False
+        self.ProfileMode = False
+        self.Instantiate = context.scene.mesh_carver.OInstanciate
+
+        self.ProfileBrush = None
+        self.ObjectBrush = None
+        self.InitBrushPosition = None
+        self.InitBrushScale = None
+        self.InitBrushQRotation = None
+        self.InitBrushERotation = None
+        self.InitBrushARotation = None
+
+        self.ObjectBrush_DT = "WIRE"
+        self.XRay = False
+
+        # Grid mesh
+        self.nbcol = 1
+        self.nbrow = 1
+        self.gapx = 0
+        self.gapy = 0
+        self.scale_x = 1
+        self.scale_y = 1
+
+        self.GridScaleX = False
+        self.GridScaleY = False
+
+        if len(context.selected_objects) > 1:
+            self.ObjectBrush = context.active_object
+
+            # Copy the brush object
+            ob = bpy.data.objects.new("CarverBrushCopy", context.object.data.copy())
+            ob.location = self.ObjectBrush.location
+            scene = context.scene
+            scene.objects.link(ob)
+            scene.update()
+
+            # Get default variables
+            self.InitBrushPosition = self.ObjectBrush.location.copy()
+            self.InitBrushScale = self.ObjectBrush.scale.copy()
+            self.InitBrushQRotation = self.ObjectBrush.rotation_quaternion.copy()
+            self.InitBrushERotation = self.ObjectBrush.rotation_euler.copy()
+            self.ObjectBrush_DT = self.ObjectBrush.draw_type
+            self.XRay = self.ObjectBrush.show_x_ray
+            # Test if flat object
+            z = self.ObjectBrush.data.vertices[0].co.z
+            ErrorMarge = 0.01
+            self.Solidify_Active_Start = True
+            for v in self.ObjectBrush.data.vertices:
+                if abs(v.co.z - z) > ErrorMarge:
+                    self.Solidify_Active_Start = False
+                    break
+            self.SolidifyPossible = False
+
+        self.CList = []
+        self.OPList = []
+        self.RList = []
+        self.OB_List = []
+
+        for ent in context.selected_objects:
+            if ent != self.ObjectBrush:
+                self.OB_List.append(ent)
+
+        # Left button
+        self.LMB = False
+
+        # Undo Variables
+        self.undo_index = 0
+        self.undo_limit = context.user_preferences.edit.undo_steps
+        self.undo_list = []
+
+        # Boolean operations type
+        self.BooleanType = 0
+
+        self.UList = []
+        self.UList_Index = -1
+        self.UndoOps = []
+
+        context.window_manager.modal_handler_add(self)
+        return {'RUNNING_MODAL'}
 
-    # --------------------------------------------------------------------------------------------------
     def CreateGeometry(self):
         context = bpy.context
-
-        region_id = context.region.id
-
         bLocalView = False
+
         for area in context.screen.areas:
             if area.type == 'VIEW_3D':
                 if area.spaces[0].local_view is not None:
@@ -3309,14 +3189,10 @@ class Carver(bpy.types.Operator):
         self.bDone = False
         self.mouse_path.clear()
         self.mouse_path = [(0, 0), (0, 0)]
-    # --------------------------------------------------------------------------------------------------
 
-    # --------------------------------------------------------------------------------------------------
     def Cut(self):
         context = bpy.context
 
-        UNDO = []
-
         # Local view ?
         bLocalView = False
         for area in context.screen.areas:
@@ -3358,7 +3234,7 @@ class Carver(bpy.types.Operator):
             bpy.ops.mesh.normals_make_consistent()
             bpy.ops.object.mode_set(mode='OBJECT')
         else:
-            # Create liste
+            # Create list
             if self.ObjectMode:
                 for o in self.CurrentSelection:
                     if o != self.ObjectBrush:
@@ -3380,7 +3256,7 @@ class Carver(bpy.types.Operator):
             if len(context.selected_objects) > 0:
                 bpy.ops.object.select_all(action='TOGGLE')
 
-            # Testif intitiale object has bevel
+            # Test if initial object has bevel
             BevelAO = False
             for obj in ActiveObjList:
                 for mb in obj.modifiers:
@@ -3407,14 +3283,11 @@ class Carver(bpy.types.Operator):
             if (self.shift is False) and (self.ForceRebool is False):
                 if self.ObjectMode or self.ProfileMode:
                     if self.BoolOps == UNION:
-                        # Union
-                        boolean_union()
+                        boolean_operation(bool_type="UNION")
                     else:
-                        # Cut object
-                        boolean_difference()
+                        boolean_operation(bool_type="DIFFERENCE")
                 else:
-                    # Cut
-                    boolean_difference()
+                    boolean_operation(bool_type="DIFFERENCE")
 
                 # Apply booleans
                 if self.DontApply is False:
@@ -3487,7 +3360,6 @@ class Carver(bpy.types.Operator):
                 if len(context.selected_objects) > 0:
                     bpy.ops.object.select_all(action='TOGGLE')
                 bpy.data.objects[self.CurrentObj.name].select = True
-                cname = self.CurrentObj.name
                 bpy.ops.object.delete(use_global=False)
             else:
                 if self.ObjectMode:
@@ -3496,7 +3368,7 @@ class Carver(bpy.types.Operator):
         if len(context.selected_objects) > 0:
             bpy.ops.object.select_all(action='TOGGLE')
 
-        # Select cutted objects
+        # Select cut objects
         for obj in lastSelected:
             bpy.data.objects[obj.name].select = True
 
@@ -3508,10 +3380,10 @@ class Carver(bpy.types.Operator):
         if self.Auto_BevelUpdate:
             update_bevel(context)
 
-        # Reselect intiale objects
+        # Re-select initial objects
         bpy.ops.object.select_all(action='TOGGLE')
         if self.ObjectMode:
-            # Reselect brush
+            # Re-select brush
             self.ObjectBrush.select = True
         for ActiveObj in ActiveObjList:
             bpy.data.objects[ActiveObj.name].select = True
@@ -3535,23 +3407,45 @@ class Carver(bpy.types.Operator):
         self.ForceRebool = False
 
 
-classes = (
-    Carver,
+class CarverProperties(bpy.types.PropertyGroup):
+    DepthCursor = BoolProperty(
+        name="DepthCursor",
+        default=False
+    )
+    OInstanciate = BoolProperty(
+        name="Obj_Instantiate",
+        default=False
+    )
+    ORandom = BoolProperty(
+        name="Random_Rotation",
+        default=False
+    )
+    DontApply = BoolProperty(
+        name="Dont_Apply",
+        default=False
     )
+    nProfile = IntProperty(
+        name="Num_Profile",
+        default=0
+    )
+
 
 addon_keymaps = []
 
+classes = (
+    CarverPrefs,
+    CarverProperties,
+    Carver,
+)
 
-def register():
-    bpy.types.Scene.DepthCursor = BoolProperty(name="DepthCursor", default=False)
-    bpy.types.Scene.OInstanciate = BoolProperty(name="Obj_Instantiate", default=False)
-    bpy.types.Scene.ORandom = BoolProperty(name="Random_Rotation", default=False)
-    bpy.types.Scene.DontApply = BoolProperty(name="Dont_Apply", default=False)
-    bpy.types.Scene.nProfile = IntProperty(name="Num_Profile", default=0)
 
-    bpy.utils.register_class(CarverPrefs)
+def register():
+    for cls in classes:
+        bpy.utils.register_class(cls)
 
-    bpy.utils.register_class(Carver)
+    bpy.types.Scene.mesh_carver = PointerProperty(
+        type=CarverProperties
+    )
     # add keymap entry
     kcfg = bpy.context.window_manager.keyconfigs.addon
     if kcfg:
@@ -3561,14 +3455,15 @@ def register():
 
 
 def unregister():
-    bpy.utils.unregister_class(CarverPrefs)
+    for cls in classes:
+        bpy.utils.unregister_class(cls)
 
     # remove keymap entry
     for km, kmi in addon_keymaps:
         km.keymap_items.remove(kmi)
     addon_keymaps.clear()
 
-    bpy.utils.unregister_class(Carver)
+    del bpy.types.Scene.mesh_carver
 
 
 if __name__ == "__main__":
diff --git a/mesh_tiny_cad/BIX.py b/mesh_tiny_cad/BIX.py
index faac521271b4e45d6965e73881fbf2060eccc988..89908f607ecffffb4e3c8317c6a60b147d4439e8 100644
--- a/mesh_tiny_cad/BIX.py
+++ b/mesh_tiny_cad/BIX.py
@@ -92,11 +92,3 @@ class TCLineOnBisection(bpy.types.Operator):
     def execute(self, context):
         add_line_to_bisection(self)
         return {'FINISHED'}
-
-
-def register():
-    bpy.utils.register_module(__name__)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
diff --git a/mesh_tiny_cad/CCEN.py b/mesh_tiny_cad/CCEN.py
index f625504b9c8d789b40b6947db6dffe992cfda0b9..ef2b5eae49d50818638594bd558b1edfe7892091 100644
--- a/mesh_tiny_cad/CCEN.py
+++ b/mesh_tiny_cad/CCEN.py
@@ -157,11 +157,3 @@ class TCCircleCenter(bpy.types.Operator):
     def execute(self, context):
         dispatch(context, mode=1)
         return {'FINISHED'}
-
-
-def register():
-    bpy.utils.register_module(__name__)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
diff --git a/mesh_tiny_cad/CFG.py b/mesh_tiny_cad/CFG.py
index ed703a2f907882a7effe200a621b37a6257eb1ce..55e0ff9fabac3b8e3c32f2eb385ab0198b06e0d8 100644
--- a/mesh_tiny_cad/CFG.py
+++ b/mesh_tiny_cad/CFG.py
@@ -74,11 +74,3 @@ def unregister_icons():
     for pcoll in icon_collection.values():
         bpy.utils.previews.remove(pcoll)
     icon_collection.clear()
-
-
-def register():
-    bpy.utils.register_module(__name__)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
diff --git a/mesh_tiny_cad/E2F.py b/mesh_tiny_cad/E2F.py
index 8c95f126dd81f138dfa430837185360da5722061..25f17e9f24890eec2335cdbd15e9d8d154e27b09 100644
--- a/mesh_tiny_cad/E2F.py
+++ b/mesh_tiny_cad/E2F.py
@@ -100,11 +100,3 @@ class TCEdgeToFace(bpy.types.Operator):
     def execute(self, context):
         extend_vertex(self)
         return {'FINISHED'}
-
-
-def register():
-    bpy.utils.register_module(__name__)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
diff --git a/mesh_tiny_cad/V2X.py b/mesh_tiny_cad/V2X.py
index c230f4a2c4be31ee2906cc346a20230bd71986dd..c8683297d292fb179f411d0e9e679ab979fde228 100644
--- a/mesh_tiny_cad/V2X.py
+++ b/mesh_tiny_cad/V2X.py
@@ -60,11 +60,3 @@ class TCVert2Intersection(bpy.types.Operator):
     def execute(self, context):
         add_vertex_to_intersection()
         return {'FINISHED'}
-
-
-def register():
-    bpy.utils.register_module(__name__)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
diff --git a/mesh_tiny_cad/VTX.py b/mesh_tiny_cad/VTX.py
index 5ad035b28abf7d56cd6192141696f4edc117a54b..5cdb2fcfe0c728dcf6c15d257bd99f92667fd47a 100644
--- a/mesh_tiny_cad/VTX.py
+++ b/mesh_tiny_cad/VTX.py
@@ -173,11 +173,3 @@ class TCAutoVTX(bpy.types.Operator):
         bmesh.update_edit_mesh(me, True)
 
         return {'FINISHED'}
-
-
-def register():
-    bpy.utils.register_module(__name__)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
diff --git a/mesh_tiny_cad/XALL.py b/mesh_tiny_cad/XALL.py
index 83ecdb52522fda09e4407fb6889645c99395a8be..fc0ed76e8f140741afb3eae481f344b698befc34 100644
--- a/mesh_tiny_cad/XALL.py
+++ b/mesh_tiny_cad/XALL.py
@@ -174,11 +174,3 @@ class TCIntersectAllEdges(bpy.types.Operator):
             print('must be in edit mode')
 
         return {'FINISHED'}
-
-
-def register():
-    bpy.utils.register_module(__name__)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
diff --git a/mesh_tiny_cad/__init__.py b/mesh_tiny_cad/__init__.py
index 611c67c4c08cfeecd7104a531ac01c02c6fa2c37..4a9a62f06e90e065a2a56c92e59e655b528bbc24 100644
--- a/mesh_tiny_cad/__init__.py
+++ b/mesh_tiny_cad/__init__.py
@@ -50,7 +50,7 @@ if "bpy" in locals():
 
 import bpy
 
-from .CFG import TinyCADProperties
+from .CFG import TinyCADProperties, VIEW3D_MT_edit_mesh_tinycad
 from .CFG import register_icons, unregister_icons
 from . import VTX, V2X, XALL, BIX, CCEN, E2F
 
@@ -59,10 +59,20 @@ def menu_func(self, context):
     self.layout.menu("VIEW3D_MT_edit_mesh_tinycad")
     self.layout.separator()
 
+classes = [
+    TinyCADProperties, VIEW3D_MT_edit_mesh_tinycad,
+    VTX.TCAutoVTX,
+    XALL.TCIntersectAllEdges,
+    V2X.TCVert2Intersection,
+    E2F.TCEdgeToFace,
+    CCEN.TCCallBackCCEN, CCEN.TCCircleCenter,
+    BIX.TCLineOnBisection
+]
 
 def register():
     register_icons()
-    bpy.utils.register_module(__name__)
+    for cls in classes:
+        bpy.utils.register_class(cls)
     bpy.types.Scene.tinycad_props = bpy.props.PointerProperty(
         name="TinyCAD props", type=TinyCADProperties)
     bpy.types.VIEW3D_MT_edit_mesh_specials.prepend(menu_func)
@@ -70,6 +80,7 @@ def register():
 
 def unregister():
     bpy.types.VIEW3D_MT_edit_mesh_specials.remove(menu_func)
-    bpy.utils.unregister_module(__name__)
+    for cls in reversed(classes):
+        bpy.utils.unregister_class(cls)
     del bpy.types.Scene.tinycad_props
     unregister_icons()
diff --git a/modules/cycles_shader_compat.py b/modules/cycles_shader_compat.py
index 8a967f465411c92c1d3d7093296b0fef253d7b6d..c85ba667aaf9795d19a0f846af52caf1c1f33b3b 100644
--- a/modules/cycles_shader_compat.py
+++ b/modules/cycles_shader_compat.py
@@ -19,6 +19,7 @@
 # <pep8 compliant>
 
 import bpy
+import math
 
 __all__ = (
     "CyclesShaderWrapper",
@@ -392,7 +393,7 @@ class CyclesShaderWrapper():
 
     def hardness_value_set(self, value):
         node = self.node_mix_color_hard
-        node.inputs["Color1"].default_value = (value,) * 4
+        node.inputs["Color1"].default_value = (math.sqrt(max(value, 0.0)),) * 4
 
     def hardness_image_set(self, image):
         node = self.node_mix_color_hard
diff --git a/modules/rna_manual_reference.py b/modules/rna_manual_reference.py
index 3cf680cb9e49a20e60c571dafae84561945b4ef1..a477d3ec11d9e180cd3bf703d66bb0577f527be2 100644
--- a/modules/rna_manual_reference.py
+++ b/modules/rna_manual_reference.py
@@ -31,6 +31,7 @@ if LANG is not None:
 url_manual_mapping = (
 	("bpy.types.cyclesobjectsettings.use_adaptive_subdivision*", "render/cycles/settings/objects/adaptive_subsurf.html#bpy-types-cyclesobjectsettings-use-adaptive-subdivision"),
 	("bpy.types.toolsettings.gpencil_stroke_placement_view3d*", "interface/grease_pencil/drawing/introduction.html#bpy-types-toolsettings-gpencil-stroke-placement-view3d"),
+	("bpy.types.cyclesrendersettings.offscreen_dicing_scale*", "render/cycles/settings/scene/render/geometry.html#bpy-types-cyclesrendersettings-offscreen-dicing-scale"),
 	("bpy.types.linestylegeometrymodifier_backbonestretcher*", "render/freestyle/parameter_editor/line_style/modifiers/geometry.html#bpy-types-linestylegeometrymodifier-backbonestretcher"),
 	("bpy.types.linestylegeometrymodifier_sinusdisplacement*", "render/freestyle/parameter_editor/line_style/modifiers/geometry.html#bpy-types-linestylegeometrymodifier-sinusdisplacement"),
 	("bpy.types.toolsettings.use_gpencil_continuous_drawing*", "interface/grease_pencil/drawing/introduction.html#bpy-types-toolsettings-use-gpencil-continuous-drawing"),
@@ -46,7 +47,7 @@ url_manual_mapping = (
 	("bpy.types.linestylegeometrymodifier_guidinglines*", "render/freestyle/parameter_editor/line_style/modifiers/geometry.html#bpy-types-linestylegeometrymodifier-guidinglines"),
 	("bpy.types.linestylegeometrymodifier_spatialnoise*", "render/freestyle/parameter_editor/line_style/modifiers/geometry.html#bpy-types-linestylegeometrymodifier-spatialnoise"),
 	("bpy.types.linestylethicknessmodifier_calligraphy*", "render/freestyle/parameter_editor/line_style/modifiers/properties.html#bpy-types-linestylethicknessmodifier-calligraphy"),
-	("bpy.types.cyclesrendersettings.max_subdivisions*", "render/cycles/settings/scene/render/integrator.html#bpy-types-cyclesrendersettings-max-subdivisions"),
+	("bpy.types.cyclesrendersettings.max_subdivisions*", "render/cycles/settings/scene/render/geometry.html#bpy-types-cyclesrendersettings-max-subdivisions"),
 	("bpy.types.linestyle*modifier_distancefromcamera*", "render/freestyle/parameter_editor/line_style/modifiers/properties.html#bpy-types-linestyle-modifier-distancefromcamera"),
 	("bpy.types.linestyle*modifier_distancefromobject*", "render/freestyle/parameter_editor/line_style/modifiers/properties.html#bpy-types-linestyle-modifier-distancefromobject"),
 	("bpy.types.linestylegeometrymodifier_2dtransform*", "render/freestyle/parameter_editor/line_style/modifiers/geometry.html#bpy-types-linestylegeometrymodifier-2dtransform"),
@@ -57,27 +58,31 @@ url_manual_mapping = (
 	("bpy.types.cyclesmaterialsettings.displacement*", "render/cycles/materials/settings.html#bpy-types-cyclesmaterialsettings-displacement"),
 	("bpy.types.linestylegeometrymodifier_blueprint*", "render/freestyle/parameter_editor/line_style/modifiers/geometry.html#bpy-types-linestylegeometrymodifier-blueprint"),
 	("bpy.types.rendersettings.simplify_subdivision*", "data_system/scenes/properties.html#bpy-types-rendersettings-simplify-subdivision"),
+	("bpy.types.cyclesrendersettings.dicing_camera*", "render/cycles/settings/scene/render/geometry.html#bpy-types-cyclesrendersettings-dicing-camera"),
 	("bpy.types.cyclesrendersettings.texture_limit*", "render/cycles/settings/scene/introduction.html#bpy-types-cyclesrendersettings-texture-limit"),
 	("bpy.types.linestylegeometrymodifier_2doffset*", "render/freestyle/parameter_editor/line_style/modifiers/geometry.html#bpy-types-linestylegeometrymodifier-2doffset"),
 	("bpy.types.linestylegeometrymodifier_sampling*", "render/freestyle/parameter_editor/line_style/modifiers/geometry.html#bpy-types-linestylegeometrymodifier-sampling"),
 	("bpy.types.spaceview3d.show_background_images*", "editors/3dview/properties/background_images.html#bpy-types-spaceview3d-show-background-images"),
-	("bpy.types.cyclesrendersettings.*dicing_rate*", "render/cycles/settings/scene/render/integrator.html#bpy-types-cyclesrendersettings-dicing-rate"),
+	("bpy.types.cyclesrendersettings.*dicing_rate*", "render/cycles/settings/scene/render/geometry.html#bpy-types-cyclesrendersettings-dicing-rate"),
+	("bpy.types.rendersettings.use_file_extension*", "render/output/output.html#bpy-types-rendersettings-use-file-extension"),
 	("bpy.types.spaceview3d.transform_orientation*", "editors/3dview/object/editing/transform/control/orientations.html#bpy-types-spaceview3d-transform-orientation"),
 	("bpy.ops.object.constraint_add_with_targets*", "rigging/constraints/interface/adding_removing.html#bpy-ops-object-constraint-add-with-targets"),
 	("bpy.types.cyclesobjectsettings.dicing_rate*", "render/cycles/settings/objects/adaptive_subsurf.html#bpy-types-cyclesobjectsettings-dicing-rate"),
-	("bpy.types.spaceuveditor.use_snap_to_pixels*", "editors/uv_image/uv_editing/layout_editing.html#bpy-types-spaceuveditor-use-snap-to-pixels"),
+	("bpy.types.spaceuveditor.use_snap_to_pixels*", "editors/uv_image/uv/editing/layout.html#bpy-types-spaceuveditor-use-snap-to-pixels"),
 	("bpy.types.linestyle*modifier_curvature_3d*", "render/freestyle/parameter_editor/line_style/modifiers/properties.html#bpy-types-linestyle-modifier-curvature-3d"),
+	("bpy.types.rendersettings.use_render_cache*", "render/output/output.html#bpy-types-rendersettings-use-render-cache"),
 	("bpy.ops.object.anim_transforms_to_deltas*", "editors/3dview/object/editing/transform/clear_apply.html#bpy-ops-object-anim-transforms-to-deltas"),
 	("bpy.types.compositornodeplanetrackdeform*", "compositing/types/distort/plane_track_deform.html#bpy-types-compositornodeplanetrackdeform"),
 	("bpy.types.gpencilsculptsettings.lockaxis*", "interface/grease_pencil/drawing/introduction.html#bpy-types-gpencilsculptsettings-lockaxis"),
 	("bpy.types.linestyle*modifier_alongstroke*", "render/freestyle/parameter_editor/line_style/modifiers/properties.html#bpy-types-linestyle-modifier-alongstroke"),
 	("bpy.types.linestyle*modifier_creaseangle*", "render/freestyle/parameter_editor/line_style/modifiers/properties.html#bpy-types-linestyle-modifier-creaseangle"),
+	("bpy.types.rendersettings.use_placeholder*", "render/output/output.html#bpy-types-rendersettings-use-placeholder"),
 	("bpy.types.shadernodesubsurfacescattering*", "render/cycles/nodes/types/shaders/sss.html#bpy-types-shadernodesubsurfacescattering"),
 	("bpy.types.compositornodecolorcorrection*", "compositing/types/color/color_correction.html#bpy-types-compositornodecolorcorrection"),
 	("bpy.types.compositornodemoviedistortion*", "compositing/types/distort/movie_distortion.html#bpy-types-compositornodemoviedistortion"),
 	("bpy.types.ffmpegsettings.audio_channels*", "data_system/scenes/properties.html#bpy-types-ffmpegsettings-audio-channels"),
-	("bpy.types.fmodifierenvelopecontrolpoint*", "editors/graph_editor/fcurves/fmodifiers.html#bpy-types-fmodifierenvelopecontrolpoint"),
-	("bpy.types.spaceuveditor.use_live_unwrap*", "editors/uv_image/uv_editing/layout_editing.html#bpy-types-spaceuveditor-use-live-unwrap"),
+	("bpy.types.fmodifierenvelopecontrolpoint*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierenvelopecontrolpoint"),
+	("bpy.types.spaceuveditor.use_live_unwrap*", "editors/uv_image/uv/editing/layout.html#bpy-types-spaceuveditor-use-live-unwrap"),
 	("bpy.types.vertexweightproximitymodifier*", "modeling/modifiers/modify/weight_proximity.html#bpy-types-vertexweightproximitymodifier"),
 	("bpy.types.compositornodebrightcontrast*", "compositing/types/color/bright_contrast.html#bpy-types-compositornodebrightcontrast"),
 	("bpy.types.compositornodedoubleedgemask*", "compositing/types/matte/double_edge_mask.html#bpy-types-compositornodedoubleedgemask"),
@@ -85,6 +90,8 @@ url_manual_mapping = (
 	("bpy.types.material.preview_render_type*", "render/blender_render/materials/properties/preview.html#bpy-types-material-preview-render-type"),
 	("bpy.types.materialraytracetransparency*", "render/blender_render/materials/properties/transparency.html#bpy-types-materialraytracetransparency"),
 	("bpy.types.materialsubsurfacescattering*", "render/blender_render/materials/properties/subsurface_scattering.html#bpy-types-materialsubsurfacescattering"),
+	("bpy.types.rendersettings.use_overwrite*", "render/output/output.html#bpy-types-rendersettings-use-overwrite"),
+	("bpy.types.shadernodevectordisplacement*", "render/cycles/nodes/types/vector/vector_displacement.html#bpy-types-shadernodevectordisplacement"),
 	("bpy.ops.object.visual_transform_apply*", "editors/3dview/object/editing/transform/clear_apply.html#bpy-ops-object-visual-transform-apply"),
 	("bpy.types.compositornodebilateralblur*", "compositing/types/filter/bilateral_blur.html#bpy-types-compositornodebilateralblur"),
 	("bpy.types.compositornodedistancematte*", "compositing/types/matte/distance_key.html#bpy-types-compositornodedistancematte"),
@@ -97,12 +104,13 @@ url_manual_mapping = (
 	("bpy.types.compositornodecolorbalance*", "compositing/types/color/color_balance.html#bpy-types-compositornodecolorbalance"),
 	("bpy.types.compositornodekeyingscreen*", "compositing/types/matte/keying_screen.html#bpy-types-compositornodekeyingscreen"),
 	("bpy.types.dynamicpaintcanvassettings*", "physics/dynamic_paint/canvas.html#bpy-types-dynamicpaintcanvassettings"),
-	("bpy.types.fmodifierfunctiongenerator*", "editors/graph_editor/fcurves/fmodifiers.html#bpy-types-fmodifierfunctiongenerator"),
+	("bpy.types.fmodifierfunctiongenerator*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierfunctiongenerator"),
 	("bpy.types.linestyle*modifier_tangent*", "render/freestyle/parameter_editor/line_style/modifiers/properties.html#bpy-types-linestyle-modifier-tangent"),
 	("bpy.types.movietrackingstabilization*", "editors/movie_clip_editor/tracking/clip/properties/stabilization/index.html#bpy-types-movietrackingstabilization"),
 	("bpy.types.shadernodeambientocclusion*", "render/cycles/nodes/types/shaders/ao.html#bpy-types-shadernodeambientocclusion"),
 	("bpy.types.shadernodevolumeabsorption*", "render/cycles/nodes/types/shaders/volume_absorption.html#bpy-types-shadernodevolumeabsorption"),
-	("bpy.types.toolsettings.use_uv_sculpt*", "editors/uv_image/uv_editing/uv_sculpt.html#bpy-types-toolsettings-use-uv-sculpt"),
+	("bpy.types.shadernodevolumeprincipled*", "render/cycles/nodes/types/shaders/volume_principled.html#bpy-types-shadernodevolumeprincipled"),
+	("bpy.types.toolsettings.use_uv_sculpt*", "editors/uv_image/uv/editing/uv_sculpt.html#bpy-types-toolsettings-use-uv-sculpt"),
 	("bpy.ops.object.duplicates_make_real*", "editors/3dview/object/editing/transform/clear_apply.html#bpy-ops-object-duplicates-make-real"),
 	("bpy.ops.object.transforms_to_deltas*", "editors/3dview/object/editing/transform/clear_apply.html#bpy-ops-object-transforms-to-deltas"),
 	("bpy.types.compositornodechromamatte*", "compositing/types/matte/chroma_key.html#bpy-types-compositornodechromamatte"),
@@ -112,27 +120,29 @@ url_manual_mapping = (
 	("bpy.types.dynamicpaintbrushsettings*", "physics/dynamic_paint/brush.html#bpy-types-dynamicpaintbrushsettings"),
 	("bpy.types.object.slow_parent_offset*", "editors/3dview/object/properties/relations/extras.html#bpy-types-object-slow-parent-offset"),
 	("bpy.types.object.use_dupli_vertices*", "editors/3dview/object/properties/duplication/dupliverts.html#bpy-types-object-use-dupli-vertices"),
+	("bpy.types.rendersettings.use_border*", "render/output/output.html#bpy-types-rendersettings-use-border"),
 	("bpy.types.shadernodebsdfanisotropic*", "render/cycles/nodes/types/shaders/anisotropic.html#bpy-types-shadernodebsdfanisotropic"),
 	("bpy.types.shadernodebsdftranslucent*", "render/cycles/nodes/types/shaders/translucent.html#bpy-types-shadernodebsdftranslucent"),
 	("bpy.types.shadernodebsdftransparent*", "render/cycles/nodes/types/shaders/transparent.html#bpy-types-shadernodebsdftransparent"),
 	("bpy.types.shadernodevectortransform*", "render/cycles/nodes/types/vector/transform.html#bpy-types-shadernodevectortransform"),
-	("bpy.types.spaceuveditor.lock_bounds*", "editors/uv_image/uv_editing/layout_editing.html#bpy-types-spaceuveditor-lock-bounds"),
+	("bpy.types.spaceuveditor.lock_bounds*", "editors/uv_image/uv/editing/layout.html#bpy-types-spaceuveditor-lock-bounds"),
 	("bpy.ops.object.datalayout_transfer*", "modeling/meshes/editing/data_transfer.html#bpy-ops-object-datalayout-transfer"),
 	("bpy.ops.object.randomize_transform*", "editors/3dview/object/editing/transform/tools.html#bpy-ops-object-randomize-transform"),
 	("bpy.types.compositornodebokehimage*", "compositing/types/input/bokeh_image.html#bpy-types-compositornodebokehimage"),
 	("bpy.types.compositornodecolormatte*", "compositing/types/matte/color_key.html#bpy-types-compositornodecolormatte"),
-	("bpy.types.compositornodecolorspill*", "compositing/types/matte/color_spill_key.html#bpy-types-compositornodecolorspill"),
+	("bpy.types.compositornodecolorspill*", "compositing/types/matte/color_spill.html#bpy-types-compositornodecolorspill"),
 	("bpy.types.compositornodehuecorrect*", "compositing/types/color/hue_correct.html#bpy-types-compositornodehuecorrect"),
 	("bpy.types.compositornodeoutputfile*", "compositing/types/output/file.html#bpy-types-compositornodeoutputfile"),
 	("bpy.types.compositornodeswitchview*", "compositing/types/converter/switch_view.html#bpy-types-compositornodeswitchview"),
 	("bpy.types.copytransformsconstraint*", "rigging/constraints/transform/copy_transforms.html#bpy-types-copytransformsconstraint"),
 	("bpy.types.correctivesmoothmodifier*", "modeling/modifiers/deform/corrective_smooth.html#bpy-types-correctivesmoothmodifier"),
-	("bpy.types.cyclesvisibilitysettings*", "render/cycles/settings/scene/render/light_paths.html#bpy-types-cyclesvisibilitysettings"),
+	("bpy.types.cyclesvisibilitysettings*", "render/cycles/settings/objects/object_data.html#bpy-types-cyclesvisibilitysettings"),
 	("bpy.types.linestyle*modifier_noise*", "render/freestyle/parameter_editor/line_style/modifiers/properties.html#bpy-types-linestyle-modifier-noise"),
 	("bpy.types.maintainvolumeconstraint*", "rigging/constraints/transform/maintain_volume.html#bpy-types-maintainvolumeconstraint"),
 	("bpy.types.particleinstancemodifier*", "modeling/modifiers/simulate/particle_instance.html#bpy-types-particleinstancemodifier"),
 	("bpy.types.rigidbodyjointconstraint*", "rigging/constraints/relationship/rigid_body_joint.html#bpy-types-rigidbodyjointconstraint"),
 	("bpy.types.shadernodebrightcontrast*", "render/cycles/nodes/types/color/bright_contrast.html#bpy-types-shadernodebrightcontrast"),
+	("bpy.types.shadernodebsdfprincipled*", "render/cycles/nodes/types/shaders/principled.html#bpy-types-shadernodebsdfprincipled"),
 	("bpy.types.shadernodebsdfrefraction*", "render/cycles/nodes/types/shaders/refraction.html#bpy-types-shadernodebsdfrefraction"),
 	("bpy.types.shadernodeoutputmaterial*", "render/cycles/nodes/types/output/material.html#bpy-types-shadernodeoutputmaterial"),
 	("bpy.types.shadernodetexenvironment*", "render/cycles/nodes/types/textures/environment.html#bpy-types-shadernodetexenvironment"),
@@ -164,7 +174,7 @@ url_manual_mapping = (
 	("bpy.types.shadernodevolumescatter*", "render/cycles/nodes/types/shaders/volume_scatter.html#bpy-types-shadernodevolumescatter"),
 	("bpy.types.vertexweightmixmodifier*", "modeling/modifiers/modify/weight_mix.html#bpy-types-vertexweightmixmodifier"),
 	("bpy.ops.object.constraints_clear*", "rigging/constraints/interface/adding_removing.html#bpy-ops-object-constraints-clear"),
-	("bpy.ops.uv.average_islands_scale*", "editors/uv_image/uv_editing/layout_editing.html#bpy-ops-uv-average-islands-scale"),
+	("bpy.ops.uv.average_islands_scale*", "editors/uv_image/uv/editing/layout.html#bpy-ops-uv-average-islands-scale"),
 	("bpy.ops.view3d.edit_mesh_extrude*", "modeling/meshes/editing/duplicating/extrude.html#bpy-ops-view3d-edit-mesh-extrude"),
 	("bpy.types.brightcontrastmodifier*", "editors/vse/sequencer/properties/modifiers.html#bpy-types-brightcontrastmodifier"),
 	("bpy.types.camerasolverconstraint*", "rigging/constraints/motion_tracking/camera_solver.html#bpy-types-camerasolverconstraint"),
@@ -172,7 +182,7 @@ url_manual_mapping = (
 	("bpy.types.compositornodecurvergb*", "compositing/types/color/rgb_curves.html#bpy-types-compositornodecurvergb"),
 	("bpy.types.compositornodecurvevec*", "compositing/types/vector/vector_curves.html#bpy-types-compositornodecurvevec"),
 	("bpy.types.compositornodedisplace*", "compositing/types/distort/displace.html#bpy-types-compositornodedisplace"),
-	("bpy.types.compositornodelensdist*", "compositing/types/distort/lens.html#bpy-types-compositornodelensdist"),
+	("bpy.types.compositornodelensdist*", "compositing/types/distort/lens_distortion.html#bpy-types-compositornodelensdist"),
 	("bpy.types.compositornodemaprange*", "compositing/types/vector/map_range.html#bpy-types-compositornodemaprange"),
 	("bpy.types.compositornodemapvalue*", "compositing/types/vector/map_value.html#bpy-types-compositornodemapvalue"),
 	("bpy.types.compositornodepixelate*", "compositing/types/filter/pixelate.html#bpy-types-compositornodepixelate"),
@@ -188,6 +198,7 @@ url_manual_mapping = (
 	("bpy.types.object.use_slow_parent*", "editors/3dview/object/properties/relations/extras.html#bpy-types-object-use-slow-parent"),
 	("bpy.types.objectsolverconstraint*", "rigging/constraints/motion_tracking/object_solver.html#bpy-types-objectsolverconstraint"),
 	("bpy.types.particlesystemmodifier*", "physics/particles/index.html#bpy-types-particlesystemmodifier"),
+	("bpy.types.shadernodedisplacement*", "render/cycles/nodes/types/vector/displacement.html#bpy-types-shadernodedisplacement"),
 	("bpy.types.shadernodelightfalloff*", "render/cycles/nodes/types/color/light_falloff.html#bpy-types-shadernodelightfalloff"),
 	("bpy.types.shadernodeparticleinfo*", "render/cycles/nodes/types/input/particle_info.html#bpy-types-shadernodeparticleinfo"),
 	("bpy.ops.object.constraints_copy*", "rigging/constraints/interface/adding_removing.html#bpy-ops-object-constraints-copy"),
@@ -271,8 +282,8 @@ url_manual_mapping = (
 	("bpy.ops.object.select_by_type*", "editors/3dview/object/selecting/tools.html#bpy-ops-object-select-by-type"),
 	("bpy.ops.object.select_grouped*", "editors/3dview/object/selecting/tools.html#bpy-ops-object-select-grouped"),
 	("bpy.ops.object.select_pattern*", "editors/3dview/object/selecting/tools.html#bpy-ops-object-select-pattern"),
-	("bpy.ops.screen.repeat_history*", "interface/undo_and_redo.html#bpy-ops-screen-repeat-history"),
-	("bpy.ops.uv.seams_from_islands*", "editors/uv_image/uv_editing/unwrapping/seams.html#bpy-ops-uv-seams-from-islands"),
+	("bpy.ops.screen.repeat_history*", "interface/undo_redo.html#bpy-ops-screen-repeat-history"),
+	("bpy.ops.uv.seams_from_islands*", "editors/uv_image/uv/editing/unwrapping/seams.html#bpy-ops-uv-seams-from-islands"),
 	("bpy.types.compositornodedblur*", "compositing/types/filter/directional_blur.html#bpy-types-compositornodedblur"),
 	("bpy.types.compositornodegamma*", "compositing/types/color/gamma.html#bpy-types-compositornodegamma"),
 	("bpy.types.compositornodeglare*", "compositing/types/filter/glare.html#bpy-types-compositornodeglare"),
@@ -290,7 +301,6 @@ url_manual_mapping = (
 	("bpy.types.movietrackingcamera*", "editors/movie_clip_editor/tracking/clip/properties/camera_data.html#bpy-types-movietrackingcamera"),
 	("bpy.types.object.dupli_frames*", "editors/3dview/object/properties/duplication/dupliframes.html#bpy-types-object-dupli-frames"),
 	("bpy.types.particledupliweight*", "physics/particles/emitter/vertex_groups.html#bpy-types-particledupliweight"),
-	("bpy.types.pointdensitytexture*", "render/blender_render/textures/types/volume/point_density.html#bpy-types-pointdensitytexture"),
 	("bpy.types.poseboneconstraints*", "rigging/armatures/posing/bone_constraints/index.html#bpy-types-poseboneconstraints"),
 	("bpy.types.rigidbodyconstraint*", "physics/rigid_body/constraints/index.html#bpy-types-rigidbodyconstraint"),
 	("bpy.types.shadernodeaddshader*", "render/cycles/nodes/types/shaders/add.html#bpy-types-shadernodeaddshader"),
@@ -334,7 +344,7 @@ url_manual_mapping = (
 	("bpy.types.compositornodemath*", "compositing/types/converter/math.html#bpy-types-compositornodemath"),
 	("bpy.types.compositornodetime*", "compositing/types/input/time.html#bpy-types-compositornodetime"),
 	("bpy.types.fluidfluidsettings*", "physics/fluid/types/fluid_object.html#bpy-types-fluidfluidsettings"),
-	("bpy.types.fmodifiergenerator*", "editors/graph_editor/fcurves/fmodifiers.html#bpy-types-fmodifiergenerator"),
+	("bpy.types.fmodifiergenerator*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifiergenerator"),
 	("bpy.types.freestylelinestyle*", "render/freestyle/parameter_editor/line_style/index.html#bpy-types-freestylelinestyle"),
 	("bpy.types.gammacrosssequence*", "editors/vse/sequencer/strips/effects/cross.html#bpy-types-gammacrosssequence"),
 	("bpy.types.huecorrectmodifier*", "editors/vse/sequencer/properties/modifiers.html#bpy-types-huecorrectmodifier"),
@@ -363,11 +373,11 @@ url_manual_mapping = (
 	("bpy.ops.curve.primitive*add*", "modeling/curves/primitives.html#bpy-ops-curve-primitive-add"),
 	("bpy.ops.mesh.duplicate_move*", "modeling/meshes/editing/duplicating/duplicate.html#bpy-ops-mesh-duplicate-move"),
 	("bpy.ops.object.parent_clear*", "editors/3dview/object/properties/relations/parents.html#bpy-ops-object-parent-clear"),
-	("bpy.ops.object.shade_smooth*", "modeling/meshes/editing/smoothing.html#bpy-ops-object-shade-smooth"),
+	("bpy.ops.object.shade_smooth*", "modeling/meshes/editing/normals.html#bpy-ops-object-shade-smooth"),
 	("bpy.ops.transform.push_pull*", "modeling/meshes/editing/transform/push_pull.html#bpy-ops-transform-push-pull"),
 	("bpy.ops.transform.transform*", "editors/3dview/object/editing/transform/control/orientations.html#bpy-ops-transform-transform"),
 	("bpy.ops.transform.translate*", "editors/3dview/object/editing/transform/basics.html#bpy-ops-transform-translate"),
-	("bpy.ops.uv.minimize_stretch*", "editors/uv_image/uv_editing/layout_editing.html#bpy-ops-uv-minimize-stretch"),
+	("bpy.ops.uv.minimize_stretch*", "editors/uv_image/uv/editing/layout.html#bpy-ops-uv-minimize-stretch"),
 	("bpy.ops.view3d.select_lasso*", "editors/3dview/object/selecting/tools.html#bpy-ops-view3d-select-lasso"),
 	("bpy.types.alphaoversequence*", "editors/vse/sequencer/strips/effects/alpha_over_under_overdrop.html#bpy-types-alphaoversequence"),
 	("bpy.types.armatureeditbones*", "rigging/armatures/bones/editing/index.html#bpy-types-armatureeditbones"),
@@ -378,8 +388,8 @@ url_manual_mapping = (
 	("bpy.types.compositornodergb*", "compositing/types/input/rgb.html#bpy-types-compositornodergb"),
 	("bpy.types.compositornodesep*", "render/blender_render/textures/nodes/types/color/combine_separate.html#bpy-types-compositornodesep"),
 	("bpy.types.edgesplitmodifier*", "modeling/modifiers/generate/edge_split.html#bpy-types-edgesplitmodifier"),
-	("bpy.types.fmodifierenvelope*", "editors/graph_editor/fcurves/fmodifiers.html#bpy-types-fmodifierenvelope"),
-	("bpy.types.freestylesettings*", "render/freestyle/viewmap.html#bpy-types-freestylesettings"),
+	("bpy.types.fmodifierenvelope*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierenvelope"),
+	("bpy.types.freestylesettings*", "render/freestyle/view_map.html#bpy-types-freestylesettings"),
 	("bpy.types.material.specular*", "render/blender_render/materials/properties/specular_shaders.html#bpy-types-material-specular"),
 	("bpy.types.meshcachemodifier*", "modeling/modifiers/modify/mesh_cache.html#bpy-types-meshcachemodifier"),
 	("bpy.types.movieclipsequence*", "editors/vse/sequencer/strips/clip_mask.html#bpy-types-movieclipsequence"),
@@ -394,7 +404,7 @@ url_manual_mapping = (
 	("bpy.types.shadernodergbtobw*", "render/cycles/nodes/types/converter/rgb_to_bw.html#bpy-types-shadernodergbtobw"),
 	("bpy.types.shadernodetangent*", "render/cycles/nodes/types/input/tangent.html#bpy-types-shadernodetangent"),
 	("bpy.types.shadernodetexwave*", "render/cycles/nodes/types/textures/wave.html#bpy-types-shadernodetexwave"),
-	("bpy.types.smokecollsettings*", "physics/smoke/types/collisions.html#bpy-types-smokecollsettings"),
+	("bpy.types.smokecollsettings*", "physics/smoke/types/collision.html#bpy-types-smokecollsettings"),
 	("bpy.types.smokeflowsettings*", "physics/smoke/types/flow_object.html#bpy-types-smokeflowsettings"),
 	("bpy.types.texturenodebricks*", "render/blender_render/textures/nodes/types/patterns/bricks.html#bpy-types-texturenodebricks"),
 	("bpy.types.texturenodemixrgb*", "render/blender_render/textures/nodes/types/color/mix_rgb.html#bpy-types-texturenodemixrgb"),
@@ -404,20 +414,21 @@ url_manual_mapping = (
 	("bpy.types.uvprojectmodifier*", "modeling/modifiers/modify/uv_project.html#bpy-types-uvprojectmodifier"),
 	("bpy.types.wireframemodifier*", "modeling/modifiers/generate/wireframe.html#bpy-types-wireframemodifier"),
 	("bpy.types.worldmistsettings*", "render/blender_render/world/mist.html#bpy-types-worldmistsettings"),
-	("bpy.ops.mesh.loopcut_slide*", "modeling/meshes/editing/subdividing/loop_subdivide.html#bpy-ops-mesh-loopcut-slide"),
+	("bpy.ops.mesh.loopcut_slide*", "modeling/meshes/editing/subdividing/loop.html#bpy-ops-mesh-loopcut-slide"),
 	("bpy.ops.mesh.primitive*add*", "modeling/meshes/primitives.html#bpy-ops-mesh-primitive-add"),
 	("bpy.ops.object.join_shapes*", "animation/shape_keys/shape_keys_panel.html#bpy-ops-object-join-shapes"),
 	("bpy.ops.object.select_less*", "editors/3dview/object/selecting/tools.html#bpy-ops-object-select-less"),
 	("bpy.ops.object.select_more*", "editors/3dview/object/selecting/tools.html#bpy-ops-object-select-more"),
 	("bpy.ops.object.track_clear*", "rigging/constraints/interface/adding_removing.html#bpy-ops-object-track-clear"),
-	("bpy.ops.screen.repeat_last*", "interface/undo_and_redo.html#bpy-ops-screen-repeat-last"),
+	("bpy.ops.screen.repeat_last*", "interface/undo_redo.html#bpy-ops-screen-repeat-last"),
 	("bpy.ops.transform.tosphere*", "modeling/meshes/editing/transform/to_sphere.html#bpy-ops-transform-tosphere"),
 	("bpy.types.actionconstraint*", "rigging/constraints/relationship/action.html#bpy-types-actionconstraint"),
 	("bpy.types.addonpreferences*", "preferences/addons.html#bpy-types-addonpreferences"),
 	("bpy.types.armaturemodifier*", "modeling/modifiers/deform/armature.html#bpy-types-armaturemodifier"),
+	("bpy.types.decimatemodifier*", "modeling/modifiers/generate/decimate.html#bpy-types-decimatemodifier"),
 	("bpy.types.displacemodifier*", "modeling/modifiers/deform/displace.html#bpy-types-displacemodifier"),
 	("bpy.types.displaysafeareas*", "render/blender_render/camera/object_data.html#bpy-types-displaysafeareas"),
-	("bpy.types.fmodifierstepped*", "editors/graph_editor/fcurves/fmodifiers.html#bpy-types-fmodifierstepped"),
+	("bpy.types.fmodifierstepped*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierstepped"),
 	("bpy.types.freestylelineset*", "render/freestyle/parameter_editor/line_set.html#bpy-types-freestylelineset"),
 	("bpy.types.material.ambient*", "render/blender_render/materials/properties/shading.html#bpy-types-material-ambient"),
 	("bpy.types.material.diffuse*", "render/blender_render/materials/properties/diffuse_shaders.html#bpy-types-material-diffuse"),
@@ -436,9 +447,11 @@ url_manual_mapping = (
 	("bpy.types.shadernodescript*", "render/cycles/nodes/types/script.html#bpy-types-shadernodescript"),
 	("bpy.types.shadernodetexsky*", "render/cycles/nodes/types/textures/sky.html#bpy-types-shadernodetexsky"),
 	("bpy.types.softbodymodifier*", "physics/soft_body/index.html#bpy-types-softbodymodifier"),
+	("bpy.types.softbodysettings*", "physics/soft_body/settings.html#bpy-types-softbodysettings"),
 	("bpy.types.solidifymodifier*", "modeling/modifiers/generate/solidify.html#bpy-types-solidifymodifier"),
 	("bpy.types.spacefilebrowser*", "editors/file_browser/index.html#bpy-types-spacefilebrowser"),
 	("bpy.types.spacegrapheditor*", "editors/graph_editor/index.html#bpy-types-spacegrapheditor"),
+	("bpy.types.spaceimageeditor*", "editors/uv_image/image/index.html#bpy-types-spaceimageeditor"),
 	("bpy.types.spacelogiceditor*", "editors/logic_editor.html#bpy-types-spacelogiceditor"),
 	("bpy.types.sphfluidsettings*", "physics/fluid/index.html#bpy-types-sphfluidsettings"),
 	("bpy.types.subtractsequence*", "editors/vse/sequencer/strips/effects/subtract.html#bpy-types-subtractsequence"),
@@ -454,18 +467,18 @@ url_manual_mapping = (
 	("bpy.ops.object.parent_set*", "editors/3dview/object/properties/relations/parents.html#bpy-ops-object-parent-set"),
 	("bpy.ops.object.proxy_make*", "data_system/linked_libraries.html#bpy-ops-object-proxy-make"),
 	("bpy.ops.object.select_all*", "editors/3dview/object/selecting/tools.html#bpy-ops-object-select-all"),
-	("bpy.ops.object.shade_flat*", "modeling/meshes/editing/smoothing.html#bpy-ops-object-shade-flat"),
+	("bpy.ops.object.shade_flat*", "modeling/meshes/editing/normals.html#bpy-ops-object-shade-flat"),
 	("bpy.ops.screen.area_dupli*", "interface/window_system/areas.html#bpy-ops-screen-area-dupli"),
-	("bpy.ops.uv.remove_doubles*", "editors/uv_image/uv_editing/layout_editing.html#bpy-ops-uv-remove-doubles"),
+	("bpy.ops.uv.remove_doubles*", "editors/uv_image/uv/editing/layout.html#bpy-ops-uv-remove-doubles"),
 	("bpy.types.backgroundimage*", "editors/3dview/properties/background_images.html#bpy-types-backgroundimage"),
 	("bpy.types.booleanmodifier*", "modeling/modifiers/generate/booleans.html#bpy-types-booleanmodifier"),
 	("bpy.types.constraint.mute*", "rigging/constraints/interface/header.html#bpy-types-constraint-mute"),
 	("bpy.types.explodemodifier*", "modeling/modifiers/simulate/explode.html#bpy-types-explodemodifier"),
-	("bpy.types.fcurvemodifiers*", "editors/graph_editor/fcurves/fmodifiers.html#bpy-types-fcurvemodifiers"),
+	("bpy.types.fcurvemodifiers*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fcurvemodifiers"),
 	("bpy.types.floorconstraint*", "rigging/constraints/relationship/floor.html#bpy-types-floorconstraint"),
 	("bpy.types.fluidmeshvertex*", "physics/fluid/index.html#bpy-types-fluidmeshvertex"),
-	("bpy.types.fmodifiercycles*", "editors/graph_editor/fcurves/fmodifiers.html#bpy-types-fmodifiercycles"),
-	("bpy.types.fmodifierlimits*", "editors/graph_editor/fcurves/fmodifiers.html#bpy-types-fmodifierlimits"),
+	("bpy.types.fmodifiercycles*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifiercycles"),
+	("bpy.types.fmodifierlimits*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierlimits"),
 	("bpy.types.gpussaosettings*", "editors/3dview/properties/shading.html#bpy-types-gpussaosettings"),
 	("bpy.types.latticemodifier*", "modeling/modifiers/deform/lattice.html#bpy-types-latticemodifier"),
 	("bpy.types.musgravetexture*", "render/blender_render/textures/types/procedural/musgrave.html#bpy-types-musgravetexture"),
@@ -474,6 +487,7 @@ url_manual_mapping = (
 	("bpy.types.particlehairkey*", "physics/particles/emitter/physics/keyed.html#bpy-types-particlehairkey"),
 	("bpy.types.pivotconstraint*", "rigging/constraints/relationship/pivot.html#bpy-types-pivotconstraint"),
 	("bpy.types.rigidbodyobject*", "physics/rigid_body/index.html#bpy-types-rigidbodyobject"),
+	("bpy.types.shadernodebevel*", "render/cycles/nodes/types/input/bevel.html#bpy-types-shadernodebevel"),
 	("bpy.types.shadernodegamma*", "render/cycles/nodes/types/color/gamma.html#bpy-types-shadernodegamma"),
 	("bpy.types.shadernodegroup*", "render/cycles/nodes/types/groups.html#bpy-types-shadernodegroup"),
 	("bpy.types.shadernodeuvmap*", "render/cycles/nodes/types/input/uv_map.html#bpy-types-shadernodeuvmap"),
@@ -494,7 +508,7 @@ url_manual_mapping = (
 	("bpy.types.curvesmodifier*", "editors/vse/sequencer/properties/modifiers.html#bpy-types-curvesmodifier"),
 	("bpy.types.effectsequence*", "editors/vse/sequencer/properties/filter.html#bpy-types-effectsequence"),
 	("bpy.types.ffmpegsettings*", "render/output/video.html#bpy-types-ffmpegsettings"),
-	("bpy.types.fmodifiernoise*", "editors/graph_editor/fcurves/fmodifiers.html#bpy-types-fmodifiernoise"),
+	("bpy.types.fmodifiernoise*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifiernoise"),
 	("bpy.types.gpudofsettings*", "editors/3dview/properties/shading.html#bpy-types-gpudofsettings"),
 	("bpy.types.materialstrand*", "render/blender_render/materials/properties/strands.html#bpy-types-materialstrand"),
 	("bpy.types.materialvolume*", "render/blender_render/materials/special_effects/volume.html#bpy-types-materialvolume"),
@@ -515,12 +529,12 @@ url_manual_mapping = (
 	("bpy.types.voronoitexture*", "render/blender_render/textures/types/procedural/voronoi.html#bpy-types-voronoitexture"),
 	("bpy.types.walknavigation*", "editors/3dview/navigate/walk_fly.html#bpy-types-walknavigation"),
 	("bpy.ops.anim.keying_set*", "animation/keyframes/keying_sets.html#bpy-ops-anim-keying-set"),
-	("bpy.ops.ed.undo_history*", "interface/undo_and_redo.html#bpy-ops-ed-undo-history"),
+	("bpy.ops.ed.undo_history*", "interface/undo_redo.html#bpy-ops-ed-undo-history"),
 	("bpy.ops.gpencil.convert*", "interface/grease_pencil/convert_to_geometry.html#bpy-ops-gpencil-convert"),
 	("bpy.ops.object.armature*", "rigging/armatures/index.html#bpy-ops-object-armature"),
 	("bpy.ops.rigidbody.world*", "physics/rigid_body/world.html#bpy-ops-rigidbody-world"),
 	("bpy.ops.transform.shear*", "modeling/meshes/editing/transform/shear.html#bpy-ops-transform-shear"),
-	("bpy.ops.uv.pack_islands*", "editors/uv_image/uv_editing/layout_editing.html#bpy-ops-uv-pack-islands"),
+	("bpy.ops.uv.pack_islands*", "editors/uv_image/uv/editing/layout.html#bpy-ops-uv-pack-islands"),
 	("bpy.types.armaturebones*", "rigging/armatures/bones/index.html#bpy-types-armaturebones"),
 	("bpy.types.arraymodifier*", "modeling/modifiers/generate/array.html#bpy-types-arraymodifier"),
 	("bpy.types.bevelmodifier*", "modeling/modifiers/generate/bevel.html#bpy-types-bevelmodifier"),
@@ -534,10 +548,10 @@ url_manual_mapping = (
 	("bpy.types.fieldsettings*", "physics/force_fields/index.html#bpy-types-fieldsettings"),
 	("bpy.types.fluidsettings*", "physics/fluid/index.html#bpy-types-fluidsettings"),
 	("bpy.types.gpufxsettings*", "editors/3dview/properties/shading.html#bpy-types-gpufxsettings"),
-	("bpy.types.imagesequence*", "editors/vse/sequencer/strips/image_movie.html#bpy-types-imagesequence"),
+	("bpy.types.imagesequence*", "editors/vse/sequencer/strips/movie_image.html#bpy-types-imagesequence"),
 	("bpy.types.marbletexture*", "render/blender_render/textures/types/procedural/marble.html#bpy-types-marbletexture"),
 	("bpy.types.modifier.show*", "modeling/modifiers/introduction.html#bpy-types-modifier-show"),
-	("bpy.types.moviesequence*", "editors/vse/sequencer/strips/image_movie.html#bpy-types-moviesequence"),
+	("bpy.types.moviesequence*", "editors/vse/sequencer/strips/movie_image.html#bpy-types-moviesequence"),
 	("bpy.types.movietracking*", "editors/movie_clip_editor/tracking/index.html#bpy-types-movietracking"),
 	("bpy.types.object.layers*", "editors/3dview/object/properties/relations/layers.html#bpy-types-object-layers"),
 	("bpy.types.object.parent*", "editors/3dview/object/properties/relations/parents.html#bpy-types-object-parent"),
@@ -549,10 +563,10 @@ url_manual_mapping = (
 	("bpy.types.sequenceproxy*", "editors/vse/sequencer/properties/proxy_timecode.html#bpy-types-sequenceproxy"),
 	("bpy.types.shadernodergb*", "render/cycles/nodes/types/input/rgb.html#bpy-types-shadernodergb"),
 	("bpy.types.smokemodifier*", "physics/smoke/index.html#bpy-types-smokemodifier"),
-	("bpy.types.soundsequence*", "editors/vse/sequencer/strips/audio.html#bpy-types-soundsequence"),
+	("bpy.types.soundsequence*", "editors/vse/sequencer/strips/sound.html#bpy-types-soundsequence"),
 	("bpy.types.spaceoutliner*", "editors/outliner.html#bpy-types-spaceoutliner"),
 	("bpy.types.spacetimeline*", "editors/timeline.html#bpy-types-spacetimeline"),
-	("bpy.types.spaceuveditor*", "editors/uv_image/uv_editing/index.html#bpy-types-spaceuveditor"),
+	("bpy.types.spaceuveditor*", "editors/uv_image/uv/index.html#bpy-types-spaceuveditor"),
 	("bpy.types.stuccitexture*", "render/blender_render/textures/types/procedural/stucci.html#bpy-types-stuccitexture"),
 	("bpy.types.windowmanager*", "interface/index.html#bpy-types-windowmanager"),
 	("bpy.types.worldlighting*", "render/blender_render/world/ambient_occlusion.html#bpy-types-worldlighting"),
@@ -613,8 +627,8 @@ url_manual_mapping = (
 	("bpy.ops.object.align*", "editors/3dview/object/editing/transform/tools.html#bpy-ops-object-align"),
 	("bpy.ops.object.empty*", "modeling/empties.html#bpy-ops-object-empty"),
 	("bpy.ops.object.quick*", "physics/introduction.html#bpy-ops-object-quick"),
-	("bpy.ops.uv.mark_seam*", "editors/uv_image/uv_editing/unwrapping/seams.html#bpy-ops-uv-mark-seam"),
-	("bpy.ops.view3d.ruler*", "interface/ruler_and_protractor.html#bpy-ops-view3d-ruler"),
+	("bpy.ops.uv.mark_seam*", "editors/uv_image/uv/editing/unwrapping/seams.html#bpy-ops-uv-mark-seam"),
+	("bpy.ops.view3d.ruler*", "interface/ruler_protractor.html#bpy-ops-view3d-ruler"),
 	("bpy.types.areaspaces*", "interface/window_system/areas.html#bpy-types-areaspaces"),
 	("bpy.types.bpy_struct*", "data_system/custom_properties.html#bpy-types-bpy-struct"),
 	("bpy.types.compositor*", "compositing/index.html#bpy-types-compositor"),
@@ -629,10 +643,11 @@ url_manual_mapping = (
 	("bpy.ops.object.join*", "editors/3dview/object/editing/introduction.html#bpy-ops-object-join"),
 	("bpy.ops.object.text*", "modeling/texts/index.html#bpy-ops-object-text"),
 	("bpy.ops.view3d.snap*", "editors/3dview/object/editing/transform/control/snap.html#bpy-ops-view3d-snap"),
+	("bpy.ops.view3d.view*", "editors/3dview/navigate/introduction.html#bpy-ops-view3d-view"),
 	("bpy.types.blenddata*", "data_system/data_blocks.html#bpy-types-blenddata"),
 	("bpy.types.colorramp*", "interface/controls/templates/color_ramp.html#bpy-types-colorramp"),
 	("bpy.types.dopesheet*", "editors/dope_sheet/index.html#bpy-types-dopesheet"),
-	("bpy.types.fmodifier*", "editors/graph_editor/fcurves/fmodifiers.html#bpy-types-fmodifier"),
+	("bpy.types.fmodifier*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifier"),
 	("bpy.types.freestyle*", "render/freestyle/index.html#bpy-types-freestyle"),
 	("bpy.types.movieclip*", "editors/movie_clip_editor/index.html#bpy-types-movieclip"),
 	("bpy.types.nodeframe*", "editors/node_editor/nodes/frame.html#bpy-types-nodeframe"),
@@ -643,7 +658,7 @@ url_manual_mapping = (
 	("bpy.types.uipiemenu*", "interface/controls/buttons/menus.html#bpy-types-uipiemenu"),
 	("bpy.ops.constraint*", "rigging/constraints/index.html#bpy-ops-constraint"),
 	("bpy.ops.curve.draw*", "modeling/curves/editing/draw.html#bpy-ops-curve-draw"),
-	("bpy.ops.mesh.knife*", "modeling/meshes/editing/subdividing/knife_subdivide.html#bpy-ops-mesh-knife"),
+	("bpy.ops.mesh.knife*", "modeling/meshes/editing/subdividing/knife.html#bpy-ops-mesh-knife"),
 	("bpy.ops.mesh.noise*", "modeling/meshes/editing/transform/noise.html#bpy-ops-mesh-noise"),
 	("bpy.ops.mesh.screw*", "modeling/meshes/editing/duplicating/screw.html#bpy-ops-mesh-screw"),
 	("bpy.ops.safe_areas*", "render/blender_render/camera/object_data.html#bpy-ops-safe-areas"),
@@ -669,8 +684,8 @@ url_manual_mapping = (
 	("bpy.ops.rigidbody*", "physics/rigid_body/index.html#bpy-ops-rigidbody"),
 	("bpy.ops.sequencer*", "editors/vse/index.html#bpy-ops-sequencer"),
 	("bpy.ops.transform*", "editors/3dview/object/editing/transform/index.html#bpy-ops-transform"),
-	("bpy.ops.uv.stitch*", "editors/uv_image/uv_editing/layout_editing.html#bpy-ops-uv-stitch"),
-	("bpy.ops.uv.unwrap*", "editors/uv_image/uv_editing/unwrapping/mapping_types.html#bpy-ops-uv-unwrap"),
+	("bpy.ops.uv.stitch*", "editors/uv_image/uv/editing/layout.html#bpy-ops-uv-stitch"),
+	("bpy.ops.uv.unwrap*", "editors/uv_image/uv/editing/unwrapping/mapping_types.html#bpy-ops-uv-unwrap"),
 	("bpy.types.animviz*", "animation/motion_paths.html#bpy-types-animviz"),
 	("bpy.types.lattice*", "rigging/lattice.html#bpy-types-lattice"),
 	("bpy.types.library*", "data_system/linked_libraries.html#bpy-types-library"),
@@ -683,7 +698,7 @@ url_manual_mapping = (
 	("bpy.ops.nla.bake*", "animation/actions.html#bpy-ops-nla-bake"),
 	("bpy.ops.outliner*", "editors/outliner.html#bpy-ops-outliner"),
 	("bpy.ops.particle*", "physics/particles/index.html#bpy-ops-particle"),
-	("bpy.ops.uv.align*", "editors/uv_image/uv_editing/layout_editing.html#bpy-ops-uv-align"),
+	("bpy.ops.uv.align*", "editors/uv_image/uv/editing/layout.html#bpy-ops-uv-align"),
 	("bpy.ops.wm.addon*", "preferences/addons.html#bpy-ops-wm-addon"),
 	("bpy.types.action*", "animation/actions.html#bpy-types-action"),
 	("bpy.types.camera*", "render/blender_render/camera/index.html#bpy-types-camera"),
@@ -700,15 +715,15 @@ url_manual_mapping = (
 	("bpy.types.window*", "interface/index.html#bpy-types-window"),
 	("bpy.ops.buttons*", "interface/index.html#bpy-ops-buttons"),
 	("bpy.ops.console*", "editors/python_console.html#bpy-ops-console"),
-	("bpy.ops.ed.redo*", "interface/undo_and_redo.html#bpy-ops-ed-redo"),
-	("bpy.ops.ed.undo*", "interface/undo_and_redo.html#bpy-ops-ed-undo"),
+	("bpy.ops.ed.redo*", "interface/undo_redo.html#bpy-ops-ed-redo"),
+	("bpy.ops.ed.undo*", "interface/undo_redo.html#bpy-ops-ed-undo"),
 	("bpy.ops.gpencil*", "interface/grease_pencil/index.html#bpy-ops-gpencil"),
 	("bpy.ops.lattice*", "rigging/lattice.html#bpy-ops-lattice"),
 	("bpy.ops.poselib*", "rigging/armatures/properties/pose_library.html#bpy-ops-poselib"),
 	("bpy.ops.ptcache*", "physics/baking.html#bpy-ops-ptcache"),
 	("bpy.ops.surface*", "modeling/surfaces/index.html#bpy-ops-surface"),
 	("bpy.ops.texture*", "render/blender_render/textures/index.html#bpy-ops-texture"),
-	("bpy.ops.uv.weld*", "editors/uv_image/uv_editing/layout_editing.html#bpy-ops-uv-weld"),
+	("bpy.ops.uv.weld*", "editors/uv_image/uv/editing/layout.html#bpy-ops-uv-weld"),
 	("bpy.types.addon*", "preferences/addons.html#bpy-types-addon"),
 	("bpy.types.brush*", "sculpt_paint/brush.html#bpy-types-brush"),
 	("bpy.types.curve*", "modeling/curves/index.html#bpy-types-curve"),
@@ -733,8 +748,8 @@ url_manual_mapping = (
 	("bpy.ops.screen*", "interface/window_system/screens.html#bpy-ops-screen"),
 	("bpy.ops.script*", "advanced/scripting/index.html#bpy-ops-script"),
 	("bpy.ops.sculpt*", "sculpt_paint/sculpting/index.html#bpy-ops-sculpt"),
-	("bpy.ops.sketch*", "rigging/armatures/bones/editing/sketching.html#bpy-ops-sketch"),
-	("bpy.ops.uv.pin*", "editors/uv_image/uv_editing/layout_editing.html#bpy-ops-uv-pin"),
+	("bpy.ops.sketch*", "rigging/armatures/bones/editing/sketching/index.html#bpy-ops-sketch"),
+	("bpy.ops.uv.pin*", "editors/uv_image/uv/editing/layout.html#bpy-ops-uv-pin"),
 	("bpy.ops.view3d*", "editors/3dview/index.html#bpy-ops-view3d"),
 	("bpy.types.area*", "interface/window_system/areas.html#bpy-types-area"),
 	("bpy.types.boid*", "physics/particles/emitter/physics/boids.html#bpy-types-boid"),
@@ -773,9 +788,9 @@ url_manual_mapping = (
 	("bpy.ops.time*", "editors/timeline.html#bpy-ops-time"),
 	("bpy.types.id*", "data_system/data_blocks.html#bpy-types-id"),
 	("bpy.ops.nla*", "editors/nla/index.html#bpy-ops-nla"),
-	("bpy.ops.ed*", "interface/undo_and_redo.html#bpy-ops-ed"),
+	("bpy.ops.ed*", "interface/undo_redo.html#bpy-ops-ed"),
 	("bpy.ops.ui*", "interface/index.html#bpy-ops-ui"),
-	("bpy.ops.uv*", "editors/uv_image/uv_editing/index.html#bpy-ops-uv"),
+	("bpy.ops.uv*", "editors/uv_image/uv/index.html#bpy-ops-uv"),
 	("bpy.ops.wm*", "interface/index.html#bpy-ops-wm"),
 	("bpy.types*", "index.html#bpy-types"),
 	("bpy.ops*", "index.html#bpy-ops"),
diff --git a/netrender/__init__.py b/netrender/__init__.py
index 4186f8b94f52b56d5cf68ffc705a77ce4b2502d7..aae33c1133ad365f724802f10dc9b659bb57aa52 100644
--- a/netrender/__init__.py
+++ b/netrender/__init__.py
@@ -21,13 +21,13 @@
 bl_info = {
     "name": "Network Renderer",
     "author": "Martin Poirier",
-    "version": (1, 8),
+    "version": (1, 8, 1),
     "blender": (2, 60, 0),
     "location": "Render > Engine > Network Render",
     "description": "Distributed rendering for Blender",
     "warning": "Stable but still work in progress",
-    "wiki_url": "http://wiki.blender.org/index.php/Doc:2.5/Manual/"
-                "Render/Engines/Netrender",
+    "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
+                "Scripts/Render/Net_render",
     "category": "Render",
 }
 
diff --git a/node_wrangler.py b/node_wrangler.py
index 9b225af1dab6adc6ff40b0e2627e0198cf5db122..24e096c8ce901449c980988f5fb58aeba2dd0cb1 100644
--- a/node_wrangler.py
+++ b/node_wrangler.py
@@ -3161,7 +3161,7 @@ class NWSelectParentChildren(Operator, NWBase):
 
 
 class NWDetachOutputs(Operator, NWBase):
-    """Detach outputs of selected node leaving inluts liked"""
+    """Detach outputs of selected node leaving inputs linked"""
     bl_idname = "node.nw_detach_outputs"
     bl_label = "Detach Outputs"
     bl_options = {'REGISTER', 'UNDO'}
diff --git a/object_boolean_tools.py b/object_boolean_tools.py
index 3c5b104bdce04b0c206e9b63b7623731dd79fbce..df082abca2b87f24732b3a047384e6f083686f7f 100644
--- a/object_boolean_tools.py
+++ b/object_boolean_tools.py
@@ -21,8 +21,8 @@
 bl_info = {
     "name": "Bool Tool",
     "author": "Vitor Balbio, Mikhail Rachinskiy, TynkaTopi, Meta-Androcto",
-    "version": (0, 3, 8),
-    "blender": (2, 78, 0),
+    "version": (0, 3, 9),
+    "blender": (2, 79, 2),
     "location": "View3D > Toolshelf",
     "description": "Bool Tool Hotkey: Ctrl Shift B",
     "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
@@ -143,7 +143,6 @@ def Operation(context, _operation):
 
     prefs = bpy.context.user_preferences.addons[__name__].preferences
     useWire = prefs.use_wire
-    solver = prefs.solver
 
     for selObj in bpy.context.selected_objects:
         if selObj != context.active_object and (selObj.type == "MESH" or selObj.type == "CURVE"):
@@ -180,7 +179,6 @@ def Operation(context, _operation):
                 clone["BoolToolRoot"] = True
             newMod = actObj.modifiers.new("BTool_" + selObj.name, "BOOLEAN")
             newMod.object = selObj
-            newMod.solver = solver
             if _operation == "SLICE":
                 newMod.operation = "INTERSECT"
             else:
@@ -615,19 +613,6 @@ class BTool_Slice(Operator):
 
 class Auto_Boolean:
 
-    solver = EnumProperty(
-            name="Boolean Solver",
-            description="Specify solver for boolean operation",
-            items=(('BMESH', "BMesh", "BMesh solver is faster, but less stable "
-                                      "and cannot handle coplanar geometry"),
-                   ('CARVE', "Carve", "Carve solver is slower, but more stable "
-                                      "and can handle simple cases of coplanar geometry")),
-            options={'SKIP_SAVE'},
-            )
-
-    def __init__(self):
-        self.solver = bpy.context.user_preferences.addons[__name__].preferences.solver
-
     def objects_prepare(self):
         for ob in bpy.context.selected_objects:
             if ob.type != 'MESH':
@@ -663,7 +648,6 @@ class Auto_Boolean:
         md = obj.modifiers.new("Auto Boolean", 'BOOLEAN')
         md.show_viewport = False
         md.operation = mode
-        md.solver = self.solver
         md.object = ob
 
         bpy.ops.object.modifier_apply(modifier="Auto Boolean")
@@ -1288,15 +1272,6 @@ class PREFS_BoolTool_Props(AddonPreferences):
             default="Tools",
             update=update_panels,
             )
-    solver = EnumProperty(
-            name="Boolean Solver",
-            items=(('BMESH', "BMesh", "BMesh solver is faster, but less stable "
-                                      "and cannot handle coplanar geometry"),
-                   ('CARVE', "Carve", "Carve solver is slower, but more stable "
-                                      "and can handle simple cases of coplanar geometry")),
-            default='BMESH',
-            description="Specify solver for boolean operations",
-            )
     Enable_Tab_01 = BoolProperty(
             default=False
             )
@@ -1309,29 +1284,23 @@ class PREFS_BoolTool_Props(AddonPreferences):
         col = split.column()
         col.label(text="Tab Category:")
         col = split.column()
-        colrow = col.row()
-        colrow.prop(self, "category", text="")
-
-        split = layout.split(percentage=split_percent)
-        col = split.column()
-        col.label("Boolean Solver:")
-        col = split.column()
-        colrow = col.row()
-        colrow.prop(self, "solver", expand=True)
+        col.prop(self, "category", text="")
 
         split = layout.split(percentage=split_percent)
         col = split.column()
         col.label("Experimental Features:")
         col = split.column()
-        colrow = col.row(align=True)
-        colrow.prop(self, "fast_transform", toggle=True)
-        colrow.prop(self, "use_wire", text="Use Wire Instead Of Bbox", toggle=True)
+        col.prop(self, "fast_transform")
+        col.prop(self, "use_wire", text="Use Wire Instead Of Bbox")
+
         layout.separator()
+
         """
         # EXPERIMENTAL
         col.prop(self, "make_vertex_groups")
         col.prop(self, "make_boundary")
         """
+
         layout.prop(self, "Enable_Tab_01", text="Hot Keys", icon="KEYINGSET")
         if self.Enable_Tab_01:
             row = layout.row()
diff --git a/object_print3d_utils/mesh_helpers.py b/object_print3d_utils/mesh_helpers.py
index ca6e07168e5f08e4548d72709c8a83d2ceeba186..e1386b84b5aac7fae8ae39d9110b90b14688e667 100644
--- a/object_print3d_utils/mesh_helpers.py
+++ b/object_print3d_utils/mesh_helpers.py
@@ -279,3 +279,19 @@ def object_merge(context, objects):
 
     # return new object
     return base_base
+
+
+def face_is_distorted(ele, angle_distort):
+    no = ele.normal
+    angle_fn = no.angle
+ 
+    for loop in ele.loops:
+        loopno = loop.calc_normal()
+
+        if loopno.dot(no) < 0.0:
+            loopno.negate()
+
+        if angle_fn(loopno, 1000.0) > angle_distort:
+            return True
+ 
+    return False
diff --git a/object_print3d_utils/operators.py b/object_print3d_utils/operators.py
index 8dcdf2110ea9cab87a7c91ba5ee60d038f8e760e..be8c323e801dfeb13347fa035692410a60d15fd9 100644
--- a/object_print3d_utils/operators.py
+++ b/object_print3d_utils/operators.py
@@ -20,6 +20,8 @@
 
 # All Operator
 
+import array
+
 import bpy
 from bpy.types import Operator
 from bpy.props import (
@@ -129,8 +131,6 @@ class MESH_OT_Print3D_Check_Solid(Operator):
 
     @staticmethod
     def main_check(obj, info):
-        import array
-
         bm = mesh_helpers.bmesh_copy_from_object(obj, transform=False, triangulate=False)
 
         edges_non_manifold = array.array('i', (i for i, ele in enumerate(bm.edges)
@@ -173,7 +173,6 @@ class MESH_OT_Print3D_Check_Degenerate(Operator):
 
     @staticmethod
     def main_check(obj, info):
-        import array
         scene = bpy.context.scene
         print_3d = scene.print_3d
         threshold = print_3d.threshold_zero
@@ -202,27 +201,17 @@ class MESH_OT_Print3D_Check_Distorted(Operator):
 
     @staticmethod
     def main_check(obj, info):
-        import array
-
         scene = bpy.context.scene
         print_3d = scene.print_3d
         angle_distort = print_3d.angle_distort
 
-        def face_is_distorted(ele):
-            no = ele.normal
-            angle_fn = no.angle
-            for loop in ele.loops:
-                loopno = loop.calc_normal()
-                if loopno.dot(no) < 0.0:
-                    loopno.negate()
-                if angle_fn(loopno, 1000.0) > angle_distort:
-                    return True
-            return False
-
         bm = mesh_helpers.bmesh_copy_from_object(obj, transform=True, triangulate=False)
         bm.normal_update()
 
-        faces_distort = array.array('i', (i for i, ele in enumerate(bm.faces) if face_is_distorted(ele)))
+        faces_distort = array.array(
+                'i',
+                (i for i, ele in enumerate(bm.faces) if mesh_helpers.face_is_distorted(ele, angle_distort))
+                )
 
         info.append(("Non-Flat Faces: %d" % len(faces_distort),
                     (bmesh.types.BMFace, faces_distort)))
@@ -418,20 +407,11 @@ class MESH_OT_Print3D_Clean_Distorted(Operator):
         print_3d = scene.print_3d
         angle_distort = print_3d.angle_distort
 
-        def face_is_distorted(ele):
-            no = ele.normal
-            angle_fn = no.angle
-            for loop in ele.loops:
-                if angle_fn(loop.calc_normal(), 1000.0) > angle_distort:
-                    return True
-            return False
-
         obj = context.active_object
         bm = mesh_helpers.bmesh_from_object(obj)
         bm.normal_update()
-        elems_triangulate = [ele for ele in bm.faces if face_is_distorted(ele)]
+        elems_triangulate = [ele for ele in bm.faces if mesh_helpers.face_is_distorted(ele, angle_distort)]
 
-        # edit
         if elems_triangulate:
             bmesh.ops.triangulate(bm, faces=elems_triangulate)
             mesh_helpers.bmesh_to_object(obj, bm)
diff --git a/oscurart_tools/__init__.py b/oscurart_tools/__init__.py
index 8affc8bbf61ed2905ad2ddb91349cf2bd28d7db4..d0f54c24d334a9b864281f39470f4f47ac78a9e7 100644
--- a/oscurart_tools/__init__.py
+++ b/oscurart_tools/__init__.py
@@ -196,6 +196,8 @@ class OscPanelMesh(Panel):
         colrow = col.row(align=1)
         colrow.operator("mesh.reconst_osc", icon="UV_SYNC_SELECT")
         colrow = col.row(align=1)
+        colrow.operator("mesh.vertex_color_mask", icon="GROUP_VCOL")        
+        colrow = col.row(align=1)
         colrow.operator("mesh.overlap_uv_faces", icon="UV_FACESEL")
         colrow = col.row(align=1)
         colrow.operator("mesh.uv_island_copy", icon="COPYDOWN")
@@ -210,6 +212,7 @@ class OscPanelMesh(Panel):
         colrow = col.row(align=1)
         colrow.operator("mesh.create_edit_multimesh", icon="IMPORT", text= "StartEdit")
         colrow.operator("mesh.apply_edit_multimesh", icon="EXPORT", text="FinishEdit")
+        
 
 class OscPanelShapes(Panel):
     bl_idname = "Oscurart Shapes Tools"
diff --git a/oscurart_tools/oscurart_meshes.py b/oscurart_tools/oscurart_meshes.py
index ea899d5329c0bac108110b5081c988c94c7b5d6a..3282c66a248143d733ee268ae59ee104f98ee454 100644
--- a/oscurart_tools/oscurart_meshes.py
+++ b/oscurart_tools/oscurart_meshes.py
@@ -19,6 +19,7 @@
 # <pep8 compliant>
 
 import bpy
+from mathutils import Vector
 from bpy.types import Operator
 from bpy.props import (
         IntProperty,
@@ -31,6 +32,7 @@ import bmesh
 import time
 import blf
 from bpy_extras.view3d_utils import location_3d_to_region_2d
+from random import uniform
 
 C = bpy.context
 D = bpy.data
@@ -152,7 +154,7 @@ class SelectMenor(Operator):
 # -------------------------RESYM VG----------------------------------
 
 
-class resymVertexGroups(Operator):
+class rvg(Operator):
     bl_idname = "mesh.resym_vertex_weights_osc"
     bl_label = "Resym Vertex Weights"
     bl_description = ("Copies the symetrical weight value of the vertices on the X axys\n"
@@ -580,12 +582,12 @@ def defCopyUvsIsland(self, context):
 
     bpy.ops.object.mode_set(mode="EDIT")        
     
-def defPasteUvsIsland(self, context):
+def defPasteUvsIsland(self, uvOffset, rotateUv,context):
     bpy.ops.object.mode_set(mode="OBJECT")
     selPolys = [poly.index for poly in bpy.context.object.data.polygons if poly.select]
-
+        
     for island in selPolys:
-        bpy.ops.object.mode_set(mode="EDIT")
+        bpy.ops.object.mode_set(mode="EDIT")      
         bpy.ops.mesh.select_all(action="DESELECT")        
         bpy.ops.object.mode_set(mode="OBJECT")  
         bpy.context.object.data.polygons[island].select = True
@@ -601,10 +603,20 @@ def defPasteUvsIsland(self, context):
                     TobLoop.append(li)    
 
         for source,target in zip(range(min(obLoop),max(obLoop)+1),range(min(TobLoop),max(TobLoop)+1)):
-            bpy.context.object.data.uv_layers.active.data[target].uv = bpy.context.object.data.uv_layers.active.data[source].uv
-   
+            bpy.context.object.data.uv_layers.active.data[target].uv = bpy.context.object.data.uv_layers.active.data[source].uv + Vector((uvOffset,0))
+              
         bpy.ops.object.mode_set(mode="EDIT")   
         
+    if rotateUv:
+        bpy.ops.object.mode_set(mode="OBJECT") 
+        for poly in selPolys:
+            bpy.context.object.data.polygons[poly].select = True
+        bpy.ops.object.mode_set(mode="EDIT")
+        bm = bmesh.from_edit_mesh(bpy.context.object.data)
+        bmesh.ops.reverse_uvs(bm, faces=[f for f in bm.faces if f.select])
+        bmesh.ops.rotate_uvs(bm, faces=[f for f in bm.faces if f.select]) 
+        #bmesh.update_edit_mesh(bpy.context.object.data, tessface=False, destructive=False)
+
 
 
 class CopyUvIsland(Operator):
@@ -628,7 +640,16 @@ class PasteUvIsland(Operator):
     bl_idname = "mesh.uv_island_paste"
     bl_label = "Paste Uv Island"
     bl_options = {"REGISTER", "UNDO"}
+    
+    uvOffset = BoolProperty(
+            name="Uv Offset",
+            default=False
+            )    
 
+    rotateUv = BoolProperty(
+            name="Rotate Uv Corner",
+            default=False
+            )  
     @classmethod
     def poll(cls, context):
         return (context.active_object is not None and
@@ -636,7 +657,7 @@ class PasteUvIsland(Operator):
                 context.active_object.mode == "EDIT")
 
     def execute(self, context):
-        defPasteUvsIsland(self, context)
+        defPasteUvsIsland(self, self.uvOffset, self.rotateUv, context)
         return {'FINISHED'}    
     
     
@@ -694,4 +715,53 @@ class ApplyEditMultimesh(Operator):
         bpy.context.scene.objects.unlink(ob) 
         return {'FINISHED'} 
         
-           
\ No newline at end of file
+# -------------------------VERTEX COLOR MASK----------------------------------
+
+
+class resymVertexGroups(Operator):
+    bl_idname = "mesh.vertex_color_mask"
+    bl_label = "Vertex Color Mask"
+    bl_description = ("Create a Vertex Color Mask")
+    bl_options = {"REGISTER", "UNDO"}
+
+    @classmethod
+    def poll(cls, context):
+        obj = context.active_object
+        return obj is not None
+
+    def execute(self, context):
+        obj = bpy.context.active_object
+        mesh= obj.data
+
+        bpy.ops.object.mode_set(mode='EDIT', toggle=False) 
+        bpy.ops.mesh.select_all(action="DESELECT") 
+
+        bm = bmesh.from_edit_mesh(mesh) 
+        bm.faces.ensure_lookup_table()
+
+        islands = []
+        faces = bm.faces
+
+        try:
+            color_layer = bm.loops.layers.color["RGBMask"]
+        except:    
+            color_layer = bm.loops.layers.color.new("RGBMask")
+
+        while faces:
+            faces[0].select_set(True) 
+            bpy.ops.mesh.select_linked() 
+            islands.append([f for f in faces if f.select])
+            bpy.ops.mesh.hide(unselected=False) 
+            faces = [f for f in bm.faces if not f.hide] 
+
+        bpy.ops.mesh.reveal()
+
+        for island in islands:
+            color = (uniform(0,1),uniform(0,1),uniform(0,1),1) 
+            for face in island:
+                for loop in face.loops:
+                    loop[color_layer] = color    
+            
+        bpy.ops.object.mode_set(mode="VERTEX_PAINT")
+
+        return {'FINISHED'}           
\ No newline at end of file
diff --git a/oscurart_tools/oscurart_render.py b/oscurart_tools/oscurart_render.py
index e65b06bf351ebb070b12b6d152ca311470eba1af..a758fae1e612fea50ea5318b8897f598ad4c8330 100644
--- a/oscurart_tools/oscurart_render.py
+++ b/oscurart_tools/oscurart_render.py
@@ -70,12 +70,21 @@ def defRenderAll(frametype, scenes):
                 for i in scene.render.layers:
                     i.use = False
                 layer.use = 1
+                
                 print("SCENE: %s" % scene.name)
                 print("LAYER: %s" % layer.name)
                 print("OVERRIDE: %s" % str(proptolist))
-                scene.render.filepath = os.path.join(
-                    os.path.dirname(renpath), filename, scene.name, layer.name, "%s_%s_%s" %
-                    (filename, scene.name, 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))
+                tokens = {
+                    "$Scene":scene.name,
+                    "$File":os.path.basename(bpy.data.filepath).split(".")[0],
+                    "$Layer":layer.name,
+                    "$Camera":scene.camera.name}
+
+                scene.render.filepath = renpath.replace("$Scene",tokens["$Scene"]).replace("$File",tokens["$File"]).replace("$Layer",tokens["$Layer"]).replace("$Camera",tokens["$Camera"])
+                
                 bpy.context.window.screen.scene = scene
                 bpy.ops.render.render(
                     animation=True,
@@ -209,7 +218,15 @@ def defoscBatchMaker(TYPE, BIN):
     SHFILE = os.path.join(
         bpy.data.filepath.rpartition(SYSBAR)[0],
         FILENAME + EXTSYS)
-
+        
+    renpath = bpy.context.scene.render.filepath    
+    tokens = {
+        "$Scene":bpy.context.scene.name,
+        "$File":os.path.basename(bpy.data.filepath).split(".")[0],
+        "$Layer":bpy.context.scene.render.layers.active.name,
+        "$Camera":bpy.context.scene.camera.name}
+
+    rfp = bpy.context.scene.render.filepath.replace("$Scene",tokens["$Scene"]).replace("$File",tokens["$File"]).replace("$Layer",tokens["$Layer"]).replace("$Camera",tokens["$Camera"])        
     with open(SHFILE, "w") as FILE:
         # assign permission in linux
         if EXTSYS == ".sh":
@@ -219,13 +236,13 @@ def defoscBatchMaker(TYPE, BIN):
                 print(
                     "** Oscurart Batch maker can not modify the permissions.")
         if not BIN:
-            FILE.writelines("%s%s%s -b %s -x 1 -o %s -P %s%s.py  -s %s -e %s -a" %
-                            (QUOTES, BINDIR, QUOTES, bpy.data.filepath, bpy.context.scene.render.filepath,
+            FILE.writelines("%s%s%s -b %s -x 1  -P %s%s.py  -s %s -e %s " %
+                            (QUOTES, BINDIR, QUOTES, bpy.data.filepath,
                              bpy.data.filepath.rpartition(SYSBAR)[0] + SYSBAR, TYPE,
                              str(bpy.context.scene.frame_start), str(bpy.context.scene.frame_end)))
         else:
-            FILE.writelines("%s -b %s -x 1 -o %s -P %s%s.py  -s %s -e %s -a" %
-                            ("blender", bpy.data.filepath, bpy.context.scene.render.filepath,
+            FILE.writelines("%s -b %s -x 1  -P %s%s.py  -s %s -e %s " %
+                            ("blender", bpy.data.filepath,
                              bpy.data.filepath.rpartition(SYSBAR)[0] + SYSBAR, TYPE,
                              str(bpy.context.scene.frame_start), str(bpy.context.scene.frame_end)))
 
diff --git a/paint_palette.py b/paint_palette.py
index 7597fde1af071bb6f701b8ed2a17b80d75a8c808..577b292bf08fa26581e04421edbf3d2d198c5628 100644
--- a/paint_palette.py
+++ b/paint_palette.py
@@ -22,7 +22,7 @@
 bl_info = {
     "name": "Paint Palettes",
     "author": "Dany Lebel (Axon D)",
-    "version": (0, 9, 3),
+    "version": (0, 9, 4),
     "blender": (2, 63, 0),
     "location": "Image Editor and 3D View > Any Paint mode > Color Palette or Weight Palette panel",
     "description": "Palettes for color and weight paint modes",
@@ -44,20 +44,20 @@ with the brush by using the button under the color.
 
 import bpy
 from bpy.types import (
-        Operator,
-        Menu,
-        Panel,
-        PropertyGroup,
-        )
+    Operator,
+    Menu,
+    Panel,
+    PropertyGroup,
+)
 from bpy.props import (
-        BoolProperty,
-        FloatProperty,
-        FloatVectorProperty,
-        IntProperty,
-        StringProperty,
-        PointerProperty,
-        CollectionProperty,
-        )
+    BoolProperty,
+    FloatProperty,
+    FloatVectorProperty,
+    IntProperty,
+    StringProperty,
+    PointerProperty,
+    CollectionProperty,
+)
 
 
 def update_panels():
@@ -97,6 +97,14 @@ def update_weight_value():
     return None
 
 
+def check_path_return():
+    from os.path import normpath
+    preset_path = bpy.path.abspath(bpy.context.scene.palette_props.presets_folder)
+    paths = normpath(preset_path)
+
+    return paths if paths else ""
+
+
 class PALETTE_MT_menu(Menu):
     bl_label = "Presets"
     preset_subdir = ""
@@ -109,61 +117,62 @@ class PALETTE_MT_menu(Menu):
         import bpy.utils
 
         layout = self.layout
+
+        if bpy.data.filepath == "":
+            layout.label("*Please save the .blend file first*")
+            return
+
         if not searchpaths[0]:
             layout.label("* Missing Paths *")
+            return
 
         # collect paths
-        else:
-            files = []
-            for directory in searchpaths:
-                files.extend([(f, os.path.join(directory, f)) for f in os.listdir(directory)])
+        files = []
+        for directory in searchpaths:
+            files.extend([(f, os.path.join(directory, f)) for f in os.listdir(directory)])
 
-            files.sort()
+        files.sort()
 
-            for f, filepath in files:
+        for f, filepath in files:
 
-                if f.startswith("."):
-                    continue
-                # do not load everything from the given folder, only .gpl files
-                if f[-4:] != ".gpl":
-                    continue
+            if f.startswith("."):
+                continue
+            # do not load everything from the given folder, only .gpl files
+            if f[-4:] != ".gpl":
+                continue
 
-                preset_name = bpy.path.display_name(f)
-                props = layout.operator(operator, text=preset_name)
+            preset_name = bpy.path.display_name(f)
+            props = layout.operator(operator, text=preset_name)
 
-                for attr, value in props_default.items():
-                    setattr(props, attr, value)
+            for attr, value in props_default.items():
+                setattr(props, attr, value)
 
-                props.filepath = filepath
-                if operator == "palette.load_gimp_palette":
-                    props.menu_idname = self.bl_idname
+            props.filepath = filepath
+            if operator == "palette.load_gimp_palette":
+                props.menu_idname = self.bl_idname
 
     def draw_preset(self, context):
-        """Define these on the subclass
-         - preset_operator
-         - preset_subdir
-        """
-        import bpy
-        self.path_menu([bpy.context.scene.palette_props.presets_folder], self.preset_operator)
+        paths = check_path_return()
+        self.path_menu([paths], self.preset_operator)
 
     draw = draw_preset
 
 
-class LoadGimpPalette(Operator):
+class PALETTE_OT_load_gimp_palette(Operator):
     """Execute a preset"""
     bl_idname = "palette.load_gimp_palette"
     bl_label = "Load a Gimp palette"
 
     filepath = StringProperty(
-            name="Path",
-            description="Path of the .gpl file to load",
-            default=""
-            )
+        name="Path",
+        description="Path of the .gpl file to load",
+        default=""
+    )
     menu_idname = StringProperty(
-            name="Menu ID Name",
-            description="ID name of the menu this was called from",
-            default=""
-            )
+        name="Menu ID Name",
+        description="ID name of the menu this was called from",
+        default=""
+    )
 
     def execute(self, context):
         from os.path import basename
@@ -255,14 +264,16 @@ class WriteGimpPalette():
     bl_options = {'REGISTER'}  # only because invoke_props_popup requires
 
     name = StringProperty(
-                name="Name",
-                description="Name of the preset, used to make the path name",
-                maxlen=64, default=""
-                )
+        name="Name",
+        description="Name of the preset, used to make the path name",
+        maxlen=64,
+        options={'SKIP_SAVE'},
+        default=""
+    )
     remove_active = BoolProperty(
-                default=False,
-                options={'HIDDEN'}
-                )
+        default=False,
+        options={'HIDDEN'}
+    )
 
     @staticmethod
     def as_filename(name):  # could reuse for other presets
@@ -278,26 +289,25 @@ class WriteGimpPalette():
             self.pre_cb(context)
 
         preset_menu_class = getattr(bpy.types, self.preset_menu)
+        target_path = check_path_return()
 
-        if not self.remove_active:
+        if not target_path:
+            self.report({'WARNING'}, "Failed to create presets path")
+            return {'CANCELLED'}
+
+        if not os.path.exists(target_path):
+            self.report({'WARNING'},
+                        "Failure to open the saved Palettes Folder. Check if the path exists")
+            return {'CANCELLED'}
 
+        if not self.remove_active:
             if not self.name:
+                self.report({'INFO'},
+                            "No name is given for the preset entry. Operation Cancelled")
                 return {'FINISHED'}
 
             filename = self.as_filename(self.name)
-            target_path = pp.presets_folder
-
-            if not target_path:
-                self.report({'WARNING'}, "Failed to create presets path")
-                return {'CANCELLED'}
-
-            if not os.path.exists(target_path):
-                self.report({'WARNING'},
-                            "Failure to open the saved Palletes Folder. Check if the path exists")
-                return {'CANCELLED'}
-
             filepath = os.path.join(target_path, filename) + ".gpl"
-
             file_preset = open(filepath, 'wb')
             gpl = "GIMP Palette\n"
             gpl += "Name: %s\n" % filename
@@ -312,18 +322,19 @@ class WriteGimpPalette():
             file_preset.close()
 
             pp.palette_name = filename
+            preset_menu_class.bl_label = bpy.path.display_name(filename)
+
+            self.report({'INFO'}, "Created Palette: {}".format(filepath))
 
         else:
             preset_active = preset_menu_class.bl_label
+            filename = self.as_filename(preset_active)
 
-            # fairly sloppy but convenient.
-            filepath = bpy.utils.preset_find(preset_active, self.preset_subdir)
-
-            if not filepath:
-                filepath = bpy.utils.preset_find(preset_active,
-                    self.preset_subdir, display_name=True)
+            filepath = os.path.join(target_path, filename) + ".gpl"
 
-            if not filepath:
+            if not filepath or not os.path.exists(filepath):
+                self.report({'WARNING'}, "Preset could not be found. Operation Cancelled")
+                self.reset_preset_name(preset_menu_class, pp)
                 return {'CANCELLED'}
 
             if hasattr(self, "remove"):
@@ -331,18 +342,24 @@ class WriteGimpPalette():
             else:
                 try:
                     os.remove(filepath)
+                    self.report({'INFO'}, "Deleted palette: {}".format(filepath))
                 except:
                     import traceback
                     traceback.print_exc()
 
-            # XXX, stupid!
-            preset_menu_class.bl_label = "Presets"
+        self.reset_preset_name(preset_menu_class, pp)
 
         if hasattr(self, "post_cb"):
             self.post_cb(context)
 
         return {'FINISHED'}
 
+    @staticmethod
+    def reset_preset_name(presets, props):
+        # XXX, still stupid!
+        presets.bl_label = "Presets"
+        props.palette_name = ""
+
     def check(self, context):
         self.name = self.as_filename(self.name)
 
@@ -350,11 +367,11 @@ class WriteGimpPalette():
         if not self.remove_active:
             wm = context.window_manager
             return wm.invoke_props_dialog(self)
-        else:
-            return self.execute(context)
 
+        return self.execute(context)
 
-class AddPresetPalette(WriteGimpPalette, Operator):
+
+class PALETTE_OT_preset_add(WriteGimpPalette, Operator):
     bl_idname = "palette.preset_add"
     bl_label = "Add Palette Preset"
     preset_menu = "PALETTE_MT_menu"
@@ -439,14 +456,13 @@ class IMAGE_OT_select_color(Operator):
 
 
 def color_palette_draw(self, context):
-    palette_props = bpy.context.scene.palette_props
+    palette_props = context.scene.palette_props
 
     layout = self.layout
-    bpy.types.PALETTE_MT_menu.preset_subdir = palette_props.presets_folder
 
     row = layout.row(align=True)
-    row.menu("PALETTE_MT_menu", text=palette_props.palette_name.rstrip())
-    row.operator("palette.preset_add", text="", icon="ZOOMIN")
+    row.menu("PALETTE_MT_menu", text=PALETTE_MT_menu.bl_label)
+    row.operator("palette.preset_add", text="", icon="ZOOMIN").remove_active = False
     row.operator("palette.preset_add", text="", icon="ZOOMOUT").remove_active = True
 
     col = layout.column(align=True)
@@ -487,8 +503,6 @@ def color_palette_draw(self, context):
     row = layout.row()
     row.prop(palette_props, "presets_folder", text="")
 
-    pass
-
 
 class BrushButtonsPanel():
     bl_space_type = 'IMAGE_EDITOR'
@@ -612,11 +626,12 @@ class VIEW3D_OT_reset_weight_palette(Operator):
     def execute(self, context):
         try:
             palette_props = context.scene.palette_props
-            dict_defs = {0: 0.0, 1: 0.1, 2: 0.25,
-                         3: 0.333, 4: 0.4, 5: 0.5,
-                         6: 0.6, 7: 0.6666, 8: 0.75,
-                         9: 0.9, 10: 1.0
-                        }
+            dict_defs = {
+                0: 0.0, 1: 0.1, 2: 0.25,
+                3: 0.333, 4: 0.4, 5: 0.5,
+                6: 0.6, 7: 0.6666, 8: 0.75,
+                9: 0.9, 10: 1.0
+            }
             current_idx = palette_props.current_weight_index
             palette_props.weight = dict_defs[current_idx]
 
@@ -673,30 +688,20 @@ class VIEW3D_PT_weight_palette(PaintPanel, Panel):
         row.operator("paint.reset_weight_palette", text="Reset")
 
 
-class Colors(PropertyGroup):
+class PALETTE_Colors(PropertyGroup):
     """Class for colors CollectionProperty"""
     color = FloatVectorProperty(
-            name="",
-            description="",
-            default=(0.8, 0.8, 0.8),
-            min=0, max=1,
-            step=1, precision=3,
-            subtype='COLOR_GAMMA',
-            size=3
-            )
-
-
-class Weights(PropertyGroup):
-    """Class for Weights Collection Property"""
-    weight = FloatProperty(
-            default=0.0,
-            min=0.0,
-            max=1.0,
-            precision=3
-            )
+        name="",
+        description="",
+        default=(0.8, 0.8, 0.8),
+        min=0, max=1,
+        step=1, precision=3,
+        subtype='COLOR_GAMMA',
+        size=3
+    )
 
 
-class PaletteProps(PropertyGroup):
+class PALETTE_Props(PropertyGroup):
 
     def update_color_name(self, context):
         pp = bpy.context.scene.palette_props
@@ -742,133 +747,151 @@ class PaletteProps(PropertyGroup):
         return None
 
     palette_name = StringProperty(
-            name="Palette Name",
-            default="Preset",
-            subtype='FILE_NAME'
-            )
+        name="Palette Name",
+        default="Preset",
+        subtype='FILE_NAME'
+    )
     color_name = StringProperty(
-            name="",
-            description="Color Name",
-            default="Untitled",
-            update=update_color_name
-            )
+        name="",
+        description="Color Name",
+        default="Untitled",
+        update=update_color_name
+    )
     columns = IntProperty(
-            name="Columns",
-            description="Number of Columns",
-            min=0, max=16,
-            default=0
-            )
+        name="Columns",
+        description="Number of Columns",
+        min=0, max=16,
+        default=0
+    )
     index = IntProperty(
-            name="Index",
-            description="Move Selected Color",
-            min=0,
-            update=move_color
-            )
+        name="Index",
+        description="Move Selected Color",
+        min=0,
+        update=move_color
+    )
     notes = StringProperty(
-            name="Palette Notes",
-            default="#\n"
-            )
+        name="Palette Notes",
+        default="#\n"
+    )
     current_color_index = IntProperty(
-            name="Current Color Index",
-            description="",
-            default=0,
-            min=0
-            )
+        name="Current Color Index",
+        description="",
+        default=0,
+        min=0
+    )
     current_weight_index = IntProperty(
-            name="Current Color Index",
-            description="",
-            default=10,
-            min=-1
-            )
+        name="Current Color Index",
+        description="",
+        default=10,
+        min=-1
+    )
     presets_folder = StringProperty(name="",
-            description="Palettes Folder",
-            subtype="DIR_PATH"
-            )
+        description="Palettes Folder",
+        subtype="DIR_PATH",
+        default="//"
+    )
     colors = CollectionProperty(
-            type=Colors
-            )
+        type=PALETTE_Colors
+    )
     weight = FloatProperty(
-            name="Weight",
-            description="Modify the active Weight preset slot value",
-            default=0.0,
-            min=0.0, max=1.0,
-            precision=3,
-            update=update_weight
-            )
+        name="Weight",
+        description="Modify the active Weight preset slot value",
+        default=0.0,
+        min=0.0, max=1.0,
+        precision=3,
+        update=update_weight
+    )
     weight_0 = FloatProperty(
-            default=0.0,
-            min=0.0, max=1.0,
-            precision=3
-            )
+        default=0.0,
+        min=0.0, max=1.0,
+        precision=3
+    )
     weight_1 = FloatProperty(
-            default=0.1,
-            min=0.0, max=1.0,
-            precision=3
-            )
+        default=0.1,
+        min=0.0, max=1.0,
+        precision=3
+    )
     weight_2 = FloatProperty(
-            default=0.25,
-            min=0.0, max=1.0,
-            precision=3
-            )
+        default=0.25,
+        min=0.0, max=1.0,
+        precision=3
+    )
     weight_3 = FloatProperty(
-            default=0.333,
-            min=0.0, max=1.0,
-            precision=3
-            )
+        default=0.333,
+        min=0.0, max=1.0,
+        precision=3
+    )
     weight_4 = FloatProperty(
-            default=0.4,
-            min=0.0, max=1.0,
-            precision=3
-            )
+        default=0.4,
+        min=0.0, max=1.0,
+        precision=3
+    )
     weight_5 = FloatProperty(
-            default=0.5,
-            min=0.0, max=1.0,
-            precision=3
-            )
+        default=0.5,
+        min=0.0, max=1.0,
+        precision=3
+    )
     weight_6 = FloatProperty(
-            default=0.6,
-            min=0.0, max=1.0,
-            precision=3
-            )
+        default=0.6,
+        min=0.0, max=1.0,
+        precision=3
+    )
     weight_7 = FloatProperty(
-            default=0.6666,
-            min=0.0, max=1.0,
-            precision=3
-            )
+        default=0.6666,
+        min=0.0, max=1.0,
+        precision=3
+    )
     weight_8 = FloatProperty(
-            default=0.75,
-            min=0.0, max=1.0,
-            precision=3
-            )
+        default=0.75,
+        min=0.0, max=1.0,
+        precision=3
+    )
     weight_9 = FloatProperty(
-            default=0.9,
-            min=0.0, max=1.0,
-            precision=3
-            )
+        default=0.9,
+        min=0.0, max=1.0,
+        precision=3
+    )
     weight_10 = FloatProperty(
-            default=1.0,
-            min=0.0, max=1.0,
-            precision=3
-            )
-    pass
+        default=1.0,
+        min=0.0, max=1.0,
+        precision=3
+    )
+
+
+classes = (
+    PALETTE_MT_menu,
+    PALETTE_OT_load_gimp_palette,
+    PALETTE_OT_preset_add,
+    PALETTE_OT_add_color,
+    PALETTE_OT_remove_color,
+    PALETTE_OT_sample_tool_color,
+    IMAGE_OT_select_color,
+    IMAGE_PT_color_palette,
+    VIEW3D_PT_color_palette,
+    VIEW3D_OT_select_weight,
+    VIEW3D_OT_reset_weight_palette,
+    VIEW3D_PT_weight_palette,
+    PALETTE_Colors,
+    PALETTE_Props,
+)
 
 
 def register():
-    bpy.utils.register_module(__name__)
+    for cls in classes:
+        bpy.utils.register_class(cls)
 
     bpy.types.Scene.palette_props = PointerProperty(
-                                        type=PaletteProps,
-                                        name="Palette Props",
-                                        description=""
-                                        )
-    pass
+        type=PALETTE_Props,
+        name="Palette Props",
+        description=""
+    )
 
 
 def unregister():
-    bpy.utils.unregister_module(__name__)
+    for cls in reversed(classes):
+        bpy.utils.unregister_class(cls)
 
     del bpy.types.Scene.palette_props
-    pass
 
 
 if __name__ == "__main__":
diff --git a/presets/pov/lamp/01_(5400K)_Direct_Sun.py b/presets/pov/lamp/01_(5400K)_Direct_Sun.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f53ce06d3d189d2324af2efb199f91da5b178f9
--- /dev/null
+++ b/presets/pov/lamp/01_(5400K)_Direct_Sun.py
@@ -0,0 +1,10 @@
+#Since the dawn of time
+
+import bpy
+bpy.context.object.data.type = 'SUN'
+lampdata = bpy.context.object.data
+
+lampdata.color = (1.0, 1.0, 0.9843137264251709)
+lampdata.energy = 1.2 #100 000lux
+#lampdata.distance = 0.001
+#lampdata.falloff_type = 'INVERSE_SQUARE'
\ No newline at end of file
diff --git a/presets/pov/lamp/02_(5400K)_High_Noon_Sun.py b/presets/pov/lamp/02_(5400K)_High_Noon_Sun.py
new file mode 100644
index 0000000000000000000000000000000000000000..6d3083a6e6a91b1ec99b542d6fb0bb771c374770
--- /dev/null
+++ b/presets/pov/lamp/02_(5400K)_High_Noon_Sun.py
@@ -0,0 +1,17 @@
+#Since the dawn of time
+
+import bpy
+bpy.context.object.rotation_euler = (0,0,0)#And loc HIGH
+bpy.context.object.location = (0,0,700000000)
+bpy.context.object.data.type = 'AREA'
+lampdata = bpy.context.object.data
+
+lampdata.shape = 'SQUARE'
+lampdata.size = 30000000#0.02
+#lampdata.size_y = 0.02
+lampdata.shadow_ray_samples_x = 2
+#lampdata.shadow_ray_samples_y = 3
+lampdata.color = (1.0, 1.0, 1.0)
+lampdata.energy = 1.094316#91193 #lux
+lampdata.distance =695699968
+
diff --git a/presets/pov/lamp/03_(6000K)_Daylight_Window.py b/presets/pov/lamp/03_(6000K)_Daylight_Window.py
new file mode 100644
index 0000000000000000000000000000000000000000..a9781f579d6e24d00f027f9c20ccd55b45b87bc6
--- /dev/null
+++ b/presets/pov/lamp/03_(6000K)_Daylight_Window.py
@@ -0,0 +1,13 @@
+#Since the dawn of time
+
+import bpy
+bpy.context.object.data.type = 'AREA'
+lampdata = bpy.context.object.data
+
+lampdata.size = 1.2
+lampdata.size_y = 2.10
+lampdata.shadow_ray_samples_x = 2
+lampdata.shadow_ray_samples_y = 3
+lampdata.color = (1.0, 1.0, 1.0)
+lampdata.energy = 1.094316#91193 #lux
+lampdata.distance = 1.0
diff --git a/presets/pov/lamp/04_(6000K)_2500W_HMI_(Halogen_Metal_Iodide).py b/presets/pov/lamp/04_(6000K)_2500W_HMI_(Halogen_Metal_Iodide).py
new file mode 100644
index 0000000000000000000000000000000000000000..0bfa95d84a1560f01d1ee671d11012a52c4fccf5
--- /dev/null
+++ b/presets/pov/lamp/04_(6000K)_2500W_HMI_(Halogen_Metal_Iodide).py
@@ -0,0 +1,14 @@
+#After 1969
+#made specifically for film and entertainment applications
+
+import bpy
+bpy.context.object.data.type = 'SPOT'
+lampdata = bpy.context.object.data
+
+lampdata.show_cone = True
+lampdata.spot_size = 0.872665
+lampdata.spot_blend = 0.9
+lampdata.color = (0.99, 0.9882352948188782, 0.998)
+lampdata.energy = 223.81796 #240000lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
+lampdata.distance = 0.001
+lampdata.falloff_type = 'INVERSE_SQUARE'
\ No newline at end of file
diff --git a/presets/pov/lamp/05_(4000K)_100W_Metal_Halide.py b/presets/pov/lamp/05_(4000K)_100W_Metal_Halide.py
new file mode 100644
index 0000000000000000000000000000000000000000..e91d3f9a49d8eb4ad30f3b71094d022586a59f31
--- /dev/null
+++ b/presets/pov/lamp/05_(4000K)_100W_Metal_Halide.py
@@ -0,0 +1,14 @@
+#After 1962
+#Common uses: outdoor lighting where good color rendering is needed, television/film lighting, sports fields, car headlights, flood lights, heavy flashlights, green house applications
+
+import bpy
+bpy.context.object.data.type = 'SPOT'
+lampdata = bpy.context.object.data
+
+lampdata.show_cone = True
+lampdata.spot_size = 0.6
+lampdata.spot_blend = 0.9
+lampdata.color = (0.9490196108818054, 0.9882352948188782, 1.0)
+lampdata.energy = 20.98293#9000lm/21.446(=lux)*0.004*6.25(distance) *2 for distance is the point of half strength
+lampdata.distance = 0.025
+lampdata.falloff_type = 'INVERSE_SQUARE'
\ No newline at end of file
diff --git a/presets/pov/lamp/06_(3200K)_100W_Quartz_Halogen.py b/presets/pov/lamp/06_(3200K)_100W_Quartz_Halogen.py
new file mode 100644
index 0000000000000000000000000000000000000000..b58edf17d44f8e78b8ea0df26d1c2eda9c8853a7
--- /dev/null
+++ b/presets/pov/lamp/06_(3200K)_100W_Quartz_Halogen.py
@@ -0,0 +1,16 @@
+#since 1960, no longer manufactured since 2016
+#8mm projectors
+#used in many automobiles headlamps ; outdoor lighting systems ; watercraft ; desktop lamps (smaller power).
+#theatrical and studio (film and television) fixtures, including Ellipsoidal reflector spotlights, Source Four, and Fresnels; PAR Cans 
+
+import bpy
+bpy.context.object.data.type = 'SPOT'
+lampdata = bpy.context.object.data
+
+lampdata.show_cone = True
+lampdata.spot_size = 1.9
+lampdata.spot_blend = 0.9
+lampdata.color = (1.0, 0.9450980424880981, 0.8784313797950745)
+lampdata.energy = 12.43433#5000/21.446 #lumen values/20 or lux when available used as a basis
+lampdata.distance = 0.015#energy calculated for length 0.075 but width gives better result
+lampdata.falloff_type = 'INVERSE_SQUARE'
diff --git a/presets/pov/lamp/07_(2850K)_100w_Tungsten.py b/presets/pov/lamp/07_(2850K)_100w_Tungsten.py
new file mode 100644
index 0000000000000000000000000000000000000000..72675de3baec0865f6348e1e862d0cf1d57966a8
--- /dev/null
+++ b/presets/pov/lamp/07_(2850K)_100w_Tungsten.py
@@ -0,0 +1,10 @@
+#1908 - today
+
+import bpy
+bpy.context.object.data.type = 'POINT'
+lampdata = bpy.context.object.data
+
+lampdata.color = (1.0, 0.8392156958580017, 0.6666666865348816)
+lampdata.energy = 7.46060#3.7303#1000/21.446/(lampdistance/candledistance)  #lumen values/21.446 or lux when available used as a basis
+lampdata.distance = 0.05
+lampdata.falloff_type = 'INVERSE_SQUARE'
\ No newline at end of file
diff --git a/presets/pov/lamp/08_(2600K)_40w_Tungsten.py b/presets/pov/lamp/08_(2600K)_40w_Tungsten.py
new file mode 100644
index 0000000000000000000000000000000000000000..88ef46a0d42101a5220a2b645b624e7edce7ed28
--- /dev/null
+++ b/presets/pov/lamp/08_(2600K)_40w_Tungsten.py
@@ -0,0 +1,10 @@
+#since 1908
+
+import bpy
+bpy.context.object.data.type = 'POINT'
+lampdata = bpy.context.object.data
+
+lampdata.color = (1.0, 0.8196078431372549, 0.6980392156862745)
+lampdata.energy = 2.98424#400/21.446 #lumen values/21.446 or lux when available used as a basis
+lampdata.distance = 0.05
+lampdata.falloff_type = 'INVERSE_SQUARE'
\ No newline at end of file
diff --git a/presets/pov/lamp/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py b/presets/pov/lamp/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py
new file mode 100644
index 0000000000000000000000000000000000000000..b0a23eda43c755418b89cf0ebe94d69a40861457
--- /dev/null
+++ b/presets/pov/lamp/09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py
@@ -0,0 +1,14 @@
+#Available since 1979 (Triphosphor lamps)
+
+import bpy
+bpy.context.object.data.type = 'AREA'
+lampdata = bpy.context.object.data
+
+lampdata.size = 0.038
+lampdata.size_y = 2.40284
+lampdata.shadow_ray_samples_x = 1
+lampdata.shadow_ray_samples_y = 2
+lampdata.color = (1.0, 0.95686274766922, 0.9490200281143188)
+lampdata.energy = 4.45304#4775lm/21.446(=lux)*0.004(distance) *2 for distance is the point of half strength 6200lm?
+lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
+#lampdata.falloff_type = 'INVERSE_SQUARE'
\ No newline at end of file
diff --git a/presets/pov/lamp/10_(4300K)_40W_Vintage_Fluorescent_T12.py b/presets/pov/lamp/10_(4300K)_40W_Vintage_Fluorescent_T12.py
new file mode 100644
index 0000000000000000000000000000000000000000..d03ce6fd98044b07ecaa49b2170bd7458541390e
--- /dev/null
+++ b/presets/pov/lamp/10_(4300K)_40W_Vintage_Fluorescent_T12.py
@@ -0,0 +1,14 @@
+#since 1939 , T12 no longer manufactured since T8 propagated
+
+import bpy
+bpy.context.object.data.type = 'AREA'
+lampdata = bpy.context.object.data
+
+lampdata.size = 0.038
+lampdata.size_y = 1.2192
+lampdata.shadow_ray_samples_x = 1
+lampdata.shadow_ray_samples_y = 2
+lampdata.color = (0.901, 1.0, 0.979)
+lampdata.energy = 2.14492#2300lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
+lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
+#lampdata.falloff_type = 'INVERSE_SQUARE'
\ No newline at end of file
diff --git a/presets/pov/lamp/11_(5000K)_18W_Standard_Fluorescent_T8.py b/presets/pov/lamp/11_(5000K)_18W_Standard_Fluorescent_T8.py
new file mode 100644
index 0000000000000000000000000000000000000000..6fef17639598fdd25ba5c625d7b8e538a4b52715
--- /dev/null
+++ b/presets/pov/lamp/11_(5000K)_18W_Standard_Fluorescent_T8.py
@@ -0,0 +1,13 @@
+#since 1973 
+
+import bpy
+bpy.context.object.data.type = 'AREA'
+lampdata = bpy.context.object.data
+
+lampdata.size = 0.026
+lampdata.size_y = 0.59
+lampdata.shadow_ray_samples_x = 1
+lampdata.shadow_ray_samples_y = 2
+lampdata.color = (0.95686274766922, 1.0, 0.9803921580314636)
+lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
+lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/lamp/12_(4200K)_18W_Cool_White_Fluorescent_T8.py b/presets/pov/lamp/12_(4200K)_18W_Cool_White_Fluorescent_T8.py
new file mode 100644
index 0000000000000000000000000000000000000000..83f8dd4e6afa2f5332e4554e02ad804056de02d6
--- /dev/null
+++ b/presets/pov/lamp/12_(4200K)_18W_Cool_White_Fluorescent_T8.py
@@ -0,0 +1,15 @@
+#Available since 1979
+#more common than the warm white
+
+import bpy
+bpy.context.object.data.type = 'AREA'
+lampdata = bpy.context.object.data
+
+lampdata.size = 0.026
+lampdata.size_y = 0.59
+lampdata.shadow_ray_samples_x = 1
+lampdata.shadow_ray_samples_y = 2
+lampdata.color = (0.8313725590705872, 0.9215686321258545, 1.0)
+lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
+lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
+#lampdata.falloff_type = 'INVERSE_SQUARE'
\ No newline at end of file
diff --git a/presets/pov/lamp/13_(3000K)_18W_Warm_Fluorescent_T8.py b/presets/pov/lamp/13_(3000K)_18W_Warm_Fluorescent_T8.py
new file mode 100644
index 0000000000000000000000000000000000000000..e1cee557d965cf7a6642d4fb5df627baec210982
--- /dev/null
+++ b/presets/pov/lamp/13_(3000K)_18W_Warm_Fluorescent_T8.py
@@ -0,0 +1,14 @@
+#Available since 1979
+#developed to get closer to tungsten atmospher in interiors
+
+import bpy
+bpy.context.object.data.type = 'AREA'
+lampdata = bpy.context.object.data
+
+lampdata.size = 0.026
+lampdata.size_y = 0.59
+lampdata.shadow_ray_samples_x = 1
+lampdata.shadow_ray_samples_y = 2
+lampdata.color = (1.0, 0.95686274766922, 0.8980392217636108)
+lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
+lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/lamp/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py b/presets/pov/lamp/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py
new file mode 100644
index 0000000000000000000000000000000000000000..55f84ab817947b2000ae656b4ffbf34c925b27cd
--- /dev/null
+++ b/presets/pov/lamp/14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py
@@ -0,0 +1,13 @@
+#Available since 1995
+
+import bpy
+bpy.context.object.data.type = 'AREA'
+lampdata = bpy.context.object.data
+
+lampdata.size = 0.016
+lampdata.size_y = 1.149
+lampdata.shadow_ray_samples_x = 1
+lampdata.shadow_ray_samples_y = 2
+lampdata.color = (1.0, 0.83, 0.986274528503418)
+lampdata.energy = 4.66287 #0.93257#4.66287#5000lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
+lampdata.distance = 0.1 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/lamp/15_(3200K)_40W_Induction_ Fluorescent.py b/presets/pov/lamp/15_(3200K)_40W_Induction_ Fluorescent.py
new file mode 100644
index 0000000000000000000000000000000000000000..1d0851e5be950f12ddc083450b32f6a373baec90
--- /dev/null
+++ b/presets/pov/lamp/15_(3200K)_40W_Induction_ Fluorescent.py	
@@ -0,0 +1,14 @@
+#since the 1990's, 
+#Often circular or rectangular closed loop electrodeless fluorescent lamps
+
+import bpy
+bpy.context.object.data.type = 'SPOT'
+lampdata = bpy.context.object.data
+
+#lampdata.use_halo = True
+lampdata.spot_size = 3.14
+lampdata.spot_blend = 0.9
+lampdata.color = (1.0, 0.9450980424880981, 0.8784313797950745)
+lampdata.energy = 2.61121#2800/21.446 #lumen values/20 or lux when available used as a basis
+lampdata.distance = 0.15#energy calculated for length 0.075 but width gives better result
+lampdata.falloff_type = 'INVERSE_SQUARE'
diff --git a/presets/pov/lamp/16_(2100K)_150W_High_Pressure_Sodium.py b/presets/pov/lamp/16_(2100K)_150W_High_Pressure_Sodium.py
new file mode 100644
index 0000000000000000000000000000000000000000..9ddb32cb43f078f8b439729386c414d12ef215c2
--- /dev/null
+++ b/presets/pov/lamp/16_(2100K)_150W_High_Pressure_Sodium.py
@@ -0,0 +1,13 @@
+#Starting from 1964
+
+import bpy
+bpy.context.object.data.type = 'SPOT'
+lampdata = bpy.context.object.data
+
+lampdata.show_cone = True
+lampdata.color = (1.0, 0.772549033164978, 0.5607843399047852)
+lampdata.energy = 4.47636#12000lm/21.446(=lux)*0.004(distance) *2 for distance is the point of half strength
+lampdata.distance = 1.0
+lampdata.spot_size = 1.9
+lampdata.spot_blend = 0.9
+lampdata.falloff_type = 'INVERSE_SQUARE'
diff --git a/presets/pov/lamp/17_(1700K)_135W_Low_Pressure_Sodium.py b/presets/pov/lamp/17_(1700K)_135W_Low_Pressure_Sodium.py
new file mode 100644
index 0000000000000000000000000000000000000000..d5e4267845a3bff8fd103a304724d962df24ed5d
--- /dev/null
+++ b/presets/pov/lamp/17_(1700K)_135W_Low_Pressure_Sodium.py
@@ -0,0 +1,11 @@
+#(1700K) 135W Low Pressure Sodium Vapor Starting from 1932
+#Mostly used for Outdoor city lighting, security lighting, long tunnel lighting 
+
+import bpy
+bpy.context.object.data.type = 'POINT'
+lampdata = bpy.context.object.data
+
+lampdata.color = (1.0, 0.5764706134796143, 0.16078431904315948)
+lampdata.energy = 8.43048#22600lm/21.446(=lux)*0.004(distance) *2 for distance is the point of half strength
+lampdata.distance = 1.0
+lampdata.falloff_type = 'INVERSE_SQUARE'
\ No newline at end of file
diff --git a/presets/pov/lamp/18_(6800K)_175W_Mercury_Vapor.py b/presets/pov/lamp/18_(6800K)_175W_Mercury_Vapor.py
new file mode 100644
index 0000000000000000000000000000000000000000..e1a5143c32a19a3c82731fa2b6c3995cbbd9b2e7
--- /dev/null
+++ b/presets/pov/lamp/18_(6800K)_175W_Mercury_Vapor.py
@@ -0,0 +1,13 @@
+#Starting from 1901
+
+import bpy
+bpy.context.object.data.type = 'SPOT'
+lampdata = bpy.context.object.data
+
+lampdata.show_cone = True
+lampdata.spot_size = 1.25
+lampdata.spot_blend = 0.9
+lampdata.color = (0.8470588326454163, 0.9686274528503418, 1.0)
+lampdata.energy = 17.25263#7400lm/21.446(=lux)*0.004*6.25(distance) *2 for distance is the point of half strength
+lampdata.distance = 0.025
+lampdata.falloff_type = 'INVERSE_SQUARE'
diff --git a/presets/pov/lamp/19_(5200K)_700W_Carbon_Arc.py b/presets/pov/lamp/19_(5200K)_700W_Carbon_Arc.py
new file mode 100644
index 0000000000000000000000000000000000000000..139dc8bb38c35efc65f84494642b98544d4edf0b
--- /dev/null
+++ b/presets/pov/lamp/19_(5200K)_700W_Carbon_Arc.py
@@ -0,0 +1,18 @@
+#Starting from 1876 (first type of commercial lamps developed with electricity)
+#Carbon arc lamps were being phased out after the 1910s. 
+#For general lighting the lamp was replaced by the 1920s and 30s in most cities. 
+#The lamp continued to be used for spot lights, film production lighting and film projector lamps.
+#Most of the remaining carbon arc lamps ceased production by the 1980s 
+
+import bpy
+bpy.context.object.data.type = 'SPOT'
+lampdata = bpy.context.object.data
+
+#lampdata.use_halo = True
+lampdata.show_cone = True
+lampdata.spot_size = 1.5
+lampdata.spot_blend = 0.3
+lampdata.color = (1.0, 0.9803921580314636, 0.95686274766922)
+lampdata.energy = 51.29162#55000lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
+lampdata.distance = 0.01
+lampdata.falloff_type = 'INVERSE_SQUARE'
\ No newline at end of file
diff --git a/presets/pov/lamp/20_(6500K)_15W_LED_Spot.py b/presets/pov/lamp/20_(6500K)_15W_LED_Spot.py
new file mode 100644
index 0000000000000000000000000000000000000000..1b70b9f10b14547301e6a76d0915ddee337cffc3
--- /dev/null
+++ b/presets/pov/lamp/20_(6500K)_15W_LED_Spot.py
@@ -0,0 +1,12 @@
+#since 2008
+
+import bpy
+bpy.context.object.data.type = 'SPOT'
+lampdata = bpy.context.object.data
+
+lampdata.show_cone = True
+lampdata.spot_size = 1.39626 #80 degrees in radian
+lampdata.spot_blend = 0.5
+lampdata.color = (1.0, 0.9372549057006836, 0.9686274528503418)
+lampdata.energy = 1.39886#1500lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
+lampdata.distance = 1.18 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/lamp/21_(2700K)_7W_OLED_Panel.py b/presets/pov/lamp/21_(2700K)_7W_OLED_Panel.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f2ebb8fedcf591dc045093a2b0690805ae3927b
--- /dev/null
+++ b/presets/pov/lamp/21_(2700K)_7W_OLED_Panel.py
@@ -0,0 +1,14 @@
+#since 2025
+#inspired by OSRAM Early Future / IKEA Vitsand / OTI Lumionics Aerelight
+
+import bpy
+bpy.context.object.data.type = 'AREA'
+lampdata = bpy.context.object.data
+
+lampdata.size = 0.033
+lampdata.size_y = 0.133
+lampdata.shadow_ray_samples_x = 2
+lampdata.shadow_ray_samples_y = 2
+lampdata.color = (1.0, 0.8292156958580017, 0.6966666865348816)
+lampdata.energy = 0.83932#900lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
+lampdata.distance = 1.18 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
diff --git a/presets/pov/lamp/22_(30000K)_40W_Black_Light_Fluorescent.py b/presets/pov/lamp/22_(30000K)_40W_Black_Light_Fluorescent.py
new file mode 100644
index 0000000000000000000000000000000000000000..ef6b4725403891510a7256417fb5239d27557c5e
--- /dev/null
+++ b/presets/pov/lamp/22_(30000K)_40W_Black_Light_Fluorescent.py
@@ -0,0 +1,12 @@
+#Starting from 1939 (World War II Byler's tubes) 
+
+import bpy
+bpy.context.object.data.type = 'AREA'
+lampdata = bpy.context.object.data
+
+lampdata.size = 0.038
+lampdata.size_y = 1.2192
+lampdata.color = (0.6549019813537598, 0.0, 1.0)
+lampdata.energy = 1.86515#100/21.446 #lumen values/21.446 or lux when available used as a basis
+lampdata.distance = 0.4 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
+
diff --git a/presets/pov/lamp/23_(30000K)_40W_Black_Light_Bulb.py b/presets/pov/lamp/23_(30000K)_40W_Black_Light_Bulb.py
new file mode 100644
index 0000000000000000000000000000000000000000..baad8234c444c61898407af4daf9abbf1058b0de
--- /dev/null
+++ b/presets/pov/lamp/23_(30000K)_40W_Black_Light_Bulb.py
@@ -0,0 +1,10 @@
+#Starting from 1918 (World War I Wood's glass) 
+
+import bpy
+bpy.context.object.data.type = 'POINT'
+lampdata = bpy.context.object.data
+
+lampdata.color = (0.6549019813537598, 0.0, 1.0)
+lampdata.energy = 1.86515#100/21.446 #lumen values/21.446 or lux when available used as a basis
+lampdata.distance = 0.01
+lampdata.falloff_type = 'INVERSE_SQUARE'
diff --git a/presets/pov/lamp/24_(1850K)_Candle.py b/presets/pov/lamp/24_(1850K)_Candle.py
new file mode 100644
index 0000000000000000000000000000000000000000..5d7ac61d75fad2aca11cf148440b06c05dbe29c0
--- /dev/null
+++ b/presets/pov/lamp/24_(1850K)_Candle.py
@@ -0,0 +1,24 @@
+#Starting from 1825 (stearin) 
+
+import bpy
+bpy.context.object.data.type = 'POINT'
+lampdata = bpy.context.object.data
+
+lampdata.color = (1.0, 0.7176470756530762, 0.2980392277240753)
+#lampdata.color = (1.0, 0.5764706134796143, 0.16078431904315948)
+#http://terpconnect.umd.edu/~pbs/2011-Sunderland-et-al-PCI.pdf
+#https://blog.1000bulbs.com/home/whats-the-difference-between-candela-lux-and-lumens
+#Environment 	Typical Lux
+#Hospital Theatre 	1,000
+#Supermarket, Workshop, Sports Hall 	750
+#Office, Show Rooms, Laboratories, Kitchens 	500
+#Warehouse Loading Bays 	300 to 400
+#School Classroom, University Lecture Hall 	250
+#Lobbies, Public Corridors, Stairwells 	200
+#Warehouse Aisles 	100 to 200
+#Homes, Theatres 	150
+#Family Living Room 50
+#Sunset & Sunrise 	400 lux
+lampdata.energy = 2.0 #two times lux value
+lampdata.distance = 0.004
+lampdata.falloff_type = 'INVERSE_SQUARE'
diff --git a/presets/pov/radiosity/01_Debug.py b/presets/pov/radiosity/01_Debug.py
new file mode 100644
index 0000000000000000000000000000000000000000..420dbd7eeb8919b2505d339f31a0b2a93dca97a0
--- /dev/null
+++ b/presets/pov/radiosity/01_Debug.py
@@ -0,0 +1,20 @@
+import bpy
+scene = bpy.context.scene
+
+scene.pov.radio_display_advanced = True
+scene.pov.radio_adc_bailout = 0.005
+scene.pov.radio_always_sample = False
+scene.pov.radio_brightness = 1.0
+scene.pov.radio_count = 10
+scene.pov.radio_error_bound = 0.3
+scene.pov.radio_gray_threshold = 0.0
+scene.pov.radio_low_error_factor = 0.8
+scene.pov.radio_media = False
+scene.pov.radio_subsurface = False
+scene.pov.radio_minimum_reuse = 0.015
+scene.pov.radio_maximum_reuse = 0.2
+scene.pov.radio_nearest_count = 1
+scene.pov.radio_normal = False
+scene.pov.radio_recursion_limit = 1
+scene.pov.radio_pretrace_start = 0.08
+scene.pov.radio_pretrace_end = 0.01
diff --git a/presets/pov/radiosity/02_Fast.py b/presets/pov/radiosity/02_Fast.py
new file mode 100644
index 0000000000000000000000000000000000000000..08864c83e11da13c73651e0ec54c49742a376876
--- /dev/null
+++ b/presets/pov/radiosity/02_Fast.py
@@ -0,0 +1,19 @@
+import bpy
+scene = bpy.context.scene
+
+scene.pov.radio_adc_bailout = 0.005
+scene.pov.radio_always_sample = False
+scene.pov.radio_brightness = 1.0
+scene.pov.radio_count = 80
+scene.pov.radio_error_bound = 0.4
+scene.pov.radio_gray_threshold = 0.0
+scene.pov.radio_low_error_factor = 0.9
+scene.pov.radio_media = False
+scene.pov.radio_subsurface = False
+scene.pov.radio_minimum_reuse = 0.025
+scene.pov.radio_maximum_reuse = 0.2
+scene.pov.radio_nearest_count = 5
+scene.pov.radio_normal = False
+scene.pov.radio_recursion_limit = 1
+scene.pov.radio_pretrace_start = 0.08
+scene.pov.radio_pretrace_end = 0.02
diff --git a/presets/pov/radiosity/03_Normal.py b/presets/pov/radiosity/03_Normal.py
new file mode 100644
index 0000000000000000000000000000000000000000..b66a1b2ac2f10a0dde9ed84fa38aaef654e8a723
--- /dev/null
+++ b/presets/pov/radiosity/03_Normal.py
@@ -0,0 +1,20 @@
+import bpy
+scene = bpy.context.scene
+
+scene.pov.radio_display_advanced = True
+scene.pov.radio_adc_bailout = 0.005
+scene.pov.radio_always_sample = False
+scene.pov.radio_brightness = 1.0
+scene.pov.radio_count = 200
+scene.pov.radio_error_bound = 0.3
+scene.pov.radio_gray_threshold = 0.0
+scene.pov.radio_low_error_factor = 0.75
+scene.pov.radio_media = False
+scene.pov.radio_subsurface = False
+scene.pov.radio_minimum_reuse = 0.017
+scene.pov.radio_maximum_reuse = 0.2
+scene.pov.radio_nearest_count = 7
+scene.pov.radio_normal = False
+scene.pov.radio_recursion_limit = 1
+scene.pov.radio_pretrace_start = 0.08
+scene.pov.radio_pretrace_end = 0.01
diff --git a/presets/pov/radiosity/04_Two_Bounces.py b/presets/pov/radiosity/04_Two_Bounces.py
new file mode 100644
index 0000000000000000000000000000000000000000..2072247adf5a053a422afb1c05d17002eb9a3515
--- /dev/null
+++ b/presets/pov/radiosity/04_Two_Bounces.py
@@ -0,0 +1,20 @@
+import bpy
+scene = bpy.context.scene
+
+scene.pov.radio_display_advanced = True
+scene.pov.radio_adc_bailout = 0.005
+scene.pov.radio_always_sample = False
+scene.pov.radio_brightness = 1.0
+scene.pov.radio_count = 200
+scene.pov.radio_error_bound = 0.3
+scene.pov.radio_gray_threshold = 0.0
+scene.pov.radio_low_error_factor = 0.75
+scene.pov.radio_media = False
+scene.pov.radio_subsurface = False
+scene.pov.radio_minimum_reuse = 0.017
+scene.pov.radio_maximum_reuse = 0.2
+scene.pov.radio_nearest_count = 7
+scene.pov.radio_normal = False
+scene.pov.radio_recursion_limit = 2
+scene.pov.radio_pretrace_start = 0.08
+scene.pov.radio_pretrace_end = 0.01
diff --git a/presets/pov/radiosity/05_Final.py b/presets/pov/radiosity/05_Final.py
new file mode 100644
index 0000000000000000000000000000000000000000..52a9d5c3595d2318e46fb13e65ee8bce6687e36e
--- /dev/null
+++ b/presets/pov/radiosity/05_Final.py
@@ -0,0 +1,20 @@
+import bpy
+scene = bpy.context.scene
+
+scene.pov.radio_display_advanced = True
+scene.pov.radio_adc_bailout = 0.005
+scene.pov.radio_always_sample = False
+scene.pov.radio_brightness = 1.0
+scene.pov.radio_count = 800
+scene.pov.radio_error_bound = 0.2
+scene.pov.radio_gray_threshold = 0.0
+scene.pov.radio_low_error_factor = 0.7
+scene.pov.radio_media = False
+scene.pov.radio_subsurface = False
+scene.pov.radio_minimum_reuse = 0.01
+scene.pov.radio_maximum_reuse = 0.2
+scene.pov.radio_nearest_count = 9
+scene.pov.radio_normal = False
+scene.pov.radio_recursion_limit = 1
+scene.pov.radio_pretrace_start = 0.08
+scene.pov.radio_pretrace_end = 0.01
diff --git a/presets/pov/radiosity/06_Outdoor_Low_Quality.py b/presets/pov/radiosity/06_Outdoor_Low_Quality.py
new file mode 100644
index 0000000000000000000000000000000000000000..53553264bbb5f903a48304c50539b7653bbdaea5
--- /dev/null
+++ b/presets/pov/radiosity/06_Outdoor_Low_Quality.py
@@ -0,0 +1,20 @@
+import bpy
+scene = bpy.context.scene
+
+scene.pov.radio_display_advanced = True
+scene.pov.radio_adc_bailout = 0.005
+scene.pov.radio_always_sample = False
+scene.pov.radio_brightness = 1.0
+scene.pov.radio_count = 80
+scene.pov.radio_error_bound = 0.6
+scene.pov.radio_gray_threshold = 0.0
+scene.pov.radio_low_error_factor = 0.8
+scene.pov.radio_media = False
+scene.pov.radio_subsurface = False
+scene.pov.radio_minimum_reuse = 0.015
+scene.pov.radio_maximum_reuse = 0.2
+scene.pov.radio_nearest_count = 4
+scene.pov.radio_normal = False
+scene.pov.radio_recursion_limit = 1
+scene.pov.radio_pretrace_start = 0.08
+scene.pov.radio_pretrace_end = 0.01
diff --git a/presets/pov/radiosity/07_Outdoor_High_Quality.py b/presets/pov/radiosity/07_Outdoor_High_Quality.py
new file mode 100644
index 0000000000000000000000000000000000000000..8b06dabef67aef5e239364d6fcb6345fc2c9d6d2
--- /dev/null
+++ b/presets/pov/radiosity/07_Outdoor_High_Quality.py
@@ -0,0 +1,20 @@
+import bpy
+scene = bpy.context.scene
+
+scene.pov.radio_display_advanced = True
+scene.pov.radio_adc_bailout = 0.005
+scene.pov.radio_always_sample = False
+scene.pov.radio_brightness = 1.0
+scene.pov.radio_count = 500
+scene.pov.radio_error_bound = 0.1
+scene.pov.radio_gray_threshold = 0.0
+scene.pov.radio_low_error_factor = 0.5
+scene.pov.radio_media = False
+scene.pov.radio_subsurface = False
+scene.pov.radio_minimum_reuse = 0.015
+scene.pov.radio_maximum_reuse = 0.2
+scene.pov.radio_nearest_count = 7
+scene.pov.radio_normal = False
+scene.pov.radio_recursion_limit = 1
+scene.pov.radio_pretrace_start = 0.08
+scene.pov.radio_pretrace_end = 0.004
diff --git a/presets/pov/radiosity/08_Outdoor_(Sun)Light.py b/presets/pov/radiosity/08_Outdoor_(Sun)Light.py
new file mode 100644
index 0000000000000000000000000000000000000000..94448c1f70245d3429fbd299bdb63d18b0b6282d
--- /dev/null
+++ b/presets/pov/radiosity/08_Outdoor_(Sun)Light.py
@@ -0,0 +1,20 @@
+import bpy
+scene = bpy.context.scene
+
+scene.pov.radio_display_advanced = True
+scene.pov.radio_adc_bailout = 0.005
+scene.pov.radio_always_sample = False
+scene.pov.radio_brightness = 1.0
+scene.pov.radio_count = 50
+scene.pov.radio_error_bound = 0.8
+scene.pov.radio_gray_threshold = 0.0
+scene.pov.radio_low_error_factor = 0.9
+scene.pov.radio_media = False
+scene.pov.radio_subsurface = False
+scene.pov.radio_minimum_reuse = 0.015
+scene.pov.radio_maximum_reuse = 0.2
+scene.pov.radio_nearest_count = 4
+scene.pov.radio_normal = False
+scene.pov.radio_recursion_limit = 1
+scene.pov.radio_pretrace_start = 0.08
+scene.pov.radio_pretrace_end = 0.01
diff --git a/presets/pov/radiosity/09_Indoor_Low_Quality.py b/presets/pov/radiosity/09_Indoor_Low_Quality.py
new file mode 100644
index 0000000000000000000000000000000000000000..e5fa7bb611ad5f456bc2e3d73435b44ce8a68642
--- /dev/null
+++ b/presets/pov/radiosity/09_Indoor_Low_Quality.py
@@ -0,0 +1,20 @@
+import bpy
+scene = bpy.context.scene
+
+scene.pov.radio_display_advanced = True
+scene.pov.radio_adc_bailout = 0.005
+scene.pov.radio_always_sample = False
+scene.pov.radio_brightness = 1.0
+scene.pov.radio_count = 80
+scene.pov.radio_error_bound = 0.7
+scene.pov.radio_gray_threshold = 0.0
+scene.pov.radio_low_error_factor = 0.8
+scene.pov.radio_media = False
+scene.pov.radio_subsurface = False
+scene.pov.radio_minimum_reuse = 0.015
+scene.pov.radio_maximum_reuse = 0.2
+scene.pov.radio_nearest_count = 5
+scene.pov.radio_normal = False
+scene.pov.radio_recursion_limit = 2
+scene.pov.radio_pretrace_start = 0.08
+scene.pov.radio_pretrace_end = 0.01
diff --git a/presets/pov/radiosity/10_Indoor_High_Quality.py b/presets/pov/radiosity/10_Indoor_High_Quality.py
new file mode 100644
index 0000000000000000000000000000000000000000..5a752f6c05842108945e08bb579511195add4925
--- /dev/null
+++ b/presets/pov/radiosity/10_Indoor_High_Quality.py
@@ -0,0 +1,20 @@
+import bpy
+scene = bpy.context.scene
+
+scene.pov.radio_display_advanced = True
+scene.pov.radio_adc_bailout = 0.005
+scene.pov.radio_always_sample = False
+scene.pov.radio_brightness = 1.0
+scene.pov.radio_count = 400
+scene.pov.radio_error_bound = 0.15
+scene.pov.radio_gray_threshold = 0.0
+scene.pov.radio_low_error_factor = 0.5
+scene.pov.radio_media = False
+scene.pov.radio_subsurface = False
+scene.pov.radio_minimum_reuse = 0.015
+scene.pov.radio_maximum_reuse = 0.2
+scene.pov.radio_nearest_count = 8
+scene.pov.radio_normal = False
+scene.pov.radio_recursion_limit = 3
+scene.pov.radio_pretrace_start = 0.08
+scene.pov.radio_pretrace_end = 0.004
diff --git a/presets/pov/world/1_Clear_Blue_Sky.py b/presets/pov/world/1_Clear_Blue_Sky.py
new file mode 100644
index 0000000000000000000000000000000000000000..0dcd5e05f92137eb61ce6b9a407e07eb2a4ab0bd
--- /dev/null
+++ b/presets/pov/world/1_Clear_Blue_Sky.py
@@ -0,0 +1,36 @@
+import bpy
+scene = bpy.context.scene
+
+scene.world.use_sky_blend = True
+#below multiplied by two for a better proportion Clear vs Overcast sky 
+#since Clear sky is 19807 lux vs 2000 for overcast (sun is min 32000 max 100000)
+#http://www.pssurvival.com/PS/Lighting/Typical_LUX_Intensities_for_Day_and_Night-2017.pdf
+#https://en.wikipedia.org/wiki/Daylight
+#https://www.engineeringtoolbox.com/light-level-rooms-d_708.html
+#https://www.cactus2000.de/fr/unit/masslux.shtml
+#https://blendergrid.com/news/cycles-physically-correct-brightness
+#researched result blue is      
+    #Hue: 0.6
+    #Saturation: 0.533
+    #Lightness: 0.7
+#put scattering scale at 0.0002 and scattering color rgb <0.2061, 0.3933, 1.0>
+#with very small value like round rgb 0.00002 0.00002 0.00008
+#Sky color at zenith, sun 90° elevation = hsl <0.6, 0.533, 0.698>
+#Ground color = rgb <0.996, 0.965, 0.855>  = hsl <0.128, 0.141, 0.996>
+#Ground Brighness = 0.996
+
+scene.world.horizon_color = (0.047, 0.034, 0.025) #24000 or 22000 lux roughly equals (sun+sky)/5
+scene.world.zenith_color = (0.006, 0.013, 0.033) #19807 lux roughly equals hign noon Sun / 5
+scene.world.ambient_color = (0.0, 0.0, 0.0)
+scene.world.mist_settings.use_mist = False
+scene.world.mist_settings.intensity = 0.0
+scene.world.mist_settings.depth = 25.0
+scene.world.mist_settings.start = 5.0
+scene.pov.media_enable = True
+scene.pov.media_scattering_type = '4'
+scene.pov.media_samples = 35
+scene.pov.media_diffusion_scale = (0.00002)
+scene.pov.media_diffusion_color = (0.000001, 0.000002, 0.000005)
+scene.pov.media_absorption_scale = (0.00002)
+scene.pov.media_absorption_color = (0.0000006067, 0.0000007939, 0.0)#up to 0.00007
+scene.pov.media_eccentricity = 0.0
diff --git a/presets/pov/world/2_Partly_Hazy_Sky.py b/presets/pov/world/2_Partly_Hazy_Sky.py
new file mode 100644
index 0000000000000000000000000000000000000000..2f6b628d8ec42fe567b8a818e6ed4992204c9f42
--- /dev/null
+++ b/presets/pov/world/2_Partly_Hazy_Sky.py
@@ -0,0 +1,36 @@
+import bpy
+scene = bpy.context.scene
+
+scene.world.use_sky_blend = True
+#below multiplied by two for a better proportion Clear vs Overcast sky 
+#since Clear sky is 19807 lux vs 2000 for overcast (sun is min 32000 max 100000)
+#http://www.pssurvival.com/PS/Lighting/Typical_LUX_Intensities_for_Day_and_Night-2017.pdf
+#https://en.wikipedia.org/wiki/Daylight
+#https://www.engineeringtoolbox.com/light-level-rooms-d_708.html
+#https://www.cactus2000.de/fr/unit/masslux.shtml
+#https://blendergrid.com/news/cycles-physically-correct-brightness
+#researched result blue is      
+    #Hue: 0.6
+    #Saturation: 0.533
+    #Lightness: 0.7
+#put scattering scale at 0.0002 and scattering color rgb <0.2061, 0.3933, 1.0>
+#with very small value like round rgb 0.00002 0.00002 0.00008
+#Sky color at zenith, sun 90° elevation = hsl <0.6, 0.533, 0.698>
+#Ground color = rgb <0.996, 0.965, 0.855>  = hsl <0.128, 0.141, 0.996>
+#Ground Brighness = 0.996
+
+scene.world.horizon_color = (0.380, 0.262, 0.183) #24000 or 22000 lux roughly equals (sun+sky)/5 + urban light pollution
+scene.world.zenith_color = (0.006, 0.013, 0.033) #19807 lux roughly equals hign noon Sun / 5
+scene.world.ambient_color = (0.0, 0.0, 0.0)
+scene.world.mist_settings.use_mist = False
+scene.world.mist_settings.intensity = 0.0
+scene.world.mist_settings.depth = 25.0
+scene.world.mist_settings.start = 5.0
+scene.pov.media_enable = True
+scene.pov.media_scattering_type = '4'
+scene.pov.media_samples = 35
+scene.pov.media_diffusion_scale = (0.00002)
+scene.pov.media_diffusion_color = (0.000001, 0.000002, 0.000005)
+scene.pov.media_absorption_scale = (0.00002)
+scene.pov.media_absorption_color = (0.0000006067, 0.0000007939, 0.0)#up to 0.00007
+scene.pov.media_eccentricity = 0.0
diff --git a/presets/pov/world/3_Overcast_Sky.py b/presets/pov/world/3_Overcast_Sky.py
new file mode 100644
index 0000000000000000000000000000000000000000..013a5d40ce74d32e92810896643cc231ed69506c
--- /dev/null
+++ b/presets/pov/world/3_Overcast_Sky.py
@@ -0,0 +1,20 @@
+import bpy
+scene = bpy.context.scene
+
+scene.world.use_sky_blend = True
+scene.world.horizon_color = (0.477, 0.536, 0.604)
+#below divided by ten for a better proportion Clear vs Overcast sky 
+#since Clear sky is 20000 lux vs 2000 up to 10000 for overcast
+scene.world.zenith_color = (0.034, 0.043, 0.047)
+scene.world.ambient_color = (0.0, 0.0, 0.0)
+scene.world.mist_settings.use_mist = False
+scene.world.mist_settings.intensity = 0.0
+scene.world.mist_settings.depth = 25.0
+scene.world.mist_settings.start = 5.0
+scene.pov.media_enable = False
+scene.pov.media_scattering_type = '1'
+scene.pov.media_samples = 35
+scene.pov.media_diffusion_scale = (1.0)
+scene.pov.media_diffusion_color = (0.58, 0.66, 0.75)
+scene.pov.media_absorption_color = (0.0, 0.0, 0.0)
+scene.pov.media_eccentricity = 0.0
diff --git a/presets/pov/world/4_Cartoony_Sky.py b/presets/pov/world/4_Cartoony_Sky.py
new file mode 100644
index 0000000000000000000000000000000000000000..e3c552c0b534ee7c406ab35adcfd7fef72b01cc3
--- /dev/null
+++ b/presets/pov/world/4_Cartoony_Sky.py
@@ -0,0 +1,19 @@
+import bpy
+scene = bpy.context.scene
+
+scene.world.use_sky_blend = True
+#below multiplied by two for a better proportion Clear vs Overcast sky 
+#since Clear sky is 20000 lux vs 2000 for overcast
+scene.world.horizon_color = (0.350*2, 0.611*2, 1.0*2)
+scene.world.zenith_color = (0.05000000074505806*2, 0.125*2, 0.5*2)
+scene.world.ambient_color = (0.0, 0.0, 0.0)
+scene.world.mist_settings.use_mist = False
+scene.world.mist_settings.intensity = 0.0
+scene.world.mist_settings.depth = 25.0
+scene.world.mist_settings.start = 5.0
+scene.pov.media_enable = False
+scene.pov.media_scattering_type = '4'
+scene.pov.media_samples = 35
+scene.pov.media_diffusion_color = (0.20000000298023224, 0.4000000059604645, 1.0)
+scene.pov.media_absorption_color = (0.0, 0.0, 0.0)
+scene.pov.media_eccentricity = 0.0
\ No newline at end of file
diff --git a/presets/pov/world/5_Under_Water.py b/presets/pov/world/5_Under_Water.py
new file mode 100644
index 0000000000000000000000000000000000000000..e6659016755b08a679153c3de89ccf859dcc569e
--- /dev/null
+++ b/presets/pov/world/5_Under_Water.py
@@ -0,0 +1,19 @@
+import bpy
+scene = bpy.context.scene
+
+scene.world.use_sky_blend = True
+#below multiplied by two for a better proportion Clear vs Overcast sky 
+#since Clear sky is 20000 lux vs 2000 for overcast
+scene.world.horizon_color = (0.0, 0.0, 0.0)
+scene.world.zenith_color = (0.250980406999588, 0.6117647290229797, 1.0)
+scene.world.ambient_color = (0.0, 0.0, 0.0)
+scene.world.mist_settings.use_mist = False
+scene.world.mist_settings.intensity = 0.0
+scene.world.mist_settings.depth = 25.0
+scene.world.mist_settings.start = 5.0
+scene.pov.media_enable = True
+scene.pov.media_scattering_type = '5'
+scene.pov.media_samples = 35
+scene.pov.media_diffusion_color = (0.000034, 0.000034, 0.000017)
+scene.pov.media_absorption_color = (0.00000455, 0.00000165, 0.00000031)
+scene.pov.media_eccentricity = 0.7
\ No newline at end of file
diff --git a/render_povray/__init__.py b/render_povray/__init__.py
index cfb45f5a9c06cdc2e6d90efe80c755a30319e87c..90d80f13ea2e060ab9e867627f212daf316c1ff6 100644
--- a/render_povray/__init__.py
+++ b/render_povray/__init__.py
@@ -19,14 +19,13 @@
 # <pep8 compliant>
 
 bl_info = {
-    "name": "POVRAY-3.7",
+    "name": "POV-3.7",
     "author": "Campbell Barton, Silvio Falcinelli, Maurice Raybaud, "
               "Constantin Rahn, Bastien Montagne, Leonid Desyatkov",
-    "version": (0, 0, 9),
-    "blender": (2, 75, 0),
+    "version": (0, 1, 0),
+    "blender": (2, 79, 0),
     "location": "Render > Engine > POV-Ray 3.7",
     "description": "Basic POV-Ray 3.7 integration for blender",
-    "warning": "this script is RC",
     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
                 "Scripts/Render/POV-Ray",
     "category": "Render",
@@ -44,6 +43,7 @@ else:
     #import addon_utils # To use some other addons
     import nodeitems_utils #for Nodes
     from nodeitems_utils import NodeCategory, NodeItem #for Nodes
+    from bl_operators.presets import AddPresetBase    
     from bpy.types import (
             AddonPreferences,
             PropertyGroup,
@@ -73,6 +73,11 @@ def string_strip_hyphen(name):
 # Scene POV properties.
 ###############################################################################
 class RenderPovSettingsScene(PropertyGroup):
+    #Linux SDL-window enable
+    sdl_window_enable = BoolProperty(
+            name="Enable SDL window",
+            description="Enable the SDL window in Linux OS",
+            default=True)
     # File Options
     text_block = StringProperty(
             name="Text Scene Name",
@@ -121,7 +126,7 @@ class RenderPovSettingsScene(PropertyGroup):
     radio_enable = BoolProperty(
             name="Enable Radiosity",
             description="Enable POV-Rays radiosity calculation",
-            default=False)
+            default=True)
 
     radio_display_advanced = BoolProperty(
             name="Advanced Options",
@@ -132,19 +137,88 @@ class RenderPovSettingsScene(PropertyGroup):
             name="Enable Media",
             description="Enable POV-Rays atmospheric media",
             default=False)
+            
     media_samples = IntProperty(
             name="Samples",
             description="Number of samples taken from camera to first object "
                         "encountered along ray path for media calculation",
             min=1, max=100, default=35)
-
-    media_color = FloatVectorProperty(
-            name="Media Color", description="The atmospheric media color",
+            
+    media_scattering_type = EnumProperty(
+            name="Scattering Type",
+            description="Scattering model",
+            items=(('1', "1 Isotropic", "The simplest form of scattering because"
+                                      " it is independent of direction."),
+                   ('2', "2 Mie haze ", "For relatively small particles such as "
+                                      "minuscule water droplets of fog, cloud "
+                                      "particles, and particles responsible "
+                                      "for the polluted sky. In this model the"
+                                      " scattering is extremely directional in"
+                                      " the forward direction i.e. the amount "
+                                      "of scattered light is largest when the "
+                                      "incident light is anti-parallel to the "
+                                      "viewing direction (the light goes "
+                                      "directly to the viewer). It is smallest"
+                                      " when the incident light is parallel to"
+                                      " the viewing direction. "),
+                   ('3', "3 Mie murky", "Like haze but much more directional"),
+                   ('4', "4 Rayleigh", "For extremely small particles such as "
+                                     "molecules of the air. The amount of "
+                                     "scattered light depends on the incident"
+                                     " light angle. It is largest when the "
+                                     "incident light is parallel or "
+                                     "anti-parallel to the viewing direction "
+                                     "and smallest when the incident light is "
+                                     "perpendicular to viewing direction."),
+                   ('5', "5 Henyey-Greenstein", "The default eccentricity value "
+                                              "of zero defines isotropic "
+                                              "scattering while positive "
+                                              "values lead to scattering in "
+                                              "the direction of the light and "
+                                              "negative values lead to "
+                                              "scattering in the opposite "
+                                              "direction of the light. Larger "
+                                              "values of e (or smaller values "
+                                              "in the negative case) increase "
+                                              "the directional property of the"
+                                              " scattering.")),                   
+            default='1')
+           
+    media_diffusion_scale = FloatProperty(
+            name="Scale", description="Scale factor of Media Diffusion Color",
+            precision=12, step=0.00000001, min=0.000000001, max=1.0,
+            default=(1.0))
+            
+    media_diffusion_color = FloatVectorProperty(
+            name="Media Diffusion Color", description="The atmospheric media color",
             precision=4, step=0.01, min=0, soft_max=1,
             default=(0.001, 0.001, 0.001),
             options={'ANIMATABLE'},
             subtype='COLOR')
 
+    media_absorption_scale = FloatProperty(
+            name="Scale", description="Scale factor of Media Absorption Color. "
+                                      "use 1/depth of media volume in meters",
+            precision=12, step=0.000001, min=0.000000001, max=1.0,
+            default=(0.00002))
+            
+    media_absorption_color = FloatVectorProperty(
+            name="Media Absorption Color", description="The atmospheric media absorption color",
+            precision=4, step=0.01, min=0, soft_max=1,
+            default=(0.0, 0.0, 0.0),
+            options={'ANIMATABLE'},
+            subtype='COLOR')            
+
+    media_eccentricity = FloatProperty(
+            name="Media Eccenticity Factor", description="Positive values lead"
+                 " to scattering in the direction of the light and negative "
+                 "values lead to scattering in the opposite direction of the "
+                 "light. Larger values of e (or smaller values in the negative"
+                 " case) increase the directional property of the scattering.",
+            precision=2, step=0.01, min=-1.0, max=1.0,
+            default=(0.0),
+            options={'ANIMATABLE'})
+                       
     baking_enable = BoolProperty(
             name="Enable Baking",
             description="Enable POV-Rays texture baking",
@@ -377,7 +451,7 @@ class RenderPovSettingsScene(PropertyGroup):
             description="",
             maxlen=1024, subtype="FILE_PATH")
 
-
+    #########RADIOSITY########
     radio_adc_bailout = FloatProperty(
             name="ADC Bailout",
             description="The adc_bailout for radiosity rays. Use "
@@ -422,7 +496,7 @@ class RenderPovSettingsScene(PropertyGroup):
 
     radio_media = BoolProperty(
             name="Media", description="Radiosity estimation can be affected by media",
-            default=False)
+            default=True)
 
     radio_subsurface = BoolProperty(
             name="Subsurface", description="Radiosity estimation can be affected by Subsurface Light Transport",
@@ -468,7 +542,6 @@ class RenderPovSettingsScene(PropertyGroup):
                         "in the mosaic preview last pass",
             min=0.000925, max=1.00, soft_min=0.01, soft_max=1.00, default=0.04, precision=3)
 
-
 ###############################################################################
 # Material POV properties.
 ###############################################################################
@@ -2199,20 +2272,14 @@ class PovrayPreferences(AddonPreferences):
 
 
 
-
-
-
-
-
-
-
-
-
 def register():
     bpy.utils.register_module(__name__)
     bpy.types.INFO_MT_add.prepend(ui.menu_func_add)
     bpy.types.INFO_MT_file_import.append(ui.menu_func_import)
     bpy.types.TEXT_MT_templates.append(ui.menu_func_templates)
+    bpy.types.RENDER_PT_povray_radiosity.prepend(ui.rad_panel_func)
+    bpy.types.LAMP_PT_POV_lamp.prepend(ui.lamp_panel_func)
+    bpy.types.WORLD_PT_world.prepend(ui.world_panel_func)    
     # was used for parametric objects but made the other addon unreachable on
     # unregister for other tools to use created a user action call instead
     #addon_utils.enable("add_mesh_extra_objects", default_set=False, persistent=True)
@@ -2244,6 +2311,9 @@ def unregister():
 
     #bpy.types.TEXTURE_PT_context_texture.remove(TEXTURE_PT_povray_type)
     #addon_utils.disable("add_mesh_extra_objects", default_set=False)
+    bpy.types.WORLD_PT_world.remove(ui.world_panel_func)
+    bpy.types.LAMP_PT_POV_lamp.remove(ui.lamp_panel_func)    
+    bpy.types.RENDER_PT_povray_radiosity.remove(ui.rad_panel_func)
     bpy.types.TEXT_MT_templates.remove(ui.menu_func_templates)
     bpy.types.INFO_MT_file_import.remove(ui.menu_func_import)
     bpy.types.INFO_MT_add.remove(ui.menu_func_add)
diff --git a/render_povray/render.py b/render_povray/render.py
index d36957807d073dff8f120180e5b83b3bb5801455..9838f25db509033ccc3333cc5d6f84e3684a40e2 100644
--- a/render_povray/render.py
+++ b/render_povray/render.py
@@ -186,13 +186,17 @@ def safety(name, Level):
 ##############end safety string name material
 ##############################EndSF###########################
 
+csg_list = []
+
 def is_renderable(scene, ob):
-    return (ob.is_visible(scene) and not ob.hide_render)
+    return (ob.is_visible(scene) and not ob.hide_render and ob not in csg_list)
 
 
 def renderable_objects(scene):
     return [ob for ob in bpy.data.objects if is_renderable(scene, ob)]
 
+def no_renderable_objects(scene):
+    return [ob for ob in csg_list]
 
 tabLevel = 0
 unpacked_images=[]
@@ -628,7 +632,7 @@ def write_pov(filename, scene=None, info_callback=None):
                 tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
                 # Area lights have no falloff type, so always use blenders lamp quad equivalent
                 # for those?
-                tabWrite("fade_power %d\n" % 0)
+                tabWrite("fade_power %d\n" % 2)
                 size_x = lamp.size
                 samples_x = lamp.shadow_ray_samples_x
                 if lamp.shape == 'SQUARE':
@@ -1446,7 +1450,7 @@ def write_pov(filename, scene=None, info_callback=None):
             file.write('      BuildWriteMesh2(VecArr, NormArr, UVArr, Iter_U, Iter_V, FileName)\n')
             file.write('   #end\n')
             file.write('#end\n\n')
-        # Empty curves    
+        # Empty curves
         if len(ob.data.splines)==0:
             tabWrite("\n//dummy sphere to represent empty curve location\n")        
             tabWrite("#declare %s =\n"%dataname)
@@ -1793,7 +1797,7 @@ def write_pov(filename, scene=None, info_callback=None):
 #    objectNames = {}
     DEF_OBJ_NAME = "Default"
 
-    def exportMeshes(scene, sel):
+    def exportMeshes(scene, sel, csg):
 #        obmatslist = []
 #        def hasUniqueMaterial():
 #            # Grab materials attached to object instances ...
@@ -2416,7 +2420,7 @@ def write_pov(filename, scene=None, info_callback=None):
                     tabWrite("#declare %s = plane{ <0,0,1>,1\n"%povdataname)
                     povMatName = "Default_texture"
                     if ob.active_material:
-                         #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
+                        #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
                         try:
                             material = ob.active_material
                             writeObjectMaterial(material, ob)
@@ -3009,7 +3013,7 @@ def write_pov(filename, scene=None, info_callback=None):
                         # POV object modifiers such as 
                         # hollow / sturm / double_illuminate etc.
                         write_object_modifiers(scene,ob,file)                        
- 
+
                         #Importance for radiosity sampling added here:
                         tabWrite("radiosity { \n")
                         tabWrite("importance %3g \n" % importance)
@@ -3254,7 +3258,7 @@ def write_pov(filename, scene=None, info_callback=None):
                                                         ob.pov.inside_vector[1],
                                                         ob.pov.inside_vector[2]))
                                             onceCSG = 1
- 
+
                         if me.materials:
                             try:
                                 material = me.materials[0]  # dodgy
@@ -3277,38 +3281,69 @@ def write_pov(filename, scene=None, info_callback=None):
 
                     bpy.data.meshes.remove(me)
 
-        duplidata_ref = []
-        for ob in sel:
-            #matrix = global_matrix * ob.matrix_world
-            if ob.is_duplicator:
-                tabWrite("\n//--DupliObjects in %s--\n\n"% ob.name)
-                ob.dupli_list_create(scene)
-                dup = ""
-                if ob.is_modified(scene, 'RENDER'):
-                    #modified object always unique so using object name rather than data name
-                    dup = "#declare OB%s = union{\n" %(string_strip_hyphen(bpy.path.clean_name(ob.name)))
+        if csg:
+            duplidata_ref = []
+            for ob in sel:
+                #matrix = global_matrix * ob.matrix_world
+                if ob.is_duplicator:
+                    tabWrite("\n//--DupliObjects in %s--\n\n"% ob.name)
+                    ob.dupli_list_create(scene)
+                    dup = ""
+                    if ob.is_modified(scene, 'RENDER'):
+                        #modified object always unique so using object name rather than data name
+                        dup = "#declare OB%s = union{\n" %(string_strip_hyphen(bpy.path.clean_name(ob.name)))
+                    else:
+                        dup = "#declare DATA%s = union{\n" %(string_strip_hyphen(bpy.path.clean_name(ob.name)))
+                    for eachduplicate in ob.dupli_list:
+                        duplidataname = "OB"+string_strip_hyphen(bpy.path.clean_name(bpy.data.objects[eachduplicate.object.name].data.name))
+                        dup += ("\tobject {\n\t\tDATA%s\n\t\t%s\t}\n" %(string_strip_hyphen(bpy.path.clean_name(bpy.data.objects[eachduplicate.object.name].data.name)), MatrixAsPovString(ob.matrix_world.inverted() * eachduplicate.matrix)))
+                        #add object to a list so that it is not rendered for some dupli_types
+                        if ob.dupli_type not in {'GROUP'} and duplidataname not in duplidata_ref:
+                            duplidata_ref.append(duplidataname) #older key [string_strip_hyphen(bpy.path.clean_name("OB"+ob.name))]
+                    dup += "}\n"
+                    ob.dupli_list_clear()
+                    tabWrite(dup)
                 else:
-                    dup = "#declare DATA%s = union{\n" %(string_strip_hyphen(bpy.path.clean_name(ob.name)))
-                for eachduplicate in ob.dupli_list:
-                    duplidataname = "OB"+string_strip_hyphen(bpy.path.clean_name(bpy.data.objects[eachduplicate.object.name].data.name))
-                    dup += ("\tobject {\n\t\tDATA%s\n\t\t%s\t}\n" %(string_strip_hyphen(bpy.path.clean_name(bpy.data.objects[eachduplicate.object.name].data.name)), MatrixAsPovString(ob.matrix_world.inverted() * eachduplicate.matrix)))
-                    #add object to a list so that it is not rendered for some dupli_types
-                    if ob.dupli_type not in {'GROUP'} and duplidataname not in duplidata_ref:
-                        duplidata_ref.append(duplidataname) #older key [string_strip_hyphen(bpy.path.clean_name("OB"+ob.name))]
-                dup += "}\n"
-                ob.dupli_list_clear()
-                tabWrite(dup)
-            else:
-                continue
-        print(duplidata_ref)
-        for data_name, inst in data_ref.items():
-            for ob_name, matrix_str in inst:
-                if ob_name not in duplidata_ref: #.items() for a dictionary
-                    tabWrite("\n//----Blender Object Name:%s----\n" % ob_name)
-                    tabWrite("object { \n")
-                    tabWrite("%s\n" % data_name)
-                    tabWrite("%s\n" % matrix_str)
-                    tabWrite("}\n")
+                    continue
+            print(duplidata_ref)
+            for data_name, inst in data_ref.items():
+                for ob_name, matrix_str in inst:
+                    if ob_name not in duplidata_ref: #.items() for a dictionary
+                        tabWrite("\n//----Blender Object Name:%s----\n" % ob_name)
+                        if ob.pov.object_as == '':
+                            tabWrite("object { \n")
+                            tabWrite("%s\n" % data_name)
+                            tabWrite("%s\n" % matrix_str)
+                            tabWrite("}\n")
+                        else:
+                            no_boolean = True
+                            for mod in ob.modifiers:
+                                if mod.type == 'BOOLEAN':
+                                    operation = None
+                                    no_boolean = False
+                                    if mod.operation == 'INTERSECT':
+                                        operation = 'intersection'
+                                    else:
+                                        operation = mod.operation.lower()
+                                    mod_ob_name = string_strip_hyphen(bpy.path.clean_name(mod.object.name))
+                                    mod_matrix = global_matrix * mod.object.matrix_world
+                                    mod_ob_matrix = MatrixAsPovString(mod_matrix)
+                                    tabWrite("%s { \n"%operation)
+                                    tabWrite("object { \n")
+                                    tabWrite("%s\n" % data_name)
+                                    tabWrite("%s\n" % matrix_str)
+                                    tabWrite("}\n")
+                                    tabWrite("object { \n")
+                                    tabWrite("%s\n" % ('DATA'+ mod_ob_name))
+                                    tabWrite("%s\n" % mod_ob_matrix)
+                                    tabWrite("}\n")
+                                    tabWrite("}\n")
+                                    break
+                            if no_boolean:
+                                tabWrite("object { \n")
+                                tabWrite("%s\n" % data_name)
+                                tabWrite("%s\n" % matrix_str)
+                                tabWrite("}\n")
 
     def exportWorld(world):
         render = scene.render
@@ -3444,18 +3479,33 @@ def write_pov(filename, scene=None, info_callback=None):
 
         if mist.use_mist:
             tabWrite("fog {\n")
-            tabWrite("distance %.6f\n" % mist.depth)
+            if mist.falloff=='LINEAR':
+                tabWrite("distance %.6f\n" % ((mist.start+mist.depth)*0.368))
+            elif mist.falloff=='QUADRATIC':    # n**2 or squrt(n)?
+                tabWrite("distance %.6f\n" % ((mist.start+mist.depth)**2*0.368))
+            elif mist.falloff=='INVERSE_QUADRATIC':    # n**2 or squrt(n)?
+                tabWrite("distance %.6f\n" % ((mist.start+mist.depth)**2*0.368))                
             tabWrite("color rgbt<%.3g, %.3g, %.3g, %.3g>\n" % \
                      (*world.horizon_color, 1.0 - mist.intensity))
-            #tabWrite("fog_offset %.6f\n" % mist.start)
-            #tabWrite("fog_alt 5\n")
+            #tabWrite("fog_offset %.6f\n" % mist.start) #create a pov property to prepend
+            #tabWrite("fog_alt %.6f\n" % mist.height) #XXX right?
             #tabWrite("turbulence 0.2\n")
             #tabWrite("turb_depth 0.3\n")
-            tabWrite("fog_type 1\n")
+            tabWrite("fog_type 1\n") #type2 for height
             tabWrite("}\n")
         if scene.pov.media_enable:
             tabWrite("media {\n")
-            tabWrite("scattering { 1, rgb <%.4g, %.4g, %.4g>}\n" % scene.pov.media_color[:])
+            tabWrite("scattering { %d, rgb %.12f*<%.4g, %.4g, %.4g>\n" % \
+                     (int(scene.pov.media_scattering_type),
+                     (scene.pov.media_diffusion_scale),                     
+                     *(scene.pov.media_diffusion_color[:])))
+            if scene.pov.media_scattering_type == '5':
+                tabWrite("eccentricity %.3g\n" % scene.pov.media_eccentricity) 
+            tabWrite("}\n") 
+            tabWrite("absorption %.12f*<%.4g, %.4g, %.4g>\n" % \
+                     (scene.pov.media_absorption_scale,
+                     *(scene.pov.media_absorption_color[:]))) 
+            tabWrite("\n")             
             tabWrite("samples %.d\n" % scene.pov.media_samples)
             tabWrite("}\n")
 
@@ -3559,7 +3609,7 @@ def write_pov(filename, scene=None, info_callback=None):
                 file.write(txt.as_string())
                 file.write("\n")
 
-    sel = renderable_objects(scene)
+    #sel = renderable_objects(scene) #removed for booleans
     if comments:
         file.write("//----------------------------------------------\n" \
                    "//--Exported with POV-Ray exporter for Blender--\n" \
@@ -3602,6 +3652,20 @@ def write_pov(filename, scene=None, info_callback=None):
     if comments:
         file.write("\n//--Lamps--\n\n")
 
+    for ob in bpy.data.objects:
+        if ob.type == 'MESH':
+            for mod in ob.modifiers:
+                if mod.type == 'BOOLEAN':
+                    if mod.object not in csg_list:
+                        csg_list.append(mod.object)
+    if csg_list != []:
+        csg = False
+        sel = no_renderable_objects(scene)
+        exportMeshes(scene, sel, csg)
+
+    csg = True
+    sel = renderable_objects(scene)
+
     exportLamps([L for L in sel if (L.type == 'LAMP' and L.pov.object_as != 'RAINBOW')])
 
     if comments:
@@ -3655,7 +3719,7 @@ def write_pov(filename, scene=None, info_callback=None):
     if comments:
         file.write("//--Mesh objects--\n")
 
-    exportMeshes(scene, sel)
+    exportMeshes(scene, sel, csg)
 
     #What follow used to happen here:
     #exportCamera()
@@ -3745,7 +3809,7 @@ def write_pov_ini(scene, filename_ini, filename_log, filename_pov, filename_imag
 
 class PovrayRender(bpy.types.RenderEngine):
     bl_idname = 'POVRAY_RENDER'
-    bl_label = "POV-Ray 3.7"
+    bl_label = "Persitence Of Vision"
     DELAY = 0.5
 
     @staticmethod
@@ -3951,8 +4015,8 @@ class PovrayRender(bpy.types.RenderEngine):
                 self._temp_file_in = os.path.join(preview_dir, povPath)
                 self._temp_file_ini = os.path.join(preview_dir, (os.path.splitext(self._temp_file_in)[0]+".INI"))
                 self._temp_file_log = os.path.join(preview_dir, "alltext.out")
-        
-        
+
+
             '''
             try:
                 os.remove(self._temp_file_in)  # so as not to load the old file
@@ -4000,7 +4064,14 @@ class PovrayRender(bpy.types.RenderEngine):
 
             # Start Rendering!
             try:
-                _process = subprocess.Popen([pov_binary, self._temp_file_ini] + extra_args,
+                if sys.platform[:3] != "win" and scene.pov.sdl_window_enable: #segfault on linux == False !!!
+                    env = {'POV_DISPLAY_SCALED': 'off'}
+                    env.update(os.environ)
+                    self._process = subprocess.Popen([pov_binary, self._temp_file_ini],
+                        stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+                        env=env)
+                else:
+                    self._process = subprocess.Popen([pov_binary, self._temp_file_ini] + extra_args,
                                                  stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
             except OSError:
                 # TODO, report api
@@ -4015,7 +4086,7 @@ class PovrayRender(bpy.types.RenderEngine):
                 print("Command line arguments passed: " + str(extra_args))
                 #return True
                 self.update_stats("", "POV-Ray 3.7: Parsing File")                  
- 
+
 
                 
             # Indented in main function now so repeated here but still not working 
@@ -4040,7 +4111,7 @@ class PovrayRender(bpy.types.RenderEngine):
                 print(f.read()) 
                 
             self.update_stats("", "")
-            
+
             if scene.pov.tempfiles_enable or scene.pov.deletefiles_enable:
                 self._cleanup()            
         else:
@@ -4394,7 +4465,7 @@ class RunPovTextRender(Operator):
 
             
         bpy.ops.render.render()
- 
+
         #empty text name property engain
         scene.pov.text_block = ""
-        return {'FINISHED'}    
\ No newline at end of file
+        return {'FINISHED'}
\ No newline at end of file
diff --git a/render_povray/shading.py b/render_povray/shading.py
index 5a37170753f5cdff742815929de858debd9941cd..03a63a9d299c7b784feb74dd8616d6846598f90c 100644
--- a/render_povray/shading.py
+++ b/render_povray/shading.py
@@ -245,13 +245,11 @@ def writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments
         for t in material.texture_slots:
             if t and t.use and t.texture is not None:
                 if (t.texture.type == 'IMAGE' and t.texture.image) or t.texture.type != 'IMAGE':
-                    validPath=True
-            else:
-                validPath=False
-            if(t and t.use and validPath and
-               (t.use_map_specular or t.use_map_raymir or t.use_map_normal or t.use_map_alpha)):
-                special_texture_found = True
-                continue  # Some texture found
+                    #validPath
+                    if(t and t.use and
+                       (t.use_map_specular or t.use_map_raymir or t.use_map_normal or t.use_map_alpha)):
+                        special_texture_found = True
+                        continue  # Some texture found
 
         if special_texture_found or colored_specular_found:
             # Level=1 Means No specular nor Mirror reflection
@@ -1087,7 +1085,6 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
         else:
             if texturesDif and texturesDif.startswith("PAT_"):
                 tabWrite("pigment{%s %s}\n" %(texturesDif, mappingDif))
-                print('XXXMEEEERDE!')
             else:
                 tabWrite("pigment {\n")
                 tabWrite("uv_mapping image_map {\n")
diff --git a/render_povray/ui.py b/render_povray/ui.py
index ca6a5db2e59c2cd6150dc12147e3b366ddec0c6c..b4a082924bd69faeeb41a1d9e037519e9c97760c 100644
--- a/render_povray/ui.py
+++ b/render_povray/ui.py
@@ -22,6 +22,7 @@ import bpy
 import sys #really import here and in render.py?
 import os #really import here and in render.py?
 from os.path import isfile
+from bl_operators.presets import AddPresetBase
 
 # Use some of the existing buttons.
 from bl_ui import properties_render
@@ -41,6 +42,61 @@ properties_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER')
 properties_world.WORLD_PT_mist.COMPAT_ENGINES.add('POVRAY_RENDER')
 del properties_world
 
+class POV_WORLD_MT_presets(bpy.types.Menu):
+    bl_label = "World Presets"
+    preset_subdir = "pov/world"
+    preset_operator = "script.execute_preset"
+    draw = bpy.types.Menu.draw_preset
+
+
+class AddPresetWorld(AddPresetBase, bpy.types.Operator):
+    '''Add a World Preset'''
+    bl_idname = "object.world_preset_add"
+    bl_label = "Add World Preset"
+    preset_menu = "POV_WORLD_MT_presets"
+
+    # variable used for all preset values
+    preset_defines = [
+        "scene = bpy.context.scene"    
+        ]
+
+    # properties to store in the preset
+    preset_values = [
+        "scene.world.use_sky_blend",
+        "scene.world.horizon_color",
+        "scene.world.zenith_color", 
+        "scene.world.ambient_color",
+        "scene.world.mist_settings.use_mist",
+        "scene.world.mist_settings.intensity",
+        "scene.world.mist_settings.depth",        
+        "scene.world.mist_settings.start",
+        "scene.pov.media_enable",
+        "scene.pov.media_scattering_type", 
+        "scene.pov.media_samples",
+        "scene.pov.media_diffusion_scale",
+        "scene.pov.media_diffusion_color",
+        "scene.pov.media_absorption_scale",
+        "scene.pov.media_absorption_color",
+        "scene.pov.media_eccentricity",        
+        ]
+
+    # where to store the preset
+    preset_subdir = "pov/world"
+
+# Draw into an existing panel
+def world_panel_func(self, context):
+    layout = self.layout
+
+    row = layout.row(align=True)
+    row.menu(POV_WORLD_MT_presets.__name__, text=POV_WORLD_MT_presets.bl_label)
+    row.operator(AddPresetWorld.bl_idname, text="", icon='ZOOMIN')
+    row.operator(AddPresetWorld.bl_idname, text="", icon='ZOOMOUT').remove_active = True
+
+
+classes = (
+    POV_WORLD_MT_presets,
+    AddPresetWorld,
+    )  
 
 # Example of wrapping every class 'as is'
 from bl_ui import properties_texture
@@ -450,6 +506,52 @@ class LAMP_PT_POV_lamp(PovLampButtonsPanel, bpy.types.Panel):
 
     draw = properties_data_lamp.DATA_PT_lamp.draw
 
+class POV_LAMP_MT_presets(bpy.types.Menu):
+    bl_label = "Lamp Presets"
+    preset_subdir = "pov/lamp"
+    preset_operator = "script.execute_preset"
+    draw = bpy.types.Menu.draw_preset
+
+
+class AddPresetLamp(AddPresetBase, bpy.types.Operator):
+    '''Add a Lamp Preset'''
+    bl_idname = "object.lamp_preset_add"
+    bl_label = "Add Lamp Preset"
+    preset_menu = "POV_LAMP_MT_presets"
+
+    # variable used for all preset values
+    preset_defines = [
+        "lampdata = bpy.context.object.data"
+        ]
+
+    # properties to store in the preset
+    preset_values = [
+        "lampdata.type",
+        "lampdata.color",      
+        ]
+
+    # where to store the preset
+    preset_subdir = "pov/lamp"
+
+
+
+
+
+# Draw into an existing panel
+def lamp_panel_func(self, context):
+    layout = self.layout
+
+    row = layout.row(align=True)
+    row.menu(POV_LAMP_MT_presets.__name__, text=POV_LAMP_MT_presets.bl_label)
+    row.operator(AddPresetLamp.bl_idname, text="", icon='ZOOMIN')
+    row.operator(AddPresetLamp.bl_idname, text="", icon='ZOOMOUT').remove_active = True
+
+
+classes = (
+    POV_LAMP_MT_presets,
+    AddPresetLamp,
+    )    
+    
 class LAMP_PT_POV_sunsky(PovLampButtonsPanel, bpy.types.Panel):
     bl_label = properties_data_lamp.DATA_PT_sunsky.bl_label
 
@@ -606,7 +708,10 @@ class RENDER_PT_povray_render_settings(RenderButtonsPanel, bpy.types.Panel):
 
         scene = context.scene
         #layout.active = (scene.pov.max_trace_level != 0)
-
+        
+        if sys.platform[:3] != "win":
+            layout.prop(scene.pov, "sdl_window_enable", text="POV-Ray SDL Window")
+            
         col = layout.column()
 
         col.label(text="Global Settings:")
@@ -784,7 +889,71 @@ class RENDER_PT_povray_radiosity(RenderButtonsPanel, bpy.types.Panel):
             col.prop(scene.pov, "radio_subsurface")
 
 
-
+            
+            
+            
+class POV_RADIOSITY_MT_presets(bpy.types.Menu):
+    bl_label = "Radiosity Presets"
+    preset_subdir = "pov/radiosity"
+    preset_operator = "script.execute_preset"
+    draw = bpy.types.Menu.draw_preset
+
+
+class AddPresetRadiosity(AddPresetBase, bpy.types.Operator):
+    '''Add a Radiosity Preset'''
+    bl_idname = "scene.radiosity_preset_add"
+    bl_label = "Add Radiosity Preset"
+    preset_menu = "POV_RADIOSITY_MT_presets"
+
+    # variable used for all preset values
+    preset_defines = [
+        "scene = bpy.context.scene"
+        ]
+
+    # properties to store in the preset
+    preset_values = [
+        "scene.pov.radio_display_advanced",    
+        "scene.pov.radio_adc_bailout",
+        "scene.pov.radio_always_sample",
+        "scene.pov.radio_brightness",
+        "scene.pov.radio_count",
+        "scene.pov.radio_error_bound",
+        "scene.pov.radio_gray_threshold",
+        "scene.pov.radio_low_error_factor",
+        "scene.pov.radio_media",
+        "scene.pov.radio_subsurface",
+        "scene.pov.radio_minimum_reuse",
+        "scene.pov.radio_maximum_reuse",
+        "scene.pov.radio_nearest_count",
+        "scene.pov.radio_normal",
+        "scene.pov.radio_recursion_limit",
+        "scene.pov.radio_pretrace_start",
+        "scene.pov.radio_pretrace_end",     
+        ]
+
+    # where to store the preset
+    preset_subdir = "pov/radiosity"
+
+
+
+
+
+# Draw into an existing panel
+def rad_panel_func(self, context):
+    layout = self.layout
+
+    row = layout.row(align=True)
+    row.menu(POV_RADIOSITY_MT_presets.__name__, text=POV_RADIOSITY_MT_presets.bl_label)
+    row.operator(AddPresetRadiosity.bl_idname, text="", icon='ZOOMIN')
+    row.operator(AddPresetRadiosity.bl_idname, text="", icon='ZOOMOUT').remove_active = True
+
+
+classes = (
+    POV_RADIOSITY_MT_presets,
+    AddPresetRadiosity,
+    )
+    
+    
 class RENDER_PT_povray_media(WorldButtonsPanel, bpy.types.Panel):
     bl_label = "Atmosphere Media"
     COMPAT_ENGINES = {'POVRAY_RENDER'}
@@ -801,10 +970,22 @@ class RENDER_PT_povray_media(WorldButtonsPanel, bpy.types.Panel):
 
         layout.active = scene.pov.media_enable
 
-        row = layout.row()
-        row.prop(scene.pov, "media_samples", text="Samples")
-        row.prop(scene.pov, "media_color", text="")
-
+        col = layout.column()
+        col.prop(scene.pov, "media_scattering_type", text="")
+        col = layout.column()
+        col.prop(scene.pov, "media_samples", text="Samples")
+        split = layout.split()        
+        col = split.column(align=True)
+        col.label(text="Scattering:")
+        col.prop(scene.pov, "media_diffusion_scale")
+        col.prop(scene.pov, "media_diffusion_color", text="")
+        col = split.column(align=True)
+        col.label(text="Absorption:")
+        col.prop(scene.pov, "media_absorption_scale")        
+        col.prop(scene.pov, "media_absorption_color", text="")
+        if scene.pov.media_scattering_type == '5':
+            col = layout.column()
+            col.prop(scene.pov, "media_eccentricity", text="Eccentricity")
 ##class RENDER_PT_povray_baking(RenderButtonsPanel, bpy.types.Panel):
 ##    bl_label = "Baking"
 ##    COMPAT_ENGINES = {'POVRAY_RENDER'}
@@ -821,7 +1002,7 @@ class RENDER_PT_povray_media(WorldButtonsPanel, bpy.types.Panel):
 ##        rd = scene.render
 ##
 ##        layout.active = scene.pov.baking_enable
-'''XXX WIP preparing for CSG
+
 class MODIFIERS_PT_povray_modifiers(ModifierButtonsPanel, bpy.types.Panel):
     bl_label = "POV-Ray"
     COMPAT_ENGINES = {'POVRAY_RENDER'}
@@ -850,7 +1031,7 @@ class MODIFIERS_PT_povray_modifiers(ModifierButtonsPanel, bpy.types.Panel):
                         col = layout.column()
                         # Inside Vector for CSG
                         col.prop(ob.pov, "inside_vector")
-'''        
+       
 
 class MATERIAL_PT_povray_activate_node(MaterialButtonsPanel, bpy.types.Panel):
     bl_label = "Activate Node Settings"
diff --git a/space_view3d_stored_views/__init__.py b/space_view3d_stored_views/__init__.py
index 8deca8f00e5b8d8ec52e71888f629a0e2d889c57..a9767bff26459fff0a6be5f807edf58a7a20f507 100644
--- a/space_view3d_stored_views/__init__.py
+++ b/space_view3d_stored_views/__init__.py
@@ -20,13 +20,14 @@ bl_info = {
     "name": "Stored Views",
     "description": "Save and restore User defined views, pov, layers and display configs",
     "author": "nfloyd, Francesco Siddi",
-    "version": (0, 3, 6),
+    "version": (0, 3, 7),
     "blender": (2, 7, 8),
     "location": "View3D > Properties > Stored Views",
     "warning": "",
     "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.5/"
                 "Py/Scripts/3D_interaction/stored_views",
-    "category": "3D View"}
+    "category": "3D View"
+}
 
 """
 ACKNOWLEDGMENT
@@ -65,14 +66,14 @@ else:
 
 import bpy
 from bpy.props import (
-        BoolProperty,
-        IntProperty,
-        PointerProperty,
-        )
+    BoolProperty,
+    IntProperty,
+    PointerProperty,
+)
 from bpy.types import (
-        AddonPreferences,
-        Operator,
-        )
+    AddonPreferences,
+    Operator,
+)
 
 
 class VIEW3D_stored_views_initialize(Operator):
@@ -99,20 +100,20 @@ class VIEW3D_stored_views_preferences(AddonPreferences):
     bl_idname = __name__
 
     show_exporters = BoolProperty(
-            name="Enable I/O Operators",
-            default=False,
-            description="Enable Import/Export Operations in the UI:\n"
-                        "Import Stored Views preset,\n"
-                        "Export Stored Views preset and \n"
-                        "Import stored views from scene",
-            )
+        name="Enable I/O Operators",
+        default=False,
+        description="Enable Import/Export Operations in the UI:\n"
+                    "Import Stored Views preset,\n"
+                    "Export Stored Views preset and \n"
+                    "Import stored views from scene",
+    )
     view_3d_update_rate = IntProperty(
-            name="3D view update",
-            description="Update rate of the 3D view redraw\n"
-                        "Increse the value if the UI feels sluggish",
-            min=1, max=10,
-            default=1
-            )
+        name="3D view update",
+        description="Update rate of the 3D view redraw\n"
+                    "Increse the value if the UI feels sluggish",
+        min=1, max=10,
+        default=1
+    )
 
     def draw(self, context):
         layout = self.layout
diff --git a/space_view3d_stored_views/io.py b/space_view3d_stored_views/io.py
index b6aec4dd5b27313cd8c5d5f6ea6c5ded25b939e1..e9c325ffa0fc01c725628b037934f628a490e848 100644
--- a/space_view3d_stored_views/io.py
+++ b/space_view3d_stored_views/io.py
@@ -8,13 +8,13 @@ import shutil
 import bpy
 from bpy.types import Operator
 from bpy.props import (
-        BoolProperty,
-        StringProperty
-        )
+    BoolProperty,
+    StringProperty,
+)
 from bpy_extras.io_utils import (
-        ExportHelper,
-        ImportHelper,
-        )
+    ExportHelper,
+    ImportHelper,
+)
 from . import bl_info
 from .core import get_preferences
 from .operators import DataStore
@@ -162,11 +162,12 @@ class IO_Utils():
             return False
 
         # io_filters = sv.settings.io_filters
-        sv_data = {"point_of_views": sv.pov_list,
-                   "views": sv.view_list,
-                   "layers": sv.layers_list,
-                   "displays": sv.display_list}
-
+        sv_data = {
+            "point_of_views": sv.pov_list,
+            "views": sv.view_list,
+            "layers": sv.layers_list,
+            "displays": sv.display_list
+        }
         for sv_struct, props in dump["data"].items():
             """
             is_filtered = getattr(io_filters, sv_struct)
@@ -203,20 +204,20 @@ class IO_Utils():
 
 
 class VIEW3D_stored_views_import(Operator, ImportHelper):
-    bl_idname = "stored_views.import"
+    bl_idname = "stored_views.import_blsv"
     bl_label = "Import Stored Views preset"
     bl_description = "Import a .blsv preset file to the current Stored Views"
 
     filename_ext = ".blsv"
     filter_glob = StringProperty(
-            default="*.blsv",
-            options={'HIDDEN'}
-            )
+        default="*.blsv",
+        options={'HIDDEN'}
+    )
     replace = BoolProperty(
-            name="Replace",
-            default=True,
-            description="Replace current stored views, otherwise append"
-            )
+        name="Replace",
+        default=True,
+        description="Replace current stored views, otherwise append"
+    )
 
     @classmethod
     def poll(cls, context):
@@ -227,7 +228,7 @@ class VIEW3D_stored_views_import(Operator, ImportHelper):
         exists = os.path.isfile(self.filepath) if self.filepath else False
         if not exists:
             self.report({'WARNING'},
-                        "No filepath specified, or file could not be found. Operation Cancelled")
+                        "No filepath specified or file could not be found. Operation Cancelled")
             return {'CANCELLED'}
 
         # apply chosen preset
@@ -258,15 +259,15 @@ class VIEW3D_stored_views_import_from_scene(Operator):
     bl_description = "Import currently stored views from an another scene"
 
     scene_name = StringProperty(
-            name="Scene Name",
-            description="A current blend scene",
-            default=""
-            )
+        name="Scene Name",
+        description="A current blend scene",
+        default=""
+    )
     replace = BoolProperty(
-            name="Replace",
-            default=True,
-            description="Replace current stored views, otherwise append"
-            )
+        name="Replace",
+        default=True,
+        description="Replace current stored views, otherwise append"
+    )
 
     @classmethod
     def poll(cls, context):
@@ -300,23 +301,23 @@ class VIEW3D_stored_views_import_from_scene(Operator):
 
 
 class VIEW3D_stored_views_export(Operator, ExportHelper):
-    bl_idname = "stored_views.export"
+    bl_idname = "stored_views.export_blsv"
     bl_label = "Export Stored Views preset"
     bl_description = "Export the current Stored Views to a .blsv preset file"
 
     filename_ext = ".blsv"
     filepath = StringProperty(
-            default=os.path.join(IO_Utils.get_preset_path()[0], "untitled")
-            )
+        default=os.path.join(IO_Utils.get_preset_path()[0], "untitled")
+    )
     filter_glob = StringProperty(
-            default="*.blsv",
-            options={'HIDDEN'}
-            )
+        default="*.blsv",
+        options={'HIDDEN'}
+    )
     preset_name = StringProperty(
-            name="Preset name",
-            default="",
-            description="Name of the stored views preset"
-            )
+        name="Preset name",
+        default="",
+        description="Name of the stored views preset"
+    )
 
     @classmethod
     def poll(cls, context):
@@ -324,4 +325,5 @@ class VIEW3D_stored_views_export(Operator, ExportHelper):
 
     def execute(self, context):
         IO_Utils.stored_views_export_to_blsv(self.filepath, self.preset_name)
+
         return{'FINISHED'}
diff --git a/space_view3d_stored_views/ui.py b/space_view3d_stored_views/ui.py
index 17d8c729857a296c487296a4e1bdf9f7a4415d40..5025db191408c2d4c3dffa1244212c6690d416bb 100644
--- a/space_view3d_stored_views/ui.py
+++ b/space_view3d_stored_views/ui.py
@@ -7,9 +7,9 @@ import bpy
 import blf
 from . import core
 from bpy.types import (
-        Operator,
-        Panel,
-        )
+    Operator,
+    Panel,
+)
 
 """
   If view name display is enabled,
@@ -185,8 +185,8 @@ class VIEW3D_PT_properties_stored_views(Panel):
         if core.get_preferences():
             row = layout.row(align=True)
             row.operator("stored_views.import_from_scene", text="Import from Scene")
-            row.operator("stored_views.import", text="", icon="IMPORT")
-            row.operator("stored_views.export", text="", icon="EXPORT")
+            row.operator("stored_views.import_blsv", text="", icon="IMPORT")
+            row.operator("stored_views.export_blsv", text="", icon="EXPORT")
 
         data_store = core.DataStore()
         list = data_store.list
diff --git a/ui_layer_manager.py b/ui_layer_manager.py
index b354b1ec3917d2c97b22ebee48b9bbe349fc3d00..018aad2658c53deca8c2fec59b03f4fda50eac66 100644
--- a/ui_layer_manager.py
+++ b/ui_layer_manager.py
@@ -364,7 +364,7 @@ class SCENE_OT_namedlayer_select_objects_by_layer(Operator):
                 for obj in objects:
                     obj.select = False
             else:
-                bpy.ops.object.select_by_layer(extend=self.extend, layers=layer_idx + 1)
+                bpy.ops.object.select_by_layer(match='SHARED', extend=self.extend, layers=layer_idx + 1)
 
         return {'FINISHED'}
 
diff --git a/uv_magic_uv/__init__.py b/uv_magic_uv/__init__.py
index 171a5ac4fb66aa7debfe332f441fd14f1ddf6a3d..080d2414fbf5b2e27f81eef620c1cbd80890a1d5 100644
--- a/uv_magic_uv/__init__.py
+++ b/uv_magic_uv/__init__.py
@@ -20,18 +20,18 @@
 
 __author__ = "Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 
 bl_info = {
     "name": "Magic UV",
-    "author": "Nutti, Mifth, Jace Priester, kgeogeo, mem, "
+    "author": "Nutti, Mifth, Jace Priester, kgeogeo, mem, imdjs"
               "Keith (Wahooney) Boshoff, McBuff, MaxRobinot, Alexander Milovsky",
-    "version": (4, 5, 0),
+    "version": (5, 1, 0),
     "blender": (2, 79, 0),
     "location": "See Add-ons Preferences",
-    "description": "UV Manipulator Tools. See Add-ons Preferences for details",
+    "description": "UV Toolset. See Add-ons Preferences for details",
     "warning": "",
     "support": "COMMUNITY",
     "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/"
@@ -42,98 +42,29 @@ bl_info = {
 
 if "bpy" in locals():
     import importlib
-    importlib.reload(muv_preferences)
-    importlib.reload(muv_menu)
-    importlib.reload(muv_common)
-    importlib.reload(muv_props)
-    importlib.reload(muv_cpuv_ops)
-    importlib.reload(muv_cpuv_selseq_ops)
-    importlib.reload(muv_fliprot_ops)
-    importlib.reload(muv_transuv_ops)
-    importlib.reload(muv_uvbb_ops)
-    importlib.reload(muv_mvuv_ops)
-    importlib.reload(muv_texproj_ops)
-    importlib.reload(muv_packuv_ops)
-    importlib.reload(muv_texlock_ops)
-    importlib.reload(muv_mirroruv_ops)
-    importlib.reload(muv_wsuv_ops)
-    importlib.reload(muv_unwrapconst_ops)
-    importlib.reload(muv_preserve_uv_aspect)
-    importlib.reload(muv_uvw_ops)
+    importlib.reload(op)
+    importlib.reload(ui)
+    importlib.reload(common)
+    importlib.reload(preferences)
+    importlib.reload(properites)
 else:
-    from . import muv_preferences
-    from . import muv_menu
-    from . import muv_common
-    from . import muv_props
-    from . import muv_cpuv_ops
-    from . import muv_cpuv_selseq_ops
-    from . import muv_fliprot_ops
-    from . import muv_transuv_ops
-    from . import muv_uvbb_ops
-    from . import muv_mvuv_ops
-    from . import muv_texproj_ops
-    from . import muv_packuv_ops
-    from . import muv_texlock_ops
-    from . import muv_mirroruv_ops
-    from . import muv_wsuv_ops
-    from . import muv_unwrapconst_ops
-    from . import muv_preserve_uv_aspect
-    from . import muv_uvw_ops
+    from . import op
+    from . import ui
+    from . import common
+    from . import preferences
+    from . import properites
 
 import bpy
 
 
-def view3d_uvmap_menu_fn(self, context):
-    self.layout.separator()
-    self.layout.menu(muv_menu.MUV_CPUVMenu.bl_idname, icon="IMAGE_COL")
-    self.layout.operator(
-        muv_fliprot_ops.MUV_FlipRot.bl_idname, icon="IMAGE_COL")
-    self.layout.menu(muv_menu.MUV_TransUVMenu.bl_idname, icon="IMAGE_COL")
-    self.layout.operator(muv_mvuv_ops.MUV_MVUV.bl_idname, icon="IMAGE_COL")
-    self.layout.menu(muv_menu.MUV_TexLockMenu.bl_idname, icon="IMAGE_COL")
-    self.layout.operator(
-        muv_mirroruv_ops.MUV_MirrorUV.bl_idname, icon="IMAGE_COL")
-    self.layout.menu(muv_menu.MUV_WSUVMenu.bl_idname, icon="IMAGE_COL")
-    self.layout.operator(
-        muv_unwrapconst_ops.MUV_UnwrapConstraint.bl_idname, icon='IMAGE_COL')
-    self.layout.menu(
-        muv_preserve_uv_aspect.MUV_PreserveUVAspectMenu.bl_idname,
-        icon='IMAGE_COL')
-    self.layout.menu(muv_menu.MUV_UVWMenu.bl_idname, icon="IMAGE_COL")
-
-
-def image_uvs_menu_fn(self, context):
-    self.layout.separator()
-    self.layout.operator(muv_packuv_ops.MUV_PackUV.bl_idname, icon="IMAGE_COL")
-
-
-def view3d_object_menu_fn(self, context):
-    self.layout.separator()
-    self.layout.menu(muv_menu.MUV_CPUVObjMenu.bl_idname, icon="IMAGE_COL")
-
-
 def register():
     bpy.utils.register_module(__name__)
-    bpy.types.VIEW3D_MT_uv_map.append(view3d_uvmap_menu_fn)
-    bpy.types.IMAGE_MT_uvs.append(image_uvs_menu_fn)
-    bpy.types.VIEW3D_MT_object.append(view3d_object_menu_fn)
-    try:
-        bpy.types.VIEW3D_MT_Object.append(view3d_object_menu_fn)
-    except:
-        pass
-    muv_props.init_props(bpy.types.Scene)
+    properites.init_props(bpy.types.Scene)
 
 
 def unregister():
     bpy.utils.unregister_module(__name__)
-    bpy.types.VIEW3D_MT_uv_map.remove(view3d_uvmap_menu_fn)
-    bpy.types.IMAGE_MT_uvs.remove(image_uvs_menu_fn)
-    bpy.types.VIEW3D_MT_object.remove(view3d_object_menu_fn)
-    try:
-        bpy.types.VIEW3D_MT_Object.remove(view3d_object_menu_fn)
-    except:
-        pass
-    muv_props.clear_props(bpy.types.Scene)
+    properites.clear_props(bpy.types.Scene)
 
 
 if __name__ == "__main__":
diff --git a/uv_magic_uv/common.py b/uv_magic_uv/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..6d3d9df7e3874530cb50786ced1144c698b8f347
--- /dev/null
+++ b/uv_magic_uv/common.py
@@ -0,0 +1,604 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+from collections import defaultdict
+from pprint import pprint
+from math import fabs, sqrt
+
+import bpy
+from mathutils import Vector
+import bmesh
+
+
+DEBUG = False
+
+
+def debug_print(*s):
+    """
+    Print message to console in debugging mode
+    """
+
+    if DEBUG:
+        pprint(s)
+
+
+def check_version(major, minor, _):
+    """
+    Check blender version
+    """
+
+    if bpy.app.version[0] == major and bpy.app.version[1] == minor:
+        return 0
+    if bpy.app.version[0] > major:
+        return 1
+    if bpy.app.version[1] > minor:
+        return 1
+    return -1
+
+
+def redraw_all_areas():
+    """
+    Redraw all areas
+    """
+
+    for area in bpy.context.screen.areas:
+        area.tag_redraw()
+
+
+def get_space(area_type, region_type, space_type):
+    """
+    Get current area/region/space
+    """
+
+    area = None
+    region = None
+    space = None
+
+    for area in bpy.context.screen.areas:
+        if area.type == area_type:
+            break
+    else:
+        return (None, None, None)
+    for region in area.regions:
+        if region.type == region_type:
+            break
+    for space in area.spaces:
+        if space.type == space_type:
+            break
+
+    return (area, region, space)
+
+
+def __get_island_info(uv_layer, islands):
+    """
+    get information about each island
+    """
+
+    island_info = []
+    for isl in islands:
+        info = {}
+        max_uv = Vector((-10000000.0, -10000000.0))
+        min_uv = Vector((10000000.0, 10000000.0))
+        ave_uv = Vector((0.0, 0.0))
+        num_uv = 0
+        for face in isl:
+            n = 0
+            a = Vector((0.0, 0.0))
+            ma = Vector((-10000000.0, -10000000.0))
+            mi = Vector((10000000.0, 10000000.0))
+            for l in face['face'].loops:
+                uv = l[uv_layer].uv
+                ma.x = max(uv.x, ma.x)
+                ma.y = max(uv.y, ma.y)
+                mi.x = min(uv.x, mi.x)
+                mi.y = min(uv.y, mi.y)
+                a = a + uv
+                n = n + 1
+            ave_uv = ave_uv + a
+            num_uv = num_uv + n
+            a = a / n
+            max_uv.x = max(ma.x, max_uv.x)
+            max_uv.y = max(ma.y, max_uv.y)
+            min_uv.x = min(mi.x, min_uv.x)
+            min_uv.y = min(mi.y, min_uv.y)
+            face['max_uv'] = ma
+            face['min_uv'] = mi
+            face['ave_uv'] = a
+        ave_uv = ave_uv / num_uv
+
+        info['center'] = ave_uv
+        info['size'] = max_uv - min_uv
+        info['num_uv'] = num_uv
+        info['group'] = -1
+        info['faces'] = isl
+        info['max'] = max_uv
+        info['min'] = min_uv
+
+        island_info.append(info)
+
+    return island_info
+
+
+def __parse_island(bm, face_idx, faces_left, island,
+                   face_to_verts, vert_to_faces):
+    """
+    Parse island
+    """
+
+    if face_idx in faces_left:
+        faces_left.remove(face_idx)
+        island.append({'face': bm.faces[face_idx]})
+        for v in face_to_verts[face_idx]:
+            connected_faces = vert_to_faces[v]
+            if connected_faces:
+                for cf in connected_faces:
+                    __parse_island(bm, cf, faces_left, island, face_to_verts,
+                                   vert_to_faces)
+
+
+def __get_island(bm, face_to_verts, vert_to_faces):
+    """
+    Get island list
+    """
+
+    uv_island_lists = []
+    faces_left = set(face_to_verts.keys())
+    while faces_left:
+        current_island = []
+        face_idx = list(faces_left)[0]
+        __parse_island(bm, face_idx, faces_left, current_island,
+                       face_to_verts, vert_to_faces)
+        uv_island_lists.append(current_island)
+
+    return uv_island_lists
+
+
+def __create_vert_face_db(faces, uv_layer):
+    # create mesh database for all faces
+    face_to_verts = defaultdict(set)
+    vert_to_faces = defaultdict(set)
+    for f in faces:
+        for l in f.loops:
+            id_ = l[uv_layer].uv.to_tuple(5), l.vert.index
+            face_to_verts[f.index].add(id_)
+            vert_to_faces[id_].add(f.index)
+
+    return (face_to_verts, vert_to_faces)
+
+
+def get_island_info(obj, only_selected=True):
+    bm = bmesh.from_edit_mesh(obj.data)
+    if check_version(2, 73, 0) >= 0:
+        bm.faces.ensure_lookup_table()
+
+    return get_island_info_from_bmesh(bm, only_selected)
+
+
+def get_island_info_from_bmesh(bm, only_selected=True):
+    if not bm.loops.layers.uv:
+        return None
+    uv_layer = bm.loops.layers.uv.verify()
+
+    # create database
+    if only_selected:
+        selected_faces = [f for f in bm.faces if f.select]
+    else:
+        selected_faces = [f for f in bm.faces]
+
+    return get_island_info_from_faces(bm, selected_faces, uv_layer)
+
+
+def get_island_info_from_faces(bm, faces, uv_layer):
+    ftv, vtf = __create_vert_face_db(faces, uv_layer)
+
+    # Get island information
+    uv_island_lists = __get_island(bm, ftv, vtf)
+    island_info = __get_island_info(uv_layer, uv_island_lists)
+
+    return island_info
+
+
+def get_uvimg_editor_board_size(area):
+    if area.spaces.active.image:
+        return area.spaces.active.image.size
+
+    return (255.0, 255.0)
+
+
+def calc_polygon_2d_area(points):
+    area = 0.0
+    for i, p1 in enumerate(points):
+        p2 = points[(i + 1) % len(points)]
+        v1 = p1 - points[0]
+        v2 = p2 - points[0]
+        a = v1.x * v2.y - v1.y * v2.x
+        area = area + a
+
+    return fabs(0.5 * area)
+
+
+def calc_polygon_3d_area(points):
+    area = 0.0
+    for i, p1 in enumerate(points):
+        p2 = points[(i + 1) % len(points)]
+        v1 = p1 - points[0]
+        v2 = p2 - points[0]
+        cx = v1.y * v2.z - v1.z * v2.y
+        cy = v1.z * v2.x - v1.x * v2.z
+        cz = v1.x * v2.y - v1.y * v2.x
+        a = sqrt(cx * cx + cy * cy + cz * cz)
+        area = area + a
+
+    return 0.5 * area
+
+
+def measure_mesh_area(obj):
+    bm = bmesh.from_edit_mesh(obj.data)
+    if check_version(2, 73, 0) >= 0:
+        bm.verts.ensure_lookup_table()
+        bm.edges.ensure_lookup_table()
+        bm.faces.ensure_lookup_table()
+
+    sel_faces = [f for f in bm.faces if f.select]
+
+    # measure
+    mesh_area = 0.0
+    for f in sel_faces:
+        verts = [l.vert.co for l in f.loops]
+        f_mesh_area = calc_polygon_3d_area(verts)
+        mesh_area = mesh_area + f_mesh_area
+
+    return mesh_area
+
+
+def measure_uv_area(obj):
+    bm = bmesh.from_edit_mesh(obj.data)
+    if check_version(2, 73, 0) >= 0:
+        bm.verts.ensure_lookup_table()
+        bm.edges.ensure_lookup_table()
+        bm.faces.ensure_lookup_table()
+
+    if not bm.loops.layers.uv:
+        return None
+    uv_layer = bm.loops.layers.uv.verify()
+
+    if not bm.faces.layers.tex:
+        return None
+    tex_layer = bm.faces.layers.tex.verify()
+
+    sel_faces = [f for f in bm.faces if f.select]
+
+    # measure
+    uv_area = 0.0
+    for f in sel_faces:
+        uvs = [l[uv_layer].uv for l in f.loops]
+        f_uv_area = calc_polygon_2d_area(uvs)
+
+        if not tex_layer:
+            return None
+        img = f[tex_layer].image
+        # not found, try to search from node
+        if not img:
+            for mat in obj.material_slots:
+                for node in mat.material.node_tree.nodes:
+                    tex_node_types = [
+                        'TEX_ENVIRONMENT',
+                        'TEX_IMAGE',
+                    ]
+                    if (node.type in tex_node_types) and node.image:
+                        img = node.image
+        if not img:
+            return None
+        uv_area = uv_area + f_uv_area * img.size[0] * img.size[1]
+
+    return uv_area
+
+
+def diff_point_to_segment(a, b, p):
+    ab = b - a
+    normal_ab = ab.normalized()
+
+    ap = p - a
+    dist_ax = normal_ab.dot(ap)
+
+    # cross point
+    x = a + normal_ab * dist_ax
+
+    # difference between cross point and point
+    xp = p - x
+
+    return xp, x
+
+
+# get selected loop pair whose loops are connected each other
+def __get_loop_pairs(l, uv_layer):
+
+    def __get_loop_pairs_internal(l_, pairs_, uv_layer_, parsed_):
+        parsed_.append(l_)
+        for ll in l_.vert.link_loops:
+            # forward direction
+            lln = ll.link_loop_next
+            # if there is same pair, skip it
+            found = False
+            for p in pairs_:
+                if (ll in p) and (lln in p):
+                    found = True
+                    break
+            # two loops must be selected
+            if ll[uv_layer_].select and lln[uv_layer_].select:
+                if not found:
+                    pairs_.append([ll, lln])
+                if lln not in parsed_:
+                    __get_loop_pairs_internal(lln, pairs_, uv_layer_, parsed_)
+
+            # backward direction
+            llp = ll.link_loop_prev
+            # if there is same pair, skip it
+            found = False
+            for p in pairs_:
+                if (ll in p) and (llp in p):
+                    found = True
+                    break
+            # two loops must be selected
+            if ll[uv_layer_].select and llp[uv_layer_].select:
+                if not found:
+                    pairs_.append([ll, llp])
+                if llp not in parsed_:
+                    __get_loop_pairs_internal(llp, pairs_, uv_layer_, parsed_)
+
+    pairs = []
+    parsed = []
+    __get_loop_pairs_internal(l, pairs, uv_layer, parsed)
+
+    return pairs
+
+
+# sort pair by vertex
+# (v0, v1) - (v1, v2) - (v2, v3) ....
+def __sort_loop_pairs(uv_layer, pairs, closed):
+    rest = pairs
+    sorted_pairs = [rest[0]]
+    rest.remove(rest[0])
+
+    # prepend
+    while True:
+        p1 = sorted_pairs[0]
+        for p2 in rest:
+            if p1[0].vert == p2[0].vert:
+                sorted_pairs.insert(0, [p2[1], p2[0]])
+                rest.remove(p2)
+                break
+            elif p1[0].vert == p2[1].vert:
+                sorted_pairs.insert(0, [p2[0], p2[1]])
+                rest.remove(p2)
+                break
+        else:
+            break
+
+    # append
+    while True:
+        p1 = sorted_pairs[-1]
+        for p2 in rest:
+            if p1[1].vert == p2[0].vert:
+                sorted_pairs.append([p2[0], p2[1]])
+                rest.remove(p2)
+                break
+            elif p1[1].vert == p2[1].vert:
+                sorted_pairs.append([p2[1], p2[0]])
+                rest.remove(p2)
+                break
+        else:
+            break
+
+    begin_vert = sorted_pairs[0][0].vert
+    end_vert = sorted_pairs[-1][-1].vert
+    if begin_vert != end_vert:
+        return sorted_pairs, ""
+    if closed and (begin_vert == end_vert):
+        # if the sequence of UV is circular, it is ok
+        return sorted_pairs, ""
+
+    # if the begin vertex and the end vertex are same, search the UVs which
+    # are separated each other
+    tmp_pairs = sorted_pairs
+    for i, (p1, p2) in enumerate(zip(tmp_pairs[:-1], tmp_pairs[1:])):
+        diff = p2[0][uv_layer].uv - p1[-1][uv_layer].uv
+        if diff.length > 0.000000001:
+            # UVs are separated
+            sorted_pairs = tmp_pairs[i + 1:]
+            sorted_pairs.extend(tmp_pairs[:i + 1])
+            break
+    else:
+        p1 = tmp_pairs[0]
+        p2 = tmp_pairs[-1]
+        diff = p2[-1][uv_layer].uv - p1[0][uv_layer].uv
+        if diff.length < 0.000000001:
+            # all UVs are not separated
+            return None, "All UVs are not separted"
+
+    return sorted_pairs, ""
+
+
+# get index of the island group which includes loop
+def __get_island_group_include_loop(loop, island_info):
+    for i, isl in enumerate(island_info):
+        for f in isl['faces']:
+            for l in f['face'].loops:
+                if l == loop:
+                    return i    # found
+
+    return -1   # not found
+
+
+# get index of the island group which includes pair.
+# if island group is not same between loops, it will be invalid
+def __get_island_group_include_pair(pair, island_info):
+    l1_grp = __get_island_group_include_loop(pair[0], island_info)
+    if l1_grp == -1:
+        return -1   # not found
+
+    for p in pair[1:]:
+        l2_grp = __get_island_group_include_loop(p, island_info)
+        if (l2_grp == -1) or (l1_grp != l2_grp):
+            return -1   # not found or invalid
+
+    return l1_grp
+
+
+# x ---- x   <- next_loop_pair
+# |      |
+# o ---- o   <- pair
+def __get_next_loop_pair(pair):
+    lp = pair[0].link_loop_prev
+    if lp.vert == pair[1].vert:
+        lp = pair[0].link_loop_next
+        if lp.vert == pair[1].vert:
+            # no loop is found
+            return None
+
+    ln = pair[1].link_loop_next
+    if ln.vert == pair[0].vert:
+        ln = pair[1].link_loop_prev
+        if ln.vert == pair[0].vert:
+            # no loop is found
+            return None
+
+    # tri-face
+    if lp == ln:
+        return [lp]
+
+    # quad-face
+    return [lp, ln]
+
+
+# | ---- |
+# % ---- %   <- next_poly_loop_pair
+# x ---- x   <- next_loop_pair
+# |      |
+# o ---- o   <- pair
+def __get_next_poly_loop_pair(pair):
+    v1 = pair[0].vert
+    v2 = pair[1].vert
+    for l1 in v1.link_loops:
+        if l1 == pair[0]:
+            continue
+        for l2 in v2.link_loops:
+            if l2 == pair[1]:
+                continue
+            if l1.link_loop_next == l2:
+                return [l1, l2]
+            elif l1.link_loop_prev == l2:
+                return [l1, l2]
+
+    # no next poly loop is found
+    return None
+
+
+# get loop sequence in the same island
+def __get_loop_sequence_internal(uv_layer, pairs, island_info, closed):
+    loop_sequences = []
+    for pair in pairs:
+        seqs = [pair]
+        p = pair
+        isl_grp = __get_island_group_include_pair(pair, island_info)
+        if isl_grp == -1:
+            return None, "Can not find the island or invalid island"
+
+        while True:
+            nlp = __get_next_loop_pair(p)
+            if not nlp:
+                break       # no more loop pair
+            nlp_isl_grp = __get_island_group_include_pair(nlp, island_info)
+            if nlp_isl_grp != isl_grp:
+                break       # another island
+            for nlpl in nlp:
+                if nlpl[uv_layer].select:
+                    return None, "Do not select UV which does not belong to " \
+                                 "the end edge"
+
+            seqs.append(nlp)
+
+            # when face is triangle, it indicates CLOSED
+            if (len(nlp) == 1) and closed:
+                break
+
+            nplp = __get_next_poly_loop_pair(nlp)
+            if not nplp:
+                break       # no more loop pair
+            nplp_isl_grp = __get_island_group_include_pair(nplp, island_info)
+            if nplp_isl_grp != isl_grp:
+                break       # another island
+
+            # check if the UVs are already parsed.
+            # this check is needed for the mesh which has the circular
+            # sequence of the verticies
+            matched = False
+            for p1 in seqs:
+                p2 = nplp
+                if ((p1[0] == p2[0]) and (p1[1] == p2[1])) or \
+                   ((p1[0] == p2[1]) and (p1[1] == p2[0])):
+                    matched = True
+            if matched:
+                debug_print("This is a circular sequence")
+                break
+
+            for nlpl in nplp:
+                if nlpl[uv_layer].select:
+                    return None, "Do not select UV which does not belong to " \
+                                 "the end edge"
+
+            seqs.append(nplp)
+
+            p = nplp
+
+        loop_sequences.append(seqs)
+    return loop_sequences, ""
+
+
+def get_loop_sequences(bm, uv_layer, closed=False):
+    sel_faces = [f for f in bm.faces if f.select]
+
+    # get candidate loops
+    cand_loops = []
+    for f in sel_faces:
+        for l in f.loops:
+            if l[uv_layer].select:
+                cand_loops.append(l)
+
+    if len(cand_loops) < 2:
+        return None, "More than 2 UVs must be selected"
+
+    first_loop = cand_loops[0]
+    isl_info = get_island_info_from_bmesh(bm, False)
+    loop_pairs = __get_loop_pairs(first_loop, uv_layer)
+    loop_pairs, err = __sort_loop_pairs(uv_layer, loop_pairs, closed)
+    if not loop_pairs:
+        return None, err
+    loop_seqs, err = __get_loop_sequence_internal(uv_layer, loop_pairs,
+                                                  isl_info, closed)
+    if not loop_seqs:
+        return None, err
+
+    return loop_seqs, ""
diff --git a/uv_magic_uv/muv_common.py b/uv_magic_uv/muv_common.py
deleted file mode 100644
index b52971ec3080d21fe05386e15a6f08748725d1d7..0000000000000000000000000000000000000000
--- a/uv_magic_uv/muv_common.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### 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 #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
-
-import bpy
-from . import muv_props
-
-
-def debug_print(*s):
-    """
-    Print message to console in debugging mode
-    """
-
-    if muv_props.DEBUG:
-        print(s)
-
-
-def check_version(major, minor, _):
-    """
-    Check blender version
-    """
-
-    if bpy.app.version[0] == major and bpy.app.version[1] == minor:
-        return 0
-    if bpy.app.version[0] > major:
-        return 1
-    if bpy.app.version[1] > minor:
-        return 1
-    return -1
-
-
-def redraw_all_areas():
-    """
-    Redraw all areas
-    """
-
-    for area in bpy.context.screen.areas:
-        area.tag_redraw()
-
-
-def get_space(area_type, region_type, space_type):
-    """
-    Get current area/region/space
-    """
-
-    area = None
-    region = None
-    space = None
-
-    for area in bpy.context.screen.areas:
-        if area.type == area_type:
-            break
-    else:
-        return (None, None, None)
-    for region in area.regions:
-        if region.type == region_type:
-            break
-    for space in area.spaces:
-        if space.type == space_type:
-            break
-
-    return (area, region, space)
diff --git a/uv_magic_uv/muv_cpuv_selseq_ops.py b/uv_magic_uv/muv_cpuv_selseq_ops.py
deleted file mode 100644
index 3cf69ff76de3b079f01291ef72e70868263d4927..0000000000000000000000000000000000000000
--- a/uv_magic_uv/muv_cpuv_selseq_ops.py
+++ /dev/null
@@ -1,279 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### 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 #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
-
-import bpy
-import bmesh
-from bpy.props import (
-    StringProperty,
-    BoolProperty,
-    IntProperty,
-    EnumProperty,
-)
-from . import muv_common
-
-
-class MUV_CPUVSelSeqCopyUV(bpy.types.Operator):
-    """
-    Operation class: Copy UV coordinate by selection sequence
-    """
-
-    bl_idname = "uv.muv_cpuv_selseq_copy_uv"
-    bl_label = "Copy UV (Selection Sequence) (Operation)"
-    bl_description = "Copy UV data by selection sequence (Operation)"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    uv_map = StringProperty(options={'HIDDEN'})
-
-    def execute(self, context):
-        props = context.scene.muv_props.cpuv_selseq
-        if self.uv_map == "":
-            self.report({'INFO'}, "Copy UV coordinate (selection sequence)")
-        else:
-            self.report(
-                {'INFO'},
-                "Copy UV coordinate (selection sequence) (UV map:%s)"
-                % (self.uv_map))
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        # get UV layer
-        if self.uv_map == "":
-            if not bm.loops.layers.uv:
-                self.report(
-                    {'WARNING'}, "Object must have more than one UV map")
-                return {'CANCELLED'}
-            uv_layer = bm.loops.layers.uv.verify()
-        else:
-            uv_layer = bm.loops.layers.uv[self.uv_map]
-
-        # get selected face
-        props.src_uvs = []
-        props.src_pin_uvs = []
-        props.src_seams = []
-        for hist in bm.select_history:
-            if isinstance(hist, bmesh.types.BMFace) and hist.select:
-                uvs = [l[uv_layer].uv.copy() for l in hist.loops]
-                pin_uvs = [l[uv_layer].pin_uv for l in hist.loops]
-                seams = [l.edge.seam for l in hist.loops]
-                props.src_uvs.append(uvs)
-                props.src_pin_uvs.append(pin_uvs)
-                props.src_seams.append(seams)
-        if not props.src_uvs or not props.src_pin_uvs:
-            self.report({'WARNING'}, "No faces are selected")
-            return {'CANCELLED'}
-        self.report({'INFO'}, "%d face(s) are selected" % len(props.src_uvs))
-
-        return {'FINISHED'}
-
-
-class MUV_CPUVSelSeqCopyUVMenu(bpy.types.Menu):
-    """
-    Menu class: Copy UV coordinate by selection sequence
-    """
-
-    bl_idname = "uv.muv_cpuv_selseq_copy_uv_menu"
-    bl_label = "Copy UV (Selection Sequence)"
-    bl_description = "Copy UV coordinate by selection sequence"
-
-    def draw(self, context):
-        layout = self.layout
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        uv_maps = bm.loops.layers.uv.keys()
-        layout.operator(
-            MUV_CPUVSelSeqCopyUV.bl_idname,
-            text="[Default]", icon="IMAGE_COL").uv_map = ""
-        for m in uv_maps:
-            layout.operator(
-                MUV_CPUVSelSeqCopyUV.bl_idname,
-                text=m, icon="IMAGE_COL").uv_map = m
-
-
-class MUV_CPUVSelSeqPasteUV(bpy.types.Operator):
-    """
-    Operation class: Paste UV coordinate by selection sequence
-    """
-
-    bl_idname = "uv.muv_cpuv_selseq_paste_uv"
-    bl_label = "Paste UV (Selection Sequence) (Operation)"
-    bl_description = "Paste UV coordinate by selection sequence (Operation)"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    uv_map = StringProperty(options={'HIDDEN'})
-    strategy = EnumProperty(
-        name="Strategy",
-        description="Paste Strategy",
-        items=[
-            ('N_N', 'N:N', 'Number of faces must be equal to source'),
-            ('N_M', 'N:M', 'Number of faces must not be equal to source')
-        ],
-        default="N_M"
-    )
-    flip_copied_uv = BoolProperty(
-        name="Flip Copied UV",
-        description="Flip Copied UV...",
-        default=False
-    )
-    rotate_copied_uv = IntProperty(
-        default=0,
-        name="Rotate Copied UV",
-        min=0,
-        max=30
-    )
-    copy_seams = BoolProperty(
-        name="Copy Seams",
-        description="Copy Seams",
-        default=True
-    )
-
-    def execute(self, context):
-        props = context.scene.muv_props.cpuv_selseq
-        if not props.src_uvs or not props.src_pin_uvs:
-            self.report({'WARNING'}, "Need copy UV at first")
-            return {'CANCELLED'}
-        if self.uv_map == "":
-            self.report({'INFO'}, "Paste UV coordinate (selection sequence)")
-        else:
-            self.report(
-                {'INFO'},
-                "Paste UV coordinate (selection sequence) (UV map:%s)"
-                % (self.uv_map))
-
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        # get UV layer
-        if self.uv_map == "":
-            if not bm.loops.layers.uv:
-                self.report(
-                    {'WARNING'}, "Object must have more than one UV map")
-                return {'CANCELLED'}
-            uv_layer = bm.loops.layers.uv.verify()
-        else:
-            uv_layer = bm.loops.layers.uv[self.uv_map]
-
-        # get selected face
-        dest_uvs = []
-        dest_pin_uvs = []
-        dest_seams = []
-        dest_face_indices = []
-        for hist in bm.select_history:
-            if isinstance(hist, bmesh.types.BMFace) and hist.select:
-                dest_face_indices.append(hist.index)
-                uvs = [l[uv_layer].uv.copy() for l in hist.loops]
-                pin_uvs = [l[uv_layer].pin_uv for l in hist.loops]
-                seams = [l.edge.seam for l in hist.loops]
-                dest_uvs.append(uvs)
-                dest_pin_uvs.append(pin_uvs)
-                dest_seams.append(seams)
-        if not dest_uvs or not dest_pin_uvs:
-            self.report({'WARNING'}, "No faces are selected")
-            return {'CANCELLED'}
-        if self.strategy == 'N_N' and len(props.src_uvs) != len(dest_uvs):
-            self.report(
-                {'WARNING'},
-                "Number of selected faces is different from copied faces " +
-                "(src:%d, dest:%d)"
-                % (len(props.src_uvs), len(dest_uvs)))
-            return {'CANCELLED'}
-
-        # paste
-        for i, idx in enumerate(dest_face_indices):
-            suv = None
-            spuv = None
-            ss = None
-            duv = None
-            if self.strategy == 'N_N':
-                suv = props.src_uvs[i]
-                spuv = props.src_pin_uvs[i]
-                ss = props.src_seams[i]
-                duv = dest_uvs[i]
-            elif self.strategy == 'N_M':
-                suv = props.src_uvs[i % len(props.src_uvs)]
-                spuv = props.src_pin_uvs[i % len(props.src_pin_uvs)]
-                ss = props.src_seams[i % len(props.src_seams)]
-                duv = dest_uvs[i]
-            if len(suv) != len(duv):
-                self.report({'WARNING'}, "Some faces are different size")
-                return {'CANCELLED'}
-            suvs_fr = [uv for uv in suv]
-            spuvs_fr = [pin_uv for pin_uv in spuv]
-            ss_fr = [s for s in ss]
-            # flip UVs
-            if self.flip_copied_uv is True:
-                suvs_fr.reverse()
-                spuvs_fr.reverse()
-                ss_fr.reverse()
-            # rotate UVs
-            for _ in range(self.rotate_copied_uv):
-                uv = suvs_fr.pop()
-                pin_uv = spuvs_fr.pop()
-                s = ss_fr.pop()
-                suvs_fr.insert(0, uv)
-                spuvs_fr.insert(0, pin_uv)
-                ss_fr.insert(0, s)
-            # paste UVs
-            for l, suv, spuv, ss in zip(bm.faces[idx].loops, suvs_fr,
-                                        spuvs_fr, ss_fr):
-                l[uv_layer].uv = suv
-                l[uv_layer].pin_uv = spuv
-                if self.copy_seams is True:
-                    l.edge.seam = ss
-
-        self.report({'INFO'}, "%d face(s) are copied" % len(dest_uvs))
-
-        bmesh.update_edit_mesh(obj.data)
-        if self.copy_seams is True:
-            obj.data.show_edge_seams = True
-
-        return {'FINISHED'}
-
-
-class MUV_CPUVSelSeqPasteUVMenu(bpy.types.Menu):
-    """
-    Menu class: Paste UV coordinate by selection sequence
-    """
-
-    bl_idname = "uv.muv_cpuv_selseq_paste_uv_menu"
-    bl_label = "Paste UV (Selection Sequence)"
-    bl_description = "Paste UV coordinate by selection sequence"
-
-    def draw(self, context):
-        layout = self.layout
-        # create sub menu
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        uv_maps = bm.loops.layers.uv.keys()
-        layout.operator(
-            MUV_CPUVSelSeqPasteUV.bl_idname,
-            text="[Default]", icon="IMAGE_COL").uv_map = ""
-        for m in uv_maps:
-            layout.operator(
-                MUV_CPUVSelSeqPasteUV.bl_idname,
-                text=m, icon="IMAGE_COL").uv_map = m
diff --git a/uv_magic_uv/muv_menu.py b/uv_magic_uv/muv_menu.py
deleted file mode 100644
index 47c79bbd1b217409a44c1197aaae82a25a612a89..0000000000000000000000000000000000000000
--- a/uv_magic_uv/muv_menu.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### 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 #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
-
-import bpy
-from . import muv_cpuv_ops
-from . import muv_cpuv_selseq_ops
-from . import muv_transuv_ops
-from . import muv_texlock_ops
-from . import muv_wsuv_ops
-from . import muv_uvw_ops
-
-
-class MUV_CPUVMenu(bpy.types.Menu):
-    """
-    Menu class: Master menu of Copy/Paste UV coordinate
-    """
-
-    bl_idname = "uv.muv_cpuv_menu"
-    bl_label = "Copy/Paste UV"
-    bl_description = "Copy and Paste UV coordinate"
-
-    def draw(self, _):
-        self.layout.menu(
-            muv_cpuv_ops.MUV_CPUVCopyUVMenu.bl_idname, icon="IMAGE_COL")
-        self.layout.menu(
-            muv_cpuv_ops.MUV_CPUVPasteUVMenu.bl_idname, icon="IMAGE_COL")
-        self.layout.menu(
-            muv_cpuv_selseq_ops.MUV_CPUVSelSeqCopyUVMenu.bl_idname,
-            icon="IMAGE_COL")
-        self.layout.menu(
-            muv_cpuv_selseq_ops.MUV_CPUVSelSeqPasteUVMenu.bl_idname,
-            icon="IMAGE_COL")
-
-
-class MUV_CPUVObjMenu(bpy.types.Menu):
-    """
-    Menu class: Master menu of Copy/Paste UV coordinate per object
-    """
-
-    bl_idname = "object.muv_cpuv_obj_menu"
-    bl_label = "Copy/Paste UV"
-    bl_description = "Copy and Paste UV coordinate per object"
-
-    def draw(self, _):
-        self.layout.menu(
-            muv_cpuv_ops.MUV_CPUVObjCopyUVMenu.bl_idname, icon="IMAGE_COL")
-        self.layout.menu(
-            muv_cpuv_ops.MUV_CPUVObjPasteUVMenu.bl_idname, icon="IMAGE_COL")
-
-
-class MUV_TransUVMenu(bpy.types.Menu):
-    """
-    Menu class: Master menu of Transfer UV coordinate
-    """
-
-    bl_idname = "uv.muv_transuv_menu"
-    bl_label = "Transfer UV"
-    bl_description = "Transfer UV coordinate"
-
-    def draw(self, _):
-        self.layout.operator(
-            muv_transuv_ops.MUV_TransUVCopy.bl_idname, icon="IMAGE_COL")
-        self.layout.operator(
-            muv_transuv_ops.MUV_TransUVPaste.bl_idname, icon="IMAGE_COL")
-
-
-class MUV_TexLockMenu(bpy.types.Menu):
-    """
-    Menu class: Master menu of Texture Lock
-    """
-
-    bl_idname = "uv.muv_texlock_menu"
-    bl_label = "Texture Lock"
-    bl_description = "Lock texture when vertices of mesh (Preserve UV)"
-
-    def draw(self, _):
-        self.layout.operator(
-            muv_texlock_ops.MUV_TexLockStart.bl_idname, icon="IMAGE_COL")
-        self.layout.operator(
-            muv_texlock_ops.MUV_TexLockStop.bl_idname, icon="IMAGE_COL")
-        self.layout.operator(
-            muv_texlock_ops.MUV_TexLockIntrStart.bl_idname, icon="IMAGE_COL")
-        self.layout.operator(
-            muv_texlock_ops.MUV_TexLockIntrStop.bl_idname, icon="IMAGE_COL")
-
-
-class MUV_WSUVMenu(bpy.types.Menu):
-    """
-    Menu class: Master menu of world scale UV
-    """
-
-    bl_idname = "uv.muv_wsuv_menu"
-    bl_label = "World Scale UV"
-    bl_description = ""
-
-    def draw(self, _):
-        self.layout.operator(
-            muv_wsuv_ops.MUV_WSUVMeasure.bl_idname, icon="IMAGE_COL")
-        self.layout.operator(
-            muv_wsuv_ops.MUV_WSUVApply.bl_idname, icon="IMAGE_COL")
-
-
-class MUV_UVWMenu(bpy.types.Menu):
-    """
-    Menu class: Master menu of UVW
-    """
-
-    bl_idname = "uv.muv_uvw_menu"
-    bl_label = "UVW"
-    bl_description = ""
-
-    def draw(self, _):
-        self.layout.operator(
-            muv_uvw_ops.MUV_UVWBoxMap.bl_idname, icon="IMAGE_COL")
-        self.layout.operator(
-            muv_uvw_ops.MUV_UVWBestPlanerMap.bl_idname, icon="IMAGE_COL")
diff --git a/uv_magic_uv/muv_preferences.py b/uv_magic_uv/muv_preferences.py
deleted file mode 100644
index e14ce99bd24e1caf7303537bd8d834d9ebf9dcf7..0000000000000000000000000000000000000000
--- a/uv_magic_uv/muv_preferences.py
+++ /dev/null
@@ -1,144 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### 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 #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
-
-from bpy.props import (
-    BoolProperty,
-    FloatProperty,
-    FloatVectorProperty,
-)
-from bpy.types import AddonPreferences
-
-
-class MUV_Preferences(AddonPreferences):
-    """Preferences class: Preferences for this add-on"""
-
-    bl_idname = __package__
-
-    # enable/disable switcher
-    enable_texproj = BoolProperty(
-        name="Texture Projection",
-        default=True)
-    enable_uvbb = BoolProperty(
-        name="Bounding Box",
-        default=True)
-
-    # for Texture Projection
-    texproj_canvas_padding = FloatVectorProperty(
-        name="Canvas Padding",
-        description="Canvas Padding",
-        size=2,
-        max=50.0,
-        min=0.0,
-        default=(20.0, 20.0))
-
-    # for UV Bounding Box
-    uvbb_cp_size = FloatProperty(
-        name="Size",
-        description="Control Point Size",
-        default=6.0,
-        min=3.0,
-        max=100.0)
-    uvbb_cp_react_size = FloatProperty(
-        name="React Size",
-        description="Size event fired",
-        default=10.0,
-        min=3.0,
-        max=100.0)
-
-    def draw(self, _):
-        layout = self.layout
-
-        layout.label("Switch Enable/Disable and Configurate Features:")
-
-        layout.prop(self, "enable_texproj")
-        if self.enable_texproj:
-            sp = layout.split(percentage=0.05)
-            col = sp.column()       # spacer
-            sp = sp.split(percentage=0.3)
-            col = sp.column()
-            col.label("Texture Display: ")
-            col.prop(self, "texproj_canvas_padding")
-
-        layout.prop(self, "enable_uvbb")
-        if self.enable_uvbb:
-            sp = layout.split(percentage=0.05)
-            col = sp.column()       # spacer
-            sp = sp.split(percentage=0.3)
-            col = sp.column()
-            col.label("Control Point: ")
-            col.prop(self, "uvbb_cp_size")
-            col.prop(self, "uvbb_cp_react_size")
-
-        layout.label("Description:")
-        column = layout.column(align=True)
-        column.label("Magic UV is composed of many UV editing features.")
-        column.label("See tutorial page if you are new to this add-on.")
-        column.label("https://github.com/nutti/Magic-UV/wiki/Tutorial")
-
-        layout.label("Location:")
-
-        row = layout.row(align=True)
-        sp = row.split(percentage=0.3)
-        sp.label("View3D > U")
-        sp = sp.split(percentage=1.0)
-        col = sp.column(align=True)
-        col.label("Copy/Paste UV Coordinates")
-        col.label("Copy/Paste UV Coordinates (by selection sequence)")
-        col.label("Flip/Rotate UVs")
-        col.label("Transfer UV")
-        col.label("Move UV from 3D View")
-        col.label("Texture Lock")
-        col.label("Mirror UV")
-        col.label("World Scale UV")
-        col.label("Unwrap Constraint")
-        col.label("Preserve UV Aspect")
-
-        row = layout.row(align=True)
-        sp = row.split(percentage=0.3)
-        sp.label("View3D > Object")
-        sp = sp.split(percentage=1.0)
-        col = sp.column(align=True)
-        col.label("Copy/Paste UV Coordinates (Among same objects)")
-
-        row = layout.row(align=True)
-        sp = row.split(percentage=0.3)
-        sp.label("ImageEditor > Property Panel")
-        sp = sp.split(percentage=1.0)
-        col = sp.column(align=True)
-        col.label("Manipulate UV with Bounding Box in UV Editor")
-
-        row = layout.row(align=True)
-        sp = row.split(percentage=0.3)
-        sp.label("View3D > Property Panel")
-        sp = sp.split(percentage=1.0)
-        col = sp.column(align=True)
-        col.label("Texture Projection")
-
-        row = layout.row(align=True)
-        sp = row.split(percentage=0.3)
-        sp.label("ImageEditor > UVs")
-        sp = sp.split(percentage=1.0)
-        col = sp.column(align=True)
-        col.label("Pack UV (with same UV island packing)")
diff --git a/uv_magic_uv/muv_props.py b/uv_magic_uv/muv_props.py
deleted file mode 100644
index c0a7d961ff9c54d2d2fcd93c8f42b0982e840652..0000000000000000000000000000000000000000
--- a/uv_magic_uv/muv_props.py
+++ /dev/null
@@ -1,148 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### 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 #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
-
-import bpy
-from bpy.props import (
-    FloatProperty,
-    EnumProperty,
-    BoolProperty,
-)
-
-
-DEBUG = False
-
-
-def get_loaded_texture_name(_, __):
-    items = [(key, key, "") for key in bpy.data.images.keys()]
-    items.append(("None", "None", ""))
-    return items
-
-
-# Properties used in this add-on.
-class MUV_Properties():
-    cpuv = None
-    cpuv_obj = None
-    cpuv_selseq = None
-    transuv = None
-    uvbb = None
-    texproj = None
-    texlock = None
-    texwrap = None
-    wsuv = None
-
-    def __init__(self):
-        self.cpuv = MUV_CPUVProps()
-        self.cpuv_obj = MUV_CPUVProps()
-        self.cpuv_selseq = MUV_CPUVSelSeqProps()
-        self.transuv = MUV_TransUVProps()
-        self.uvbb = MUV_UVBBProps()
-        self.texproj = MUV_TexProjProps()
-        self.texlock = MUV_TexLockProps()
-        self.texwrap = MUV_TexWrapProps()
-        self.wsuv = MUV_WSUVProps()
-
-
-class MUV_CPUVProps():
-    src_uvs = []
-    src_pin_uvs = []
-    src_seams = []
-
-
-class MUV_CPUVSelSeqProps():
-    src_uvs = []
-    src_pin_uvs = []
-    src_seams = []
-
-
-class MUV_TransUVProps():
-    topology_copied = []
-
-
-class MUV_UVBBProps():
-    uv_info_ini = []
-    ctrl_points_ini = []
-    ctrl_points = []
-    running = False
-
-
-class MUV_TexProjProps():
-    running = False
-
-
-class MUV_TexLockProps():
-    verts_orig = None
-    intr_verts_orig = None
-    intr_running = False
-
-
-class MUV_TexWrapProps():
-    src_face_index = -1
-
-
-class MUV_WSUVProps():
-    ref_sv = None
-    ref_suv = None
-
-
-def init_props(scene):
-    scene.muv_props = MUV_Properties()
-    scene.muv_uvbb_uniform_scaling = BoolProperty(
-        name="Uniform Scaling",
-        description="Enable Uniform Scaling",
-        default=False)
-    scene.muv_texproj_tex_magnitude = FloatProperty(
-        name="Magnitude",
-        description="Texture Magnitude",
-        default=0.5,
-        min=0.0,
-        max=100.0)
-    scene.muv_texproj_tex_image = EnumProperty(
-        name="Image",
-        description="Texture Image",
-        items=get_loaded_texture_name)
-    scene.muv_texproj_tex_transparency = FloatProperty(
-        name="Transparency",
-        description="Texture Transparency",
-        default=0.2,
-        min=0.0,
-        max=1.0)
-    scene.muv_texproj_adjust_window = BoolProperty(
-        name="Adjust Window",
-        description="Size of renderered texture is fitted to window",
-        default=True)
-    scene.muv_texproj_apply_tex_aspect = BoolProperty(
-        name="Texture Aspect Ratio",
-        description="Apply Texture Aspect ratio to displayed texture",
-        default=True)
-
-
-def clear_props(scene):
-    del scene.muv_props
-    del scene.muv_uvbb_uniform_scaling
-    del scene.muv_texproj_tex_magnitude
-    del scene.muv_texproj_tex_image
-    del scene.muv_texproj_tex_transparency
-    del scene.muv_texproj_adjust_window
-    del scene.muv_texproj_apply_tex_aspect
diff --git a/uv_magic_uv/op/__init__.py b/uv_magic_uv/op/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..75885ef6ae1bf48791c55e535d7cd19775d56974
--- /dev/null
+++ b/uv_magic_uv/op/__init__.py
@@ -0,0 +1,72 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+if "bpy" in locals():
+    import importlib
+    importlib.reload(align_uv)
+    importlib.reload(align_uv_cursor)
+    importlib.reload(copy_paste_uv)
+    importlib.reload(copy_paste_uv_object)
+    importlib.reload(copy_paste_uv_uvedit)
+    importlib.reload(flip_rotate_uv)
+    importlib.reload(mirror_uv)
+    importlib.reload(move_uv)
+    importlib.reload(pack_uv)
+    importlib.reload(preserve_uv_aspect)
+    importlib.reload(smooth_uv)
+    importlib.reload(texture_lock)
+    importlib.reload(texture_projection)
+    importlib.reload(texture_wrap)
+    importlib.reload(transfer_uv)
+    importlib.reload(unwrap_constraint)
+    importlib.reload(uv_bounding_box)
+    importlib.reload(uv_inspection)
+    importlib.reload(uv_sculpt)
+    importlib.reload(uvw)
+    importlib.reload(world_scale_uv)
+else:
+    from . import align_uv
+    from . import align_uv_cursor
+    from . import copy_paste_uv
+    from . import copy_paste_uv_object
+    from . import copy_paste_uv_uvedit
+    from . import flip_rotate_uv
+    from . import mirror_uv
+    from . import move_uv
+    from . import pack_uv
+    from . import preserve_uv_aspect
+    from . import smooth_uv
+    from . import texture_lock
+    from . import texture_projection
+    from . import texture_wrap
+    from . import transfer_uv
+    from . import unwrap_constraint
+    from . import uv_bounding_box
+    from . import uv_inspection
+    from . import uv_sculpt
+    from . import uvw
+    from . import world_scale_uv
+
+import bpy
diff --git a/uv_magic_uv/op/align_uv.py b/uv_magic_uv/op/align_uv.py
new file mode 100644
index 0000000000000000000000000000000000000000..dcfb57c3fb4f82703709267d63c6def9373a75f9
--- /dev/null
+++ b/uv_magic_uv/op/align_uv.py
@@ -0,0 +1,757 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import math
+from math import atan2, tan, sin, cos
+
+import bpy
+import bmesh
+from mathutils import Vector
+from bpy.props import EnumProperty, BoolProperty
+
+from .. import common
+
+
+# get sum vertex length of loop sequences
+def get_loop_vert_len(loops):
+    length = 0
+    for l1, l2 in zip(loops[:-1], loops[1:]):
+        diff = l2.vert.co - l1.vert.co
+        length = length + abs(diff.length)
+
+    return length
+
+
+# get sum uv length of loop sequences
+def get_loop_uv_len(loops, uv_layer):
+    length = 0
+    for l1, l2 in zip(loops[:-1], loops[1:]):
+        diff = l2[uv_layer].uv - l1[uv_layer].uv
+        length = length + abs(diff.length)
+
+    return length
+
+
+# get center/radius of circle by 3 vertices
+def get_circle(v):
+    alpha = atan2((v[0].y - v[1].y), (v[0].x - v[1].x)) + math.pi / 2
+    beta = atan2((v[1].y - v[2].y), (v[1].x - v[2].x)) + math.pi / 2
+    ex = (v[0].x + v[1].x) / 2.0
+    ey = (v[0].y + v[1].y) / 2.0
+    fx = (v[1].x + v[2].x) / 2.0
+    fy = (v[1].y + v[2].y) / 2.0
+    cx = (ey - fy - ex * tan(alpha) + fx * tan(beta)) / \
+         (tan(beta) - tan(alpha))
+    cy = ey - (ex - cx) * tan(alpha)
+    center = Vector((cx, cy))
+
+    r = v[0] - center
+    radian = r.length
+
+    return center, radian
+
+
+# get position on circle with same arc length
+def calc_v_on_circle(v, center, radius):
+    base = v[0]
+    theta = atan2(base.y - center.y, base.x - center.x)
+    new_v = []
+    for i in range(len(v)):
+        angle = theta + i * 2 * math.pi / len(v)
+        new_v.append(Vector((center.x + radius * sin(angle),
+                             center.y + radius * cos(angle))))
+
+    return new_v
+
+
+class MUV_AUVCircle(bpy.types.Operator):
+
+    bl_idname = "uv.muv_auv_circle"
+    bl_label = "Circle"
+    bl_description = "Align UV coordinates to Circle"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    transmission = BoolProperty(
+        name="Transmission",
+        description="Align linked UVs",
+        default=False
+    )
+    select = BoolProperty(
+        name="Select",
+        description="Select UVs which are aligned",
+        default=False
+    )
+
+    @classmethod
+    def poll(cls, context):
+        return context.mode == 'EDIT_MESH'
+
+    def execute(self, context):
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        # loop_seqs[horizontal][vertical][loop]
+        loop_seqs, error = common.get_loop_sequences(bm, uv_layer, True)
+        if not loop_seqs:
+            self.report({'WARNING'}, error)
+            return {'CANCELLED'}
+
+        # get circle and new UVs
+        uvs = [hseq[0][0][uv_layer].uv.copy() for hseq in loop_seqs]
+        c, r = get_circle(uvs[0:3])
+        new_uvs = calc_v_on_circle(uvs, c, r)
+
+        # check center UV of circle
+        center = loop_seqs[0][-1][0].vert
+        for hseq in loop_seqs[1:]:
+            if len(hseq[-1]) != 1:
+                self.report({'WARNING'}, "Last face must be triangle")
+                return {'CANCELLED'}
+            if hseq[-1][0].vert != center:
+                self.report({'WARNING'}, "Center must be identical")
+                return {'CANCELLED'}
+
+        # align to circle
+        if self.transmission:
+            for hidx, hseq in enumerate(loop_seqs):
+                for vidx, pair in enumerate(hseq):
+                    all_ = int((len(hseq) + 1) / 2)
+                    r = (all_ - int((vidx + 1) / 2)) / all_
+                    pair[0][uv_layer].uv = c + (new_uvs[hidx] - c) * r
+                    if self.select:
+                        pair[0][uv_layer].select = True
+
+                    if len(pair) < 2:
+                        continue
+                    # for quad polygon
+                    next_hidx = (hidx + 1) % len(loop_seqs)
+                    pair[1][uv_layer].uv = c + ((new_uvs[next_hidx]) - c) * r
+                    if self.select:
+                        pair[1][uv_layer].select = True
+        else:
+            for hidx, hseq in enumerate(loop_seqs):
+                pair = hseq[0]
+                pair[0][uv_layer].uv = new_uvs[hidx]
+                pair[1][uv_layer].uv = new_uvs[(hidx + 1) % len(loop_seqs)]
+                if self.select:
+                    pair[0][uv_layer].select = True
+                    pair[1][uv_layer].select = True
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
+
+
+# get horizontal differential of UV influenced by mesh vertex
+def get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, pair_idx):
+    common.debug_print(
+        "vidx={0}, hidx={1}, pair_idx={2}".format(vidx, hidx, pair_idx))
+
+    # get total vertex length
+    hloops = []
+    for s in loop_seqs:
+        hloops.extend([s[vidx][0], s[vidx][1]])
+    vert_total_hlen = get_loop_vert_len(hloops)
+    common.debug_print(vert_total_hlen)
+
+    # target vertex length
+    hloops = []
+    for s in loop_seqs[:hidx]:
+        hloops.extend([s[vidx][0], s[vidx][1]])
+    for pidx, l in enumerate(loop_seqs[hidx][vidx]):
+        if pidx > pair_idx:
+            break
+        hloops.append(l)
+    vert_hlen = get_loop_vert_len(hloops)
+    common.debug_print(vert_hlen)
+
+    # get total UV length
+    # uv_all_hdiff = loop_seqs[-1][0][-1][uv_layer].uv -
+    # loop_seqs[0][0][0][uv_layer].uv
+    uv_total_hlen = loop_seqs[-1][vidx][-1][uv_layer].uv -\
+        loop_seqs[0][vidx][0][uv_layer].uv
+    common.debug_print(uv_total_hlen)
+
+    return uv_total_hlen * vert_hlen / vert_total_hlen
+
+
+# get vertical differential of UV influenced by mesh vertex
+def get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, pair_idx):
+    common.debug_print(
+        "vidx={0}, hidx={1}, pair_idx={2}".format(vidx, hidx, pair_idx))
+
+    # get total vertex length
+    hloops = []
+    for s in loop_seqs[hidx]:
+        hloops.append(s[pair_idx])
+    vert_total_hlen = get_loop_vert_len(hloops)
+    common.debug_print(vert_total_hlen)
+
+    # target vertex length
+    hloops = []
+    for s in loop_seqs[hidx][:vidx + 1]:
+        hloops.append(s[pair_idx])
+    vert_hlen = get_loop_vert_len(hloops)
+    common.debug_print(vert_hlen)
+
+    # get total UV length
+    # uv_all_hdiff = loop_seqs[0][-1][pair_idx][uv_layer].uv - \
+    #                loop_seqs[0][0][pair_idx][uv_layer].uv
+    uv_total_hlen = loop_seqs[hidx][-1][pair_idx][uv_layer].uv -\
+        loop_seqs[hidx][0][pair_idx][uv_layer].uv
+    common.debug_print(uv_total_hlen)
+
+    return uv_total_hlen * vert_hlen / vert_total_hlen
+
+
+# get horizontal differential of UV no influenced
+def get_hdiff_uv(uv_layer, loop_seqs, hidx):
+    base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+    h_uv = loop_seqs[-1][0][1][uv_layer].uv.copy() - base_uv
+
+    return hidx * h_uv / len(loop_seqs)
+
+
+# get vertical differential of UV no influenced
+def get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx):
+    base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+    v_uv = loop_seqs[0][-1][0][uv_layer].uv.copy() - base_uv
+
+    hseq = loop_seqs[hidx]
+    return int((vidx + 1) / 2) * v_uv / (len(hseq) / 2)
+
+
+class MUV_AUVStraighten(bpy.types.Operator):
+
+    bl_idname = "uv.muv_auv_straighten"
+    bl_label = "Straighten"
+    bl_description = "Straighten UV coordinates"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    transmission = BoolProperty(
+        name="Transmission",
+        description="Align linked UVs",
+        default=False
+    )
+    select = BoolProperty(
+        name="Select",
+        description="Select UVs which are aligned",
+        default=False
+    )
+    vertical = BoolProperty(
+        name="Vert-Infl (Vertical)",
+        description="Align vertical direction influenced "
+                    "by mesh vertex proportion",
+        default=False
+    )
+    horizontal = BoolProperty(
+        name="Vert-Infl (Horizontal)",
+        description="Align horizontal direction influenced "
+                    "by mesh vertex proportion",
+        default=False
+    )
+
+    @classmethod
+    def poll(cls, context):
+        return context.mode == 'EDIT_MESH'
+
+    # selected and paralleled UV loop sequence will be aligned
+    def __align_w_transmission(self, loop_seqs, uv_layer):
+        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+
+        # calculate diff UVs
+        diff_uvs = []
+        # hseq[vertical][loop]
+        for hidx, hseq in enumerate(loop_seqs):
+            # pair[loop]
+            diffs = []
+            for vidx in range(0, len(hseq), 2):
+                if self.horizontal:
+                    hdiff_uvs = [
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0),
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1),
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 0),
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 1),
+                    ]
+                else:
+                    hdiff_uvs = [
+                        get_hdiff_uv(uv_layer, loop_seqs, hidx),
+                        get_hdiff_uv(uv_layer, loop_seqs, hidx + 1),
+                        get_hdiff_uv(uv_layer, loop_seqs, hidx),
+                        get_hdiff_uv(uv_layer, loop_seqs, hidx + 1)
+                    ]
+                if self.vertical:
+                    vdiff_uvs = [
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0),
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1),
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 0),
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 1),
+                    ]
+                else:
+                    vdiff_uvs = [
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
+                    ]
+                diffs.append([hdiff_uvs, vdiff_uvs])
+            diff_uvs.append(diffs)
+
+        # update UV
+        for hseq, diffs in zip(loop_seqs, diff_uvs):
+            for vidx in range(0, len(hseq), 2):
+                loops = [
+                    hseq[vidx][0], hseq[vidx][1],
+                    hseq[vidx + 1][0], hseq[vidx + 1][1]
+                ]
+                for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
+                                           diffs[int(vidx / 2)][1]):
+                    l[uv_layer].uv = base_uv + hdiff + vdiff
+                    if self.select:
+                        l[uv_layer].select = True
+
+    # only selected UV loop sequence will be aligned
+    def __align_wo_transmission(self, loop_seqs, uv_layer):
+        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+
+        h_uv = loop_seqs[-1][0][1][uv_layer].uv.copy() - base_uv
+        for hidx, hseq in enumerate(loop_seqs):
+            # only selected loop pair is targeted
+            pair = hseq[0]
+            hdiff_uv_0 = hidx * h_uv / len(loop_seqs)
+            hdiff_uv_1 = (hidx + 1) * h_uv / len(loop_seqs)
+            pair[0][uv_layer].uv = base_uv + hdiff_uv_0
+            pair[1][uv_layer].uv = base_uv + hdiff_uv_1
+            if self.select:
+                pair[0][uv_layer].select = True
+                pair[1][uv_layer].select = True
+
+    def __align(self, loop_seqs, uv_layer):
+        if self.transmission:
+            self.__align_w_transmission(loop_seqs, uv_layer)
+        else:
+            self.__align_wo_transmission(loop_seqs, uv_layer)
+
+    def execute(self, context):
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        # loop_seqs[horizontal][vertical][loop]
+        loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
+        if not loop_seqs:
+            self.report({'WARNING'}, error)
+            return {'CANCELLED'}
+
+        # align
+        self.__align(loop_seqs, uv_layer)
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
+
+
+class MUV_AUVAxis(bpy.types.Operator):
+
+    bl_idname = "uv.muv_auv_axis"
+    bl_label = "XY-Axis"
+    bl_description = "Align UV to XY-axis"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    transmission = BoolProperty(
+        name="Transmission",
+        description="Align linked UVs",
+        default=False
+    )
+    select = BoolProperty(
+        name="Select",
+        description="Select UVs which are aligned",
+        default=False
+    )
+    vertical = BoolProperty(
+        name="Vert-Infl (Vertical)",
+        description="Align vertical direction influenced "
+                    "by mesh vertex proportion",
+        default=False
+    )
+    horizontal = BoolProperty(
+        name="Vert-Infl (Horizontal)",
+        description="Align horizontal direction influenced "
+                    "by mesh vertex proportion",
+        default=False
+    )
+    location = EnumProperty(
+        name="Location",
+        description="Align location",
+        items=[
+            ('LEFT_TOP', "Left/Top", "Align to Left or Top"),
+            ('MIDDLE', "Middle", "Align to middle"),
+            ('RIGHT_BOTTOM', "Right/Bottom", "Align to Right or Bottom")
+        ],
+        default='MIDDLE'
+    )
+
+    @classmethod
+    def poll(cls, context):
+        return context.mode == 'EDIT_MESH'
+
+    # get min/max of UV
+    def __get_uv_max_min(self, loop_seqs, uv_layer):
+        uv_max = Vector((-1000000.0, -1000000.0))
+        uv_min = Vector((1000000.0, 1000000.0))
+        for hseq in loop_seqs:
+            for l in hseq[0]:
+                uv = l[uv_layer].uv
+                uv_max.x = max(uv.x, uv_max.x)
+                uv_max.y = max(uv.y, uv_max.y)
+                uv_min.x = min(uv.x, uv_min.x)
+                uv_min.y = min(uv.y, uv_min.y)
+
+        return uv_max, uv_min
+
+    # get UV differentiation when UVs are aligned to X-axis
+    def __get_x_axis_align_diff_uvs(self, loop_seqs, uv_layer, uv_min,
+                                    width, height):
+        diff_uvs = []
+        for hidx, hseq in enumerate(loop_seqs):
+            pair = hseq[0]
+            luv0 = pair[0][uv_layer]
+            luv1 = pair[1][uv_layer]
+            target_uv0 = Vector((0.0, 0.0))
+            target_uv1 = Vector((0.0, 0.0))
+            if self.location == 'RIGHT_BOTTOM':
+                target_uv0.y = target_uv1.y = uv_min.y
+            elif self.location == 'MIDDLE':
+                target_uv0.y = target_uv1.y = uv_min.y + height * 0.5
+            elif self.location == 'LEFT_TOP':
+                target_uv0.y = target_uv1.y = uv_min.y + height
+            if luv0.uv.x < luv1.uv.x:
+                target_uv0.x = uv_min.x + hidx * width / len(loop_seqs)
+                target_uv1.x = uv_min.x + (hidx + 1) * width / len(loop_seqs)
+            else:
+                target_uv0.x = uv_min.x + (hidx + 1) * width / len(loop_seqs)
+                target_uv1.x = uv_min.x + hidx * width / len(loop_seqs)
+            diff_uvs.append([target_uv0 - luv0.uv, target_uv1 - luv1.uv])
+
+        return diff_uvs
+
+    # get UV differentiation when UVs are aligned to Y-axis
+    def __get_y_axis_align_diff_uvs(self, loop_seqs, uv_layer, uv_min,
+                                    width, height):
+        diff_uvs = []
+        for hidx, hseq in enumerate(loop_seqs):
+            pair = hseq[0]
+            luv0 = pair[0][uv_layer]
+            luv1 = pair[1][uv_layer]
+            target_uv0 = Vector((0.0, 0.0))
+            target_uv1 = Vector((0.0, 0.0))
+            if self.location == 'RIGHT_BOTTOM':
+                target_uv0.x = target_uv1.x = uv_min.x + width
+            elif self.location == 'MIDDLE':
+                target_uv0.x = target_uv1.x = uv_min.x + width * 0.5
+            elif self.location == 'LEFT_TOP':
+                target_uv0.x = target_uv1.x = uv_min.x
+            if luv0.uv.y < luv1.uv.y:
+                target_uv0.y = uv_min.y + hidx * height / len(loop_seqs)
+                target_uv1.y = uv_min.y + (hidx + 1) * height / len(loop_seqs)
+            else:
+                target_uv0.y = uv_min.y + (hidx + 1) * height / len(loop_seqs)
+                target_uv1.y = uv_min.y + hidx * height / len(loop_seqs)
+            diff_uvs.append([target_uv0 - luv0.uv, target_uv1 - luv1.uv])
+
+        return diff_uvs
+
+    # only selected UV loop sequence will be aligned along to X-axis
+    def __align_to_x_axis_wo_transmission(self, loop_seqs, uv_layer,
+                                          uv_min, width, height):
+        # reverse if the UV coordinate is not sorted by position
+        need_revese = loop_seqs[0][0][0][uv_layer].uv.x > \
+            loop_seqs[-1][0][0][uv_layer].uv.x
+        if need_revese:
+            loop_seqs.reverse()
+            for hidx, hseq in enumerate(loop_seqs):
+                for vidx, pair in enumerate(hseq):
+                    tmp = loop_seqs[hidx][vidx][0]
+                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+                    loop_seqs[hidx][vidx][1] = tmp
+
+        # get UV differential
+        diff_uvs = self.__get_x_axis_align_diff_uvs(loop_seqs, uv_layer,
+                                                    uv_min, width, height)
+
+        # update UV
+        for hseq, duv in zip(loop_seqs, diff_uvs):
+            pair = hseq[0]
+            luv0 = pair[0][uv_layer]
+            luv1 = pair[1][uv_layer]
+            luv0.uv = luv0.uv + duv[0]
+            luv1.uv = luv1.uv + duv[1]
+
+    # only selected UV loop sequence will be aligned along to Y-axis
+    def __align_to_y_axis_wo_transmission(self, loop_seqs, uv_layer,
+                                          uv_min, width, height):
+        # reverse if the UV coordinate is not sorted by position
+        need_revese = loop_seqs[0][0][0][uv_layer].uv.y > \
+            loop_seqs[-1][0][0][uv_layer].uv.y
+        if need_revese:
+            loop_seqs.reverse()
+            for hidx, hseq in enumerate(loop_seqs):
+                for vidx, pair in enumerate(hseq):
+                    tmp = loop_seqs[hidx][vidx][0]
+                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+                    loop_seqs[hidx][vidx][1] = tmp
+
+        # get UV differential
+        diff_uvs = self.__get_y_axis_align_diff_uvs(loop_seqs, uv_layer,
+                                                    uv_min, width, height)
+
+        # update UV
+        for hseq, duv in zip(loop_seqs, diff_uvs):
+            pair = hseq[0]
+            luv0 = pair[0][uv_layer]
+            luv1 = pair[1][uv_layer]
+            luv0.uv = luv0.uv + duv[0]
+            luv1.uv = luv1.uv + duv[1]
+
+    # selected and paralleled UV loop sequence will be aligned along to X-axis
+    def __align_to_x_axis_w_transmission(self, loop_seqs, uv_layer,
+                                         uv_min, width, height):
+        # reverse if the UV coordinate is not sorted by position
+        need_revese = loop_seqs[0][0][0][uv_layer].uv.x > \
+            loop_seqs[-1][0][0][uv_layer].uv.x
+        if need_revese:
+            loop_seqs.reverse()
+            for hidx, hseq in enumerate(loop_seqs):
+                for vidx in range(len(hseq)):
+                    tmp = loop_seqs[hidx][vidx][0]
+                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+                    loop_seqs[hidx][vidx][1] = tmp
+
+        # get offset UVs when the UVs are aligned to X-axis
+        align_diff_uvs = self.__get_x_axis_align_diff_uvs(loop_seqs, uv_layer,
+                                                          uv_min, width,
+                                                          height)
+        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+        offset_uvs = []
+        for hseq, aduv in zip(loop_seqs, align_diff_uvs):
+            luv0 = hseq[0][0][uv_layer]
+            luv1 = hseq[0][1][uv_layer]
+            offset_uvs.append([luv0.uv + aduv[0] - base_uv,
+                               luv1.uv + aduv[1] - base_uv])
+
+        # get UV differential
+        diff_uvs = []
+        # hseq[vertical][loop]
+        for hidx, hseq in enumerate(loop_seqs):
+            # pair[loop]
+            diffs = []
+            for vidx in range(0, len(hseq), 2):
+                if self.horizontal:
+                    hdiff_uvs = [
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0),
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1),
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 0),
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 1),
+                    ]
+                    hdiff_uvs[0].y = hdiff_uvs[0].y + offset_uvs[hidx][0].y
+                    hdiff_uvs[1].y = hdiff_uvs[1].y + offset_uvs[hidx][1].y
+                    hdiff_uvs[2].y = hdiff_uvs[2].y + offset_uvs[hidx][0].y
+                    hdiff_uvs[3].y = hdiff_uvs[3].y + offset_uvs[hidx][1].y
+                else:
+                    hdiff_uvs = [
+                        offset_uvs[hidx][0],
+                        offset_uvs[hidx][1],
+                        offset_uvs[hidx][0],
+                        offset_uvs[hidx][1],
+                    ]
+                if self.vertical:
+                    vdiff_uvs = [
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0),
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1),
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 0),
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 1),
+                    ]
+                else:
+                    vdiff_uvs = [
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
+                    ]
+                diffs.append([hdiff_uvs, vdiff_uvs])
+            diff_uvs.append(diffs)
+
+        # update UV
+        for hseq, diffs in zip(loop_seqs, diff_uvs):
+            for vidx in range(0, len(hseq), 2):
+                loops = [
+                    hseq[vidx][0], hseq[vidx][1],
+                    hseq[vidx + 1][0], hseq[vidx + 1][1]
+                ]
+                for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
+                                           diffs[int(vidx / 2)][1]):
+                    l[uv_layer].uv = base_uv + hdiff + vdiff
+                    if self.select:
+                        l[uv_layer].select = True
+
+    # selected and paralleled UV loop sequence will be aligned along to Y-axis
+    def __align_to_y_axis_w_transmission(self, loop_seqs, uv_layer,
+                                         uv_min, width, height):
+        # reverse if the UV coordinate is not sorted by position
+        need_revese = loop_seqs[0][0][0][uv_layer].uv.y > \
+            loop_seqs[-1][0][-1][uv_layer].uv.y
+        if need_revese:
+            loop_seqs.reverse()
+            for hidx, hseq in enumerate(loop_seqs):
+                for vidx in range(len(hseq)):
+                    tmp = loop_seqs[hidx][vidx][0]
+                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+                    loop_seqs[hidx][vidx][1] = tmp
+
+        # get offset UVs when the UVs are aligned to Y-axis
+        align_diff_uvs = self.__get_y_axis_align_diff_uvs(loop_seqs, uv_layer,
+                                                          uv_min, width,
+                                                          height)
+        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+        offset_uvs = []
+        for hseq, aduv in zip(loop_seqs, align_diff_uvs):
+            luv0 = hseq[0][0][uv_layer]
+            luv1 = hseq[0][1][uv_layer]
+            offset_uvs.append([luv0.uv + aduv[0] - base_uv,
+                               luv1.uv + aduv[1] - base_uv])
+
+        # get UV differential
+        diff_uvs = []
+        # hseq[vertical][loop]
+        for hidx, hseq in enumerate(loop_seqs):
+            # pair[loop]
+            diffs = []
+            for vidx in range(0, len(hseq), 2):
+                if self.horizontal:
+                    hdiff_uvs = [
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0),
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1),
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 0),
+                        get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 1),
+                    ]
+                    hdiff_uvs[0].x = hdiff_uvs[0].x + offset_uvs[hidx][0].x
+                    hdiff_uvs[1].x = hdiff_uvs[1].x + offset_uvs[hidx][1].x
+                    hdiff_uvs[2].x = hdiff_uvs[2].x + offset_uvs[hidx][0].x
+                    hdiff_uvs[3].x = hdiff_uvs[3].x + offset_uvs[hidx][1].x
+                else:
+                    hdiff_uvs = [
+                        offset_uvs[hidx][0],
+                        offset_uvs[hidx][1],
+                        offset_uvs[hidx][0],
+                        offset_uvs[hidx][1],
+                    ]
+                if self.vertical:
+                    vdiff_uvs = [
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0),
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1),
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 0),
+                        get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                           hidx, 1),
+                    ]
+                else:
+                    vdiff_uvs = [
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
+                        get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
+                    ]
+                diffs.append([hdiff_uvs, vdiff_uvs])
+            diff_uvs.append(diffs)
+
+        # update UV
+        for hseq, diffs in zip(loop_seqs, diff_uvs):
+            for vidx in range(0, len(hseq), 2):
+                loops = [
+                    hseq[vidx][0], hseq[vidx][1],
+                    hseq[vidx + 1][0], hseq[vidx + 1][1]
+                ]
+                for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
+                                           diffs[int(vidx / 2)][1]):
+                    l[uv_layer].uv = base_uv + hdiff + vdiff
+                    if self.select:
+                        l[uv_layer].select = True
+
+    def __align(self, loop_seqs, uv_layer, uv_min, width, height):
+        # align along to x-axis
+        if width > height:
+            if self.transmission:
+                self.__align_to_x_axis_w_transmission(loop_seqs, uv_layer,
+                                                      uv_min, width, height)
+            else:
+                self.__align_to_x_axis_wo_transmission(loop_seqs, uv_layer,
+                                                       uv_min, width, height)
+        # align along to y-axis
+        else:
+            if self.transmission:
+                self.__align_to_y_axis_w_transmission(loop_seqs, uv_layer,
+                                                      uv_min, width, height)
+            else:
+                self.__align_to_y_axis_wo_transmission(loop_seqs, uv_layer,
+                                                       uv_min, width, height)
+
+    def execute(self, context):
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        # loop_seqs[horizontal][vertical][loop]
+        loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
+        if not loop_seqs:
+            self.report({'WARNING'}, error)
+            return {'CANCELLED'}
+
+        # get height and width
+        uv_max, uv_min = self.__get_uv_max_min(loop_seqs, uv_layer)
+        width = uv_max.x - uv_min.x
+        height = uv_max.y - uv_min.y
+
+        self.__align(loop_seqs, uv_layer, uv_min, width, height)
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/align_uv_cursor.py b/uv_magic_uv/op/align_uv_cursor.py
new file mode 100644
index 0000000000000000000000000000000000000000..cae1c89a55fd693b7debd2defa27a3e4d6e1d39d
--- /dev/null
+++ b/uv_magic_uv/op/align_uv_cursor.py
@@ -0,0 +1,154 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+from mathutils import Vector
+from bpy.props import EnumProperty
+import bmesh
+
+from .. import common
+
+
+class MUV_AUVCAlignOps(bpy.types.Operator):
+
+    bl_idname = "uv.muv_auvc_align"
+    bl_label = "Align"
+    bl_description = "Align cursor to the center of UV island"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    position = EnumProperty(
+        items=(
+            ('CENTER', "Center", "Align to Center"),
+            ('LEFT_TOP', "Left Top", "Align to Left Top"),
+            ('LEFT_MIDDLE', "Left Middle", "Align to Left Middle"),
+            ('LEFT_BOTTOM', "Left Bottom", "Align to Left Bottom"),
+            ('MIDDLE_TOP', "Middle Top", "Align to Middle Top"),
+            ('MIDDLE_BOTTOM', "Middle Bottom", "Align to Middle Bottom"),
+            ('RIGHT_TOP', "Right Top", "Align to Right Top"),
+            ('RIGHT_MIDDLE', "Right Middle", "Align to Right Middle"),
+            ('RIGHT_BOTTOM', "Right Bottom", "Align to Right Bottom")
+        ),
+        name="Position",
+        description="Align position",
+        default='CENTER'
+    )
+    base = EnumProperty(
+        items=(
+            ('TEXTURE', "Texture", "Align based on Texture"),
+            ('UV', "UV", "Align to UV"),
+            ('UV_SEL', "UV (Selected)", "Align to Selected UV")
+        ),
+        name="Base",
+        description="Align base",
+        default='TEXTURE'
+    )
+
+    def execute(self, context):
+        area, _, space = common.get_space('IMAGE_EDITOR', 'WINDOW',
+                                          'IMAGE_EDITOR')
+        bd_size = common.get_uvimg_editor_board_size(area)
+
+        if self.base == 'UV':
+            obj = context.active_object
+            bm = bmesh.from_edit_mesh(obj.data)
+            if not bm.loops.layers.uv:
+                return None
+            uv_layer = bm.loops.layers.uv.verify()
+
+            max_ = Vector((-10000000.0, -10000000.0))
+            min_ = Vector((10000000.0, 10000000.0))
+            for f in bm.faces:
+                if not f.select:
+                    continue
+                for l in f.loops:
+                    uv = l[uv_layer].uv
+                    max_.x = max(max_.x, uv.x)
+                    max_.y = max(max_.y, uv.y)
+                    min_.x = min(min_.x, uv.x)
+                    min_.y = min(min_.y, uv.y)
+            center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
+
+        elif self.base == 'UV_SEL':
+            obj = context.active_object
+            bm = bmesh.from_edit_mesh(obj.data)
+            if not bm.loops.layers.uv:
+                return None
+            uv_layer = bm.loops.layers.uv.verify()
+
+            max_ = Vector((-10000000.0, -10000000.0))
+            min_ = Vector((10000000.0, 10000000.0))
+            for f in bm.faces:
+                if not f.select:
+                    continue
+                for l in f.loops:
+                    if not l[uv_layer].select:
+                        continue
+                    uv = l[uv_layer].uv
+                    max_.x = max(max_.x, uv.x)
+                    max_.y = max(max_.y, uv.y)
+                    min_.x = min(min_.x, uv.x)
+                    min_.y = min(min_.y, uv.y)
+            center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
+
+        elif self.base == 'TEXTURE':
+            min_ = Vector((0.0, 0.0))
+            max_ = Vector((1.0, 1.0))
+            center = Vector((0.5, 0.5))
+        else:
+            self.report({'ERROR'}, "Unknown Operation")
+
+        if self.position == 'CENTER':
+            cx = center.x * bd_size[0]
+            cy = center.y * bd_size[1]
+        elif self.position == 'LEFT_TOP':
+            cx = min_.x * bd_size[0]
+            cy = max_.y * bd_size[1]
+        elif self.position == 'LEFT_MIDDLE':
+            cx = min_.x * bd_size[0]
+            cy = center.y * bd_size[1]
+        elif self.position == 'LEFT_BOTTOM':
+            cx = min_.x * bd_size[0]
+            cy = min_.y * bd_size[1]
+        elif self.position == 'MIDDLE_TOP':
+            cx = center.x * bd_size[0]
+            cy = max_.y * bd_size[1]
+        elif self.position == 'MIDDLE_BOTTOM':
+            cx = center.x * bd_size[0]
+            cy = min_.y * bd_size[1]
+        elif self.position == 'RIGHT_TOP':
+            cx = max_.x * bd_size[0]
+            cy = max_.y * bd_size[1]
+        elif self.position == 'RIGHT_MIDDLE':
+            cx = max_.x * bd_size[0]
+            cy = center.y * bd_size[1]
+        elif self.position == 'RIGHT_BOTTOM':
+            cx = max_.x * bd_size[0]
+            cy = min_.y * bd_size[1]
+        else:
+            self.report({'ERROR'}, "Unknown Operation")
+
+        space.cursor_location = Vector((cx, cy))
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/muv_cpuv_ops.py b/uv_magic_uv/op/copy_paste_uv.py
similarity index 50%
rename from uv_magic_uv/muv_cpuv_ops.py
rename to uv_magic_uv/op/copy_paste_uv.py
index 82f043c62d6cbc0b4161be42126b34cfd021954b..ee89b5e965afc996d94be49c37fb60db042e2e65 100644
--- a/uv_magic_uv/muv_cpuv_ops.py
+++ b/uv_magic_uv/op/copy_paste_uv.py
@@ -18,10 +18,13 @@
 #
 # ##### END GPL LICENSE BLOCK #####
 
-__author__ = "Nutti <nutti.metro@gmail.com>, Jace Priester"
+__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import math
+from math import atan2, sin, cos
 
 import bpy
 import bmesh
@@ -31,16 +34,9 @@ from bpy.props import (
     IntProperty,
     EnumProperty,
 )
-from . import muv_common
-
+from mathutils import Vector
 
-def memorize_view_3d_mode(fn):
-    def __memorize_view_3d_mode(self, context):
-        mode_orig = bpy.context.object.mode
-        result = fn(self, context)
-        bpy.ops.object.mode_set(mode=mode_orig)
-        return result
-    return __memorize_view_3d_mode
+from .. import common
 
 
 class MUV_CPUVCopyUV(bpy.types.Operator):
@@ -64,7 +60,7 @@ class MUV_CPUVCopyUV(bpy.types.Operator):
                 {'INFO'}, "Copy UV coordinate (UV map:%s)" % (self.uv_map))
         obj = context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
 
         # get UV layer
@@ -174,7 +170,7 @@ class MUV_CPUVPasteUV(bpy.types.Operator):
                 {'INFO'}, "Paste UV coordinate (UV map:%s)" % (self.uv_map))
         obj = context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
 
         # get UV layer
@@ -273,46 +269,158 @@ class MUV_CPUVPasteUVMenu(bpy.types.Menu):
     bl_description = "Paste UV coordinate"
 
     def draw(self, context):
+        sc = context.scene
         layout = self.layout
         # create sub menu
         obj = context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
         uv_maps = bm.loops.layers.uv.keys()
-        layout.operator(
-            MUV_CPUVPasteUV.bl_idname,
-            text="[Default]", icon="IMAGE_COL").uv_map = ""
+        ops = layout.operator(MUV_CPUVPasteUV.bl_idname, text="[Default]")
+        ops.uv_map = ""
+        ops.copy_seams = sc.muv_cpuv_copy_seams
+        ops.strategy = sc.muv_cpuv_strategy
         for m in uv_maps:
-            layout.operator(
-                MUV_CPUVPasteUV.bl_idname,
-                text=m, icon="IMAGE_COL").uv_map = m
+            ops = layout.operator(MUV_CPUVPasteUV.bl_idname, text=m)
+            ops.uv_map = m
+            ops.copy_seams = sc.muv_cpuv_copy_seams
+            ops.strategy = sc.muv_cpuv_strategy
 
 
-class MUV_CPUVObjCopyUV(bpy.types.Operator):
+class MUV_CPUVIECopyUV(bpy.types.Operator):
     """
-    Operation class: Copy UV coordinate per object
+    Operation class: Copy UV coordinate on UV/Image Editor
     """
 
-    bl_idname = "object.muv_cpuv_obj_copy_uv"
+    bl_idname = "uv.muv_cpuv_ie_copy_uv"
     bl_label = "Copy UV"
-    bl_description = "Copy UV coordinate"
+    bl_description = "Copy UV coordinate (only selected in UV/Image Editor)"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.mode == 'EDIT_MESH'
+
+    def execute(self, context):
+        props = context.scene.muv_props.cpuv
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        uv_layer = bm.loops.layers.uv.verify()
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        for face in bm.faces:
+            if not face.select:
+                continue
+            skip = False
+            for l in face.loops:
+                if not l[uv_layer].select:
+                    skip = True
+                    break
+            if skip:
+                continue
+            props.src_uvs.append([l[uv_layer].uv.copy() for l in face.loops])
+
+        return {'FINISHED'}
+
+
+class MUV_CPUVIEPasteUV(bpy.types.Operator):
+    """
+    Operation class: Paste UV coordinate on UV/Image Editor
+    """
+
+    bl_idname = "uv.muv_cpuv_ie_paste_uv"
+    bl_label = "Paste UV"
+    bl_description = "Paste UV coordinate (only selected in UV/Image Editor)"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.mode == 'EDIT_MESH'
+
+    def execute(self, context):
+        props = context.scene.muv_props.cpuv
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        uv_layer = bm.loops.layers.uv.verify()
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        dest_uvs = []
+        dest_face_indices = []
+        for face in bm.faces:
+            if not face.select:
+                continue
+            skip = False
+            for l in face.loops:
+                if not l[uv_layer].select:
+                    skip = True
+                    break
+            if skip:
+                continue
+            dest_face_indices.append(face.index)
+            uvs = [l[uv_layer].uv.copy() for l in face.loops]
+            dest_uvs.append(uvs)
+
+        for suvs, duvs in zip(props.src_uvs, dest_uvs):
+            src_diff = suvs[1] - suvs[0]
+            dest_diff = duvs[1] - duvs[0]
+
+            src_base = suvs[0]
+            dest_base = duvs[0]
+
+            src_rad = atan2(src_diff.y, src_diff.x)
+            dest_rad = atan2(dest_diff.y, dest_diff.x)
+            if src_rad < dest_rad:
+                radian = dest_rad - src_rad
+            elif src_rad > dest_rad:
+                radian = math.pi * 2 - (src_rad - dest_rad)
+            else:       # src_rad == dest_rad
+                radian = 0.0
+
+            ratio = dest_diff.length / src_diff.length
+            break
+
+        for suvs, fidx in zip(props.src_uvs, dest_face_indices):
+            for l, suv in zip(bm.faces[fidx].loops, suvs):
+                base = suv - src_base
+                radian_ref = atan2(base.y, base.x)
+                radian_fin = (radian + radian_ref)
+                length = base.length
+                turn = Vector((length * cos(radian_fin),
+                               length * sin(radian_fin)))
+                target_uv = Vector((turn.x * ratio, turn.y * ratio)) + \
+                    dest_base
+                l[uv_layer].uv = target_uv
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
+
+
+class MUV_CPUVSelSeqCopyUV(bpy.types.Operator):
+    """
+    Operation class: Copy UV coordinate by selection sequence
+    """
+
+    bl_idname = "uv.muv_cpuv_selseq_copy_uv"
+    bl_label = "Copy UV (Selection Sequence) (Operation)"
+    bl_description = "Copy UV data by selection sequence (Operation)"
     bl_options = {'REGISTER', 'UNDO'}
 
     uv_map = StringProperty(options={'HIDDEN'})
 
-    @memorize_view_3d_mode
     def execute(self, context):
-        props = context.scene.muv_props.cpuv_obj
+        props = context.scene.muv_props.cpuv_selseq
         if self.uv_map == "":
-            self.report({'INFO'}, "Copy UV coordinate per object")
+            self.report({'INFO'}, "Copy UV coordinate (selection sequence)")
         else:
             self.report(
                 {'INFO'},
-                "Copy UV coordinate per object (UV map:%s)" % (self.uv_map))
-        bpy.ops.object.mode_set(mode='EDIT')
-
+                "Copy UV coordinate (selection sequence) (UV map:%s)"
+                % (self.uv_map))
         obj = context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
 
         # get UV layer
@@ -329,171 +437,210 @@ class MUV_CPUVObjCopyUV(bpy.types.Operator):
         props.src_uvs = []
         props.src_pin_uvs = []
         props.src_seams = []
-        for face in bm.faces:
-            uvs = [l[uv_layer].uv.copy() for l in face.loops]
-            pin_uvs = [l[uv_layer].pin_uv for l in face.loops]
-            seams = [l.edge.seam for l in face.loops]
-            props.src_uvs.append(uvs)
-            props.src_pin_uvs.append(pin_uvs)
-            props.src_seams.append(seams)
-
-        self.report({'INFO'}, "%s's UV coordinates are copied" % (obj.name))
+        for hist in bm.select_history:
+            if isinstance(hist, bmesh.types.BMFace) and hist.select:
+                uvs = [l[uv_layer].uv.copy() for l in hist.loops]
+                pin_uvs = [l[uv_layer].pin_uv for l in hist.loops]
+                seams = [l.edge.seam for l in hist.loops]
+                props.src_uvs.append(uvs)
+                props.src_pin_uvs.append(pin_uvs)
+                props.src_seams.append(seams)
+        if not props.src_uvs or not props.src_pin_uvs:
+            self.report({'WARNING'}, "No faces are selected")
+            return {'CANCELLED'}
+        self.report({'INFO'}, "%d face(s) are selected" % len(props.src_uvs))
 
         return {'FINISHED'}
 
 
-class MUV_CPUVObjCopyUVMenu(bpy.types.Menu):
+class MUV_CPUVSelSeqCopyUVMenu(bpy.types.Menu):
     """
-    Menu class: Copy UV coordinate per object
+    Menu class: Copy UV coordinate by selection sequence
     """
 
-    bl_idname = "object.muv_cpuv_obj_copy_uv_menu"
-    bl_label = "Copy UV"
-    bl_description = "Copy UV coordinate per object"
+    bl_idname = "uv.muv_cpuv_selseq_copy_uv_menu"
+    bl_label = "Copy UV (Selection Sequence)"
+    bl_description = "Copy UV coordinate by selection sequence"
 
-    def draw(self, _):
+    def draw(self, context):
         layout = self.layout
-        # create sub menu
-        uv_maps = bpy.context.active_object.data.uv_textures.keys()
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        uv_maps = bm.loops.layers.uv.keys()
         layout.operator(
-            MUV_CPUVObjCopyUV.bl_idname,
+            MUV_CPUVSelSeqCopyUV.bl_idname,
             text="[Default]", icon="IMAGE_COL").uv_map = ""
         for m in uv_maps:
             layout.operator(
-                MUV_CPUVObjCopyUV.bl_idname,
+                MUV_CPUVSelSeqCopyUV.bl_idname,
                 text=m, icon="IMAGE_COL").uv_map = m
 
 
-class MUV_CPUVObjPasteUV(bpy.types.Operator):
+class MUV_CPUVSelSeqPasteUV(bpy.types.Operator):
     """
-    Operation class: Paste UV coordinate per object
+    Operation class: Paste UV coordinate by selection sequence
     """
 
-    bl_idname = "object.muv_cpuv_obj_paste_uv"
-    bl_label = "Paste UV"
-    bl_description = "Paste UV coordinate"
+    bl_idname = "uv.muv_cpuv_selseq_paste_uv"
+    bl_label = "Paste UV (Selection Sequence) (Operation)"
+    bl_description = "Paste UV coordinate by selection sequence (Operation)"
     bl_options = {'REGISTER', 'UNDO'}
 
     uv_map = StringProperty(options={'HIDDEN'})
+    strategy = EnumProperty(
+        name="Strategy",
+        description="Paste Strategy",
+        items=[
+            ('N_N', 'N:N', 'Number of faces must be equal to source'),
+            ('N_M', 'N:M', 'Number of faces must not be equal to source')
+        ],
+        default="N_M"
+    )
+    flip_copied_uv = BoolProperty(
+        name="Flip Copied UV",
+        description="Flip Copied UV...",
+        default=False
+    )
+    rotate_copied_uv = IntProperty(
+        default=0,
+        name="Rotate Copied UV",
+        min=0,
+        max=30
+    )
     copy_seams = BoolProperty(
         name="Copy Seams",
         description="Copy Seams",
         default=True
     )
 
-    @memorize_view_3d_mode
     def execute(self, context):
-        props = context.scene.muv_props.cpuv_obj
+        props = context.scene.muv_props.cpuv_selseq
         if not props.src_uvs or not props.src_pin_uvs:
             self.report({'WARNING'}, "Need copy UV at first")
             return {'CANCELLED'}
+        if self.uv_map == "":
+            self.report({'INFO'}, "Paste UV coordinate (selection sequence)")
+        else:
+            self.report(
+                {'INFO'},
+                "Paste UV coordinate (selection sequence) (UV map:%s)"
+                % (self.uv_map))
 
-        for o in bpy.data.objects:
-            if not hasattr(o.data, "uv_textures") or not o.select:
-                continue
-
-            bpy.ops.object.mode_set(mode='OBJECT')
-            bpy.context.scene.objects.active = o
-            bpy.ops.object.mode_set(mode='EDIT')
-
-            obj = context.active_object
-            bm = bmesh.from_edit_mesh(obj.data)
-            if muv_common.check_version(2, 73, 0) >= 0:
-                bm.faces.ensure_lookup_table()
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
 
-            if (self.uv_map == "" or
-                    self.uv_map not in bm.loops.layers.uv.keys()):
-                self.report({'INFO'}, "Paste UV coordinate per object")
-            else:
+        # get UV layer
+        if self.uv_map == "":
+            if not bm.loops.layers.uv:
                 self.report(
-                    {'INFO'},
-                    "Paste UV coordinate per object (UV map: %s)"
-                    % (self.uv_map))
-
-            # get UV layer
-            if (self.uv_map == "" or
-                    self.uv_map not in bm.loops.layers.uv.keys()):
-                if not bm.loops.layers.uv:
-                    self.report(
-                        {'WARNING'}, "Object must have more than one UV map")
-                    return {'CANCELLED'}
-                uv_layer = bm.loops.layers.uv.verify()
-            else:
-                uv_layer = bm.loops.layers.uv[self.uv_map]
-
-            # get selected face
-            dest_uvs = []
-            dest_pin_uvs = []
-            dest_seams = []
-            dest_face_indices = []
-            for face in bm.faces:
-                dest_face_indices.append(face.index)
-                uvs = [l[uv_layer].uv.copy() for l in face.loops]
-                pin_uvs = [l[uv_layer].pin_uv for l in face.loops]
-                seams = [l.edge.seam for l in face.loops]
+                    {'WARNING'}, "Object must have more than one UV map")
+                return {'CANCELLED'}
+            uv_layer = bm.loops.layers.uv.verify()
+        else:
+            uv_layer = bm.loops.layers.uv[self.uv_map]
+
+        # get selected face
+        dest_uvs = []
+        dest_pin_uvs = []
+        dest_seams = []
+        dest_face_indices = []
+        for hist in bm.select_history:
+            if isinstance(hist, bmesh.types.BMFace) and hist.select:
+                dest_face_indices.append(hist.index)
+                uvs = [l[uv_layer].uv.copy() for l in hist.loops]
+                pin_uvs = [l[uv_layer].pin_uv for l in hist.loops]
+                seams = [l.edge.seam for l in hist.loops]
                 dest_uvs.append(uvs)
                 dest_pin_uvs.append(pin_uvs)
                 dest_seams.append(seams)
-            if len(props.src_uvs) != len(dest_uvs):
-                self.report(
-                    {'WARNING'},
-                    "Number of faces is different from copied " +
-                    "(src:%d, dest:%d)"
-                    % (len(props.src_uvs), len(dest_uvs))
-                )
-                return {'CANCELLED'}
+        if not dest_uvs or not dest_pin_uvs:
+            self.report({'WARNING'}, "No faces are selected")
+            return {'CANCELLED'}
+        if self.strategy == 'N_N' and len(props.src_uvs) != len(dest_uvs):
+            self.report(
+                {'WARNING'},
+                "Number of selected faces is different from copied faces " +
+                "(src:%d, dest:%d)"
+                % (len(props.src_uvs), len(dest_uvs)))
+            return {'CANCELLED'}
 
-            # paste
-            for i, idx in enumerate(dest_face_indices):
+        # paste
+        for i, idx in enumerate(dest_face_indices):
+            suv = None
+            spuv = None
+            ss = None
+            duv = None
+            if self.strategy == 'N_N':
                 suv = props.src_uvs[i]
                 spuv = props.src_pin_uvs[i]
                 ss = props.src_seams[i]
                 duv = dest_uvs[i]
-                if len(suv) != len(duv):
-                    self.report({'WARNING'}, "Some faces are different size")
-                    return {'CANCELLED'}
-                suvs_fr = [uv for uv in suv]
-                spuvs_fr = [pin_uv for pin_uv in spuv]
-                ss_fr = [s for s in ss]
-                # paste UVs
-                for l, suv, spuv, ss in zip(
-                        bm.faces[idx].loops, suvs_fr, spuvs_fr, ss_fr):
-                    l[uv_layer].uv = suv
-                    l[uv_layer].pin_uv = spuv
-                    if self.copy_seams is True:
-                        l.edge.seam = ss
-
-            bmesh.update_edit_mesh(obj.data)
-            if self.copy_seams is True:
-                obj.data.show_edge_seams = True
+            elif self.strategy == 'N_M':
+                suv = props.src_uvs[i % len(props.src_uvs)]
+                spuv = props.src_pin_uvs[i % len(props.src_pin_uvs)]
+                ss = props.src_seams[i % len(props.src_seams)]
+                duv = dest_uvs[i]
+            if len(suv) != len(duv):
+                self.report({'WARNING'}, "Some faces are different size")
+                return {'CANCELLED'}
+            suvs_fr = [uv for uv in suv]
+            spuvs_fr = [pin_uv for pin_uv in spuv]
+            ss_fr = [s for s in ss]
+            # flip UVs
+            if self.flip_copied_uv is True:
+                suvs_fr.reverse()
+                spuvs_fr.reverse()
+                ss_fr.reverse()
+            # rotate UVs
+            for _ in range(self.rotate_copied_uv):
+                uv = suvs_fr.pop()
+                pin_uv = spuvs_fr.pop()
+                s = ss_fr.pop()
+                suvs_fr.insert(0, uv)
+                spuvs_fr.insert(0, pin_uv)
+                ss_fr.insert(0, s)
+            # paste UVs
+            for l, suv, spuv, ss in zip(bm.faces[idx].loops, suvs_fr,
+                                        spuvs_fr, ss_fr):
+                l[uv_layer].uv = suv
+                l[uv_layer].pin_uv = spuv
+                if self.copy_seams is True:
+                    l.edge.seam = ss
 
-            self.report(
-                {'INFO'}, "%s's UV coordinates are pasted" % (obj.name))
+        self.report({'INFO'}, "%d face(s) are copied" % len(dest_uvs))
+
+        bmesh.update_edit_mesh(obj.data)
+        if self.copy_seams is True:
+            obj.data.show_edge_seams = True
 
         return {'FINISHED'}
 
 
-class MUV_CPUVObjPasteUVMenu(bpy.types.Menu):
+class MUV_CPUVSelSeqPasteUVMenu(bpy.types.Menu):
     """
-    Menu class: Paste UV coordinate per object
+    Menu class: Paste UV coordinate by selection sequence
     """
 
-    bl_idname = "object.muv_cpuv_obj_paste_uv_menu"
-    bl_label = "Paste UV"
-    bl_description = "Paste UV coordinate per object"
+    bl_idname = "uv.muv_cpuv_selseq_paste_uv_menu"
+    bl_label = "Paste UV (Selection Sequence)"
+    bl_description = "Paste UV coordinate by selection sequence"
 
-    def draw(self, _):
+    def draw(self, context):
+        sc = context.scene
         layout = self.layout
         # create sub menu
-        uv_maps = []
-        for obj in bpy.data.objects:
-            if hasattr(obj.data, "uv_textures") and obj.select:
-                uv_maps.extend(obj.data.uv_textures.keys())
-        uv_maps = list(set(uv_maps))
-        layout.operator(
-            MUV_CPUVObjPasteUV.bl_idname,
-            text="[Default]", icon="IMAGE_COL").uv_map = ""
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        uv_maps = bm.loops.layers.uv.keys()
+        ops = layout.operator(MUV_CPUVSelSeqPasteUV.bl_idname,
+                              text="[Default]")
+        ops.uv_map = ""
+        ops.copy_seams = sc.muv_cpuv_copy_seams
+        ops.strategy = sc.muv_cpuv_strategy
         for m in uv_maps:
-            layout.operator(
-                MUV_CPUVObjPasteUV.bl_idname,
-                text=m, icon="IMAGE_COL").uv_map = m
+            ops = layout.operator(MUV_CPUVSelSeqPasteUV.bl_idname, text=m)
+            ops.uv_map = m
+            ops.copy_seams = sc.muv_cpuv_copy_seams
+            ops.strategy = sc.muv_cpuv_strategy
diff --git a/uv_magic_uv/op/copy_paste_uv_object.py b/uv_magic_uv/op/copy_paste_uv_object.py
new file mode 100644
index 0000000000000000000000000000000000000000..d80ee4152a4ffc133c9b6eeb801968eb28b230ca
--- /dev/null
+++ b/uv_magic_uv/op/copy_paste_uv_object.py
@@ -0,0 +1,252 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+import bmesh
+from bpy.props import (
+    StringProperty,
+    BoolProperty,
+)
+
+from .. import common
+
+
+def memorize_view_3d_mode(fn):
+    def __memorize_view_3d_mode(self, context):
+        mode_orig = bpy.context.object.mode
+        result = fn(self, context)
+        bpy.ops.object.mode_set(mode=mode_orig)
+        return result
+    return __memorize_view_3d_mode
+
+
+class MUV_CPUVObjCopyUV(bpy.types.Operator):
+    """
+    Operation class: Copy UV coordinate per object
+    """
+
+    bl_idname = "object.muv_cpuv_obj_copy_uv"
+    bl_label = "Copy UV"
+    bl_description = "Copy UV coordinate"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    uv_map = StringProperty(options={'HIDDEN'})
+
+    @memorize_view_3d_mode
+    def execute(self, context):
+        props = context.scene.muv_props.cpuv_obj
+        if self.uv_map == "":
+            self.report({'INFO'}, "Copy UV coordinate per object")
+        else:
+            self.report(
+                {'INFO'},
+                "Copy UV coordinate per object (UV map:%s)" % (self.uv_map))
+        bpy.ops.object.mode_set(mode='EDIT')
+
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        # get UV layer
+        if self.uv_map == "":
+            if not bm.loops.layers.uv:
+                self.report(
+                    {'WARNING'}, "Object must have more than one UV map")
+                return {'CANCELLED'}
+            uv_layer = bm.loops.layers.uv.verify()
+        else:
+            uv_layer = bm.loops.layers.uv[self.uv_map]
+
+        # get selected face
+        props.src_uvs = []
+        props.src_pin_uvs = []
+        props.src_seams = []
+        for face in bm.faces:
+            uvs = [l[uv_layer].uv.copy() for l in face.loops]
+            pin_uvs = [l[uv_layer].pin_uv for l in face.loops]
+            seams = [l.edge.seam for l in face.loops]
+            props.src_uvs.append(uvs)
+            props.src_pin_uvs.append(pin_uvs)
+            props.src_seams.append(seams)
+
+        self.report({'INFO'}, "%s's UV coordinates are copied" % (obj.name))
+
+        return {'FINISHED'}
+
+
+class MUV_CPUVObjCopyUVMenu(bpy.types.Menu):
+    """
+    Menu class: Copy UV coordinate per object
+    """
+
+    bl_idname = "object.muv_cpuv_obj_copy_uv_menu"
+    bl_label = "Copy UV"
+    bl_description = "Copy UV coordinate per object"
+
+    def draw(self, _):
+        layout = self.layout
+        # create sub menu
+        uv_maps = bpy.context.active_object.data.uv_textures.keys()
+        layout.operator(MUV_CPUVObjCopyUV.bl_idname, text="[Default]")\
+            .uv_map = ""
+        for m in uv_maps:
+            layout.operator(MUV_CPUVObjCopyUV.bl_idname, text=m).uv_map = m
+
+
+class MUV_CPUVObjPasteUV(bpy.types.Operator):
+    """
+    Operation class: Paste UV coordinate per object
+    """
+
+    bl_idname = "object.muv_cpuv_obj_paste_uv"
+    bl_label = "Paste UV"
+    bl_description = "Paste UV coordinate"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    uv_map = StringProperty(options={'HIDDEN'})
+    copy_seams = BoolProperty(
+        name="Copy Seams",
+        description="Copy Seams",
+        default=True
+    )
+
+    @memorize_view_3d_mode
+    def execute(self, context):
+        props = context.scene.muv_props.cpuv_obj
+        if not props.src_uvs or not props.src_pin_uvs:
+            self.report({'WARNING'}, "Need copy UV at first")
+            return {'CANCELLED'}
+
+        for o in bpy.data.objects:
+            if not hasattr(o.data, "uv_textures") or not o.select:
+                continue
+
+            bpy.ops.object.mode_set(mode='OBJECT')
+            bpy.context.scene.objects.active = o
+            bpy.ops.object.mode_set(mode='EDIT')
+
+            obj = context.active_object
+            bm = bmesh.from_edit_mesh(obj.data)
+            if common.check_version(2, 73, 0) >= 0:
+                bm.faces.ensure_lookup_table()
+
+            if (self.uv_map == "" or
+                    self.uv_map not in bm.loops.layers.uv.keys()):
+                self.report({'INFO'}, "Paste UV coordinate per object")
+            else:
+                self.report(
+                    {'INFO'},
+                    "Paste UV coordinate per object (UV map: %s)"
+                    % (self.uv_map))
+
+            # get UV layer
+            if (self.uv_map == "" or
+                    self.uv_map not in bm.loops.layers.uv.keys()):
+                if not bm.loops.layers.uv:
+                    self.report(
+                        {'WARNING'}, "Object must have more than one UV map")
+                    return {'CANCELLED'}
+                uv_layer = bm.loops.layers.uv.verify()
+            else:
+                uv_layer = bm.loops.layers.uv[self.uv_map]
+
+            # get selected face
+            dest_uvs = []
+            dest_pin_uvs = []
+            dest_seams = []
+            dest_face_indices = []
+            for face in bm.faces:
+                dest_face_indices.append(face.index)
+                uvs = [l[uv_layer].uv.copy() for l in face.loops]
+                pin_uvs = [l[uv_layer].pin_uv for l in face.loops]
+                seams = [l.edge.seam for l in face.loops]
+                dest_uvs.append(uvs)
+                dest_pin_uvs.append(pin_uvs)
+                dest_seams.append(seams)
+            if len(props.src_uvs) != len(dest_uvs):
+                self.report(
+                    {'WARNING'},
+                    "Number of faces is different from copied " +
+                    "(src:%d, dest:%d)"
+                    % (len(props.src_uvs), len(dest_uvs))
+                )
+                return {'CANCELLED'}
+
+            # paste
+            for i, idx in enumerate(dest_face_indices):
+                suv = props.src_uvs[i]
+                spuv = props.src_pin_uvs[i]
+                ss = props.src_seams[i]
+                duv = dest_uvs[i]
+                if len(suv) != len(duv):
+                    self.report({'WARNING'}, "Some faces are different size")
+                    return {'CANCELLED'}
+                suvs_fr = [uv for uv in suv]
+                spuvs_fr = [pin_uv for pin_uv in spuv]
+                ss_fr = [s for s in ss]
+                # paste UVs
+                for l, suv, spuv, ss in zip(
+                        bm.faces[idx].loops, suvs_fr, spuvs_fr, ss_fr):
+                    l[uv_layer].uv = suv
+                    l[uv_layer].pin_uv = spuv
+                    if self.copy_seams is True:
+                        l.edge.seam = ss
+
+            bmesh.update_edit_mesh(obj.data)
+            if self.copy_seams is True:
+                obj.data.show_edge_seams = True
+
+            self.report(
+                {'INFO'}, "%s's UV coordinates are pasted" % (obj.name))
+
+        return {'FINISHED'}
+
+
+class MUV_CPUVObjPasteUVMenu(bpy.types.Menu):
+    """
+    Menu class: Paste UV coordinate per object
+    """
+
+    bl_idname = "object.muv_cpuv_obj_paste_uv_menu"
+    bl_label = "Paste UV"
+    bl_description = "Paste UV coordinate per object"
+
+    def draw(self, context):
+        sc = context.scene
+        layout = self.layout
+        # create sub menu
+        uv_maps = []
+        for obj in bpy.data.objects:
+            if hasattr(obj.data, "uv_textures") and obj.select:
+                uv_maps.extend(obj.data.uv_textures.keys())
+        uv_maps = list(set(uv_maps))
+        ops = layout.operator(MUV_CPUVObjPasteUV.bl_idname, text="[Default]")
+        ops.uv_map = ""
+        ops.copy_seams = sc.muv_cpuv_copy_seams
+        for m in uv_maps:
+            ops = layout.operator(MUV_CPUVObjPasteUV.bl_idname, text=m)
+            ops.uv_map = m
+            ops.copy_seams = sc.muv_cpuv_copy_seams
diff --git a/uv_magic_uv/op/copy_paste_uv_uvedit.py b/uv_magic_uv/op/copy_paste_uv_uvedit.py
new file mode 100644
index 0000000000000000000000000000000000000000..96908020a1028ee159f387525bc6baf2e1d9e8a3
--- /dev/null
+++ b/uv_magic_uv/op/copy_paste_uv_uvedit.py
@@ -0,0 +1,144 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>, Jace Priester"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import math
+from math import atan2, sin, cos
+
+import bpy
+import bmesh
+from mathutils import Vector
+
+from .. import common
+
+
+class MUV_CPUVIECopyUV(bpy.types.Operator):
+    """
+    Operation class: Copy UV coordinate on UV/Image Editor
+    """
+
+    bl_idname = "uv.muv_cpuv_ie_copy_uv"
+    bl_label = "Copy UV"
+    bl_description = "Copy UV coordinate (only selected in UV/Image Editor)"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.mode == 'EDIT_MESH'
+
+    def execute(self, context):
+        props = context.scene.muv_props.cpuv
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        uv_layer = bm.loops.layers.uv.verify()
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        for face in bm.faces:
+            if not face.select:
+                continue
+            skip = False
+            for l in face.loops:
+                if not l[uv_layer].select:
+                    skip = True
+                    break
+            if skip:
+                continue
+            props.src_uvs.append([l[uv_layer].uv.copy() for l in face.loops])
+
+        return {'FINISHED'}
+
+
+class MUV_CPUVIEPasteUV(bpy.types.Operator):
+    """
+    Operation class: Paste UV coordinate on UV/Image Editor
+    """
+
+    bl_idname = "uv.muv_cpuv_ie_paste_uv"
+    bl_label = "Paste UV"
+    bl_description = "Paste UV coordinate (only selected in UV/Image Editor)"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.mode == 'EDIT_MESH'
+
+    def execute(self, context):
+        props = context.scene.muv_props.cpuv
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        uv_layer = bm.loops.layers.uv.verify()
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        dest_uvs = []
+        dest_face_indices = []
+        for face in bm.faces:
+            if not face.select:
+                continue
+            skip = False
+            for l in face.loops:
+                if not l[uv_layer].select:
+                    skip = True
+                    break
+            if skip:
+                continue
+            dest_face_indices.append(face.index)
+            uvs = [l[uv_layer].uv.copy() for l in face.loops]
+            dest_uvs.append(uvs)
+
+        for suvs, duvs in zip(props.src_uvs, dest_uvs):
+            src_diff = suvs[1] - suvs[0]
+            dest_diff = duvs[1] - duvs[0]
+
+            src_base = suvs[0]
+            dest_base = duvs[0]
+
+            src_rad = atan2(src_diff.y, src_diff.x)
+            dest_rad = atan2(dest_diff.y, dest_diff.x)
+            if src_rad < dest_rad:
+                radian = dest_rad - src_rad
+            elif src_rad > dest_rad:
+                radian = math.pi * 2 - (src_rad - dest_rad)
+            else:       # src_rad == dest_rad
+                radian = 0.0
+
+            ratio = dest_diff.length / src_diff.length
+            break
+
+        for suvs, fidx in zip(props.src_uvs, dest_face_indices):
+            for l, suv in zip(bm.faces[fidx].loops, suvs):
+                base = suv - src_base
+                radian_ref = atan2(base.y, base.x)
+                radian_fin = (radian + radian_ref)
+                length = base.length
+                turn = Vector((length * cos(radian_fin),
+                               length * sin(radian_fin)))
+                target_uv = Vector((turn.x * ratio, turn.y * ratio)) + \
+                    dest_base
+                l[uv_layer].uv = target_uv
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/muv_fliprot_ops.py b/uv_magic_uv/op/flip_rotate_uv.py
similarity index 97%
rename from uv_magic_uv/muv_fliprot_ops.py
rename to uv_magic_uv/op/flip_rotate_uv.py
index 334eb14c57d2a9767a6a6641e4860c972b74d517..30f6b0f7c9fb35446fa83919dfa3a1bad22c98c9 100644
--- a/uv_magic_uv/muv_fliprot_ops.py
+++ b/uv_magic_uv/op/flip_rotate_uv.py
@@ -20,8 +20,8 @@
 
 __author__ = "Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 import bpy
 import bmesh
@@ -29,7 +29,8 @@ from bpy.props import (
     BoolProperty,
     IntProperty,
 )
-from . import muv_common
+
+from .. import common
 
 
 class MUV_FlipRot(bpy.types.Operator):
@@ -63,7 +64,7 @@ class MUV_FlipRot(bpy.types.Operator):
         self.report({'INFO'}, "Flip/Rotate UV")
         obj = context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
 
         # get UV layer
diff --git a/uv_magic_uv/muv_mirroruv_ops.py b/uv_magic_uv/op/mirror_uv.py
similarity index 97%
rename from uv_magic_uv/muv_mirroruv_ops.py
rename to uv_magic_uv/op/mirror_uv.py
index 63eb9bd549c52c9c46396ab57da3d7d157e3f025..f4849d18bb7135c7b94db78daaa358ffa80dc3a8 100644
--- a/uv_magic_uv/muv_mirroruv_ops.py
+++ b/uv_magic_uv/op/mirror_uv.py
@@ -20,8 +20,8 @@
 
 __author__ = "Keith (Wahooney) Boshoff, Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 import bpy
 from bpy.props import (
@@ -30,7 +30,8 @@ from bpy.props import (
 )
 import bmesh
 from mathutils import Vector
-from . import muv_common
+
+from .. import common
 
 
 class MUV_MirrorUV(bpy.types.Operator):
@@ -113,7 +114,7 @@ class MUV_MirrorUV(bpy.types.Operator):
         error = self.error
         axis = self.axis
 
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
         if not bm.loops.layers.uv:
             self.report({'WARNING'}, "Object must have more than one UV map")
diff --git a/uv_magic_uv/muv_mvuv_ops.py b/uv_magic_uv/op/move_uv.py
similarity index 94%
rename from uv_magic_uv/muv_mvuv_ops.py
rename to uv_magic_uv/op/move_uv.py
index 28346270d0a0fc3c415c7935a77f09c2c882ef84..6382376cf656b38bcc606d659d4f658b3b09be4e 100644
--- a/uv_magic_uv/muv_mvuv_ops.py
+++ b/uv_magic_uv/op/move_uv.py
@@ -20,8 +20,8 @@
 
 __author__ = "kgeogeo, mem, Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 import bpy
 import bmesh
@@ -64,6 +64,7 @@ class MUV_MVUV(bpy.types.Operator):
         return context.edit_object
 
     def modal(self, context, event):
+        props = context.scene.muv_props.mvuv
         if self.__first_time is True:
             self.__prev_mouse = Vector((
                 event.mouse_region_x, event.mouse_region_y))
@@ -84,7 +85,7 @@ class MUV_MVUV(bpy.types.Operator):
             event.mouse_region_x, event.mouse_region_y))
 
         # check if operation is started
-        if self.__running is True:
+        if self.__running:
             if event.type == 'LEFTMOUSE' and event.value == 'RELEASE':
                 self.__running = False
             return {'RUNNING_MODAL'}
@@ -110,16 +111,20 @@ class MUV_MVUV(bpy.types.Operator):
         if event.type == cancel_btn and event.value == 'PRESS':
             for (fidx, vidx), uv in zip(self.__topology_dict, self.__ini_uvs):
                 bm.faces[fidx].loops[vidx][active_uv].uv = uv
+            props.running = False
             return {'FINISHED'}
         # confirmed
         if event.type == confirm_btn and event.value == 'PRESS':
+            props.running = False
             return {'FINISHED'}
 
         return {'RUNNING_MODAL'}
 
     def execute(self, context):
-        self.__first_time = True
+        props = context.scene.muv_props.mvuv
+        props.running = True
         self.__running = True
+        self.__first_time = True
         context.window_manager.modal_handler_add(self)
         self.__topology_dict, self.__ini_uvs = self.__find_uv(context)
         return {'RUNNING_MODAL'}
diff --git a/uv_magic_uv/muv_packuv_ops.py b/uv_magic_uv/op/pack_uv.py
similarity index 69%
rename from uv_magic_uv/muv_packuv_ops.py
rename to uv_magic_uv/op/pack_uv.py
index f663e662774448cb4a07bccebac79f77522e24ca..a780af3e765e6f3ab3108c7327d49bf0aabe5c40 100644
--- a/uv_magic_uv/muv_packuv_ops.py
+++ b/uv_magic_uv/op/pack_uv.py
@@ -20,11 +20,10 @@
 
 __author__ = "Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 from math import fabs
-from collections import defaultdict
 
 import bpy
 import bmesh
@@ -36,7 +35,7 @@ from bpy.props import (
 )
 from mathutils import Vector
 
-from . import muv_common
+from .. import common
 
 
 class MUV_PackUV(bpy.types.Operator):
@@ -69,23 +68,21 @@ class MUV_PackUV(bpy.types.Operator):
         min=0.000001,
         max=0.1,
         default=(0.001, 0.001),
-        size=2)
+        size=2
+    )
     allowable_size_deviation = FloatVectorProperty(
         name="Allowable Size Deviation",
         description="Allowable sizse deviation to judge same UV island",
         min=0.000001,
         max=0.1,
         default=(0.001, 0.001),
-        size=2)
+        size=2
+    )
 
-    def __init__(self):
-        self.__face_to_verts = defaultdict(set)
-        self.__vert_to_faces = defaultdict(set)
-
-    def execute(self, _):
-        obj = bpy.context.active_object
+    def execute(self, context):
+        obj = context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
         if not bm.loops.layers.uv:
             self.report({'WARNING'}, "Object must have more than one UV map")
@@ -93,17 +90,7 @@ class MUV_PackUV(bpy.types.Operator):
         uv_layer = bm.loops.layers.uv.verify()
 
         selected_faces = [f for f in bm.faces if f.select]
-
-        # create mesh database
-        for f in selected_faces:
-            for l in f.loops:
-                id_ = l[uv_layer].uv.to_tuple(5), l.vert.index
-                self.__face_to_verts[f.index].add(id_)
-                self.__vert_to_faces[id_].add(f.index)
-
-        # Group island
-        uv_island_lists = self.__get_island(bm)
-        island_info = self.__get_island_info(uv_layer, uv_island_lists)
+        island_info = common.get_island_info(obj)
         num_group = self.__group_island(island_info)
 
         loop_lists = [l for f in bm.faces for l in f.loops]
@@ -183,13 +170,17 @@ class MUV_PackUV(bpy.types.Operator):
                     dsx = isl_2['size'].x - isl_1['size'].x
                     dsy = isl_2['size'].y - isl_1['size'].y
                     center_x_matched = (
-                        fabs(dcx) < self.allowable_center_deviation[0])
+                        fabs(dcx) < self.allowable_center_deviation[0]
+                    )
                     center_y_matched = (
-                        fabs(dcy) < self.allowable_center_deviation[1])
+                        fabs(dcy) < self.allowable_center_deviation[1]
+                    )
                     size_x_matched = (
-                        fabs(dsx) < self.allowable_size_deviation[0])
+                        fabs(dsx) < self.allowable_size_deviation[0]
+                    )
                     size_y_matched = (
-                        fabs(dsy) < self.allowable_size_deviation[1])
+                        fabs(dsy) < self.allowable_size_deviation[1]
+                    )
                     center_matched = center_x_matched and center_y_matched
                     size_matched = size_x_matched and size_y_matched
                     num_uv_matched = (isl_2['num_uv'] == isl_1['num_uv'])
@@ -214,75 +205,3 @@ class MUV_PackUV(bpy.types.Operator):
             num_group = num_group + 1
 
         return num_group
-
-    def __get_island_info(self, uv_layer, islands):
-        """
-        get information about each island
-        """
-
-        island_info = []
-        for isl in islands:
-            info = {}
-            max_uv = Vector((-10000000.0, -10000000.0))
-            min_uv = Vector((10000000.0, 10000000.0))
-            ave_uv = Vector((0.0, 0.0))
-            num_uv = 0
-            for face in isl:
-                n = 0
-                a = Vector((0.0, 0.0))
-                for l in face['face'].loops:
-                    uv = l[uv_layer].uv
-                    if uv.x > max_uv.x:
-                        max_uv.x = uv.x
-                    if uv.y > max_uv.y:
-                        max_uv.y = uv.y
-                    if uv.x < min_uv.x:
-                        min_uv.x = uv.x
-                    if uv.y < min_uv.y:
-                        min_uv.y = uv.y
-                    a = a + uv
-                    n = n + 1
-                ave_uv = ave_uv + a
-                num_uv = num_uv + n
-                a = a / n
-                face['ave_uv'] = a
-            ave_uv = ave_uv / num_uv
-
-            info['center'] = ave_uv
-            info['size'] = max_uv - min_uv
-            info['num_uv'] = num_uv
-            info['group'] = -1
-            info['faces'] = isl
-
-            island_info.append(info)
-
-        return island_info
-
-    def __parse_island(self, bm, face_idx, faces_left, island):
-        """
-        Parse island
-        """
-
-        if face_idx in faces_left:
-            faces_left.remove(face_idx)
-            island.append({'face': bm.faces[face_idx]})
-            for v in self.__face_to_verts[face_idx]:
-                connected_faces = self.__vert_to_faces[v]
-                if connected_faces:
-                    for cf in connected_faces:
-                        self.__parse_island(bm, cf, faces_left, island)
-
-    def __get_island(self, bm):
-        """
-        Get island list
-        """
-
-        uv_island_lists = []
-        faces_left = set(self.__face_to_verts.keys())
-        while faces_left:
-            current_island = []
-            face_idx = list(faces_left)[0]
-            self.__parse_island(bm, face_idx, faces_left, current_island)
-            uv_island_lists.append(current_island)
-
-        return uv_island_lists
diff --git a/uv_magic_uv/muv_preserve_uv_aspect.py b/uv_magic_uv/op/preserve_uv_aspect.py
similarity index 92%
rename from uv_magic_uv/muv_preserve_uv_aspect.py
rename to uv_magic_uv/op/preserve_uv_aspect.py
index 68e75f74a15c2803609a332bf3cb0f181b1ff943..bc2f1b81ee7b633f43ca63b4ce7908285ffd63da 100644
--- a/uv_magic_uv/muv_preserve_uv_aspect.py
+++ b/uv_magic_uv/op/preserve_uv_aspect.py
@@ -20,14 +20,15 @@
 
 __author__ = "Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 import bpy
 import bmesh
 from bpy.props import StringProperty, EnumProperty
 from mathutils import Vector
-from . import muv_common
+
+from .. import common
 
 
 class MUV_PreserveUVAspect(bpy.types.Operator):
@@ -71,7 +72,7 @@ class MUV_PreserveUVAspect(bpy.types.Operator):
         obj = context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
 
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
 
         if not bm.loops.layers.uv:
@@ -202,22 +203,3 @@ class MUV_PreserveUVAspect(bpy.types.Operator):
         bmesh.update_edit_mesh(obj.data)
 
         return {'FINISHED'}
-
-
-class MUV_PreserveUVAspectMenu(bpy.types.Menu):
-    """
-    Menu class: Preserve UV Aspect
-    """
-
-    bl_idname = "uv.muv_preserve_uv_aspect_menu"
-    bl_label = "Preserve UV Aspect"
-    bl_description = "Preserve UV Aspect"
-
-    def draw(self, _):
-        layout = self.layout
-
-        # create sub menu
-        for key in bpy.data.images.keys():
-            layout.operator(
-                MUV_PreserveUVAspect.bl_idname,
-                text=key, icon="IMAGE_COL").dest_img_name = key
diff --git a/uv_magic_uv/op/smooth_uv.py b/uv_magic_uv/op/smooth_uv.py
new file mode 100644
index 0000000000000000000000000000000000000000..aa9b22c09c0c4518809264d4368255df92a9b53a
--- /dev/null
+++ b/uv_magic_uv/op/smooth_uv.py
@@ -0,0 +1,215 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+import bmesh
+from bpy.props import BoolProperty, FloatProperty
+
+from .. import common
+
+
+class MUV_AUVSmooth(bpy.types.Operator):
+
+    bl_idname = "uv.muv_auv_smooth"
+    bl_label = "Smooth"
+    bl_description = "Smooth UV coordinates"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    transmission = BoolProperty(
+        name="Transmission",
+        description="Smooth linked UVs",
+        default=False
+    )
+    mesh_infl = FloatProperty(
+        name="Mesh Influence",
+        description="Influence rate of mesh vertex",
+        min=0.0,
+        max=1.0,
+        default=0.0
+    )
+    select = BoolProperty(
+        name="Select",
+        description="Select UVs which are smoothed",
+        default=False
+    )
+
+    @classmethod
+    def poll(cls, context):
+        return context.mode == 'EDIT_MESH'
+
+    def __smooth_wo_transmission(self, loop_seqs, uv_layer):
+        # calculate path length
+        loops = []
+        for hseq in loop_seqs:
+            loops.extend([hseq[0][0], hseq[0][1]])
+        full_vlen = 0
+        accm_vlens = [0.0]
+        full_uvlen = 0
+        accm_uvlens = [0.0]
+        orig_uvs = [loop_seqs[0][0][0][uv_layer].uv.copy()]
+        for l1, l2 in zip(loops[:-1], loops[1:]):
+            diff_v = l2.vert.co - l1.vert.co
+            full_vlen = full_vlen + diff_v.length
+            accm_vlens.append(full_vlen)
+            diff_uv = l2[uv_layer].uv - l1[uv_layer].uv
+            full_uvlen = full_uvlen + diff_uv.length
+            accm_uvlens.append(full_uvlen)
+            orig_uvs.append(l2[uv_layer].uv.copy())
+
+        for hidx, hseq in enumerate(loop_seqs):
+            pair = hseq[0]
+            for pidx, l in enumerate(pair):
+                if self.select:
+                    l[uv_layer].select = True
+
+                # ignore start/end loop
+                if (hidx == 0 and pidx == 0) or\
+                   ((hidx == len(loop_seqs) - 1) and (pidx == len(pair) - 1)):
+                    continue
+
+                # calculate target path length
+                # target = no influenced * (1 - infl) + influenced * infl
+                tgt_noinfl = full_uvlen * (hidx + pidx) / (len(loop_seqs))
+                tgt_infl = full_uvlen * accm_vlens[hidx * 2 + pidx] / full_vlen
+                target_length = tgt_noinfl * (1 - self.mesh_infl) + \
+                    tgt_infl * self.mesh_infl
+
+                # get target UV
+                for i in range(len(accm_uvlens[:-1])):
+                    # get line segment which UV will be placed
+                    if ((accm_uvlens[i] <= target_length) and
+                            (accm_uvlens[i + 1] > target_length)):
+                        tgt_seg_len = target_length - accm_uvlens[i]
+                        seg_len = accm_uvlens[i + 1] - accm_uvlens[i]
+                        uv1 = orig_uvs[i]
+                        uv2 = orig_uvs[i + 1]
+                        target_uv = uv1 + (uv2 - uv1) * tgt_seg_len / seg_len
+                        break
+                else:
+                    self.report({'ERROR'}, "Failed to get target UV")
+                    return {'CANCELLED'}
+
+                # update UV
+                l[uv_layer].uv = target_uv
+
+    def __smooth_w_transmission(self, loop_seqs, uv_layer):
+        # calculate path length
+        loops = []
+        for vidx in range(len(loop_seqs[0])):
+            ls = []
+            for hseq in loop_seqs:
+                ls.extend(hseq[vidx])
+            loops.append(ls)
+
+        orig_uvs = []
+        accm_vlens = []
+        full_vlens = []
+        accm_uvlens = []
+        full_uvlens = []
+        for ls in loops:
+            full_v = 0.0
+            accm_v = [0.0]
+            full_uv = 0.0
+            accm_uv = [0.0]
+            uvs = [ls[0][uv_layer].uv.copy()]
+            for l1, l2 in zip(ls[:-1], ls[1:]):
+                diff_v = l2.vert.co - l1.vert.co
+                full_v = full_v + diff_v.length
+                accm_v.append(full_v)
+                diff_uv = l2[uv_layer].uv - l1[uv_layer].uv
+                full_uv = full_uv + diff_uv.length
+                accm_uv.append(full_uv)
+                uvs.append(l2[uv_layer].uv.copy())
+            accm_vlens.append(accm_v)
+            full_vlens.append(full_v)
+            accm_uvlens.append(accm_uv)
+            full_uvlens.append(full_uv)
+            orig_uvs.append(uvs)
+
+        for hidx, hseq in enumerate(loop_seqs):
+            for vidx, (pair, uvs, accm_v, full_v, accm_uv, full_uv)\
+                    in enumerate(zip(hseq, orig_uvs, accm_vlens, full_vlens,
+                                     accm_uvlens, full_uvlens)):
+                for pidx, l in enumerate(pair):
+                    if self.select:
+                        l[uv_layer].select = True
+
+                    # ignore start/end loop
+                    if hidx == 0 and pidx == 0:
+                        continue
+                    if hidx == len(loop_seqs) - 1 and pidx == len(pair) - 1:
+                        continue
+
+                    # calculate target path length
+                    # target = no influenced * (1 - infl) + influenced * infl
+                    tgt_noinfl = full_uv * (hidx + pidx) / (len(loop_seqs))
+                    tgt_infl = full_uv * accm_v[hidx * 2 + pidx] / full_v
+                    target_length = tgt_noinfl * (1 - self.mesh_infl) + \
+                        tgt_infl * self.mesh_infl
+
+                    # get target UV
+                    for i in range(len(accm_uv[:-1])):
+                        # get line segment to be placed
+                        if ((accm_uv[i] <= target_length) and
+                                (accm_uv[i + 1] > target_length)):
+                            tgt_seg_len = target_length - accm_uv[i]
+                            seg_len = accm_uv[i + 1] - accm_uv[i]
+                            uv1 = uvs[i]
+                            uv2 = uvs[i + 1]
+                            target_uv = uv1 +\
+                                (uv2 - uv1) * tgt_seg_len / seg_len
+                            break
+                    else:
+                        self.report({'ERROR'}, "Failed to get target UV")
+                        return {'CANCELLED'}
+
+                    # update UV
+                    l[uv_layer].uv = target_uv
+
+    def __smooth(self, loop_seqs, uv_layer):
+        if self.transmission:
+            self.__smooth_w_transmission(loop_seqs, uv_layer)
+        else:
+            self.__smooth_wo_transmission(loop_seqs, uv_layer)
+
+    def execute(self, context):
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        # loop_seqs[horizontal][vertical][loop]
+        loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
+        if not loop_seqs:
+            self.report({'WARNING'}, error)
+            return {'CANCELLED'}
+
+        # smooth
+        self.__smooth(loop_seqs, uv_layer)
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/muv_texlock_ops.py b/uv_magic_uv/op/texture_lock.py
similarity index 96%
rename from uv_magic_uv/muv_texlock_ops.py
rename to uv_magic_uv/op/texture_lock.py
index bfc951299cefeff8ab0017e3a94f176cac682c08..d6c56f5afc4be2e584f8c9105f1dca5e43c5c795 100644
--- a/uv_magic_uv/muv_texlock_ops.py
+++ b/uv_magic_uv/op/texture_lock.py
@@ -20,20 +20,18 @@
 
 __author__ = "Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 import math
-from math import (
-    atan2, cos,
-    sqrt, sin, fabs,
-)
+from math import atan2, cos, sqrt, sin, fabs
 
 import bpy
 import bmesh
 from mathutils import Vector
 from bpy.props import BoolProperty
-from . import muv_common
+
+from .. import common
 
 
 def get_vco(verts_orig, loop):
@@ -195,7 +193,7 @@ class MUV_TexLockStart(bpy.types.Operator):
         props = context.scene.muv_props.texlock
         obj = bpy.context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.verts.ensure_lookup_table()
             bm.edges.ensure_lookup_table()
             bm.faces.ensure_lookup_table()
@@ -224,13 +222,15 @@ class MUV_TexLockStop(bpy.types.Operator):
 
     connect = BoolProperty(
         name="Connect UV",
-        default=True)
+        default=True
+    )
 
     def execute(self, context):
-        props = context.scene.muv_props.texlock
+        sc = context.scene
+        props = sc.muv_props.texlock
         obj = bpy.context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.verts.ensure_lookup_table()
             bm.edges.ensure_lookup_table()
             bm.faces.ensure_lookup_table()
@@ -297,14 +297,14 @@ class MUV_TexLockUpdater(bpy.types.Operator):
         props = context.scene.muv_props.texlock
         obj = bpy.context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.verts.ensure_lookup_table()
             bm.edges.ensure_lookup_table()
             bm.faces.ensure_lookup_table()
 
         if not bm.loops.layers.uv:
             self.report({'WARNING'}, "Object must have more than one UV map")
-            return {'CANCELLED'}
+            return
         uv_layer = bm.loops.layers.uv.verify()
 
         verts = [v.index for v in bm.verts if v.select]
@@ -313,7 +313,7 @@ class MUV_TexLockUpdater(bpy.types.Operator):
         for vidx, v_orig in zip(verts, verts_orig):
             if vidx != v_orig["vidx"]:
                 self.report({'ERROR'}, "Internal Error")
-                return {"CANCELLED"}
+                return
 
             v = bm.verts[vidx]
             link_loops = get_link_loops(v)
@@ -336,7 +336,7 @@ class MUV_TexLockUpdater(bpy.types.Operator):
             v_orig["moved"] = True
             bmesh.update_edit_mesh(obj.data)
 
-        muv_common.redraw_all_areas()
+        common.redraw_all_areas()
         props.intr_verts_orig = [
             {"vidx": v.index, "vco": v.co.copy(), "moved": False}
             for v in bm.verts if v.select]
@@ -395,7 +395,7 @@ class MUV_TexLockIntrStart(bpy.types.Operator):
 
         obj = bpy.context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.verts.ensure_lookup_table()
             bm.edges.ensure_lookup_table()
             bm.faces.ensure_lookup_table()
diff --git a/uv_magic_uv/muv_texproj_ops.py b/uv_magic_uv/op/texture_projection.py
similarity index 80%
rename from uv_magic_uv/muv_texproj_ops.py
rename to uv_magic_uv/op/texture_projection.py
index ffa4e789e5b4cf7bbfc152f99bb6907f664bc7eb..77a81aa0a0162b1672d337f143edaf73cdc3b531 100644
--- a/uv_magic_uv/muv_texproj_ops.py
+++ b/uv_magic_uv/op/texture_projection.py
@@ -20,8 +20,8 @@
 
 __author__ = "Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 from collections import namedtuple
 
@@ -31,7 +31,7 @@ import bmesh
 import mathutils
 from bpy_extras import view3d_utils
 
-from . import muv_common
+from .. import common
 
 
 Rect = namedtuple('Rect', 'x0 y0 x1 y1')
@@ -237,28 +237,28 @@ class MUV_TexProjProject(bpy.types.Operator):
     def execute(self, context):
         sc = context.scene
 
-        if context.mode != "EDIT_MESH":
-            self.report({'WARNING'}, "Mesh must be in Edit mode")
-            return {'CANCELLED'}
-
         if sc.muv_texproj_tex_image == "None":
             self.report({'WARNING'}, "No textures are selected")
             return {'CANCELLED'}
 
-        _, region, space = muv_common.get_space(
+        _, region, space = common.get_space(
             'VIEW_3D', 'WINDOW', 'VIEW_3D')
 
         # get faces to be texture projected
         obj = context.active_object
         world_mat = obj.matrix_world
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
 
         # get UV and texture layer
         if not bm.loops.layers.uv:
-            self.report({'WARNING'}, "Object must have more than one UV map")
-            return {'CANCELLED'}
+            if sc.muv_texproj_assign_uvmap:
+                bm.loops.layers.uv.new()
+            else:
+                self.report({'WARNING'},
+                            "Object must have more than one UV map")
+                return {'CANCELLED'}
 
         uv_layer = bm.loops.layers.uv.verify()
         tex_layer = bm.faces.layers.tex.verify()
@@ -290,50 +290,7 @@ class MUV_TexProjProject(bpy.types.Operator):
                 l[uv_layer].uv = v_canvas[i].to_2d()
                 i = i + 1
 
-        muv_common.redraw_all_areas()
+        common.redraw_all_areas()
         bmesh.update_edit_mesh(obj.data)
 
         return {'FINISHED'}
-
-
-class OBJECT_PT_TP(bpy.types.Panel):
-    """
-    Panel class: Texture Projection Menu on Property Panel on View3D
-    """
-
-    bl_label = "Texture Projection"
-    bl_description = "Texture Projection Menu"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_context = 'mesh_edit'
-
-    @classmethod
-    def poll(cls, context):
-        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
-        return prefs.enable_texproj
-
-    def draw_header(self, _):
-        layout = self.layout
-        layout.label(text="", icon='IMAGE_COL')
-
-    def draw(self, context):
-        sc = context.scene
-        layout = self.layout
-        props = sc.muv_props.texproj
-        if props.running is False:
-            layout.operator(
-                MUV_TexProjStart.bl_idname, text="Start", icon='PLAY')
-        else:
-            layout.operator(
-                MUV_TexProjStop.bl_idname, text="Stop", icon='PAUSE')
-            layout.prop(sc, "muv_texproj_tex_image", text="Image")
-            layout.prop(
-                sc, "muv_texproj_tex_transparency", text="Transparency"
-            )
-            layout.prop(sc, "muv_texproj_adjust_window", text="Adjust Window")
-            if not sc.muv_texproj_adjust_window:
-                layout.prop(sc, "muv_texproj_tex_magnitude", text="Magnitude")
-            layout.prop(
-                sc, "muv_texproj_apply_tex_aspect", text="Texture Aspect Ratio"
-            )
-            layout.operator(MUV_TexProjProject.bl_idname, text="Project")
diff --git a/uv_magic_uv/op/texture_wrap.py b/uv_magic_uv/op/texture_wrap.py
new file mode 100644
index 0000000000000000000000000000000000000000..01e507bda2897e42d76fdc3c9d63e7bfbcdd9bbd
--- /dev/null
+++ b/uv_magic_uv/op/texture_wrap.py
@@ -0,0 +1,212 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+import bmesh
+
+from .. import common
+
+
+class MUV_TexWrapRefer(bpy.types.Operator):
+    """
+    Operation class: Refer UV
+    """
+
+    bl_idname = "uv.muv_texwrap_refer"
+    bl_label = "Refer"
+    bl_description = "Refer UV"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    def execute(self, context):
+        props = context.scene.muv_props.texwrap
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        if not bm.loops.layers.uv:
+            self.report({'WARNING'}, "Object must have more than one UV map")
+            return {'CANCELLED'}
+
+        sel_faces = [f for f in bm.faces if f.select]
+        if len(sel_faces) != 1:
+            self.report({'WARNING'}, "Must select only one face")
+            return {'CANCELLED'}
+
+        props.ref_face_index = sel_faces[0].index
+        props.ref_obj = obj
+
+        return {'FINISHED'}
+
+
+class MUV_TexWrapSet(bpy.types.Operator):
+    """
+    Operation class: Set UV
+    """
+
+    bl_idname = "uv.muv_texwrap_set"
+    bl_label = "Set"
+    bl_description = "Set UV"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    def execute(self, context):
+        sc = context.scene
+        props = sc.muv_props.texwrap
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        if not bm.loops.layers.uv:
+            self.report({'WARNING'}, "Object must have more than one UV map")
+            return {'CANCELLED'}
+        uv_layer = bm.loops.layers.uv.verify()
+
+        if sc.muv_texwrap_selseq:
+            sel_faces = []
+            for hist in bm.select_history:
+                if isinstance(hist, bmesh.types.BMFace) and hist.select:
+                    sel_faces.append(hist)
+            if not sel_faces:
+                self.report({'WARNING'}, "Must select more than one face")
+                return {'CANCELLED'}
+        else:
+            sel_faces = [f for f in bm.faces if f.select]
+            if len(sel_faces) != 1:
+                self.report({'WARNING'}, "Must select only one face")
+                return {'CANCELLED'}
+
+        ref_face_index = props.ref_face_index
+        for face in sel_faces:
+            tgt_face_index = face.index
+            if ref_face_index == tgt_face_index:
+                self.report({'WARNING'}, "Must select different face")
+                return {'CANCELLED'}
+
+            if props.ref_obj != obj:
+                self.report({'WARNING'}, "Object must be same")
+                return {'CANCELLED'}
+
+            ref_face = bm.faces[ref_face_index]
+            tgt_face = bm.faces[tgt_face_index]
+
+            # get common vertices info
+            common_verts = []
+            for sl in ref_face.loops:
+                for dl in tgt_face.loops:
+                    if sl.vert == dl.vert:
+                        info = {"vert": sl.vert, "ref_loop": sl,
+                                "tgt_loop": dl}
+                        common_verts.append(info)
+                        break
+
+            if len(common_verts) != 2:
+                self.report({'WARNING'},
+                            "2 verticies must be shared among faces")
+                return {'CANCELLED'}
+
+            # get reference other vertices info
+            ref_other_verts = []
+            for sl in ref_face.loops:
+                for ci in common_verts:
+                    if sl.vert == ci["vert"]:
+                        break
+                else:
+                    info = {"vert": sl.vert, "loop": sl}
+                    ref_other_verts.append(info)
+
+            if not ref_other_verts:
+                self.report({'WARNING'}, "More than 1 vertex must be unshared")
+                return {'CANCELLED'}
+
+            # get reference info
+            ref_info = {}
+            cv0 = common_verts[0]["vert"].co
+            cv1 = common_verts[1]["vert"].co
+            cuv0 = common_verts[0]["ref_loop"][uv_layer].uv
+            cuv1 = common_verts[1]["ref_loop"][uv_layer].uv
+            ov0 = ref_other_verts[0]["vert"].co
+            ouv0 = ref_other_verts[0]["loop"][uv_layer].uv
+            ref_info["vert_vdiff"] = cv1 - cv0
+            ref_info["uv_vdiff"] = cuv1 - cuv0
+            ref_info["vert_hdiff"], _ = common.diff_point_to_segment(
+                cv0, cv1, ov0)
+            ref_info["uv_hdiff"], _ = common.diff_point_to_segment(
+                cuv0, cuv1, ouv0)
+
+            # get target other vertices info
+            tgt_other_verts = []
+            for dl in tgt_face.loops:
+                for ci in common_verts:
+                    if dl.vert == ci["vert"]:
+                        break
+                else:
+                    info = {"vert": dl.vert, "loop": dl}
+                    tgt_other_verts.append(info)
+
+            if not tgt_other_verts:
+                self.report({'WARNING'}, "More than 1 vertex must be unshared")
+                return {'CANCELLED'}
+
+            # get target info
+            for info in tgt_other_verts:
+                cv0 = common_verts[0]["vert"].co
+                cv1 = common_verts[1]["vert"].co
+                cuv0 = common_verts[0]["ref_loop"][uv_layer].uv
+                ov = info["vert"].co
+                info["vert_hdiff"], x = common.diff_point_to_segment(
+                    cv0, cv1, ov)
+                info["vert_vdiff"] = x - common_verts[0]["vert"].co
+
+                # calclulate factor
+                fact_h = -info["vert_hdiff"].length / \
+                    ref_info["vert_hdiff"].length
+                fact_v = info["vert_vdiff"].length / \
+                    ref_info["vert_vdiff"].length
+                duv_h = ref_info["uv_hdiff"] * fact_h
+                duv_v = ref_info["uv_vdiff"] * fact_v
+
+                # get target UV
+                info["target_uv"] = cuv0 + duv_h + duv_v
+
+            # apply to common UVs
+            for info in common_verts:
+                info["tgt_loop"][uv_layer].uv = \
+                    info["ref_loop"][uv_layer].uv.copy()
+            # apply to other UVs
+            for info in tgt_other_verts:
+                info["loop"][uv_layer].uv = info["target_uv"]
+
+            common.debug_print("===== Target Other Verticies =====")
+            common.debug_print(tgt_other_verts)
+
+            bmesh.update_edit_mesh(obj.data)
+
+            ref_face_index = tgt_face_index
+
+        if sc.muv_texwrap_set_and_refer:
+            props.ref_face_index = tgt_face_index
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/muv_transuv_ops.py b/uv_magic_uv/op/transfer_uv.py
similarity index 97%
rename from uv_magic_uv/muv_transuv_ops.py
rename to uv_magic_uv/op/transfer_uv.py
index ed0a3c46241d376472da0731d176c8d2ede18141..132f395eda81c291bda778d6f14a7c1ce85c3df9 100644
--- a/uv_magic_uv/muv_transuv_ops.py
+++ b/uv_magic_uv/op/transfer_uv.py
@@ -20,8 +20,8 @@
 
 __author__ = "Nutti <nutti.metro@gmail.com>, Mifth, MaxRobinot"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 from collections import OrderedDict
 
@@ -29,8 +29,7 @@ import bpy
 import bmesh
 from bpy.props import BoolProperty
 
-from . import muv_props
-from . import muv_common
+from .. import common
 
 
 class MUV_TransUVCopy(bpy.types.Operator):
@@ -48,7 +47,7 @@ class MUV_TransUVCopy(bpy.types.Operator):
         props = context.scene.muv_props.transuv
         active_obj = context.scene.objects.active
         bm = bmesh.from_edit_mesh(active_obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
 
         # get UV layer
@@ -115,7 +114,7 @@ class MUV_TransUVPaste(bpy.types.Operator):
         props = context.scene.muv_props.transuv
         active_obj = context.scene.objects.active
         bm = bmesh.from_edit_mesh(active_obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
 
         # get UV layer
@@ -291,19 +290,19 @@ def parse_faces(
                 vert1 = sorted_edge.verts[0]
                 vert2 = sorted_edge.verts[1]
 
-                muv_common.debug_print(face_stuff[0], vert1, vert2)
+                common.debug_print(face_stuff[0], vert1, vert2)
                 if face_stuff[0].index(vert1) > face_stuff[0].index(vert2):
                     vert1 = sorted_edge.verts[1]
                     vert2 = sorted_edge.verts[0]
 
-                muv_common.debug_print(shared_face.verts, vert1, vert2)
+                common.debug_print(shared_face.verts, vert1, vert2)
                 new_face_stuff = get_other_verts_edges(
                     shared_face, vert1, vert2, sorted_edge, uv_layer)
                 all_sorted_faces[shared_face] = new_face_stuff
                 used_verts.update(shared_face.verts)
                 used_edges.update(shared_face.edges)
 
-                if muv_props.DEBUG:
+                if common.DEBUG:
                     shared_face.select = True  # test which faces are parsed
 
                 new_shared_faces.append(shared_face)
diff --git a/uv_magic_uv/muv_unwrapconst_ops.py b/uv_magic_uv/op/unwrap_constraint.py
similarity index 94%
rename from uv_magic_uv/muv_unwrapconst_ops.py
rename to uv_magic_uv/op/unwrap_constraint.py
index 1a6911199221ad3e8c8bacd4712d847ac6fcdabe..e98879b762c51328077bff12ce68f7eea0b24621 100644
--- a/uv_magic_uv/muv_unwrapconst_ops.py
+++ b/uv_magic_uv/op/unwrap_constraint.py
@@ -18,8 +18,8 @@
 
 __author__ = "Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 import bpy
 import bmesh
@@ -28,7 +28,8 @@ from bpy.props import (
     EnumProperty,
     FloatProperty,
 )
-from . import muv_common
+
+from .. import common
 
 
 class MUV_UnwrapConstraint(bpy.types.Operator):
@@ -74,18 +75,21 @@ class MUV_UnwrapConstraint(bpy.types.Operator):
     u_const = BoolProperty(
         name="U-Constraint",
         description="Keep UV U-axis coordinate",
-        default=False)
+        default=False
+    )
     v_const = BoolProperty(
         name="V-Constraint",
         description="Keep UV V-axis coordinate",
-        default=False)
+        default=False
+    )
 
     def execute(self, _):
         obj = bpy.context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
 
+        # bpy.ops.uv.unwrap() makes one UV map at least
         if not bm.loops.layers.uv:
             self.report({'WARNING'}, "Object must have more than one UV map")
             return {'CANCELLED'}
diff --git a/uv_magic_uv/muv_uvbb_ops.py b/uv_magic_uv/op/uv_bounding_box.py
similarity index 94%
rename from uv_magic_uv/muv_uvbb_ops.py
rename to uv_magic_uv/op/uv_bounding_box.py
index 4f7b0631b597aa7c559d4636df8216d779a2c022..9ebc76c47e6f4c97b56534936f89bf7e8cfd068f 100644
--- a/uv_magic_uv/muv_uvbb_ops.py
+++ b/uv_magic_uv/op/uv_bounding_box.py
@@ -20,8 +20,8 @@
 
 __author__ = "Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 from enum import IntEnum
 import math
@@ -31,7 +31,7 @@ import bgl
 import mathutils
 import bmesh
 
-from . import muv_common
+from .. import common
 
 
 MAX_VALUE = 100000.0
@@ -602,17 +602,23 @@ class MUV_UVBBUpdater(bpy.types.Operator):
         """
         Get UV coordinate
         """
+        sc = context.scene
         obj = context.active_object
         uv_info = []
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
         if not bm.loops.layers.uv:
             return None
         uv_layer = bm.loops.layers.uv.verify()
         for f in bm.faces:
-            if f.select:
-                for i, l in enumerate(f.loops):
+            if not f.select:
+                continue
+            for i, l in enumerate(f.loops):
+                if sc.muv_uvbb_boundary == 'UV_SEL':
+                    if l[uv_layer].select:
+                        uv_info.append((f.index, i, l[uv_layer].uv.copy()))
+                elif sc.muv_uvbb_boundary == 'UV':
                     uv_info.append((f.index, i, l[uv_layer].uv.copy()))
         if not uv_info:
             return None
@@ -661,7 +667,7 @@ class MUV_UVBBUpdater(bpy.types.Operator):
         """
         obj = context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
         if not bm.loops.layers.uv:
             return
@@ -683,10 +689,17 @@ class MUV_UVBBUpdater(bpy.types.Operator):
 
     def modal(self, context, event):
         props = context.scene.muv_props.uvbb
-        muv_common.redraw_all_areas()
+        common.redraw_all_areas()
         if props.running is False:
             self.__handle_remove(context)
             return {'FINISHED'}
+
+        area, _, _ = common.get_space('VIEW_3D', 'WINDOW', 'VIEW_3D')
+
+        if event.mouse_region_x < 0 or event.mouse_region_x > area.width or \
+           event.mouse_region_y < 0 or event.mouse_region_y > area.height:
+            return {'PASS_THROUGH'}
+
         if event.type == 'TIMER':
             trans_mat = self.__cmd_exec.execute()
             self.__update_uvs(context, props.uv_info_ini, trans_mat)
@@ -695,7 +708,7 @@ class MUV_UVBBUpdater(bpy.types.Operator):
 
         self.__state_mgr.update(context, props.ctrl_points, event)
 
-        return {'PASS_THROUGH'}
+        return {'RUNNING_MODAL'}
 
     def execute(self, context):
         props = context.scene.muv_props.uvbb
@@ -717,37 +730,3 @@ class MUV_UVBBUpdater(bpy.types.Operator):
         props.running = True
 
         return {'RUNNING_MODAL'}
-
-
-class IMAGE_PT_MUV_UVBB(bpy.types.Panel):
-    """
-    Panel class: UV Bounding Box Menu on Property Panel on UV/ImageEditor
-    """
-
-    bl_space_type = 'IMAGE_EDITOR'
-    bl_region_type = 'UI'
-    bl_label = "UV Bounding Box"
-    bl_context = 'mesh_edit'
-
-    @classmethod
-    def poll(cls, context):
-        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
-        return prefs.enable_uvbb
-
-    def draw_header(self, _):
-        layout = self.layout
-        layout.label(text="", icon='IMAGE_COL')
-
-    def draw(self, context):
-        sc = context.scene
-        props = sc.muv_props.uvbb
-        layout = self.layout
-        if props.running is False:
-            layout.operator(
-                MUV_UVBBUpdater.bl_idname, text="Display UV Bounding Box",
-                icon='PLAY')
-        else:
-            layout.operator(
-                MUV_UVBBUpdater.bl_idname, text="Hide UV Bounding Box",
-                icon='PAUSE')
-        layout.prop(sc, "muv_uvbb_uniform_scaling", text="Uniform Scaling")
diff --git a/uv_magic_uv/op/uv_inspection.py b/uv_magic_uv/op/uv_inspection.py
new file mode 100644
index 0000000000000000000000000000000000000000..60a754a30a293f685a945ca32eff1dea18c706bc
--- /dev/null
+++ b/uv_magic_uv/op/uv_inspection.py
@@ -0,0 +1,623 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+import bmesh
+import bgl
+from mathutils import Vector
+
+from .. import common
+
+
+def is_polygon_same(points1, points2):
+    if len(points1) != len(points2):
+        return False
+
+    pts1 = points1.as_list()
+    pts2 = points2.as_list()
+
+    for p1 in pts1:
+        for p2 in pts2:
+            diff = p2 - p1
+            if diff.length < 0.0000001:
+                pts2.remove(p2)
+                break
+        else:
+            return False
+
+    return True
+
+
+def is_segment_intersect(start1, end1, start2, end2):
+    seg1 = end1 - start1
+    seg2 = end2 - start2
+
+    a1 = -seg1.y
+    b1 = seg1.x
+    d1 = -(a1 * start1.x + b1 * start1.y)
+
+    a2 = -seg2.y
+    b2 = seg2.x
+    d2 = -(a2 * start2.x + b2 * start2.y)
+
+    seg1_line2_start = a2 * start1.x + b2 * start1.y + d2
+    seg1_line2_end = a2 * end1.x + b2 * end1.y + d2
+
+    seg2_line1_start = a1 * start2.x + b1 * start2.y + d1
+    seg2_line1_end = a1 * end2.x + b1 * end2.y + d1
+
+    if (seg1_line2_start * seg1_line2_end >= 0) or \
+            (seg2_line1_start * seg2_line1_end >= 0):
+        return False, None
+
+    u = seg1_line2_start / (seg1_line2_start - seg1_line2_end)
+    out = start1 + u * seg1
+
+    return True, out
+
+
+class RingBuffer:
+    def __init__(self, arr):
+        self.__buffer = arr.copy()
+        self.__pointer = 0
+
+    def __repr__(self):
+        return repr(self.__buffer)
+
+    def __len__(self):
+        return len(self.__buffer)
+
+    def insert(self, val, offset=0):
+        self.__buffer.insert(self.__pointer + offset, val)
+
+    def head(self):
+        return self.__buffer[0]
+
+    def tail(self):
+        return self.__buffer[-1]
+
+    def get(self, offset=0):
+        size = len(self.__buffer)
+        val = self.__buffer[(self.__pointer + offset) % size]
+        return val
+
+    def next(self):
+        size = len(self.__buffer)
+        self.__pointer = (self.__pointer + 1) % size
+
+    def reset(self):
+        self.__pointer = 0
+
+    def find(self, obj):
+        try:
+            idx = self.__buffer.index(obj)
+        except ValueError:
+            return None
+        return self.__buffer[idx]
+
+    def find_and_next(self, obj):
+        size = len(self.__buffer)
+        idx = self.__buffer.index(obj)
+        self.__pointer = (idx + 1) % size
+
+    def find_and_set(self, obj):
+        idx = self.__buffer.index(obj)
+        self.__pointer = idx
+
+    def as_list(self):
+        return self.__buffer.copy()
+
+    def reverse(self):
+        self.__buffer.reverse()
+        self.reset()
+
+
+# clip: reference polygon
+# subject: tested polygon
+def do_weiler_atherton_cliping(clip, subject, uv_layer, mode):
+
+    clip_uvs = RingBuffer([l[uv_layer].uv.copy() for l in clip.loops])
+    if is_polygon_flipped(clip_uvs):
+        clip_uvs.reverse()
+    subject_uvs = RingBuffer([l[uv_layer].uv.copy() for l in subject.loops])
+    if is_polygon_flipped(subject_uvs):
+        subject_uvs.reverse()
+
+    common.debug_print("===== Clip UV List =====")
+    common.debug_print(clip_uvs)
+    common.debug_print("===== Subject UV List =====")
+    common.debug_print(subject_uvs)
+
+    # check if clip and subject is overlapped completely
+    if is_polygon_same(clip_uvs, subject_uvs):
+        polygons = [subject_uvs.as_list()]
+        common.debug_print("===== Polygons Overlapped Completely =====")
+        common.debug_print(polygons)
+        return True, polygons
+
+    # check if subject is in clip
+    if is_points_in_polygon(subject_uvs, clip_uvs):
+        polygons = [subject_uvs.as_list()]
+        return True, polygons
+
+    # check if clip is in subject
+    if is_points_in_polygon(clip_uvs, subject_uvs):
+        polygons = [subject_uvs.as_list()]
+        return True, polygons
+
+    # check if clip and subject is overlapped partially
+    intersections = []
+    while True:
+        subject_uvs.reset()
+        while True:
+            uv_start1 = clip_uvs.get()
+            uv_end1 = clip_uvs.get(1)
+            uv_start2 = subject_uvs.get()
+            uv_end2 = subject_uvs.get(1)
+            intersected, point = is_segment_intersect(uv_start1, uv_end1,
+                                                      uv_start2, uv_end2)
+            if intersected:
+                clip_uvs.insert(point, 1)
+                subject_uvs.insert(point, 1)
+                intersections.append([point,
+                                      [clip_uvs.get(), clip_uvs.get(1)]])
+            subject_uvs.next()
+            if subject_uvs.get() == subject_uvs.head():
+                break
+        clip_uvs.next()
+        if clip_uvs.get() == clip_uvs.head():
+            break
+
+    common.debug_print("===== Intersection List =====")
+    common.debug_print(intersections)
+
+    # no intersection, so subject and clip is not overlapped
+    if not intersections:
+        return False, None
+
+    def get_intersection_pair(intersections, key):
+        for sect in intersections:
+            if sect[0] == key:
+                return sect[1]
+
+        return None
+
+    # make enter/exit pair
+    subject_uvs.reset()
+    subject_entering = []
+    subject_exiting = []
+    clip_entering = []
+    clip_exiting = []
+    intersect_uv_list = []
+    while True:
+        pair = get_intersection_pair(intersections, subject_uvs.get())
+        if pair:
+            sub = subject_uvs.get(1) - subject_uvs.get(-1)
+            inter = pair[1] - pair[0]
+            cross = sub.x * inter.y - inter.x * sub.y
+            if cross < 0:
+                subject_entering.append(subject_uvs.get())
+                clip_exiting.append(subject_uvs.get())
+            else:
+                subject_exiting.append(subject_uvs.get())
+                clip_entering.append(subject_uvs.get())
+            intersect_uv_list.append(subject_uvs.get())
+
+        subject_uvs.next()
+        if subject_uvs.get() == subject_uvs.head():
+            break
+
+    common.debug_print("===== Enter List =====")
+    common.debug_print(clip_entering)
+    common.debug_print(subject_entering)
+    common.debug_print("===== Exit List =====")
+    common.debug_print(clip_exiting)
+    common.debug_print(subject_exiting)
+
+    # for now, can't handle the situation when fulfill all below conditions
+    #        * two faces have common edge
+    #        * each face is intersected
+    #        * Show Mode is "Part"
+    #       so for now, ignore this situation
+    if len(subject_entering) != len(subject_exiting):
+        if mode == 'FACE':
+            polygons = [subject_uvs.as_list()]
+            return True, polygons
+        return False, None
+
+    def traverse(current_list, entering, exiting, poly, current, other_list):
+        result = current_list.find(current)
+        if not result:
+            return None
+        if result != current:
+            print("Internal Error")
+            return None
+
+        # enter
+        if entering.count(current) >= 1:
+            entering.remove(current)
+
+        current_list.find_and_next(current)
+        current = current_list.get()
+
+        while exiting.count(current) == 0:
+            poly.append(current.copy())
+            current_list.find_and_next(current)
+            current = current_list.get()
+
+        # exit
+        poly.append(current.copy())
+        exiting.remove(current)
+
+        other_list.find_and_set(current)
+        return other_list.get()
+
+    # Traverse
+    polygons = []
+    current_uv_list = subject_uvs
+    other_uv_list = clip_uvs
+    current_entering = subject_entering
+    current_exiting = subject_exiting
+
+    poly = []
+    current_uv = current_entering[0]
+
+    while True:
+        current_uv = traverse(current_uv_list, current_entering,
+                              current_exiting, poly, current_uv, other_uv_list)
+
+        if current_uv_list == subject_uvs:
+            current_uv_list = clip_uvs
+            other_uv_list = subject_uvs
+            current_entering = clip_entering
+            current_exiting = clip_exiting
+            common.debug_print("-- Next: Clip --")
+        else:
+            current_uv_list = subject_uvs
+            other_uv_list = clip_uvs
+            current_entering = subject_entering
+            current_exiting = subject_exiting
+            common.debug_print("-- Next: Subject --")
+
+        common.debug_print(clip_entering)
+        common.debug_print(clip_exiting)
+        common.debug_print(subject_entering)
+        common.debug_print(subject_exiting)
+
+        if not clip_entering and not clip_exiting \
+                and not subject_entering and not subject_exiting:
+            break
+
+    polygons.append(poly)
+
+    common.debug_print("===== Polygons Overlapped Partially =====")
+    common.debug_print(polygons)
+
+    return True, polygons
+
+
+class MUV_UVInspRenderer(bpy.types.Operator):
+    """
+    Operation class: Render UV Inspection
+    No operation (only rendering)
+    """
+
+    bl_idname = "uv.muv_uvinsp_renderer"
+    bl_description = "Render overlapped/flipped UVs"
+    bl_label = "Overlapped/Flipped UV renderer"
+
+    __handle = None
+
+    @staticmethod
+    def handle_add(obj, context):
+        sie = bpy.types.SpaceImageEditor
+        MUV_UVInspRenderer.__handle = sie.draw_handler_add(
+            MUV_UVInspRenderer.draw, (obj, context), 'WINDOW', 'POST_PIXEL')
+
+    @staticmethod
+    def handle_remove():
+        if MUV_UVInspRenderer.__handle is not None:
+            bpy.types.SpaceImageEditor.draw_handler_remove(
+                MUV_UVInspRenderer.__handle, 'WINDOW')
+            MUV_UVInspRenderer.__handle = None
+
+    @staticmethod
+    def draw(_, context):
+        sc = context.scene
+        props = sc.muv_props.uvinsp
+        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
+
+        # OpenGL configuration
+        bgl.glEnable(bgl.GL_BLEND)
+
+        # render overlapped UV
+        if sc.muv_uvinsp_show_overlapped:
+            color = prefs.uvinsp_overlapped_color
+            for info in props.overlapped_info:
+                if sc.muv_uvinsp_show_mode == 'PART':
+                    for poly in info["polygons"]:
+                        bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+                        bgl.glColor4f(color[0], color[1], color[2], color[3])
+                        for uv in poly:
+                            x, y = context.region.view2d.view_to_region(
+                                uv.x, uv.y)
+                            bgl.glVertex2f(x, y)
+                        bgl.glEnd()
+                elif sc.muv_uvinsp_show_mode == 'FACE':
+                    bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+                    bgl.glColor4f(color[0], color[1], color[2], color[3])
+                    for uv in info["subject_uvs"]:
+                        x, y = context.region.view2d.view_to_region(uv.x, uv.y)
+                        bgl.glVertex2f(x, y)
+                    bgl.glEnd()
+
+        # render flipped UV
+        if sc.muv_uvinsp_show_flipped:
+            color = prefs.uvinsp_flipped_color
+            for info in props.flipped_info:
+                if sc.muv_uvinsp_show_mode == 'PART':
+                    for poly in info["polygons"]:
+                        bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+                        bgl.glColor4f(color[0], color[1], color[2], color[3])
+                        for uv in poly:
+                            x, y = context.region.view2d.view_to_region(
+                                uv.x, uv.y)
+                            bgl.glVertex2f(x, y)
+                        bgl.glEnd()
+                elif sc.muv_uvinsp_show_mode == 'FACE':
+                    bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+                    bgl.glColor4f(color[0], color[1], color[2], color[3])
+                    for uv in info["uvs"]:
+                        x, y = context.region.view2d.view_to_region(uv.x, uv.y)
+                        bgl.glVertex2f(x, y)
+                    bgl.glEnd()
+
+
+def is_polygon_flipped(points):
+    area = 0.0
+    for i in range(len(points)):
+        uv1 = points.get(i)
+        uv2 = points.get(i + 1)
+        a = uv1.x * uv2.y - uv1.y * uv2.x
+        area = area + a
+    if area < 0:
+        # clock-wise
+        return True
+    return False
+
+
+def is_point_in_polygon(point, subject_points):
+    count = 0
+    for i in range(len(subject_points)):
+        uv_start1 = subject_points.get(i)
+        uv_end1 = subject_points.get(i + 1)
+        uv_start2 = point
+        uv_end2 = Vector((1000000.0, point.y))
+        intersected, _ = is_segment_intersect(uv_start1, uv_end1,
+                                              uv_start2, uv_end2)
+        if intersected:
+            count = count + 1
+
+    return count % 2
+
+
+def is_points_in_polygon(points, subject_points):
+    for i in range(len(points)):
+        internal = is_point_in_polygon(points.get(i), subject_points)
+        if not internal:
+            return False
+
+    return True
+
+
+def get_overlapped_uv_info(bm, faces, uv_layer, mode):
+    # at first, check island overlapped
+    isl = common.get_island_info_from_faces(bm, faces, uv_layer)
+    overlapped_isl_pairs = []
+    for i, i1 in enumerate(isl):
+        for i2 in isl[i + 1:]:
+            if (i1["max"].x < i2["min"].x) or (i2["max"].x < i1["min"].x) or \
+               (i1["max"].y < i2["min"].y) or (i2["max"].y < i1["min"].y):
+                continue
+            overlapped_isl_pairs.append([i1, i2])
+
+    # next, check polygon overlapped
+    overlapped_uvs = []
+    for oip in overlapped_isl_pairs:
+        for clip in oip[0]["faces"]:
+            f_clip = clip["face"]
+            for subject in oip[1]["faces"]:
+                f_subject = subject["face"]
+
+                # fast operation, apply bounding box algorithm
+                if (clip["max_uv"].x < subject["min_uv"].x) or \
+                   (subject["max_uv"].x < clip["min_uv"].x) or \
+                   (clip["max_uv"].y < subject["min_uv"].y) or \
+                   (subject["max_uv"].y < clip["min_uv"].y):
+                    continue
+
+                # slow operation, apply Weiler-Atherton cliping algorithm
+                result, polygons = do_weiler_atherton_cliping(f_clip,
+                                                              f_subject,
+                                                              uv_layer, mode)
+                if result:
+                    subject_uvs = [l[uv_layer].uv.copy()
+                                   for l in f_subject.loops]
+                    overlapped_uvs.append({"clip_face": f_clip,
+                                           "subject_face": f_subject,
+                                           "subject_uvs": subject_uvs,
+                                           "polygons": polygons})
+
+    return overlapped_uvs
+
+
+def get_flipped_uv_info(faces, uv_layer):
+    flipped_uvs = []
+    for f in faces:
+        polygon = RingBuffer([l[uv_layer].uv.copy() for l in f.loops])
+        if is_polygon_flipped(polygon):
+            uvs = [l[uv_layer].uv.copy() for l in f.loops]
+            flipped_uvs.append({"face": f, "uvs": uvs,
+                                "polygons": [polygon.as_list()]})
+
+    return flipped_uvs
+
+
+def update_uvinsp_info(context):
+    sc = context.scene
+    props = sc.muv_props.uvinsp
+
+    obj = context.active_object
+    bm = bmesh.from_edit_mesh(obj.data)
+    if common.check_version(2, 73, 0) >= 0:
+        bm.faces.ensure_lookup_table()
+    uv_layer = bm.loops.layers.uv.verify()
+
+    if context.tool_settings.use_uv_select_sync:
+        sel_faces = [f for f in bm.faces]
+    else:
+        sel_faces = [f for f in bm.faces if f.select]
+    props.overlapped_info = get_overlapped_uv_info(bm, sel_faces, uv_layer,
+                                                   sc.muv_uvinsp_show_mode)
+    props.flipped_info = get_flipped_uv_info(sel_faces, uv_layer)
+
+
+class MUV_UVInspUpdate(bpy.types.Operator):
+    """
+    Operation class: Update
+    """
+
+    bl_idname = "uv.muv_uvinsp_update"
+    bl_label = "Update"
+    bl_description = "Update Overlapped/Flipped UV"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    def execute(self, context):
+        update_uvinsp_info(context)
+
+        if context.area:
+            context.area.tag_redraw()
+
+        return {'FINISHED'}
+
+
+class MUV_UVInspDisplay(bpy.types.Operator):
+    """
+    Operation class: Display
+    """
+
+    bl_idname = "uv.muv_uvinsp_display"
+    bl_label = "Display"
+    bl_description = "Display Overlapped/Flipped UV"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    def execute(self, context):
+        sc = context.scene
+        props = sc.muv_props.uvinsp
+        if not props.display_running:
+            update_uvinsp_info(context)
+            MUV_UVInspRenderer.handle_add(self, context)
+            props.display_running = True
+        else:
+            MUV_UVInspRenderer.handle_remove()
+            props.display_running = False
+
+        if context.area:
+            context.area.tag_redraw()
+
+        return {'FINISHED'}
+
+
+class MUV_UVInspSelectOverlapped(bpy.types.Operator):
+    """
+    Operation class: Select faces which have overlapped UVs
+    """
+
+    bl_idname = "uv.muv_uvinsp_select_overlapped"
+    bl_label = "Overlapped"
+    bl_description = "Select faces which have overlapped UVs"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    def execute(self, context):
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        if context.tool_settings.use_uv_select_sync:
+            sel_faces = [f for f in bm.faces]
+        else:
+            sel_faces = [f for f in bm.faces if f.select]
+
+        overlapped_info = get_overlapped_uv_info(bm, sel_faces, uv_layer,
+                                                 'FACE')
+
+        for info in overlapped_info:
+            if context.tool_settings.use_uv_select_sync:
+                info["subject_face"].select = True
+            else:
+                for l in info["subject_face"].loops:
+                    l[uv_layer].select = True
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
+
+
+class MUV_UVInspSelectFlipped(bpy.types.Operator):
+    """
+    Operation class: Select faces which have flipped UVs
+    """
+
+    bl_idname = "uv.muv_uvinsp_select_flipped"
+    bl_label = "Flipped"
+    bl_description = "Select faces which have flipped UVs"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    def execute(self, context):
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        if context.tool_settings.use_uv_select_sync:
+            sel_faces = [f for f in bm.faces]
+        else:
+            sel_faces = [f for f in bm.faces if f.select]
+
+        flipped_info = get_flipped_uv_info(sel_faces, uv_layer)
+
+        for info in flipped_info:
+            if context.tool_settings.use_uv_select_sync:
+                info["face"].select = True
+            else:
+                for l in info["face"].loops:
+                    l[uv_layer].select = True
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/uv_sculpt.py b/uv_magic_uv/op/uv_sculpt.py
new file mode 100644
index 0000000000000000000000000000000000000000..2bf76abd5a6fea4b7cbede13d1a7a024e195f9d9
--- /dev/null
+++ b/uv_magic_uv/op/uv_sculpt.py
@@ -0,0 +1,360 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+from math import pi, cos, tan, sin
+
+import bpy
+import bmesh
+import bgl
+from mathutils import Vector
+from bpy_extras import view3d_utils
+from mathutils.bvhtree import BVHTree
+from mathutils.geometry import barycentric_transform
+
+from .. import common
+
+
+class MUV_UVSculptRenderer(bpy.types.Operator):
+    """
+    Operation class: Render Brush
+    """
+
+    bl_idname = "uv.muv_uvsculpt_renderer"
+    bl_label = "Brush Renderer"
+    bl_description = "Brush Renderer in View3D"
+
+    __handle = None
+
+    @staticmethod
+    def handle_add(obj, context):
+        if MUV_UVSculptRenderer.__handle is None:
+            sv = bpy.types.SpaceView3D
+            MUV_UVSculptRenderer.__handle = sv.draw_handler_add(
+                MUV_UVSculptRenderer.draw_brush,
+                (obj, context), "WINDOW", "POST_PIXEL")
+
+    @staticmethod
+    def handle_remove():
+        if MUV_UVSculptRenderer.__handle is not None:
+            sv = bpy.types.SpaceView3D
+            sv.draw_handler_remove(
+                MUV_UVSculptRenderer.__handle, "WINDOW")
+            MUV_UVSculptRenderer.__handle = None
+
+    @staticmethod
+    def draw_brush(obj, context):
+        sc = context.scene
+        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
+
+        num_segment = 180
+        theta = 2 * pi / num_segment
+        fact_t = tan(theta)
+        fact_r = cos(theta)
+        color = prefs.uvsculpt_brush_color
+
+        bgl.glBegin(bgl.GL_LINE_STRIP)
+        bgl.glColor4f(color[0], color[1], color[2], color[3])
+        x = sc.muv_uvsculpt_radius * cos(0.0)
+        y = sc.muv_uvsculpt_radius * sin(0.0)
+        for _ in range(num_segment):
+            bgl.glVertex2f(x + obj.current_mco.x, y + obj.current_mco.y)
+            tx = -y
+            ty = x
+            x = x + tx * fact_t
+            y = y + ty * fact_t
+            x = x * fact_r
+            y = y * fact_r
+        bgl.glEnd()
+
+
+class MUV_UVSculptOps(bpy.types.Operator):
+    """
+    Operation class: UV Sculpt in View3D
+    """
+
+    bl_idname = "uv.muv_uvsculpt_ops"
+    bl_label = "UV Sculpt"
+    bl_description = "UV Sculpt in View3D"
+    bl_options = {'REGISTER'}
+
+    def __init__(self):
+        self.__timer = None
+        self.__loop_info = []
+        self.__stroking = False
+        self.current_mco = Vector((0.0, 0.0))
+        self.__initial_mco = Vector((0.0, 0.0))
+
+    def __get_strength(self, p, len_, factor):
+        f = factor
+
+        if p > len_:
+            return 0.0
+
+        if p < 0.0:
+            return f
+
+        return (len_ - p) * f / len_
+
+    def __stroke_init(self, context, _):
+        sc = context.scene
+
+        self.__initial_mco = self.current_mco
+
+        # get influenced UV
+        obj = context.active_object
+        world_mat = obj.matrix_world
+        bm = bmesh.from_edit_mesh(obj.data)
+        uv_layer = bm.loops.layers.uv.verify()
+        _, region, space = common.get_space('VIEW_3D', 'WINDOW', 'VIEW_3D')
+
+        self.__loop_info = []
+        for f in bm.faces:
+            if not f.select:
+                continue
+            for i, l in enumerate(f.loops):
+                loc_2d = view3d_utils.location_3d_to_region_2d(
+                    region, space.region_3d, world_mat * l.vert.co)
+                diff = loc_2d - self.__initial_mco
+                if diff.length < sc.muv_uvsculpt_radius:
+                    info = {
+                        "face_idx": f.index,
+                        "loop_idx": i,
+                        "initial_vco": l.vert.co.copy(),
+                        "initial_vco_2d": loc_2d,
+                        "initial_uv": l[uv_layer].uv.copy(),
+                        "strength": self.__get_strength(
+                            diff.length, sc.muv_uvsculpt_radius,
+                            sc.muv_uvsculpt_strength)
+                    }
+                    self.__loop_info.append(info)
+
+    def __stroke_apply(self, context, _):
+        sc = context.scene
+        obj = context.active_object
+        world_mat = obj.matrix_world
+        bm = bmesh.from_edit_mesh(obj.data)
+        uv_layer = bm.loops.layers.uv.verify()
+        mco = self.current_mco
+
+        if sc.muv_uvsculpt_tools == 'GRAB':
+            for info in self.__loop_info:
+                diff_uv = (mco - self.__initial_mco) * info["strength"]
+                l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
+                l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0
+
+        elif sc.muv_uvsculpt_tools == 'PINCH':
+            _, region, space = common.get_space('VIEW_3D', 'WINDOW', 'VIEW_3D')
+            loop_info = []
+            for f in bm.faces:
+                if not f.select:
+                    continue
+                for i, l in enumerate(f.loops):
+                    loc_2d = view3d_utils.location_3d_to_region_2d(
+                        region, space.region_3d, world_mat * l.vert.co)
+                    diff = loc_2d - self.__initial_mco
+                    if diff.length < sc.muv_uvsculpt_radius:
+                        info = {
+                            "face_idx": f.index,
+                            "loop_idx": i,
+                            "initial_vco": l.vert.co.copy(),
+                            "initial_vco_2d": loc_2d,
+                            "initial_uv": l[uv_layer].uv.copy(),
+                            "strength": self.__get_strength(
+                                diff.length, sc.muv_uvsculpt_radius,
+                                sc.muv_uvsculpt_strength)
+                        }
+                        loop_info.append(info)
+
+            # mouse coordinate to UV coordinate
+            ray_vec = view3d_utils.region_2d_to_vector_3d(region,
+                                                          space.region_3d, mco)
+            ray_vec.normalize()
+            ray_orig = view3d_utils.region_2d_to_origin_3d(region,
+                                                           space.region_3d,
+                                                           mco)
+            ray_tgt = ray_orig + ray_vec * 1000000.0
+            mwi = world_mat.inverted()
+            ray_orig_obj = mwi * ray_orig
+            ray_tgt_obj = mwi * ray_tgt
+            ray_dir_obj = ray_tgt_obj - ray_orig_obj
+            ray_dir_obj.normalize()
+            tree = BVHTree.FromBMesh(bm)
+            loc, _, fidx, _ = tree.ray_cast(ray_orig_obj, ray_dir_obj)
+            if not loc:
+                return
+            loops = [l for l in bm.faces[fidx].loops]
+            uvs = [Vector((l[uv_layer].uv.x, l[uv_layer].uv.y, 0.0))
+                   for l in loops]
+            target_uv = barycentric_transform(
+                loc, loops[0].vert.co, loops[1].vert.co, loops[2].vert.co,
+                uvs[0], uvs[1], uvs[2])
+            target_uv = Vector((target_uv.x, target_uv.y))
+
+            # move to target UV coordinate
+            for info in loop_info:
+                l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
+                if sc.muv_uvsculpt_pinch_invert:
+                    diff_uv = (l[uv_layer].uv - target_uv) * info["strength"]
+                else:
+                    diff_uv = (target_uv - l[uv_layer].uv) * info["strength"]
+                l[uv_layer].uv = l[uv_layer].uv + diff_uv / 10.0
+
+        elif sc.muv_uvsculpt_tools == 'RELAX':
+            _, region, space = common.get_space('VIEW_3D', 'WINDOW', 'VIEW_3D')
+
+            # get vertex and loop relation
+            vert_db = {}
+            for f in bm.faces:
+                for l in f.loops:
+                    if l.vert in vert_db:
+                        vert_db[l.vert]["loops"].append(l)
+                    else:
+                        vert_db[l.vert] = {"loops": [l]}
+
+            # get relaxation information
+            for k in vert_db.keys():
+                d = vert_db[k]
+                d["uv_sum"] = Vector((0.0, 0.0))
+                d["uv_count"] = 0
+
+                for l in d["loops"]:
+                    ln = l.link_loop_next
+                    lp = l.link_loop_prev
+                    d["uv_sum"] = d["uv_sum"] + ln[uv_layer].uv
+                    d["uv_sum"] = d["uv_sum"] + lp[uv_layer].uv
+                    d["uv_count"] = d["uv_count"] + 2
+                d["uv_p"] = d["uv_sum"] / d["uv_count"]
+                d["uv_b"] = d["uv_p"] - d["loops"][0][uv_layer].uv
+            for k in vert_db.keys():
+                d = vert_db[k]
+                d["uv_sum_b"] = Vector((0.0, 0.0))
+                for l in d["loops"]:
+                    ln = l.link_loop_next
+                    lp = l.link_loop_prev
+                    dn = vert_db[ln.vert]
+                    dp = vert_db[lp.vert]
+                    d["uv_sum_b"] = d["uv_sum_b"] + dn["uv_b"] + dp["uv_b"]
+
+            # apply
+            for f in bm.faces:
+                if not f.select:
+                    continue
+                for i, l in enumerate(f.loops):
+                    loc_2d = view3d_utils.location_3d_to_region_2d(
+                        region, space.region_3d, world_mat * l.vert.co)
+                    diff = loc_2d - self.__initial_mco
+                    if diff.length >= sc.muv_uvsculpt_radius:
+                        continue
+                    db = vert_db[l.vert]
+                    strength = self.__get_strength(diff.length,
+                                                   sc.muv_uvsculpt_radius,
+                                                   sc.muv_uvsculpt_strength)
+
+                    base = (1.0 - strength) * l[uv_layer].uv
+                    if sc.muv_uvsculpt_relax_method == 'HC':
+                        t = 0.5 * (db["uv_b"] + db["uv_sum_b"] / d["uv_count"])
+                        diff = strength * (db["uv_p"] - t)
+                        target_uv = base + diff
+                    elif sc.muv_uvsculpt_relax_method == 'LAPLACIAN':
+                        diff = strength * db["uv_p"]
+                        target_uv = base + diff
+                    else:
+                        continue
+
+                    l[uv_layer].uv = target_uv
+
+        bmesh.update_edit_mesh(obj.data)
+
+    def __stroke_exit(self, context, _):
+        sc = context.scene
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        uv_layer = bm.loops.layers.uv.verify()
+        mco = self.current_mco
+
+        if sc.muv_uvsculpt_tools == 'GRAB':
+            for info in self.__loop_info:
+                diff_uv = (mco - self.__initial_mco) * info["strength"]
+                l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
+                l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0
+
+        bmesh.update_edit_mesh(obj.data)
+
+    def modal(self, context, event):
+        props = context.scene.muv_props.uvsculpt
+
+        if context.area:
+            context.area.tag_redraw()
+
+        if not props.running:
+            if self.__timer is not None:
+                MUV_UVSculptRenderer.handle_remove()
+                context.window_manager.event_timer_remove(self.__timer)
+                self.__timer = None
+            return {'FINISHED'}
+
+        self.current_mco = Vector((event.mouse_region_x, event.mouse_region_y))
+        area, _, _ = common.get_space('VIEW_3D', 'WINDOW', 'VIEW_3D')
+
+        if self.current_mco.x < 0 or self.current_mco.x > area.width or \
+           self.current_mco.y < 0 or self.current_mco.y > area.height:
+            return {'PASS_THROUGH'}
+
+        if event.type == 'LEFTMOUSE':
+            if event.value == 'PRESS':
+                if not self.__stroking:
+                    self.__stroke_init(context, event)
+                self.__stroking = True
+            elif event.value == 'RELEASE':
+                if self.__stroking:
+                    self.__stroke_exit(context, event)
+                self.__stroking = False
+        elif event.type == 'MOUSEMOVE':
+            if self.__stroking:
+                self.__stroke_apply(context, event)
+        elif event.type == 'TIMER':
+            if self.__stroking:
+                self.__stroke_apply(context, event)
+
+        return {'RUNNING_MODAL'}
+
+    def invoke(self, context, _):
+        props = context.scene.muv_props.uvsculpt
+
+        if context.area:
+            context.area.tag_redraw()
+
+        if props.running:
+            props.running = False
+            return {'FINISHED'}
+
+        props.running = True
+        if self.__timer is None:
+            self.__timer = context.window_manager.event_timer_add(
+                0.1, context.window)
+            context.window_manager.modal_handler_add(self)
+            MUV_UVSculptRenderer.handle_add(self, context)
+
+        return {'RUNNING_MODAL'}
diff --git a/uv_magic_uv/muv_uvw_ops.py b/uv_magic_uv/op/uvw.py
similarity index 86%
rename from uv_magic_uv/muv_uvw_ops.py
rename to uv_magic_uv/op/uvw.py
index eb366e97641adf15a1d623e4f6719d06f7b06270..10202677663d1fb6240ea66072df44fd84df50b1 100644
--- a/uv_magic_uv/muv_uvw_ops.py
+++ b/uv_magic_uv/op/uvw.py
@@ -20,9 +20,8 @@
 
 __author__ = "Alexander Milovsky, Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
-
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
 from math import sin, cos, pi
 
@@ -30,11 +29,12 @@ import bpy
 import bmesh
 from bpy.props import (
     FloatProperty,
-    FloatVectorProperty
+    FloatVectorProperty,
+    BoolProperty
 )
 from mathutils import Vector
 
-from . import muv_common
+from .. import common
 
 
 class MUV_UVWBoxMap(bpy.types.Operator):
@@ -62,6 +62,11 @@ class MUV_UVWBoxMap(bpy.types.Operator):
         default=1.0,
         precision=4
     )
+    assign_uvmap = BoolProperty(
+        name="Assign UVMap",
+        description="Assign UVMap when no UVmaps are available",
+        default=True
+    )
 
     @classmethod
     def poll(cls, context):
@@ -71,15 +76,17 @@ class MUV_UVWBoxMap(bpy.types.Operator):
     def execute(self, context):
         obj = context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
 
         # get UV layer
         if not bm.loops.layers.uv:
-            self.report(
-                {'WARNING'}, "Object must have more than one UV map")
-            return {'CANCELLED'}
-
+            if self.assign_uvmap:
+                bm.loops.layers.uv.new()
+            else:
+                self.report(
+                    {'WARNING'}, "Object must have more than one UV map")
+                return {'CANCELLED'}
         uv_layer = bm.loops.layers.uv.verify()
 
         scale = 1.0 / self.size
@@ -168,6 +175,11 @@ class MUV_UVWBestPlanerMap(bpy.types.Operator):
         default=1.0,
         precision=4
     )
+    assign_uvmap = BoolProperty(
+        name="Assign UVMap",
+        description="Assign UVMap when no UVmaps are available",
+        default=True
+    )
 
     @classmethod
     def poll(cls, context):
@@ -177,14 +189,17 @@ class MUV_UVWBestPlanerMap(bpy.types.Operator):
     def execute(self, context):
         obj = context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.faces.ensure_lookup_table()
 
         # get UV layer
         if not bm.loops.layers.uv:
-            self.report(
-                {'WARNING'}, "Object must have more than one UV map")
-            return {'CANCELLED'}
+            if self.assign_uvmap:
+                bm.loops.layers.uv.new()
+            else:
+                self.report(
+                    {'WARNING'}, "Object must have more than one UV map")
+                return {'CANCELLED'}
 
         uv_layer = bm.loops.layers.uv.verify()
 
diff --git a/uv_magic_uv/muv_wsuv_ops.py b/uv_magic_uv/op/world_scale_uv.py
similarity index 70%
rename from uv_magic_uv/muv_wsuv_ops.py
rename to uv_magic_uv/op/world_scale_uv.py
index 4ee8b4f932ec53bea4a80ca60767a277dd2d3f55..e256fbac87c59effcd15acc268d0a78a5d88e414 100644
--- a/uv_magic_uv/muv_wsuv_ops.py
+++ b/uv_magic_uv/op/world_scale_uv.py
@@ -20,43 +20,32 @@
 
 __author__ = "McBuff, Nutti <nutti.metro@gmail.com>"
 __status__ = "production"
-__version__ = "4.5"
-__date__ = "19 Nov 2017"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
 
+from math import sqrt
 
 import bpy
 import bmesh
 from mathutils import Vector
-from bpy.props import (
-    FloatProperty,
-    BoolProperty,
-    EnumProperty
-)
-from . import muv_common
+from bpy.props import EnumProperty
 
+from .. import common
 
-def calc_edge_scale(uv_layer, loop0, loop1):
-    v0 = loop0.vert.co
-    v1 = loop1.vert.co
-    uv0 = loop0[uv_layer].uv.copy()
-    uv1 = loop1[uv_layer].uv.copy()
 
-    dv = v1 - v0
-    duv = uv1 - uv0
+def measure_wsuv_info(obj):
+    mesh_area = common.measure_mesh_area(obj)
+    uv_area = common.measure_uv_area(obj)
 
-    scale = 0.0
-    if dv.magnitude > 0.00000001:
-        scale = duv.magnitude / dv.magnitude
+    if not uv_area:
+        return None, None, None
 
-    return scale
+    if mesh_area == 0.0:
+        density = 0.0
+    else:
+        density = sqrt(uv_area) / sqrt(mesh_area)
 
-
-def calc_face_scale(uv_layer, face):
-    es = 0.0
-    for i, l in enumerate(face.loops[1:]):
-        es = es + calc_edge_scale(uv_layer, face.loops[i], l)
-
-    return es
+    return uv_area, mesh_area, density
 
 
 class MUV_WSUVMeasure(bpy.types.Operator):
@@ -70,30 +59,22 @@ class MUV_WSUVMeasure(bpy.types.Operator):
     bl_options = {'REGISTER', 'UNDO'}
 
     def execute(self, context):
-        props = context.scene.muv_props.wsuv
-        obj = bpy.context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
-            bm.verts.ensure_lookup_table()
-            bm.edges.ensure_lookup_table()
-            bm.faces.ensure_lookup_table()
+        sc = context.scene
+        obj = context.active_object
 
-        if not bm.loops.layers.uv:
-            self.report({'WARNING'}, "Object must have more than one UV map")
+        uv_area, mesh_area, density = measure_wsuv_info(obj)
+        if not uv_area:
+            self.report({'WARNING'},
+                        "Object must have more than one UV map and texture")
             return {'CANCELLED'}
-        uv_layer = bm.loops.layers.uv.verify()
 
-        sel_faces = [f for f in bm.faces if f.select]
-
-        # measure average face size
-        scale = 0.0
-        for f in sel_faces:
-            scale = scale + calc_face_scale(uv_layer, f)
+        sc.muv_wsuv_src_uv_area = uv_area
+        sc.muv_wsuv_src_mesh_area = mesh_area
+        sc.muv_wsuv_src_density = density
 
-        props.ref_scale = scale / len(sel_faces)
-
-        self.report(
-            {'INFO'}, "Average face size: {0}".format(props.ref_scale))
+        self.report({'INFO'},
+                    "UV Area: {0}, Mesh Area: {1}, Texel Density: {2}"
+                    .format(uv_area, mesh_area, density))
 
         return {'FINISHED'}
 
@@ -108,16 +89,6 @@ class MUV_WSUVApply(bpy.types.Operator):
     bl_description = "Apply scaled UV based on scale calculation"
     bl_options = {'REGISTER', 'UNDO'}
 
-    proportional_scaling = BoolProperty(
-        name="Proportional Scaling",
-        default=True
-    )
-    scaling_factor = FloatProperty(
-        name="Scaling Factor",
-        default=1.0,
-        max=1000.0,
-        min=0.00001
-    )
     origin = EnumProperty(
         name="Origin",
         description="Aspect Origin",
@@ -139,43 +110,38 @@ class MUV_WSUVApply(bpy.types.Operator):
     def draw(self, _):
         layout = self.layout
 
-        row = layout.row()
-        row.prop(self, "proportional_scaling")
-        row = layout.row()
-        row.prop(self, "scaling_factor")
-        if self.proportional_scaling:
-            row.enabled = False
+        layout.prop(self, "origin")
 
     def execute(self, context):
-        props = context.scene.muv_props.wsuv
-        obj = bpy.context.active_object
+        sc = context.scene
+        obj = context.active_object
         bm = bmesh.from_edit_mesh(obj.data)
-        if muv_common.check_version(2, 73, 0) >= 0:
+        if common.check_version(2, 73, 0) >= 0:
             bm.verts.ensure_lookup_table()
             bm.edges.ensure_lookup_table()
             bm.faces.ensure_lookup_table()
 
-        if not bm.loops.layers.uv:
-            self.report(
-                {'WARNING'}, "Object must have more than one UV map")
-            return {'CANCELLED'}
-        uv_layer = bm.loops.layers.uv.verify()
-
         sel_faces = [f for f in bm.faces if f.select]
 
-        # measure average face size
-        scale = 0.0
-        for f in sel_faces:
-            scale = scale + calc_face_scale(uv_layer, f)
-        scale = scale / len(sel_faces)
+        uv_area, mesh_area, density = measure_wsuv_info(obj)
+        if not uv_area:
+            self.report({'WARNING'},
+                        "Object must have more than one UV map and texture")
+            return {'CANCELLED'}
 
-        self.report(
-            {'INFO'}, "Average face size: {0}".format(scale))
+        uv_layer = bm.loops.layers.uv.verify()
 
-        if self.proportional_scaling:
-            factor = props.ref_scale / scale
-        else:
-            factor = self.scaling_factor
+        if sc.muv_wsuv_mode == 'PROPORTIONAL':
+            tgt_density = sc.muv_wsuv_src_density * sqrt(mesh_area) / \
+                sqrt(sc.muv_wsuv_src_mesh_area)
+        elif sc.muv_wsuv_mode == 'SCALING':
+            tgt_density = sc.muv_wsuv_src_density * sc.muv_wsuv_scaling_factor
+        elif sc.muv_wsuv_mode == 'USER':
+            tgt_density = sc.muv_wsuv_tgt_density
+        elif sc.muv_wsuv_mode == 'CONSTANT':
+            tgt_density = sc.muv_wsuv_src_density
+
+        factor = tgt_density / density
 
         # calculate origin
         if self.origin == 'CENTER':
diff --git a/uv_magic_uv/preferences.py b/uv_magic_uv/preferences.py
new file mode 100644
index 0000000000000000000000000000000000000000..d8cdf86bb54024229c9dd2233456019576e9f2b4
--- /dev/null
+++ b/uv_magic_uv/preferences.py
@@ -0,0 +1,216 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+from bpy.props import (
+    FloatProperty,
+    FloatVectorProperty,
+)
+from bpy.types import AddonPreferences
+
+
+class MUV_Preferences(AddonPreferences):
+    """Preferences class: Preferences for this add-on"""
+
+    bl_idname = __package__
+
+    # for UV Sculpt
+    uvsculpt_brush_color = FloatVectorProperty(
+        name="Color",
+        description="Color",
+        default=(1.0, 0.4, 0.4, 1.0),
+        min=0.0,
+        max=1.0,
+        size=4,
+        subtype='COLOR'
+    )
+
+    # for Overlapped UV
+    uvinsp_overlapped_color = FloatVectorProperty(
+        name="Color",
+        description="Color",
+        default=(0.0, 0.0, 1.0, 0.3),
+        min=0.0,
+        max=1.0,
+        size=4,
+        subtype='COLOR'
+    )
+
+    # for Flipped UV
+    uvinsp_flipped_color = FloatVectorProperty(
+        name="Color",
+        description="Color",
+        default=(1.0, 0.0, 0.0, 0.3),
+        min=0.0,
+        max=1.0,
+        size=4,
+        subtype='COLOR'
+    )
+
+    # for Texture Projection
+    texproj_canvas_padding = FloatVectorProperty(
+        name="Canvas Padding",
+        description="Canvas Padding",
+        size=2,
+        max=50.0,
+        min=0.0,
+        default=(20.0, 20.0))
+
+    # for UV Bounding Box
+    uvbb_cp_size = FloatProperty(
+        name="Size",
+        description="Control Point Size",
+        default=6.0,
+        min=3.0,
+        max=100.0)
+    uvbb_cp_react_size = FloatProperty(
+        name="React Size",
+        description="Size event fired",
+        default=10.0,
+        min=3.0,
+        max=100.0)
+
+    def draw(self, _):
+        layout = self.layout
+
+        layout.label("[Configuration]")
+
+        layout.label("UV Sculpt:")
+        sp = layout.split(percentage=0.05)
+        col = sp.column()  # spacer
+        sp = sp.split(percentage=0.3)
+        col = sp.column()
+        col.label("Brush Color:")
+        col.prop(self, "uvsculpt_brush_color", text="")
+
+        layout.separator()
+
+        layout.label("UV Inspection:")
+        sp = layout.split(percentage=0.05)
+        col = sp.column()  # spacer
+        sp = sp.split(percentage=0.3)
+        col = sp.column()
+        col.label("Overlapped UV Color:")
+        col.prop(self, "uvinsp_overlapped_color", text="")
+        sp = sp.split(percentage=0.45)
+        col = sp.column()
+        col.label("Flipped UV Color:")
+        col.prop(self, "uvinsp_flipped_color", text="")
+
+        layout.separator()
+
+        layout.label("Texture Projection:")
+        sp = layout.split(percentage=0.05)
+        col = sp.column()       # spacer
+        sp = sp.split(percentage=0.3)
+        col = sp.column()
+        col.prop(self, "texproj_canvas_padding")
+
+        layout.separator()
+
+        layout.label("UV Bounding Box:")
+        sp = layout.split(percentage=0.05)
+        col = sp.column()       # spacer
+        sp = sp.split(percentage=0.3)
+        col = sp.column()
+        col.label("Control Point:")
+        col.prop(self, "uvbb_cp_size")
+        col.prop(self, "uvbb_cp_react_size")
+
+        layout.label("--------------------------------------")
+
+        layout.label("[Description]")
+        column = layout.column(align=True)
+        column.label("Magic UV is composed of many UV editing features.")
+        column.label("See tutorial page if you are new to this add-on.")
+        column.label("https://github.com/nutti/Magic-UV/wiki/Tutorial")
+
+        layout.label("--------------------------------------")
+
+        layout.label("[Location]")
+
+        row = layout.row(align=True)
+        sp = row.split(percentage=0.5)
+        sp.label("3D View > Tool shelf > Copy/Paste UV (Object mode)")
+        sp = sp.split(percentage=1.0)
+        col = sp.column(align=True)
+        col.label("Copy/Paste UV (Among objects)")
+
+        row = layout.row(align=True)
+        sp = row.split(percentage=0.5)
+        sp.label("3D View > Tool shelf > Copy/Paste UV (Edit mode)")
+        sp = sp.split(percentage=1.0)
+        col = sp.column(align=True)
+        col.label("Copy/Paste UV (Among faces in 3D View)")
+        col.label("Transfer UV")
+
+        row = layout.row(align=True)
+        sp = row.split(percentage=0.5)
+        sp.label("3D View > Tool shelf > UV Manipulation (Edit mode)")
+        sp = sp.split(percentage=1.0)
+        col = sp.column(align=True)
+        col.label("Flip/Rotate UV")
+        col.label("Mirror UV")
+        col.label("Move UV")
+        col.label("World Scale UV")
+        col.label("Preserve UV Aspect")
+        col.label("Texture Lock")
+        col.label("Texture Wrap")
+        col.label("UV Sculpt")
+
+        row = layout.row(align=True)
+        sp = row.split(percentage=0.5)
+        sp.label("3D View > Tool shelf > UV Manipulation (Edit mode)")
+        sp = sp.split(percentage=1.0)
+        col = sp.column(align=True)
+        col.label("Unwrap Constraint")
+        col.label("Texture Projection")
+        col.label("UVW")
+
+        row = layout.row(align=True)
+        sp = row.split(percentage=0.5)
+        sp.label("UV/Image Editor > Tool shelf > Copy/Paste UV")
+        sp = sp.split(percentage=1.0)
+        col = sp.column(align=True)
+        col.label("Copy/Paste UV (Among faces in UV/Image Editor)")
+
+        row = layout.row(align=True)
+        sp = row.split(percentage=0.5)
+        sp.label("UV/Image Editor > Tool shelf > UV Manipulation")
+        sp = sp.split(percentage=1.0)
+        col = sp.column(align=True)
+        col.label("Align UV")
+        col.label("Smooth UV")
+        col.label("Select UV")
+        col.label("Pack UV (Extension)")
+
+        row = layout.row(align=True)
+        sp = row.split(percentage=0.5)
+        sp.label("UV/Image Editor > Tool shelf > Editor Enhancement")
+        sp = sp.split(percentage=1.0)
+        col = sp.column(align=True)
+        col.label("Align UV Cursor")
+        col.label("UV Cursor Location")
+        col.label("UV Bounding Box")
+        col.label("UV Inspection")
diff --git a/uv_magic_uv/properites.py b/uv_magic_uv/properites.py
new file mode 100644
index 0000000000000000000000000000000000000000..3b61fcfcd8aae37fa885f2e4fab27b44bff22078
--- /dev/null
+++ b/uv_magic_uv/properites.py
@@ -0,0 +1,765 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+from bpy.props import (
+    FloatProperty,
+    EnumProperty,
+    BoolProperty,
+    FloatVectorProperty,
+    IntProperty
+)
+from mathutils import Vector
+
+from . import common
+
+
+def get_loaded_texture_name(_, __):
+    items = [(key, key, "") for key in bpy.data.images.keys()]
+    items.append(("None", "None", ""))
+    return items
+
+
+# Properties used in this add-on.
+class MUV_Properties():
+    cpuv = None
+    cpuv_obj = None
+    cpuv_selseq = None
+    transuv = None
+    uvbb = None
+    texlock = None
+    texproj = None
+    texwrap = None
+    mvuv = None
+    uvinsp = None
+    uvsculpt = None
+
+    def __init__(self):
+        self.cpuv = MUV_CPUVProps()
+        self.cpuv_obj = MUV_CPUVProps()
+        self.cpuv_selseq = MUV_CPUVSelSeqProps()
+        self.transuv = MUV_TransUVProps()
+        self.uvbb = MUV_UVBBProps()
+        self.texlock = MUV_TexLockProps()
+        self.texproj = MUV_TexProjProps()
+        self.texwrap = MUV_TexWrapProps()
+        self.mvuv = MUV_MVUVProps()
+        self.uvinsp = MUV_UVInspProps()
+        self.uvsculpt = MUV_UVSculptProps()
+
+
+class MUV_CPUVProps():
+    src_uvs = []
+    src_pin_uvs = []
+    src_seams = []
+
+
+class MUV_CPUVSelSeqProps():
+    src_uvs = []
+    src_pin_uvs = []
+    src_seams = []
+
+
+class MUV_TransUVProps():
+    topology_copied = []
+
+
+class MUV_TexProjProps():
+    running = False
+
+
+class MUV_UVBBProps():
+    uv_info_ini = []
+    ctrl_points_ini = []
+    ctrl_points = []
+    running = False
+
+
+class MUV_TexLockProps():
+    verts_orig = None
+    intr_verts_orig = None
+    intr_running = False
+
+
+class MUV_TexWrapProps():
+    ref_face_index = -1
+    ref_obj = None
+
+
+class MUV_MVUVProps():
+    running = False
+
+
+class MUV_UVInspProps():
+    display_running = False
+    overlapped_info = []
+    flipped_info = []
+
+
+class MUV_UVSculptProps():
+    running = False
+
+
+def init_props(scene):
+    scene.muv_props = MUV_Properties()
+
+    # UV Sculpt
+    scene.muv_uvsculpt_enabled = BoolProperty(
+        name="UV Sculpt",
+        description="UV Sculpt is enabled",
+        default=False
+    )
+    scene.muv_uvsculpt_radius = IntProperty(
+        name="Radius",
+        description="Radius of the brush",
+        min=1,
+        max=500,
+        default=30
+    )
+    scene.muv_uvsculpt_strength = FloatProperty(
+        name="Strength",
+        description="How powerful the effect of the brush when applied",
+        min=0.0,
+        max=1.0,
+        default=0.03,
+    )
+    scene.muv_uvsculpt_tools = EnumProperty(
+        name="Tools",
+        description="Select Tools for the UV sculpt brushes",
+        items=[
+            ('GRAB', "Grab", "Grab UVs"),
+            ('RELAX', "Relax", "Relax UVs"),
+            ('PINCH', "Pinch", "Pinch UVs")
+        ],
+        default='GRAB'
+    )
+    scene.muv_uvsculpt_show_brush = BoolProperty(
+        name="Show Brush",
+        description="Show Brush",
+        default=True
+    )
+    scene.muv_uvsculpt_pinch_invert = BoolProperty(
+        name="Invert",
+        description="Pinch UV to invert direction",
+        default=False
+    )
+    scene.muv_uvsculpt_relax_method = EnumProperty(
+        name="Method",
+        description="Algorithm used for relaxation",
+        items=[
+            ('HC', "HC", "Use HC method for relaxation"),
+            ('LAPLACIAN', "Laplacian", "Use laplacian method for relaxation")
+        ],
+        default='HC'
+    )
+
+    # Texture Wrap
+    scene.muv_texwrap_enabled = BoolProperty(
+        name="Texture Wrap",
+        description="Texture Wrap is enabled",
+        default=False
+    )
+    scene.muv_texwrap_set_and_refer = BoolProperty(
+        name="Set and Refer",
+        description="Refer and set UV",
+        default=True
+    )
+    scene.muv_texwrap_selseq = BoolProperty(
+        name="Selection Sequence",
+        description="Set UV sequentially",
+        default=False
+    )
+
+    # UV inspection
+    scene.muv_seluv_enabled = BoolProperty(
+        name="Select UV Enabled",
+        description="Select UV is enabled",
+        default=False
+    )
+    scene.muv_uvinsp_enabled = BoolProperty(
+        name="UV Inspection Enabled",
+        description="UV Inspection is enabled",
+        default=False
+    )
+    scene.muv_uvinsp_show_overlapped = BoolProperty(
+        name="Overlapped",
+        description="Show overlapped UVs",
+        default=False
+    )
+    scene.muv_uvinsp_show_flipped = BoolProperty(
+        name="Flipped",
+        description="Show flipped UVs",
+        default=False
+    )
+    scene.muv_uvinsp_show_mode = EnumProperty(
+        name="Mode",
+        description="Show mode",
+        items=[
+            ('PART', "Part", "Show only overlapped/flipped part"),
+            ('FACE', "Face", "Show overlapped/flipped face")
+        ],
+        default='PART'
+    )
+
+    # Align UV
+    scene.muv_auv_enabled = BoolProperty(
+        name="Aline UV Enabled",
+        description="Align UV is enabled",
+        default=False
+    )
+    scene.muv_auv_transmission = BoolProperty(
+        name="Transmission",
+        description="Align linked UVs",
+        default=False
+    )
+    scene.muv_auv_select = BoolProperty(
+        name="Select",
+        description="Select UVs which are aligned",
+        default=False
+    )
+    scene.muv_auv_vertical = BoolProperty(
+        name="Vert-Infl (Vertical)",
+        description="Align vertical direction influenced "
+                    "by mesh vertex proportion",
+        default=False
+    )
+    scene.muv_auv_horizontal = BoolProperty(
+        name="Vert-Infl (Horizontal)",
+        description="Align horizontal direction influenced "
+                    "by mesh vertex proportion",
+        default=False
+    )
+    scene.muv_auv_location = EnumProperty(
+        name="Location",
+        description="Align location",
+        items=[
+            ('LEFT_TOP', "Left/Top", "Align to Left or Top"),
+            ('MIDDLE', "Middle", "Align to middle"),
+            ('RIGHT_BOTTOM', "Right/Bottom", "Align to Right or Bottom")
+        ],
+        default='MIDDLE'
+    )
+
+    # Smooth UV
+    scene.muv_smuv_enabled = BoolProperty(
+        name="Smooth UV Enabled",
+        description="Smooth UV is enabled",
+        default=False
+    )
+    scene.muv_smuv_transmission = BoolProperty(
+        name="Transmission",
+        description="Smooth linked UVs",
+        default=False
+    )
+    scene.muv_smuv_mesh_infl = FloatProperty(
+        name="Mesh Influence",
+        description="Influence rate of mesh vertex",
+        min=0.0,
+        max=1.0,
+        default=0.0
+    )
+    scene.muv_smuv_select = BoolProperty(
+        name="Select",
+        description="Select UVs which are smoothed",
+        default=False
+    )
+
+    # UV Bounding Box
+    scene.muv_uvbb_enabled = BoolProperty(
+        name="UV Bounding Box Enabled",
+        description="UV Bounding Box is enabled",
+        default=False
+    )
+    scene.muv_uvbb_uniform_scaling = BoolProperty(
+        name="Uniform Scaling",
+        description="Enable Uniform Scaling",
+        default=False
+    )
+    scene.muv_uvbb_boundary = EnumProperty(
+        name="Boundary",
+        description="Boundary",
+        default='UV_SEL',
+        items=[
+            ('UV', "UV", "Boundary is decided by UV"),
+            ('UV_SEL', "UV (Selected)", "Boundary is decided by Selected UV")
+        ]
+    )
+
+    # Pack UV
+    scene.muv_packuv_enabled = BoolProperty(
+        name="Pack UV Enabled",
+        description="Pack UV is enabled",
+        default=False
+    )
+    scene.muv_packuv_allowable_center_deviation = FloatVectorProperty(
+        name="Allowable Center Deviation",
+        description="Allowable center deviation to judge same UV island",
+        min=0.000001,
+        max=0.1,
+        default=(0.001, 0.001),
+        size=2
+    )
+    scene.muv_packuv_allowable_size_deviation = FloatVectorProperty(
+        name="Allowable Size Deviation",
+        description="Allowable sizse deviation to judge same UV island",
+        min=0.000001,
+        max=0.1,
+        default=(0.001, 0.001),
+        size=2
+    )
+
+    # Move UV
+    scene.muv_mvuv_enabled = BoolProperty(
+        name="Move UV Enabled",
+        description="Move UV is enabled",
+        default=False
+    )
+
+    # UVW
+    scene.muv_uvw_enabled = BoolProperty(
+        name="UVW Enabled",
+        description="UVW is enabled",
+        default=False
+    )
+    scene.muv_uvw_assign_uvmap = BoolProperty(
+        name="Assign UVMap",
+        description="Assign UVMap when no UVmaps are available",
+        default=True
+    )
+
+    # Texture Projection
+    scene.muv_texproj_enabled = BoolProperty(
+        name="Texture Projection Enabled",
+        description="Texture Projection is enabled",
+        default=False
+    )
+    scene.muv_texproj_tex_magnitude = FloatProperty(
+        name="Magnitude",
+        description="Texture Magnitude",
+        default=0.5,
+        min=0.0,
+        max=100.0
+    )
+    scene.muv_texproj_tex_image = EnumProperty(
+        name="Image",
+        description="Texture Image",
+        items=get_loaded_texture_name
+    )
+    scene.muv_texproj_tex_transparency = FloatProperty(
+        name="Transparency",
+        description="Texture Transparency",
+        default=0.2,
+        min=0.0,
+        max=1.0
+    )
+    scene.muv_texproj_adjust_window = BoolProperty(
+        name="Adjust Window",
+        description="Size of renderered texture is fitted to window",
+        default=True
+    )
+    scene.muv_texproj_apply_tex_aspect = BoolProperty(
+        name="Texture Aspect Ratio",
+        description="Apply Texture Aspect ratio to displayed texture",
+        default=True
+    )
+    scene.muv_texproj_assign_uvmap = BoolProperty(
+        name="Assign UVMap",
+        description="Assign UVMap when no UVmaps are available",
+        default=True
+    )
+
+    # Texture Lock
+    scene.muv_texlock_enabled = BoolProperty(
+        name="Texture Lock Enabled",
+        description="Texture Lock is enabled",
+        default=False
+    )
+    scene.muv_texlock_connect = BoolProperty(
+        name="Connect UV",
+        default=True
+    )
+
+    # World Scale UV
+    scene.muv_wsuv_enabled = BoolProperty(
+        name="World Scale UV Enabled",
+        description="World Scale UV is enabled",
+        default=False
+    )
+    scene.muv_wsuv_src_mesh_area = FloatProperty(
+        name="Mesh Area",
+        description="Source Mesh Area",
+        default=0.0,
+        min=0.0
+    )
+    scene.muv_wsuv_src_uv_area = FloatProperty(
+        name="UV Area",
+        description="Source UV Area",
+        default=0.0,
+        min=0.0
+    )
+    scene.muv_wsuv_src_density = FloatProperty(
+        name="Density",
+        description="Source Texel Density",
+        default=0.0,
+        min=0.0
+    )
+    scene.muv_wsuv_tgt_density = FloatProperty(
+        name="Density",
+        description="Target Texel Density",
+        default=0.0,
+        min=0.0
+    )
+    scene.muv_wsuv_mode = EnumProperty(
+        name="Mode",
+        description="Density calculation mode",
+        items=[
+            ('PROPORTIONAL', 'Proportional', 'Scale proportionally by mesh'),
+            ('SCALING', 'Scaling', 'Specify scale factor'),
+            ('USER', 'User', 'Specify density'),
+            ('CONSTANT', 'Constant', 'Constant density')
+        ],
+        default='CONSTANT'
+    )
+    scene.muv_wsuv_scaling_factor = FloatProperty(
+        name="Scaling Factor",
+        default=1.0,
+        max=1000.0,
+        min=0.00001
+    )
+    scene.muv_wsuv_origin = EnumProperty(
+        name="Origin",
+        description="Aspect Origin",
+        items=[
+            ('CENTER', 'Center', 'Center'),
+            ('LEFT_TOP', 'Left Top', 'Left Bottom'),
+            ('LEFT_CENTER', 'Left Center', 'Left Center'),
+            ('LEFT_BOTTOM', 'Left Bottom', 'Left Bottom'),
+            ('CENTER_TOP', 'Center Top', 'Center Top'),
+            ('CENTER_BOTTOM', 'Center Bottom', 'Center Bottom'),
+            ('RIGHT_TOP', 'Right Top', 'Right Top'),
+            ('RIGHT_CENTER', 'Right Center', 'Right Center'),
+            ('RIGHT_BOTTOM', 'Right Bottom', 'Right Bottom')
+
+        ],
+        default='CENTER'
+    )
+
+    # Unwrap Constraint
+    scene.muv_unwrapconst_enabled = BoolProperty(
+        name="Unwrap Constraint Enabled",
+        description="Unwrap Constraint is enabled",
+        default=False
+    )
+    scene.muv_unwrapconst_u_const = BoolProperty(
+        name="U-Constraint",
+        description="Keep UV U-axis coordinate",
+        default=False
+    )
+    scene.muv_unwrapconst_v_const = BoolProperty(
+        name="V-Constraint",
+        description="Keep UV V-axis coordinate",
+        default=False
+    )
+
+    # Preserve UV Aspect
+    scene.muv_preserve_uv_enabled = BoolProperty(
+        name="Preserve UV Aspect Enabled",
+        description="Preserve UV Aspect is enabled",
+        default=False
+    )
+    scene.muv_preserve_uv_tex_image = EnumProperty(
+        name="Image",
+        description="Texture Image",
+        items=get_loaded_texture_name
+    )
+    scene.muv_preserve_uv_origin = EnumProperty(
+        name="Origin",
+        description="Aspect Origin",
+        items=[
+            ('CENTER', 'Center', 'Center'),
+            ('LEFT_TOP', 'Left Top', 'Left Bottom'),
+            ('LEFT_CENTER', 'Left Center', 'Left Center'),
+            ('LEFT_BOTTOM', 'Left Bottom', 'Left Bottom'),
+            ('CENTER_TOP', 'Center Top', 'Center Top'),
+            ('CENTER_BOTTOM', 'Center Bottom', 'Center Bottom'),
+            ('RIGHT_TOP', 'Right Top', 'Right Top'),
+            ('RIGHT_CENTER', 'Right Center', 'Right Center'),
+            ('RIGHT_BOTTOM', 'Right Bottom', 'Right Bottom')
+
+        ],
+        default="CENTER"
+    )
+
+    # Flip/Rotate UV
+    scene.muv_fliprot_enabled = BoolProperty(
+        name="Flip/Rotate UV Enabled",
+        description="Flip/Rotate UV is enabled",
+        default=False
+    )
+    scene.muv_fliprot_seams = BoolProperty(
+        name="Seams",
+        description="Seams",
+        default=True
+    )
+
+    # Mirror UV
+    scene.muv_mirroruv_enabled = BoolProperty(
+        name="Mirror UV Enabled",
+        description="Mirror UV is enabled",
+        default=False
+    )
+    scene.muv_mirroruv_axis = EnumProperty(
+        items=[
+            ('X', "X", "Mirror Along X axis"),
+            ('Y', "Y", "Mirror Along Y axis"),
+            ('Z', "Z", "Mirror Along Z axis")
+        ],
+        name="Axis",
+        description="Mirror Axis",
+        default='X'
+    )
+
+    # Copy/Paste UV
+    scene.muv_cpuv_enabled = BoolProperty(
+        name="Copy/Paste UV Enabled",
+        description="Copy/Paste UV is enabled",
+        default=False
+    )
+    scene.muv_cpuv_copy_seams = BoolProperty(
+        name="Copy Seams",
+        description="Copy Seams",
+        default=True
+    )
+    scene.muv_cpuv_mode = EnumProperty(
+        items=[
+            ('DEFAULT', "Default", "Default Mode"),
+            ('SEL_SEQ', "Selection Sequence", "Selection Sequence Mode")
+        ],
+        name="Copy/Paste UV Mode",
+        description="Copy/Paste UV Mode",
+        default='DEFAULT'
+    )
+    scene.muv_cpuv_strategy = EnumProperty(
+        name="Strategy",
+        description="Paste Strategy",
+        items=[
+            ('N_N', 'N:N', 'Number of faces must be equal to source'),
+            ('N_M', 'N:M', 'Number of faces must not be equal to source')
+        ],
+        default='N_M'
+    )
+
+    # Transfer UV
+    scene.muv_transuv_enabled = BoolProperty(
+        name="Transfer UV Enabled",
+        description="Transfer UV is enabled",
+        default=False
+    )
+    scene.muv_transuv_invert_normals = BoolProperty(
+        name="Invert Normals",
+        description="Invert Normals",
+        default=False
+    )
+    scene.muv_transuv_copy_seams = BoolProperty(
+        name="Copy Seams",
+        description="Copy Seams",
+        default=True
+    )
+
+    # Align UV Cursor
+    def auvc_get_cursor_loc(self):
+        area, _, space = common.get_space('IMAGE_EDITOR', 'WINDOW',
+                                          'IMAGE_EDITOR')
+        bd_size = common.get_uvimg_editor_board_size(area)
+        loc = space.cursor_location
+        if bd_size[0] < 0.000001:
+            cx = 0.0
+        else:
+            cx = loc[0] / bd_size[0]
+        if bd_size[1] < 0.000001:
+            cy = 0.0
+        else:
+            cy = loc[1] / bd_size[1]
+        self['muv_auvc_cursor_loc'] = Vector((cx, cy))
+        return self.get('muv_auvc_cursor_loc', (0.0, 0.0))
+
+    def auvc_set_cursor_loc(self, value):
+        self['muv_auvc_cursor_loc'] = value
+        area, _, space = common.get_space('IMAGE_EDITOR', 'WINDOW',
+                                          'IMAGE_EDITOR')
+        bd_size = common.get_uvimg_editor_board_size(area)
+        cx = bd_size[0] * value[0]
+        cy = bd_size[1] * value[1]
+        space.cursor_location = Vector((cx, cy))
+
+    scene.muv_auvc_enabled = BoolProperty(
+        name="Align UV Cursor Enabled",
+        description="Align UV Cursor is enabled",
+        default=False
+    )
+    scene.muv_auvc_cursor_loc = FloatVectorProperty(
+        name="UV Cursor Location",
+        size=2,
+        precision=4,
+        soft_min=-1.0,
+        soft_max=1.0,
+        step=1,
+        default=(0.000, 0.000),
+        get=auvc_get_cursor_loc,
+        set=auvc_set_cursor_loc
+    )
+    scene.muv_auvc_align_menu = EnumProperty(
+        name="Align Method",
+        description="Align Method",
+        default='TEXTURE',
+        items=[
+            ('TEXTURE', "Texture", "Align to texture"),
+            ('UV', "UV", "Align to UV"),
+            ('UV_SEL', "UV (Selected)", "Align to Selected UV")
+        ]
+    )
+
+    # UV Cursor Location
+    scene.muv_uvcloc_enabled = BoolProperty(
+        name="UV Cursor Location Enabled",
+        description="UV Cursor Location is enabled",
+        default=False
+    )
+
+
+def clear_props(scene):
+    del scene.muv_props
+
+    # UV Sculpt
+    del scene.muv_uvsculpt_enabled
+    del scene.muv_uvsculpt_radius
+    del scene.muv_uvsculpt_strength
+    del scene.muv_uvsculpt_tools
+    del scene.muv_uvsculpt_show_brush
+    del scene.muv_uvsculpt_pinch_invert
+    del scene.muv_uvsculpt_relax_method
+
+    # Texture Wrap
+    del scene.muv_texwrap_enabled
+    del scene.muv_texwrap_set_and_refer
+    del scene.muv_texwrap_selseq
+
+    # UV Inspection
+    del scene.muv_seluv_enabled
+    del scene.muv_uvinsp_enabled
+    del scene.muv_uvinsp_show_overlapped
+    del scene.muv_uvinsp_show_flipped
+    del scene.muv_uvinsp_show_mode
+
+    # Align UV
+    del scene.muv_auv_enabled
+    del scene.muv_auv_transmission
+    del scene.muv_auv_select
+    del scene.muv_auv_vertical
+    del scene.muv_auv_horizontal
+    del scene.muv_auv_location
+
+    # Smooth UV
+    del scene.muv_smuv_enabled
+    del scene.muv_smuv_transmission
+    del scene.muv_smuv_mesh_infl
+    del scene.muv_smuv_select
+
+    # UV Bounding Box
+    del scene.muv_uvbb_enabled
+    del scene.muv_uvbb_uniform_scaling
+    del scene.muv_uvbb_boundary
+
+    # Pack UV
+    del scene.muv_packuv_enabled
+    del scene.muv_packuv_allowable_center_deviation
+    del scene.muv_packuv_allowable_size_deviation
+
+    # Move UV
+    del scene.muv_mvuv_enabled
+
+    # UVW
+    del scene.muv_uvw_enabled
+    del scene.muv_uvw_assign_uvmap
+
+    # Texture Projection
+    del scene.muv_texproj_enabled
+    del scene.muv_texproj_tex_magnitude
+    del scene.muv_texproj_tex_image
+    del scene.muv_texproj_tex_transparency
+    del scene.muv_texproj_adjust_window
+    del scene.muv_texproj_apply_tex_aspect
+    del scene.muv_texproj_assign_uvmap
+
+    # Texture Lock
+    del scene.muv_texlock_enabled
+    del scene.muv_texlock_connect
+
+    # World Scale UV
+    del scene.muv_wsuv_enabled
+    del scene.muv_wsuv_src_mesh_area
+    del scene.muv_wsuv_src_uv_area
+    del scene.muv_wsuv_src_density
+    del scene.muv_wsuv_tgt_density
+    del scene.muv_wsuv_mode
+    del scene.muv_wsuv_scaling_factor
+    del scene.muv_wsuv_origin
+
+    # Unwrap Constraint
+    del scene.muv_unwrapconst_enabled
+    del scene.muv_unwrapconst_u_const
+    del scene.muv_unwrapconst_v_const
+
+    # Preserve UV Aspect
+    del scene.muv_preserve_uv_enabled
+    del scene.muv_preserve_uv_tex_image
+    del scene.muv_preserve_uv_origin
+
+    # Flip/Rotate UV
+    del scene.muv_fliprot_enabled
+    del scene.muv_fliprot_seams
+
+    # Mirror UV
+    del scene.muv_mirroruv_enabled
+    del scene.muv_mirroruv_axis
+
+    # Copy/Paste UV
+    del scene.muv_cpuv_enabled
+    del scene.muv_cpuv_copy_seams
+    del scene.muv_cpuv_mode
+    del scene.muv_cpuv_strategy
+
+    # Transfer UV
+    del scene.muv_transuv_enabled
+    del scene.muv_transuv_invert_normals
+    del scene.muv_transuv_copy_seams
+
+    # Align UV Cursor
+    del scene.muv_auvc_enabled
+    del scene.muv_auvc_cursor_loc
+    del scene.muv_auvc_align_menu
+
+    # UV Cursor Location
+    del scene.muv_uvcloc_enabled
diff --git a/uv_magic_uv/ui/__init__.py b/uv_magic_uv/ui/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..ad56aeb3c47e71c556442649e35b7ff42a2c7f13
--- /dev/null
+++ b/uv_magic_uv/ui/__init__.py
@@ -0,0 +1,44 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+if "bpy" in locals():
+    import importlib
+    importlib.reload(view3d_copy_paste_uv_objectmode)
+    importlib.reload(view3d_copy_paste_uv_editmode)
+    importlib.reload(view3d_uv_manipulation)
+    importlib.reload(view3d_uv_mapping)
+    importlib.reload(uvedit_copy_paste_uv)
+    importlib.reload(uvedit_uv_manipulation)
+    importlib.reload(uvedit_editor_enhance)
+else:
+    from . import view3d_copy_paste_uv_objectmode
+    from . import view3d_copy_paste_uv_editmode
+    from . import view3d_uv_manipulation
+    from . import view3d_uv_mapping
+    from . import uvedit_copy_paste_uv
+    from . import uvedit_uv_manipulation
+    from . import uvedit_editor_enhance
+
+import bpy
diff --git a/uv_magic_uv/ui/uvedit_copy_paste_uv.py b/uv_magic_uv/ui/uvedit_copy_paste_uv.py
new file mode 100644
index 0000000000000000000000000000000000000000..d87dbef3e86855bd50eb9350952f32ef9a188210
--- /dev/null
+++ b/uv_magic_uv/ui/uvedit_copy_paste_uv.py
@@ -0,0 +1,54 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+
+from ..op import copy_paste_uv_uvedit
+
+
+class IMAGE_PT_MUV_CPUV(bpy.types.Panel):
+    """
+    Panel class: Copy/Paste UV on Property Panel on UV/ImageEditor
+    """
+
+    bl_space_type = 'IMAGE_EDITOR'
+    bl_region_type = 'TOOLS'
+    bl_label = "Copy/Paste UV"
+    bl_category = "Magic UV"
+    bl_context = 'mesh_edit'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw_header(self, _):
+        layout = self.layout
+        layout.label(text="", icon='IMAGE_COL')
+
+    def draw(self, _):
+        layout = self.layout
+
+        row = layout.row(align=True)
+        row.operator(copy_paste_uv_uvedit.MUV_CPUVIECopyUV.bl_idname,
+                     text="Copy")
+        row.operator(copy_paste_uv_uvedit.MUV_CPUVIEPasteUV.bl_idname,
+                     text="Paste")
diff --git a/uv_magic_uv/ui/uvedit_editor_enhance.py b/uv_magic_uv/ui/uvedit_editor_enhance.py
new file mode 100644
index 0000000000000000000000000000000000000000..88a2492c64230fd8f7bc2ce56e12cfe4a97870f7
--- /dev/null
+++ b/uv_magic_uv/ui/uvedit_editor_enhance.py
@@ -0,0 +1,136 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+
+from ..op import align_uv_cursor
+from ..op import uv_bounding_box
+from ..op import uv_inspection
+
+
+class IMAGE_PT_MUV_EE(bpy.types.Panel):
+    """
+    Panel class: UV/Image Editor Enhancement
+    """
+
+    bl_space_type = 'IMAGE_EDITOR'
+    bl_region_type = 'TOOLS'
+    bl_label = "Editor Enhancement"
+    bl_category = "Magic UV"
+    bl_context = 'mesh_edit'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw_header(self, _):
+        layout = self.layout
+        layout.label(text="", icon='IMAGE_COL')
+
+    def draw(self, context):
+        layout = self.layout
+        sc = context.scene
+        props = sc.muv_props
+
+        box = layout.box()
+        box.prop(sc, "muv_auvc_enabled", text="Align UV Cursor")
+        if sc.muv_auvc_enabled:
+            box.prop(sc, "muv_auvc_align_menu", expand=True)
+
+            col = box.column(align=True)
+
+            row = col.row(align=True)
+            ops = row.operator(align_uv_cursor.MUV_AUVCAlignOps.bl_idname,
+                               text="Left Top")
+            ops.position = 'LEFT_TOP'
+            ops.base = sc.muv_auvc_align_menu
+            ops = row.operator(align_uv_cursor.MUV_AUVCAlignOps.bl_idname,
+                               text="Middle Top")
+            ops.position = 'MIDDLE_TOP'
+            ops.base = sc.muv_auvc_align_menu
+            ops = row.operator(align_uv_cursor.MUV_AUVCAlignOps.bl_idname,
+                               text="Right Top")
+            ops.position = 'RIGHT_TOP'
+            ops.base = sc.muv_auvc_align_menu
+
+            row = col.row(align=True)
+            ops = row.operator(align_uv_cursor.MUV_AUVCAlignOps.bl_idname,
+                               text="Left Middle")
+            ops.position = 'LEFT_MIDDLE'
+            ops.base = sc.muv_auvc_align_menu
+            ops = row.operator(align_uv_cursor.MUV_AUVCAlignOps.bl_idname,
+                               text="Center")
+            ops.position = 'CENTER'
+            ops.base = sc.muv_auvc_align_menu
+            ops = row.operator(align_uv_cursor.MUV_AUVCAlignOps.bl_idname,
+                               text="Right Middle")
+            ops.position = 'RIGHT_MIDDLE'
+            ops.base = sc.muv_auvc_align_menu
+
+            row = col.row(align=True)
+            ops = row.operator(align_uv_cursor.MUV_AUVCAlignOps.bl_idname,
+                               text="Left Bottom")
+            ops.position = 'LEFT_BOTTOM'
+            ops.base = sc.muv_auvc_align_menu
+            ops = row.operator(align_uv_cursor.MUV_AUVCAlignOps.bl_idname,
+                               text="Middle Bottom")
+            ops.position = 'MIDDLE_BOTTOM'
+            ops.base = sc.muv_auvc_align_menu
+            ops = row.operator(align_uv_cursor.MUV_AUVCAlignOps.bl_idname,
+                               text="Right Bottom")
+            ops.position = 'RIGHT_BOTTOM'
+            ops.base = sc.muv_auvc_align_menu
+
+        box = layout.box()
+        box.prop(sc, "muv_uvcloc_enabled", text="UV Cursor Location")
+        if sc.muv_uvcloc_enabled:
+            box.prop(sc, "muv_auvc_cursor_loc", text="")
+
+        box = layout.box()
+        box.prop(sc, "muv_uvbb_enabled", text="UV Bounding Box")
+        if sc.muv_uvbb_enabled:
+            if props.uvbb.running is False:
+                box.operator(uv_bounding_box.MUV_UVBBUpdater.bl_idname,
+                             text="Display", icon='PLAY')
+            else:
+                box.operator(uv_bounding_box.MUV_UVBBUpdater.bl_idname,
+                             text="Hide", icon='PAUSE')
+            box.prop(sc, "muv_uvbb_uniform_scaling", text="Uniform Scaling")
+            box.prop(sc, "muv_uvbb_boundary", text="Boundary")
+
+        box = layout.box()
+        box.prop(sc, "muv_uvinsp_enabled", text="UV Inspection")
+        if sc.muv_uvinsp_enabled:
+            row = box.row()
+            if not sc.muv_props.uvinsp.display_running:
+                row.operator(uv_inspection.MUV_UVInspDisplay.bl_idname,
+                             text="Display", icon='PLAY')
+            else:
+                row.operator(uv_inspection.MUV_UVInspDisplay.bl_idname,
+                             text="Hide", icon='PAUSE')
+                row.operator(uv_inspection.MUV_UVInspUpdate.bl_idname,
+                             text="Update")
+            row = box.row()
+            row.prop(sc, "muv_uvinsp_show_overlapped")
+            row.prop(sc, "muv_uvinsp_show_flipped")
+            row = box.row()
+            row.prop(sc, "muv_uvinsp_show_mode")
diff --git a/uv_magic_uv/ui/uvedit_uv_manipulation.py b/uv_magic_uv/ui/uvedit_uv_manipulation.py
new file mode 100644
index 0000000000000000000000000000000000000000..f391c4cbf2062d8b9af542a11e2908915b036e5c
--- /dev/null
+++ b/uv_magic_uv/ui/uvedit_uv_manipulation.py
@@ -0,0 +1,117 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+
+from ..op import uv_inspection
+from ..op import align_uv
+from ..op import smooth_uv
+from ..op import pack_uv
+
+
+class IMAGE_PT_MUV_UVManip(bpy.types.Panel):
+    """
+    Panel class: UV Manipulation on Property Panel on UV/ImageEditor
+    """
+
+    bl_space_type = 'IMAGE_EDITOR'
+    bl_region_type = 'TOOLS'
+    bl_label = "UV Manipulation"
+    bl_category = "Magic UV"
+    bl_context = 'mesh_edit'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw_header(self, _):
+        layout = self.layout
+        layout.label(text="", icon='IMAGE_COL')
+
+    def draw(self, context):
+        sc = context.scene
+        layout = self.layout
+
+        box = layout.box()
+        box.prop(sc, "muv_auv_enabled", text="Align UV")
+        if sc.muv_auv_enabled:
+            col = box.column()
+            row = col.row(align=True)
+            ops = row.operator(align_uv.MUV_AUVCircle.bl_idname, text="Circle")
+            ops.transmission = sc.muv_auv_transmission
+            ops.select = sc.muv_auv_select
+            ops = row.operator(align_uv.MUV_AUVStraighten.bl_idname,
+                               text="Straighten")
+            ops.transmission = sc.muv_auv_transmission
+            ops.select = sc.muv_auv_select
+            ops.vertical = sc.muv_auv_vertical
+            ops.horizontal = sc.muv_auv_horizontal
+            row = col.row()
+            ops = row.operator(align_uv.MUV_AUVAxis.bl_idname, text="XY-axis")
+            ops.transmission = sc.muv_auv_transmission
+            ops.select = sc.muv_auv_select
+            ops.vertical = sc.muv_auv_vertical
+            ops.horizontal = sc.muv_auv_horizontal
+            ops.location = sc.muv_auv_location
+            row.prop(sc, "muv_auv_location", text="")
+
+            col = box.column(align=True)
+            row = col.row(align=True)
+            row.prop(sc, "muv_auv_transmission", text="Transmission")
+            row.prop(sc, "muv_auv_select", text="Select")
+            row = col.row(align=True)
+            row.prop(sc, "muv_auv_vertical", text="Vertical")
+            row.prop(sc, "muv_auv_horizontal", text="Horizontal")
+
+        box = layout.box()
+        box.prop(sc, "muv_smuv_enabled", text="Smooth UV")
+        if sc.muv_smuv_enabled:
+            ops = box.operator(smooth_uv.MUV_AUVSmooth.bl_idname,
+                               text="Smooth")
+            ops.transmission = sc.muv_smuv_transmission
+            ops.select = sc.muv_smuv_select
+            ops.mesh_infl = sc.muv_smuv_mesh_infl
+            col = box.column(align=True)
+            row = col.row(align=True)
+            row.prop(sc, "muv_smuv_transmission", text="Transmission")
+            row.prop(sc, "muv_smuv_select", text="Select")
+            col.prop(sc, "muv_smuv_mesh_infl", text="Mesh Influence")
+
+        box = layout.box()
+        box.prop(sc, "muv_seluv_enabled", text="Select UV")
+        if sc.muv_seluv_enabled:
+            row = box.row(align=True)
+            row.operator(uv_inspection.MUV_UVInspSelectOverlapped.bl_idname)
+            row.operator(uv_inspection.MUV_UVInspSelectFlipped.bl_idname)
+
+        box = layout.box()
+        box.prop(sc, "muv_packuv_enabled", text="Pack UV (Extension)")
+        if sc.muv_packuv_enabled:
+            ops = box.operator(pack_uv.MUV_PackUV.bl_idname, text="Pack UV")
+            ops.allowable_center_deviation = \
+                sc.muv_packuv_allowable_center_deviation
+            ops.allowable_size_deviation = \
+                sc.muv_packuv_allowable_size_deviation
+            box.label("Allowable Center Deviation:")
+            box.prop(sc, "muv_packuv_allowable_center_deviation", text="")
+            box.label("Allowable Size Deviation:")
+            box.prop(sc, "muv_packuv_allowable_size_deviation", text="")
diff --git a/uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py b/uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py
new file mode 100644
index 0000000000000000000000000000000000000000..a22adf035c282f969bb59084f33894a238a84d4b
--- /dev/null
+++ b/uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py
@@ -0,0 +1,81 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+
+from ..op import copy_paste_uv
+from ..op import transfer_uv
+
+
+class OBJECT_PT_MUV_CPUV(bpy.types.Panel):
+    """
+    Panel class: Copy/Paste UV on Property Panel on View3D
+    """
+
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_label = "Copy/Paste UV"
+    bl_category = "Magic UV"
+    bl_context = 'mesh_edit'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw_header(self, _):
+        layout = self.layout
+        layout.label(text="", icon='IMAGE_COL')
+
+    def draw(self, context):
+        sc = context.scene
+        layout = self.layout
+
+        box = layout.box()
+        box.prop(sc, "muv_cpuv_enabled", text="Copy/Paste UV")
+        if sc.muv_cpuv_enabled:
+            row = box.row(align=True)
+            if sc.muv_cpuv_mode == 'DEFAULT':
+                row.menu(copy_paste_uv.MUV_CPUVCopyUVMenu.bl_idname,
+                         text="Copy")
+                row.menu(copy_paste_uv.MUV_CPUVPasteUVMenu.bl_idname,
+                         text="Paste")
+            elif sc.muv_cpuv_mode == 'SEL_SEQ':
+                row.menu(copy_paste_uv.MUV_CPUVSelSeqCopyUVMenu.bl_idname,
+                         text="Copy")
+                row.menu(copy_paste_uv.MUV_CPUVSelSeqPasteUVMenu.bl_idname,
+                         text="Paste")
+            box.prop(sc, "muv_cpuv_mode", expand=True)
+            box.prop(sc, "muv_cpuv_copy_seams", text="Seams")
+            box.prop(sc, "muv_cpuv_strategy", text="Strategy")
+
+        box = layout.box()
+        box.prop(sc, "muv_transuv_enabled", text="Transfer UV")
+        if sc.muv_transuv_enabled:
+            row = box.row(align=True)
+            row.operator(transfer_uv.MUV_TransUVCopy.bl_idname, text="Copy")
+            ops = row.operator(transfer_uv.MUV_TransUVPaste.bl_idname,
+                               text="Paste")
+            ops.invert_normals = sc.muv_transuv_invert_normals
+            ops.copy_seams = sc.muv_transuv_copy_seams
+            row = box.row()
+            row.prop(sc, "muv_transuv_invert_normals", text="Invert Normals")
+            row.prop(sc, "muv_transuv_copy_seams", text="Seams")
diff --git a/uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py b/uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py
new file mode 100644
index 0000000000000000000000000000000000000000..f9e2bec0ccf3813fc1e79ace4e4a24d2b8ef58b3
--- /dev/null
+++ b/uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py
@@ -0,0 +1,56 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+
+from ..op import copy_paste_uv_object
+
+
+class OBJECT_PT_MUV_CPUVObj(bpy.types.Panel):
+    """
+    Panel class: Copy/Paste UV on Property Panel on View3D
+    """
+
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_label = "Copy/Paste UV"
+    bl_category = "Magic UV"
+    bl_context = 'objectmode'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw_header(self, _):
+        layout = self.layout
+        layout.label(text="", icon='IMAGE_COL')
+
+    def draw(self, context):
+        sc = context.scene
+        layout = self.layout
+
+        row = layout.row(align=True)
+        row.menu(copy_paste_uv_object.MUV_CPUVObjCopyUVMenu.bl_idname,
+                 text="Copy")
+        row.menu(copy_paste_uv_object.MUV_CPUVObjPasteUVMenu.bl_idname,
+                 text="Paste")
+        layout.prop(sc, "muv_cpuv_copy_seams", text="Copy Seams")
diff --git a/uv_magic_uv/ui/view3d_uv_manipulation.py b/uv_magic_uv/ui/view3d_uv_manipulation.py
new file mode 100644
index 0000000000000000000000000000000000000000..1e9b7d7e85557b38449da1fd60e4f09c2cb63f4b
--- /dev/null
+++ b/uv_magic_uv/ui/view3d_uv_manipulation.py
@@ -0,0 +1,180 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+
+from ..op import flip_rotate_uv
+from ..op import mirror_uv
+from ..op import move_uv
+from ..op import preserve_uv_aspect
+from ..op import texture_lock
+from ..op import texture_wrap
+from ..op import uv_sculpt
+from ..op import world_scale_uv
+
+
+class OBJECT_PT_MUV_UVManip(bpy.types.Panel):
+    """
+    Panel class: UV Manipulation on Property Panel on View3D
+    """
+
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_label = "UV Manipulation"
+    bl_category = "Magic UV"
+    bl_context = 'mesh_edit'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw_header(self, _):
+        layout = self.layout
+        layout.label(text="", icon='IMAGE_COL')
+
+    def draw(self, context):
+        sc = context.scene
+        props = sc.muv_props
+        layout = self.layout
+
+        box = layout.box()
+        box.prop(sc, "muv_fliprot_enabled", text="Flip/Rotate UV")
+        if sc.muv_fliprot_enabled:
+            row = box.row()
+            ops = row.operator(flip_rotate_uv.MUV_FlipRot.bl_idname,
+                               text="Flip/Rotate")
+            ops.seams = sc.muv_fliprot_seams
+            row.prop(sc, "muv_fliprot_seams", text="Seams")
+
+        box = layout.box()
+        box.prop(sc, "muv_mirroruv_enabled", text="Mirror UV")
+        if sc.muv_mirroruv_enabled:
+            row = box.row()
+            ops = row.operator(mirror_uv.MUV_MirrorUV.bl_idname, text="Mirror")
+            ops.axis = sc.muv_mirroruv_axis
+            row.prop(sc, "muv_mirroruv_axis", text="")
+
+        box = layout.box()
+        box.prop(sc, "muv_mvuv_enabled", text="Move UV")
+        if sc.muv_mvuv_enabled:
+            col = box.column()
+            col.operator(move_uv.MUV_MVUV.bl_idname, icon='PLAY', text="Start")
+            if props.mvuv.running:
+                col.enabled = False
+            else:
+                col.enabled = True
+
+        box = layout.box()
+        box.prop(sc, "muv_wsuv_enabled", text="World Scale UV")
+        if sc.muv_wsuv_enabled:
+            row = box.row(align=True)
+            row.operator(world_scale_uv.MUV_WSUVMeasure.bl_idname,
+                         text="Measure")
+            ops = row.operator(world_scale_uv.MUV_WSUVApply.bl_idname,
+                               text="Apply")
+            ops.origin = sc.muv_wsuv_origin
+            box.label("Source:")
+            sp = box.split(percentage=0.7)
+            col = sp.column(align=True)
+            col.prop(sc, "muv_wsuv_src_mesh_area", text="Mesh Area")
+            col.prop(sc, "muv_wsuv_src_uv_area", text="UV Area")
+            col.prop(sc, "muv_wsuv_src_density", text="Density")
+            col.enabled = False
+            sp = sp.split(percentage=1.0)
+            col = sp.column(align=True)
+            col.label("cm x cm")
+            col.label("px x px")
+            col.label("px/cm")
+            col.enabled = False
+            sp = box.split(percentage=0.3)
+            sp.label("Mode:")
+            sp = sp.split(percentage=1.0)
+            col = sp.column()
+            col.prop(sc, "muv_wsuv_mode", text="")
+            if sc.muv_wsuv_mode == 'USER':
+                col.prop(sc, "muv_wsuv_tgt_density", text="Density")
+            if sc.muv_wsuv_mode == 'SCALING':
+                col.prop(sc, "muv_wsuv_scaling_factor", text="Scaling Factor")
+            box.prop(sc, "muv_wsuv_origin", text="Origin")
+
+        box = layout.box()
+        box.prop(sc, "muv_preserve_uv_enabled", text="Preserve UV Aspect")
+        if sc.muv_preserve_uv_enabled:
+            row = box.row()
+            ops = row.operator(
+                preserve_uv_aspect.MUV_PreserveUVAspect.bl_idname,
+                text="Change Image")
+            ops.dest_img_name = sc.muv_preserve_uv_tex_image
+            ops.origin = sc.muv_preserve_uv_origin
+            row.prop(sc, "muv_preserve_uv_tex_image", text="")
+            box.prop(sc, "muv_preserve_uv_origin", text="Origin")
+
+        box = layout.box()
+        box.prop(sc, "muv_texlock_enabled", text="Texture Lock")
+        if sc.muv_texlock_enabled:
+            row = box.row(align=True)
+            col = row.column(align=True)
+            col.label("Normal Mode:")
+            col = row.column(align=True)
+            col.operator(texture_lock.MUV_TexLockStart.bl_idname, text="Lock")
+            ops = col.operator(texture_lock.MUV_TexLockStop.bl_idname,
+                               text="Unlock")
+            ops.connect = sc.muv_texlock_connect
+            col.prop(sc, "muv_texlock_connect", text="Connect")
+
+            row = box.row(align=True)
+            row.label("Interactive Mode:")
+            if not props.texlock.intr_running:
+                row.operator(texture_lock.MUV_TexLockIntrStart.bl_idname,
+                             icon='PLAY', text="Start")
+            else:
+                row.operator(texture_lock.MUV_TexLockIntrStop.bl_idname,
+                             icon="PAUSE", text="Stop")
+
+        box = layout.box()
+        box.prop(sc, "muv_texwrap_enabled", text="Texture Wrap")
+        if sc.muv_texwrap_enabled:
+            row = box.row(align=True)
+            row.operator(texture_wrap.MUV_TexWrapRefer.bl_idname, text="Refer")
+            row.operator(texture_wrap.MUV_TexWrapSet.bl_idname, text="Set")
+            box.prop(sc, "muv_texwrap_set_and_refer")
+            box.prop(sc, "muv_texwrap_selseq")
+
+        box = layout.box()
+        box.prop(sc, "muv_uvsculpt_enabled", text="UV Sculpt")
+        if sc.muv_uvsculpt_enabled:
+            if not props.uvsculpt.running:
+                box.operator(uv_sculpt.MUV_UVSculptOps.bl_idname,
+                             icon='PLAY', text="Start")
+            else:
+                box.operator(uv_sculpt.MUV_UVSculptOps.bl_idname,
+                             icon='PAUSE', text="Stop")
+            col = box.column()
+            col.label("Brush:")
+            col.prop(sc, "muv_uvsculpt_radius")
+            col.prop(sc, "muv_uvsculpt_strength")
+            box.prop(sc, "muv_uvsculpt_tools")
+            if sc.muv_uvsculpt_tools == 'PINCH':
+                box.prop(sc, "muv_uvsculpt_pinch_invert")
+            elif sc.muv_uvsculpt_tools == 'RELAX':
+                box.prop(sc, "muv_uvsculpt_relax_method")
+            box.prop(sc, "muv_uvsculpt_show_brush")
diff --git a/uv_magic_uv/ui/view3d_uv_mapping.py b/uv_magic_uv/ui/view3d_uv_mapping.py
new file mode 100644
index 0000000000000000000000000000000000000000..2dc241c0de0c0860e728fa984f4d8f7491b2ac12
--- /dev/null
+++ b/uv_magic_uv/ui/view3d_uv_mapping.py
@@ -0,0 +1,99 @@
+# <pep8-80 compliant>
+
+# ##### 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 #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.1"
+__date__ = "24 Feb 2018"
+
+import bpy
+
+from ..op import texture_projection
+from ..op import unwrap_constraint
+from ..op import uvw
+
+
+class OBJECT_PT_MUV_UVMapping(bpy.types.Panel):
+    """
+    Panel class: UV Mapping on Property Panel on View3D
+    """
+
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_label = "UV Mapping"
+    bl_category = "Magic UV"
+    bl_context = 'mesh_edit'
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw_header(self, _):
+        layout = self.layout
+        layout.label(text="", icon='IMAGE_COL')
+
+    def draw(self, context):
+        sc = context.scene
+        props = sc.muv_props
+        layout = self.layout
+
+        box = layout.box()
+        box.prop(sc, "muv_unwrapconst_enabled", text="Unwrap Constraint")
+        if sc.muv_unwrapconst_enabled:
+            ops = box.operator(
+                unwrap_constraint.MUV_UnwrapConstraint.bl_idname,
+                text="Unwrap")
+            ops.u_const = sc.muv_unwrapconst_u_const
+            ops.v_const = sc.muv_unwrapconst_v_const
+            row = box.row(align=True)
+            row.prop(sc, "muv_unwrapconst_u_const", text="U-Constraint")
+            row.prop(sc, "muv_unwrapconst_v_const", text="V-Constraint")
+
+        box = layout.box()
+        box.prop(sc, "muv_texproj_enabled", text="Texture Projection")
+        if sc.muv_texproj_enabled:
+            row = box.row()
+            if not props.texproj.running:
+                row.operator(texture_projection.MUV_TexProjStart.bl_idname,
+                             text="Start", icon='PLAY')
+            else:
+                row.operator(texture_projection.MUV_TexProjStop.bl_idname,
+                             text="Stop", icon='PAUSE')
+            row.prop(sc, "muv_texproj_tex_image", text="")
+            box.prop(sc, "muv_texproj_tex_transparency", text="Transparency")
+            col = box.column(align=True)
+            row = col.row()
+            row.prop(sc, "muv_texproj_adjust_window", text="Adjust Window")
+            if not sc.muv_texproj_adjust_window:
+                row.prop(sc, "muv_texproj_tex_magnitude", text="Magnitude")
+            col.prop(sc, "muv_texproj_apply_tex_aspect",
+                     text="Texture Aspect Ratio")
+            col.prop(sc, "muv_texproj_assign_uvmap", text="Assign UVMap")
+            if props.texproj.running:
+                box.operator(texture_projection.MUV_TexProjProject.bl_idname,
+                             text="Project")
+
+        box = layout.box()
+        box.prop(sc, "muv_uvw_enabled", text="UVW")
+        if sc.muv_uvw_enabled:
+            row = box.row(align=True)
+            ops = row.operator(uvw.MUV_UVWBoxMap.bl_idname, text="Box")
+            ops.assign_uvmap = sc.muv_uvw_assign_uvmap
+            ops = row.operator(uvw.MUV_UVWBestPlanerMap.bl_idname,
+                               text="Best Planner")
+            ops.assign_uvmap = sc.muv_uvw_assign_uvmap
+            box.prop(sc, "muv_uvw_assign_uvmap", text="Assign UVMap")