diff --git a/blenderkit/README.md b/blenderkit/README.md
deleted file mode 100644
index e2e77067e22f4a25ec8c2e2af58247f2bad72ffe..0000000000000000000000000000000000000000
--- a/blenderkit/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-BlenderKit add-on is the official addon of the BlenderKit service for Blender 3d.
-It enables users to upload, search, download, and rate different assets for blender.
-It works together with BlenderKit server.
\ No newline at end of file
diff --git a/blenderkit/__init__.py b/blenderkit/__init__.py
deleted file mode 100644
index 22afd2a19110b9871561e6c281d8dff4a08bc85e..0000000000000000000000000000000000000000
--- a/blenderkit/__init__.py
+++ /dev/null
@@ -1,1977 +0,0 @@
-# ##### 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 #####
-
-bl_info = {
-    "name": "BlenderKit Online Asset Library",
-    "author": "Vilem Duha, Petr Dlouhy",
-    "version": (3, 0, 0),
-    "blender": (2, 93, 0),
-    "location": "View3D > Properties > BlenderKit",
-    "description": "Online BlenderKit library (materials, models, brushes and more). Connects to the internet.",
-    "warning": "",
-    "doc_url": "{BLENDER_MANUAL_URL}/addons/3d_view/blenderkit.html",
-    "category": "3D View",
-}
-
-if "bpy" in locals():
-    from importlib import reload
-
-    # alphabetically sorted all add-on modules since reload only happens from __init__.
-    # modules with _bg are used for background computations in separate blender instance and that's why they don't need reload.
-
-    append_link = reload(append_link)
-    asset_bar_op = reload(asset_bar_op)
-    asset_inspector = reload(asset_inspector)
-    autothumb = reload(autothumb)
-    bg_blender = reload(bg_blender)
-    bkit_oauth = reload(bkit_oauth)
-    categories = reload(categories)
-    colors = reload(colors)
-    download = reload(download)
-    icons = reload(icons)
-    image_utils = reload(image_utils)
-    oauth = reload(oauth)
-    overrides = reload(overrides)
-    paths = reload(paths)
-    ratings = reload(ratings)
-    ratings_utils = reload(ratings_utils)
-    comments_utils = reload(comments_utils)
-    resolutions = reload(resolutions)
-    search = reload(search)
-    tasks_queue = reload(tasks_queue)
-    ui = reload(ui)
-    ui_bgl = reload(ui_bgl)
-    ui_panels = reload(ui_panels)
-    upload = reload(upload)
-    upload_bg = reload(upload_bg)
-    utils = reload(utils)
-    reports = reload(reports)
-
-    bl_ui_widget = reload(bl_ui_widget)
-    bl_ui_label = reload(bl_ui_label)
-    bl_ui_button = reload(bl_ui_button)
-    bl_ui_image = reload(bl_ui_image)
-    # bl_ui_checkbox = reload(bl_ui_checkbox)
-    # bl_ui_slider = reload(bl_ui_slider)
-    # bl_ui_up_down = reload(bl_ui_up_down)
-    bl_ui_drag_panel = reload(bl_ui_drag_panel)
-    bl_ui_draw_op = reload(bl_ui_draw_op)
-    # bl_ui_textbox = reload(bl_ui_textbox)
-
-else:
-    from blenderkit import append_link
-    from blenderkit import asset_bar_op
-    from blenderkit import asset_inspector
-    from blenderkit import autothumb
-    from blenderkit import bg_blender
-    from blenderkit import bkit_oauth
-    from blenderkit import categories
-    from blenderkit import colors
-    from blenderkit import download
-    from blenderkit import icons
-    from blenderkit import image_utils
-    from blenderkit import oauth
-    from blenderkit import overrides
-    from blenderkit import paths
-    from blenderkit import ratings
-    from blenderkit import ratings_utils
-    from blenderkit import comments_utils
-    from blenderkit import resolutions
-    from blenderkit import search
-    from blenderkit import tasks_queue
-    from blenderkit import ui
-    from blenderkit import ui_bgl
-    from blenderkit import ui_panels
-    from blenderkit import upload
-    from blenderkit import upload_bg
-    from blenderkit import utils
-    from blenderkit import reports
-
-    from blenderkit.bl_ui_widgets import bl_ui_widget
-    from blenderkit.bl_ui_widgets import bl_ui_label
-    from blenderkit.bl_ui_widgets import bl_ui_button
-    from blenderkit.bl_ui_widgets import bl_ui_image
-    # from blenderkit.bl_ui_widgets import bl_ui_checkbox
-    # from blenderkit.bl_ui_widgets import bl_ui_slider
-    # from blenderkit.bl_ui_widgets import bl_ui_up_down
-    from blenderkit.bl_ui_widgets import bl_ui_draw_op
-    from blenderkit.bl_ui_widgets import bl_ui_drag_panel
-    # from blenderkit.bl_ui_widgets import bl_ui_textbox
-
-import os
-import math
-import time
-import logging
-import bpy
-import pathlib
-
-log = logging.getLogger(__name__)
-
-from bpy.app.handlers import persistent
-import bpy.utils.previews
-import mathutils
-from mathutils import Vector
-from bpy.props import (
-    IntProperty,
-    FloatProperty,
-    FloatVectorProperty,
-    StringProperty,
-    EnumProperty,
-    BoolProperty,
-    PointerProperty,
-)
-from bpy.types import (
-    Operator,
-    Panel,
-    AddonPreferences,
-    PropertyGroup,
-)
-
-
-# logging.basicConfig(filename = 'blenderkit.log', level = logging.INFO,
-#                     format = '	%(asctime)s:%(filename)s:%(funcName)s:%(lineno)d:%(message)s')
-
-
-@persistent
-def scene_load(context):
-    ui_props = bpy.context.window_manager.blenderkitUI
-    ui_props.assetbar_on = False
-    ui_props.turn_off = False
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    preferences.login_attempt = False
-
-
-@bpy.app.handlers.persistent
-def check_timers_timer():
-    ''' checks if all timers are registered regularly. Prevents possible bugs from stopping the addon.'''
-    if not bpy.app.background:
-        if not bpy.app.timers.is_registered(search.search_timer):
-            bpy.app.timers.register(search.search_timer)
-        if not bpy.app.timers.is_registered(download.download_timer):
-            bpy.app.timers.register(download.download_timer)
-        if not (bpy.app.timers.is_registered(tasks_queue.queue_worker)):
-            bpy.app.timers.register(tasks_queue.queue_worker)
-        if not bpy.app.timers.is_registered(bg_blender.bg_update):
-            bpy.app.timers.register(bg_blender.bg_update)
-        return 5.0
-
-
-conditions = (
-    ('UNSPECIFIED', 'Unspecified', ""),
-    ('NEW', 'New', 'Shiny new item'),
-    ('USED', 'Used', 'Casually used item'),
-    ('OLD', 'Old', 'Old item'),
-    ('DESOLATE', 'Desolate', 'Desolate item - dusty & rusty'),
-)
-model_styles = (
-    ('REALISTIC', 'Realistic', "Photo realistic model"),
-    ('PAINTERLY', 'Painterly', 'Hand painted with visible strokes'),
-    ('LOWPOLY', 'Lowpoly', "Lowpoly art -don't mix up with polycount!"),
-    ('ANIME', 'Anime', 'Anime style'),
-    ('2D_VECTOR', '2D Vector', '2D vector'),
-    ('3D_GRAPHICS', '3D Graphics', '3D graphics'),
-    ('OTHER', 'Other', 'Other styles'),
-)
-search_model_styles = (
-    ('REALISTIC', 'Realistic', "Photo realistic model"),
-    ('PAINTERLY', 'Painterly', 'Hand painted with visible strokes'),
-    ('LOWPOLY', 'Lowpoly', "Lowpoly art -don't mix up with polycount!"),
-    ('ANIME', 'Anime', 'Anime style'),
-    ('2D_VECTOR', '2D Vector', '2D vector'),
-    ('3D_GRAPHICS', '3D Graphics', '3D graphics'),
-    ('OTHER', 'Other', 'Other Style'),
-    ('ANY', 'Any', 'Any Style'),
-)
-material_styles = (
-    ('REALISTIC', 'Realistic', "Photo realistic model"),
-    ('NPR', 'Non photorealistic', 'Hand painted with visible strokes'),
-    ('OTHER', 'Other', 'Other style'),
-)
-search_material_styles = (
-    ('REALISTIC', 'Realistic', "Photo realistic model"),
-    ('NPR', 'Non photorealistic', 'Hand painted with visible strokes'),
-    ('ANY', 'Any', 'Any'),
-)
-engines = (
-    ('CYCLES', 'Cycles', 'Blender Cycles'),
-    ('EEVEE', 'Eevee', 'Blender eevee renderer'),
-    ('OCTANE', 'Octane', 'Octane render enginge'),
-    ('ARNOLD', 'Arnold', 'Arnold render engine'),
-    ('V-RAY', 'V-Ray', 'V-Ray renderer'),
-    ('UNREAL', 'Unreal', 'Unreal engine'),
-    ('UNITY', 'Unity', 'Unity engine'),
-    ('GODOT', 'Godot', 'Godot engine'),
-    ('3D-PRINT', '3D printer', 'object can be 3D printed'),
-    ('OTHER', 'Other', 'any other engine'),
-    ('NONE', 'None', 'no more engine block'),
-)
-pbr_types = (
-    ('METALLIC', 'Metallic-Roughness', 'Metallic/Roughness PBR material type'),
-    ('SPECULAR', 'Specular  Glossy', ''),
-)
-
-mesh_poly_types = (
-    ('QUAD', 'quad', ''),
-    ('QUAD_DOMINANT', 'quad_dominant', ''),
-    ('TRI_DOMINANT', 'tri_dominant', ''),
-    ('TRI', 'tri', ''),
-    ('NGON', 'ngon_dominant', ''),
-    ('OTHER', 'other', ''),
-)
-
-
-
-
-
-
-
-def udate_down_up(self, context):
-    """Perform a search if results are empty."""
-    s = context.scene
-    wm = bpy.context.window_manager
-    props = bpy.context.window_manager.blenderkitUI
-    if wm.get('search results') == None and props.down_up == 'SEARCH':
-        search.search()
-
-
-def switch_search_results(self, context):
-    s = bpy.context.scene
-    wm = bpy.context.window_manager
-    props = bpy.context.window_manager.blenderkitUI
-    if props.asset_type == 'MODEL':
-        wm['search results'] = wm.get('bkit model search')
-        wm['search results orig'] = wm.get('bkit model search orig')
-    elif props.asset_type == 'SCENE':
-        wm['search results'] = wm.get('bkit scene search')
-        wm['search results orig'] = wm.get('bkit scene search orig')
-    elif props.asset_type == 'HDR':
-        wm['search results'] = wm.get('bkit hdr search')
-        wm['search results orig'] = wm.get('bkit hdr search orig')
-    elif props.asset_type == 'MATERIAL':
-        wm['search results'] = wm.get('bkit material search')
-        wm['search results orig'] = wm.get('bkit material search orig')
-    elif props.asset_type == 'TEXTURE':
-        wm['search results'] = wm.get('bkit texture search')
-        wm['search results orig'] = wm.get('bkit texture search orig')
-    elif props.asset_type == 'BRUSH':
-        wm['search results'] = wm.get('bkit brush search')
-        wm['search results orig'] = wm.get('bkit brush search orig')
-        if not (context.sculpt_object or context.image_paint_object):
-            reports.add_report(
-                'Switch to paint or sculpt mode to search in BlenderKit brushes.')
-    # if wm['search results'] == None:
-    #     wm['search results'] = []
-    # if wm['search results orig'] == None:
-    #     wm['search results orig'] = {'count': 0, 'results': []}
-
-    search.load_previews()
-    if wm['search results'] == None and props.down_up == 'SEARCH':
-        search.search()
-
-
-def asset_type_callback(self, context):
-    '''
-    Returns
-    items for Enum property, depending on the down_up property - BlenderKit is either in search or in upload mode.
-
-    '''
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-    if self.down_up == 'SEARCH':
-        items = (
-            ('MODEL', 'Models', 'Find models', 'OBJECT_DATAMODE', 0),
-            ('MATERIAL', 'Materials', 'Find materials', 'MATERIAL', 2),
-            # ('TEXTURE', 'Texture', 'Browse textures', 'TEXTURE', 3),
-            ('SCENE', 'Scenes', 'Find scenes', 'SCENE_DATA', 3),
-            ('HDR', 'HDRs', 'Find HDRs', 'WORLD', 4),
-            ('BRUSH', 'Brushes', 'Find brushes', 'BRUSH_DATA', 5)
-        )
-    else:
-        items = (
-            ('MODEL', 'Model', 'Upload a model', 'OBJECT_DATAMODE', 0),
-            # ('SCENE', 'SCENE', 'Browse scenes', 'SCENE_DATA', 1),
-            ('MATERIAL', 'Material', 'Upload a material', 'MATERIAL', 2),
-            # ('TEXTURE', 'Texture', 'Browse textures', 'TEXTURE', 3),
-            ('SCENE', 'Scene', 'Upload a scene', 'SCENE_DATA', 3),
-            ('HDR', 'HDR', 'Upload a HDR', 'WORLD', 4),
-            ('BRUSH', 'Brush', 'Upload a brush', 'BRUSH_DATA', 5)
-        )
-
-    return items
-
-
-def run_drag_drop_update(self, context):
-    if self.drag_init_button:
-        ui_props = bpy.context.window_manager.blenderkitUI
-        # ctx = utils.get_fake_context(bpy.context)
-
-        bpy.ops.view3d.close_popup_button('INVOKE_DEFAULT')
-        bpy.ops.view3d.asset_drag_drop('INVOKE_DEFAULT', asset_search_index=ui_props.active_index + ui_props.scroll_offset)
-
-        self.drag_init_button = False
-
-
-class BlenderKitUIProps(PropertyGroup):
-
-    down_up: EnumProperty(
-        name="Download vs Upload",
-        items=(
-            ('SEARCH', 'Search', 'Activate searching', 'VIEWZOOM', 0),
-            ('UPLOAD', 'Upload', 'Activate uploading', 'COPYDOWN', 1),
-            # ('RATING', 'Rating', 'Activate rating', 'SOLO_ON', 2)
-        ),
-        description="BlenderKit",
-        default="SEARCH",
-        update=udate_down_up
-    )
-    asset_type: EnumProperty(
-        name=" ",
-        items=asset_type_callback,
-        description="",
-        default=None,
-        update=switch_search_results
-    )
-
-    asset_type_fold:  BoolProperty(name="Expand asset types", default=False)
-    # these aren't actually used ( by now, seems to better use globals in UI module:
-    draw_tooltip: BoolProperty(name="Draw Tooltip", default=False)
-    addon_update: BoolProperty(name="Should Update Addon", default=False)
-    tooltip: StringProperty(
-        name="Tooltip",
-        description="asset preview info",
-        default="")
-
-    ui_scale = 1
-
-    thumb_size_def = 96
-    margin_def = 0
-
-    thumb_size: IntProperty(name="Thumbnail Size", default=thumb_size_def, min=-1, max=256)
-
-    margin: IntProperty(name="Margin", default=margin_def, min=-1, max=256)
-    highlight_margin: IntProperty(name="Highlight Margin", default=int(margin_def / 2), min=-10, max=256)
-
-    bar_height: IntProperty(name="Bar Height", default=thumb_size_def + 2 * margin_def, min=-1, max=2048)
-    bar_x_offset: IntProperty(name="Bar X Offset", default=40, min=0, max=5000)
-    bar_y_offset: IntProperty(name="Bar Y Offset", default=80, min=0, max=5000)
-
-    bar_x: IntProperty(name="Bar X", default=100, min=0, max=5000)
-    bar_y: IntProperty(name="Bar Y", default=100, min=50, max=5000)
-    bar_end: IntProperty(name="Bar End", default=100, min=0, max=5000)
-    bar_width: IntProperty(name="Bar Width", default=100, min=0, max=5000)
-
-    wcount: IntProperty(name="Width Count", default=10, min=0, max=5000)
-    hcount: IntProperty(name="Rows", default=5, min=0, max=5000)
-
-    reports_y: IntProperty(name="Reports Y", default=5, min=0, max=5000)
-    reports_x: IntProperty(name="Reports X", default=5, min=0, max=5000)
-
-    assetbar_on: BoolProperty(name="Assetbar On", default=False)
-    turn_off: BoolProperty(name="Turn Off", default=False)
-
-    mouse_x: IntProperty(name="Mouse X", default=0)
-    mouse_y: IntProperty(name="Mouse Y", default=0)
-
-    active_index: IntProperty(name="Active Index", default=-3)
-    scroll_offset: IntProperty(name="Scroll Offset", default=0)
-    drawoffset: IntProperty(name="Draw Offset", default=0)
-
-    dragging: BoolProperty(name="Dragging", default=False)
-    drag_init: BoolProperty(name="Drag Initialisation", default=False)
-    drag_init_button: BoolProperty(name="Drag Initialisation from button",
-                                   default=False,
-                                   description="Click or drag into scene for download",
-                                   update = run_drag_drop_update)
-    drag_length: IntProperty(name="Drag length", default=0)
-    draw_drag_image: BoolProperty(name="Draw Drag Image", default=False)
-    draw_snapped_bounds: BoolProperty(name="Draw Snapped Bounds", default=False)
-
-    snapped_location: FloatVectorProperty(name="Snapped Location", default=(0, 0, 0))
-    snapped_bbox_min: FloatVectorProperty(name="Snapped Bbox Min", default=(0, 0, 0))
-    snapped_bbox_max: FloatVectorProperty(name="Snapped Bbox Max", default=(0, 0, 0))
-    snapped_normal: FloatVectorProperty(name="Snapped Normal", default=(0, 0, 0))
-
-    snapped_rotation: FloatVectorProperty(name="Snapped Rotation", default=(0, 0, 0), subtype='QUATERNION')
-
-    has_hit: BoolProperty(name="has_hit", default=False)
-    thumbnail_image = StringProperty(
-        name="Thumbnail Image",
-        description="",
-        default=paths.get_addon_thumbnail_path('thumbnail_notready.jpg'))
-
-    #### rating UI props
-    rating_ui_scale = ui_scale
-
-    rating_button_on: BoolProperty(name="Rating Button On", default=True)
-    rating_menu_on: BoolProperty(name="Rating Menu On", default=False)
-    rating_on: BoolProperty(name="Rating on", default=True)
-
-    rating_button_width: IntProperty(name="Rating Button Width", default=50 * ui_scale)
-    rating_button_height: IntProperty(name="Rating Button Height", default=50 * ui_scale)
-
-    rating_x: IntProperty(name="Rating UI X", default=10)
-    rating_y: IntProperty(name="Rating UI Y", default=10)
-
-    rating_ui_width: IntProperty(name="Rating UI Width", default=rating_ui_scale * 600)
-    rating_ui_height: IntProperty(name="Rating UI Heightt", default=rating_ui_scale * 256)
-
-    quality_stars_x: IntProperty(name="Rating UI Stars X", default=rating_ui_scale * 90)
-    quality_stars_y: IntProperty(name="Rating UI Stars Y", default=rating_ui_scale * 190)
-
-    star_size: IntProperty(name="Star Size", default=rating_ui_scale * 50)
-
-    workhours_bar_slider_size: IntProperty(name="Workhours Bar Slider Size", default=rating_ui_scale * 30)
-
-    workhours_bar_x: IntProperty(name="Workhours Bar X", default=rating_ui_scale * (100 - 15))
-    workhours_bar_y: IntProperty(name="Workhours Bar Y", default=rating_ui_scale * (45 - 15))
-
-    workhours_bar_x_max: IntProperty(name="Workhours Bar X Max", default=rating_ui_scale * (480 - 15))
-
-    dragging_rating: BoolProperty(name="Dragging Rating", default=False)
-    dragging_rating_quality: BoolProperty(name="Dragging Rating Quality", default=False)
-    dragging_rating_work_hours: BoolProperty(name="Dragging Rating Work Hours", default=False)
-    last_rating_time: FloatProperty(name="Last Rating Time", default=0.0)
-
-    hdr_upload_image: PointerProperty(name='Upload HDR',
-                                      type=bpy.types.Image,
-                                      description='Pick an image to upload')
-
-    # StringProperty(
-    # name="Upload HDR",
-    # description="Active HDR image to upload",
-    # default="")
-
-
-def search_procedural_update(self, context):
-    if self.search_procedural in ('PROCEDURAL', 'BOTH'):
-        self.search_texture_resolution = False
-    search.search_update(self, context)
-
-
-class BlenderKitCommonSearchProps(object):
-    # STATES
-    is_searching: BoolProperty(name="Searching", description="search is currently running (internal)", default=False)
-    is_downloading: BoolProperty(name="Downloading", description="download is currently running (internal)",
-                                 default=False)
-    search_done: BoolProperty(name="Search Completed", description="at least one search did run (internal)",
-                              default=False)
-    own_only: BoolProperty(name="My Assets Only", description="Search only for your assets",
-                           default=False, update=search.search_update)
-    use_filters: BoolProperty(name="Filters are on", description="some filters are used",
-                                  default=False)
-
-    search_error: BoolProperty(name="Search Error", description="last search had an error", default=False)
-    report: StringProperty(
-        name="Report",
-        description="errors and messages",
-        default="")
-
-    # TEXTURE RESOLUTION
-    search_texture_resolution: BoolProperty(name="Texture Resolution",
-                                            description="Limit texture resolutions",
-                                            default=False,
-                                            update=search.search_update,
-                                            )
-    search_texture_resolution_min: IntProperty(name="Min Texture Resolution",
-                                               description="Minimum texture resolution",
-                                               default=256,
-                                               min=0,
-                                               max=32768,
-                                               update=search.search_update,
-                                               )
-
-    search_texture_resolution_max: IntProperty(name="Max Texture Resolution",
-                                               description="Maximum texture resolution",
-                                               default=4096,
-                                               min=0,
-                                               max=32768,
-                                               update=search.search_update,
-                                               )
-
-    # file_size
-    search_file_size: BoolProperty(name="File Size",
-                                   description="Limit file sizes",
-                                   default=False,
-                                   update=search.search_update,
-                                   )
-    search_file_size_min: IntProperty(name="Min File Size",
-                                      description="Minimum file size",
-                                      default=0,
-                                      min=0,
-                                      max=2000,
-                                      update=search.search_update,
-                                      )
-
-    search_file_size_max: IntProperty(name="Max File Size",
-                                      description="Maximum file size",
-                                      default=500,
-                                      min=0,
-                                      max=2000,
-                                      update=search.search_update,
-                                      )
-
-    search_procedural: EnumProperty(
-        items=(
-            ('BOTH', 'Both', ''),
-            ('PROCEDURAL', 'Procedural', ''),
-            ('TEXTURE_BASED', 'Texture based', ''),
-
-        ),
-        default='BOTH',
-        description='Search only procedural/texture based assets',
-        update=search_procedural_update
-    )
-
-    search_verification_status: EnumProperty(
-        name="Verification status",
-        description="Search by verification status",
-        items=
-        (
-            ('ALL', 'All', 'All'),
-            ('UPLOADING', 'Uploading', 'Uploading'),
-            ('UPLOADED', 'Uploaded', 'Uploaded'),
-            ('READY', 'Ready for V.', 'Ready for validation (deprecated since 2.8)'),
-            ('VALIDATED', 'Validated', 'Validated'),
-            ('ON_HOLD', 'On Hold', 'On Hold'),
-            ('REJECTED', 'Rejected', 'Rejected'),
-            ('DELETED', 'Deleted', 'Deleted'),
-        ),
-        default='ALL',
-        update=search.search_update,
-    )
-
-    # resolution download/import settings
-    resolution: EnumProperty(
-        name="Max resolution",
-        description="Cap texture sizes in the file to this resolution",
-        items=
-        (
-            # ('256', '256x256', ''),
-            ('512', '512x512', ''),
-            ('1024', '1024x1024', ''),
-            ('2048', '2048x2048', ''),
-            ('4096', '4096x4096', ''),
-            ('8192', '8192x8192', ''),
-            ('ORIGINAL', 'ORIGINAL FILE', ''),
-
-        ),
-        default='1024',
-    )
-    free_only: BoolProperty(name="Free first", description="Show free models first",
-                            default=False, update=search.search_update)
-
-    unpack_files: BoolProperty(name="Unpack Files",
-                               description="Unpack files after download",
-                               default=True
-                               )
-
-    unrated_only: BoolProperty(name="Unrated only", description="Show only unrated models",
-                               default=False, update=search.search_update)
-    quality_limit: IntProperty(name="Quality limit",
-                               description = 'Only show assets with a higher quality',
-                               default=0, min=0, max=10, update=search.search_update)
-
-
-
-def name_update(self, context):
-    ''' checks for name change, because it decides if whole asset has to be re-uploaded. Name is stored in the blend file
-    and that's the reason.'''
-    utils.name_update(self)
-
-
-def update_free(self, context):
-    if self.is_free == 'FULL':
-        self.is_free = 'FREE'
-        ui_panels.ui_message(title="All BlenderKit materials are free",
-                             message="Any material uploaded to BlenderKit is free." \
-                                     " However, it can still earn money for the author," \
-                                     " based on our fair share system. " \
-                                     "Part of subscription is sent to artists based on usage by paying users.\n")
-
-# common_upload_props = [
-#     {
-#         'identifier':'id',
-#         'name':"Asset Version Id",
-#         'type':'StringProperty',
-#         'description':'Unique name of the asset version(hidden)',
-#         'default':''
-# }
-# {
-#         'identifier':'id',
-#         'name':"Asset Version Id",
-#         'type':'StringProperty',
-#         'description':'Unique name of the asset version(hidden)',
-#         'default':''
-# }
-# ]
-
-
-
-
-class BlenderKitCommonUploadProps(object):
-    # for p in common_upload_props:
-    #     exec(f"{p['identifier']}: {p['type']}(name='{p['name']}',description='{p['description']}',default='{p['default']}')")
-
-    id: StringProperty(
-        name="Asset Version Id",
-        description="Unique name of the asset version(hidden)",
-        default="")
-    asset_base_id: StringProperty(
-        name="Asset Base Id",
-        description="Unique name of the asset (hidden)",
-        default="")
-    name: StringProperty(
-        name="Name",
-        description="Main name of the asset",
-        default="",
-        update=name_update
-    )
-    # this is to store name for purpose of checking if name has changed.
-    name_old: StringProperty(
-        name="Old Name",
-        description="Old name of the asset",
-        default="",
-    )
-
-    description: StringProperty(
-        name="Description",
-        description="Description of the asset",
-        default="")
-    tags: StringProperty(
-        name="Tags",
-        description="List of tags, separated by commas (optional)",
-        default="",
-        update=utils.update_tags
-    )
-
-    name_changed: BoolProperty(name="Name Changed",
-                               description="Name has changed, the asset has to be re-uploaded with all data",
-                               default=False)
-
-    pbr: BoolProperty(name="Pure PBR Compatible",
-                      description="Is compatible with PBR standard. This means only image textures are used with no"
-                                  " procedurals and no color correction, only principled shader is used",
-                      default=False)
-
-    pbr_type: EnumProperty(
-        name="PBR Type",
-        items=pbr_types,
-        description="PBR type",
-        default="METALLIC",
-    )
-    license: EnumProperty(
-        items=upload.licenses,
-        default='royalty_free',
-        description='License. Please read our help for choosing the right licenses',
-    )
-
-    is_private: EnumProperty(
-        name="Thumbnail Style",
-        items=(
-            ('PRIVATE', 'Private', ""),
-            ('PUBLIC', 'Public', "")
-        ),
-        description="Public assets go into the validation process. \n"
-                    "Validated assets are visible to all users.\n"
-                    "Private assets are limited by your plan quota\n"
-                    "State",
-        default="PUBLIC",
-    )
-
-    is_procedural: BoolProperty(name="Procedural",
-                                description="Asset is procedural - has no texture",
-                                default=True
-                                )
-    node_count: IntProperty(name="Node count", description="Total nodes in the asset", default=0)
-    texture_count: IntProperty(name="Texture count", description="Total texture count in asset", default=0)
-    total_megapixels: IntProperty(name="Megapixels", description="Total megapixels of texture", default=0)
-
-    # is_private: BoolProperty(name="Asset is Private",
-    #                       description="If not marked private, your asset will go into the validation process automatically\n"
-    #                                   "Private assets are limited by quota",
-    #                       default=False)
-
-    is_free: EnumProperty(
-        name="Thumbnail Style",
-        items=(
-            ('FULL', 'Full', "Your asset will be only available for subscribers"),
-            ('FREE', 'Free', "You consent you want to release this asset as free for everyone")
-        ),
-        description="Assets can be in Free or in Full plan. Also free assets generate credits",
-        default="FULL",
-    )
-
-    uploading: BoolProperty(name="Uploading",
-                            description="True when background process is running",
-                            default=False,
-                            update=autothumb.update_upload_material_preview)
-    upload_state: StringProperty(
-        name="State Of Upload",
-        description="bg process reports for upload",
-        default='')
-
-    has_thumbnail: BoolProperty(name="Has Thumbnail", description="True when thumbnail was checked and loaded",
-                                default=False)
-
-    thumbnail_generating_state: StringProperty(
-        name="Thumbnail Generating State",
-        description="bg process reports for thumbnail generation",
-        default='Please add thumbnail(jpg or png, at least 512x512)')
-
-    report: StringProperty(
-        name="Missing Upload Properties",
-        description="used to write down what's missing",
-        default='')
-
-    category: EnumProperty(
-        name="Category",
-        description="main category to put into",
-        items=categories.get_category_enums,
-        update=categories.update_category_enums
-    )
-    subcategory: EnumProperty(
-        name="Subcategory",
-        description="Subcategory to put into",
-        items=categories.get_subcategory_enums,
-        update=categories.update_subcategory_enums
-    )
-    subcategory1: EnumProperty(
-        name="Subcategory lvl2",
-        description="Subcategory to put into",
-        items=categories.get_subcategory1_enums
-    )
-
-
-class BlenderKitRatingProps(PropertyGroup):
-    rating_quality: IntProperty(name="Quality",
-                                description="quality of the material",
-                                default=0,
-                                min=-1, max=10,
-                                update=ratings_utils.update_ratings_quality)
-
-    # the following enum is only to ease interaction - enums support 'drag over' and enable to draw the stars easily.
-    rating_quality_ui: EnumProperty(name='rating_quality_ui',
-                                    items=ratings_utils.stars_enum_callback,
-                                    description='Rating stars 0 - 10',
-                                    default=None,
-                                    update=ratings_utils.update_quality_ui,
-                                    )
-
-    rating_work_hours: FloatProperty(name="Work Hours",
-                                     description="How many hours did this work take?",
-                                     default=0.00,
-                                     min=0.0, max=150, update=ratings_utils.update_ratings_work_hours
-                                     )
-
-    # rating_complexity: IntProperty(name="Complexity",
-    #                                description="Complexity is a number estimating how much work was spent on the asset.aaa",
-    #                                default=0, min=0, max=10)
-    # rating_virtual_price: FloatProperty(name="Virtual Price",
-    #                                     description="How much would you pay for this object if buing it?",
-    #                                     default=0, min=0, max=10000)
-    rating_problems: StringProperty(
-        name="Problems",
-        description="Problems found/ why did you take points down - this will be available for the author"
-                    " As short as possible",
-        default="",
-    )
-    rating_compliments: StringProperty(
-        name="Compliments",
-        description="Comliments - let the author know you like his work! "
-                    " As short as possible",
-        default="",
-    )
-
-
-class BlenderKitMaterialSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
-    search_keywords: StringProperty(
-        name="Search",
-        description="Search for these keywords",
-        default="",
-        update=search.search_update
-    )
-    search_style: EnumProperty(
-        name="Style",
-        items=search_material_styles,
-        description="Style of material",
-        default="ANY",
-        update=search.search_update,
-    )
-    search_style_other: StringProperty(
-        name="Style Other",
-        description="Style not in the list",
-        default="",
-        update=search.search_update,
-    )
-    search_engine: EnumProperty(
-        name='Engine',
-        items=engines,
-        default='NONE',
-        description='Output engine',
-        update=search.search_update,
-    )
-    search_engine_other: StringProperty(
-        name="Engine",
-        description="engine not specified by addon",
-        default="",
-        update=search.search_update,
-    )
-    append_method: EnumProperty(
-        name="Import Method",
-        items=(
-            ('LINK', 'Link', "Link Material - will be in external file and can't be directly edited"),
-            ('APPEND', 'Append', 'Append if you need to edit the material'),
-        ),
-        description="Appended materials are editable in your scene. Linked assets are saved in original files, "
-                    "aren't editable directly, but also don't increase your file size",
-        default="APPEND"
-    )
-    automap: BoolProperty(name="Auto-Map",
-                          description="reset object texture space and also add automatically a cube mapped UV "
-                                      "to the object. \n this allows most materials to apply instantly to any mesh",
-                          default=True)
-
-
-class BlenderKitMaterialUploadProps(PropertyGroup, BlenderKitCommonUploadProps):
-    style: EnumProperty(
-        name="Style",
-        items=material_styles,
-        description="Style of material",
-        default="REALISTIC",
-    )
-    style_other: StringProperty(
-        name="Style Other",
-        description="Style not in the list",
-        default="",
-    )
-    engine: EnumProperty(
-        name='Engine',
-        items=engines,
-        default='CYCLES',
-        description='Output engine',
-    )
-    engine_other: StringProperty(
-        name="Engine Other",
-        description="engine not specified by addon",
-        default="",
-    )
-
-    shaders: StringProperty(
-        name="Shaders Used",
-        description="shaders used in asset, autofilled",
-        default="",
-    )
-
-    is_free: EnumProperty(
-        name="Thumbnail Style",
-        items=(
-            ('FULL', 'Full', "Your asset will be only available for subscribers."),
-            ('FREE', 'Free', "You consent you want to release this asset as free for everyone.")
-        ),
-        description="Assets can be in Free or in Full plan. Also free assets generate credits. \n"
-                    "All BlenderKit materials are free",
-        default="FREE",
-        update=update_free
-    )
-
-
-
-    uv: BoolProperty(name="Needs UV", description="needs an UV set", default=False)
-    # printable_3d : BoolProperty( name = "3d printable", description = "can be 3d printed", default = False)
-    animated: BoolProperty(name="Animated", description="is animated", default=False)
-    texture_resolution_min: IntProperty(name="Texture Resolution Min", description="texture resolution minimum",
-                                        default=0)
-    texture_resolution_max: IntProperty(name="Texture Resolution Max", description="texture resolution maximum",
-                                        default=0)
-
-    texture_size_meters: FloatProperty(name="Texture Size in Meters", description="Size of texture in real world units",
-                                       default=1.0, min=0)
-
-    thumbnail_scale: FloatProperty(name="Thumbnail Object Size",
-                                   description="Size of material preview object in meters."
-                                               "Change for materials that look better at sizes different than 1m",
-                                   default=1, min=0.00001, max=10)
-    thumbnail_background: BoolProperty(name="Thumbnail Background (for Glass only)",
-                                       description="For refractive materials, you might need a background.\n"
-                                                   "Don't use for other types of materials.\n"
-                                                   "Transparent background is preferred",
-                                       default=False)
-    thumbnail_background_lightness: FloatProperty(name="Thumbnail Background Lightness",
-                                                  description="Set to make your material stand out with enough contrast",
-                                                  default=.9,
-                                                  min=0.00001, max=1)
-    thumbnail_samples: IntProperty(name="Cycles Samples",
-                                   description="Cycles samples", default=100,
-                                   min=5, max=5000)
-    thumbnail_denoising: BoolProperty(name="Use Denoising",
-                                      description="Use denoising", default=True)
-    adaptive_subdivision: BoolProperty(name="Adaptive Subdivide",
-                                       description="Use adaptive displacement subdivision", default=False)
-
-    thumbnail_resolution: EnumProperty(
-        name="Resolution",
-        items=autothumb.thumbnail_resolutions,
-        description="Thumbnail resolution",
-        default="1024",
-    )
-
-    thumbnail_generator_type: EnumProperty(
-        name="Thumbnail Style",
-        items=(
-            ('BALL', 'Ball', ""),
-            ('BALL_COMPLEX', 'Ball complex', 'Complex ball to highlight edgewear or material thickness'),
-            ('FLUID', 'Fluid', 'Fluid'),
-            ('CLOTH', 'Cloth', 'Cloth'),
-            ('HAIR', 'Hair', 'Hair  ')
-        ),
-        description="Style of asset",
-        default="BALL",
-    )
-
-    thumbnail: StringProperty(
-        name="Thumbnail",
-        description="Thumbnail path - 512x512 .jpg image, rendered with cycles.\n"
-                    "Only standard BlenderKit previews will be accepted.\n"
-                    "Only exception are special effects like fire or similar",
-        subtype='FILE_PATH',
-        default="",
-        update=autothumb.update_upload_material_preview)
-
-    is_generating_thumbnail: BoolProperty(name="Generating Thumbnail",
-                                          description="True when background process is running", default=False,
-                                          update=autothumb.update_upload_material_preview)
-
-
-class BlenderKitTextureUploadProps(PropertyGroup, BlenderKitCommonUploadProps):
-    style: EnumProperty(
-        name="Style",
-        items=material_styles,
-        description="Style of texture",
-        default="REALISTIC",
-    )
-    style_other: StringProperty(
-        name="Style Other",
-        description="Style not in the list",
-        default="",
-    )
-
-    pbr: BoolProperty(name="PBR Compatible", description="Is compatible with PBR standard", default=False)
-
-    # printable_3d : BoolProperty( name = "3d printable", description = "can be 3d printed", default = False)
-    animated: BoolProperty(name="Animated", description="is animated", default=False)
-    resolution: IntProperty(name="Texture Resolution", description="texture resolution", default=0)
-
-
-class BlenderKitBrushSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
-    search_keywords: StringProperty(
-        name="Search",
-        description="Search for these keywords",
-        default="",
-        update=search.search_update
-    )
-
-
-class BlenderKitHDRUploadProps(PropertyGroup, BlenderKitCommonUploadProps):
-    texture_resolution_max: IntProperty(name="Texture Resolution Max", description="texture resolution maximum",
-                                        default=0)
-    evs_cap: IntProperty(name="EV cap", description="EVs dynamic range",
-                                        default=0)
-    true_hdr: BoolProperty(name="Real HDR", description="Image has High dynamic range.",default=False)
-
-
-class BlenderKitBrushUploadProps(PropertyGroup, BlenderKitCommonUploadProps):
-    mode: EnumProperty(
-        name="Mode",
-        items=(
-            ("IMAGE", "Texture paint", "Texture brush"),
-            ("SCULPT", "Sculpt", "Sculpt brush"),
-            ("VERTEX", "Vertex paint", "Vertex paint brush"),
-            ("WEIGHT", "Weight paint", "Weight paint brush"),
-        ),
-        description="Mode where the brush works",
-        default="SCULPT",
-    )
-
-
-# upload properties
-class BlenderKitModelUploadProps(PropertyGroup, BlenderKitCommonUploadProps):
-    style: EnumProperty(
-        name="Style",
-        items=model_styles,
-        description="Style of asset",
-        default="REALISTIC",
-    )
-    style_other: StringProperty(
-        name="Style Other",
-        description="Style not in the list",
-        default="",
-    )
-    engine: EnumProperty(
-        name='Engine',
-        items=engines,
-        default='CYCLES',
-        description='Output engine',
-    )
-
-    production_level: EnumProperty(
-        name='Production Level',
-        items=(
-            ('FINISHED', 'Finished', 'Render or animation ready asset'),
-            ('TEMPLATE', 'Template', 'Asset intended to help in creation of something else'),
-        ),
-        default='FINISHED',
-        description='Production state of the asset. \n'
-                    'Templates should be tools to finish certain tasks, like a thumbnailer scene, \n '
-                    'finished mesh topology as start for modelling or others',
-    )
-
-    engine_other: StringProperty(
-        name="Engine",
-        description="engine not specified by addon",
-        default="",
-    )
-
-    engine1: EnumProperty(
-        name='2nd Engine',
-        items=engines,
-        default='NONE',
-        description='Output engine',
-    )
-    engine2: EnumProperty(
-        name='3rd Engine',
-        items=engines,
-        default='NONE',
-        description='Output engine',
-    )
-    engine3: EnumProperty(
-        name='4th Engine',
-        items=engines,
-        default='NONE',
-        description='Output engine',
-    )
-
-    manufacturer: StringProperty(
-        name="Manufacturer",
-        description="Manufacturer, company making a design piece or product. Not you",
-        default="",
-    )
-
-    designer: StringProperty(
-        name="Designer",
-        description="Author of the original design piece depicted. Usually not you",
-        default="",
-    )
-
-    design_collection: StringProperty(
-        name="Design Collection",
-        description="Fill if this piece is part of a real world design collection",
-        default="",
-    )
-
-    design_variant: StringProperty(
-        name="Variant",
-        description="Colour or material variant of the product",
-        default="",
-    )
-
-    thumbnail: StringProperty(
-        name="Thumbnail",
-        description="Thumbnail path - 512x512 .jpg\n"
-                    "Rendered with cycles",
-
-        subtype='FILE_PATH',
-        default="",
-        update=autothumb.update_upload_model_preview)
-
-    thumbnail_background_lightness: FloatProperty(name="Thumbnail Background Lightness",
-                                                  description="set to make your material stand out", default=1.0,
-                                                  min=0.01, max=10)
-
-    thumbnail_angle: EnumProperty(
-        name='Thumbnail Angle',
-        items=autothumb.thumbnail_angles,
-        default='DEFAULT',
-        description='thumbnailer angle',
-    )
-
-    thumbnail_snap_to: EnumProperty(
-        name='Model Snaps To:',
-        items=autothumb.thumbnail_snap,
-        default='GROUND',
-        description='typical placing of the interior. Leave on ground for most objects that respect gravity :)',
-    )
-
-    thumbnail_resolution: EnumProperty(
-        name="Resolution",
-        items=autothumb.thumbnail_resolutions,
-        description="Thumbnail resolution",
-        default="1024",
-    )
-
-    thumbnail_samples: IntProperty(name="Cycles Samples",
-                                   description="cycles samples setting", default=100,
-                                   min=5, max=5000)
-    thumbnail_denoising: BoolProperty(name="Use Denoising",
-                                      description="Use denoising", default=True)
-
-    use_design_year: BoolProperty(name="Use Design Year",
-                                  description="When this thing came into world for the first time\n"
-                                              " e.g. for dinosaur, you set -240 million years ;) ",
-                                  default=False)
-    design_year: IntProperty(name="Design Year", description="when was this item designed", default=1960)
-    # use_age : BoolProperty( name = "use item age", description = "use item age", default = False)
-    condition: EnumProperty(
-        items=conditions,
-        default='UNSPECIFIED',
-        description='age of the object',
-    )
-
-    adult: BoolProperty(name="Adult Content", description="adult content", default=False)
-
-    work_hours: FloatProperty(name="Work Hours", description="How long did it take you to finish the asset?",
-                              default=0.0, min=0.0, max=8760)
-
-    modifiers: StringProperty(
-        name="Modifiers Used",
-        description="if you need specific modifiers, autofilled",
-        default="",
-    )
-
-    materials: StringProperty(
-        name="Material Names",
-        description="names of materials in the file, autofilled",
-        default="",
-    )
-    shaders: StringProperty(
-        name="Shaders Used",
-        description="shaders used in asset, autofilled",
-        default="",
-    )
-
-    dimensions: FloatVectorProperty(
-        name="Dimensions",
-        description="dimensions of the whole asset hierarchy",
-        default=(0, 0, 0),
-    )
-    bbox_min: FloatVectorProperty(
-        name="Bbox Min",
-        description="dimensions of the whole asset hierarchy",
-        default=(-.25, -.25, 0),
-    )
-    bbox_max: FloatVectorProperty(
-        name="Bbox Max",
-        description="dimensions of the whole asset hierarchy",
-        default=(.25, .25, .5),
-    )
-
-    texture_resolution_min: IntProperty(name="Texture Resolution Min",
-                                        description="texture resolution min, autofilled", default=0)
-    texture_resolution_max: IntProperty(name="Texture Resolution Max",
-                                        description="texture resolution max, autofilled", default=0)
-
-    pbr: BoolProperty(name="PBR Compatible", description="Is compatible with PBR standard", default=False)
-
-    uv: BoolProperty(name="Has UV", description="has an UV set", default=False)
-    # printable_3d : BoolProperty( name = "3d printable", description = "can be 3d printed", default = False)
-    animated: BoolProperty(name="Animated", description="is animated", default=False)
-    face_count: IntProperty(name="Face count", description="face count, autofilled", default=0)
-    face_count_render: IntProperty(name="Render Face Count", description="render face count, autofilled", default=0)
-
-    object_count: IntProperty(name="Number of Objects", description="how many objects are in the asset, autofilled",
-                              default=0)
-    mesh_poly_type: EnumProperty(
-        name='Dominant Poly Type',
-        items=mesh_poly_types,
-        default='OTHER',
-        description='',
-    )
-
-    manifold: BoolProperty(name="Manifold", description="asset is manifold, autofilled", default=False)
-
-    rig: BoolProperty(name="Rig", description="asset is rigged, autofilled", default=False)
-    simulation: BoolProperty(name="Simulation", description="asset uses simulation, autofilled", default=False)
-    '''
-    filepath : StringProperty(
-            name="Filepath",
-            description="file path",
-            default="",
-            )
-    '''
-
-    # THUMBNAIL STATES
-    is_generating_thumbnail: BoolProperty(name="Generating Thumbnail",
-                                          description="True when background process is running", default=False,
-                                          update=autothumb.update_upload_model_preview)
-
-    has_autotags: BoolProperty(name="Has Autotagging Done", description="True when autotagging done", default=False)
-
-
-class BlenderKitSceneUploadProps(PropertyGroup, BlenderKitCommonUploadProps):
-    style: EnumProperty(
-        name="Style",
-        items=model_styles,
-        description="Style of asset",
-        default="REALISTIC",
-    )
-    style_other: StringProperty(
-        name="Style Other",
-        description="Style not in the list",
-        default="",
-    )
-    engine: EnumProperty(
-        name='Engine',
-        items=engines,
-        default='CYCLES',
-        description='Output engine',
-    )
-
-    production_level: EnumProperty(
-        name='Production Level',
-        items=(
-            ('FINISHED', 'Finished', 'Render or animation ready asset'),
-            ('TEMPLATE', 'Template', 'Asset intended to help in creation of something else'),
-        ),
-        default='FINISHED',
-        description='Production state of the asset, \n also template should be actually finished, \n'
-                    'just the nature of it can be a template, like a thumbnailer scene, \n '
-                    'finished mesh topology as start for modelling or similar',
-    )
-
-    engine_other: StringProperty(
-        name="Engine",
-        description="engine not specified by addon",
-        default="",
-    )
-
-    engine1: EnumProperty(
-        name='2nd Engine',
-        items=engines,
-        default='NONE',
-        description='Output engine',
-    )
-    engine2: EnumProperty(
-        name='3rd Engine',
-        items=engines,
-        default='NONE',
-        description='Output engine',
-    )
-    engine3: EnumProperty(
-        name='4th Engine',
-        items=engines,
-        default='NONE',
-        description='Output engine',
-    )
-
-    thumbnail: StringProperty(
-        name="Thumbnail",
-        description="Thumbnail path - 512x512 .jpg\n"
-                    "Rendered with cycles",
-        subtype='FILE_PATH',
-        default="",
-        update=autothumb.update_upload_scene_preview)
-
-    use_design_year: BoolProperty(name="Use Design Year",
-                                  description="When this thing came into world for the first time\n"
-                                              " e.g. for dinosaur, you set -240 million years ;) ",
-                                  default=False)
-    design_year: IntProperty(name="Design Year", description="when was this item designed", default=1960)
-    # use_age : BoolProperty( name = "use item age", description = "use item age", default = False)
-    condition: EnumProperty(
-        items=conditions,
-        default='UNSPECIFIED',
-        description='age of the object',
-    )
-
-    adult: BoolProperty(name="Adult Content", description="adult content", default=False)
-
-    work_hours: FloatProperty(name="Work Hours", description="How long did it take you to finish the asset?",
-                              default=0.0, min=0.0, max=8760)
-
-    modifiers: StringProperty(
-        name="Modifiers Used",
-        description="if you need specific modifiers, autofilled",
-        default="",
-    )
-
-    materials: StringProperty(
-        name="Material Names",
-        description="names of materials in the file, autofilled",
-        default="",
-    )
-    shaders: StringProperty(
-        name="Shaders Used",
-        description="shaders used in asset, autofilled",
-        default="",
-    )
-
-    dimensions: FloatVectorProperty(
-        name="Dimensions",
-        description="dimensions of the whole asset hierarchy",
-        default=(0, 0, 0),
-    )
-    bbox_min: FloatVectorProperty(
-        name="Dimensions",
-        description="dimensions of the whole asset hierarchy",
-        default=(-.25, -.25, 0),
-    )
-    bbox_max: FloatVectorProperty(
-        name="Dimensions",
-        description="dimensions of the whole asset hierarchy",
-        default=(.25, .25, .5),
-    )
-
-    texture_resolution_min: IntProperty(name="Texture Resolution Min",
-                                        description="texture resolution min, autofilled", default=0)
-    texture_resolution_max: IntProperty(name="Texture Resolution Max",
-                                        description="texture resolution max, autofilled", default=0)
-
-    pbr: BoolProperty(name="PBR Compatible", description="Is compatible with PBR standard", default=False)
-
-    uv: BoolProperty(name="Has UV", description="has an UV set", default=False)
-    # printable_3d : BoolProperty( name = "3d printable", description = "can be 3d printed", default = False)
-    animated: BoolProperty(name="Animated", description="is animated", default=False)
-    face_count: IntProperty(name="Face Count", description="face count, autofilled", default=0)
-    face_count_render: IntProperty(name="Render Face Count", description="render face count, autofilled", default=0)
-
-    object_count: IntProperty(name="Number of Objects", description="how many objects are in the asset, autofilled",
-                              default=0)
-    mesh_poly_type: EnumProperty(
-        name='Dominant Poly Type',
-        items=mesh_poly_types,
-        default='OTHER',
-        description='',
-    )
-
-    rig: BoolProperty(name="Rig", description="asset is rigged, autofilled", default=False)
-    simulation: BoolProperty(name="Simulation", description="asset uses simulation, autofilled", default=False)
-
-    # THUMBNAIL STATES
-    is_generating_thumbnail: BoolProperty(name="Generating Thumbnail",
-                                          description="True when background process is running", default=False,
-                                          update=autothumb.update_upload_model_preview)
-
-    has_autotags: BoolProperty(name="Has Autotagging Done", description="True when autotagging done", default=False)
-
-
-class BlenderKitModelSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
-    search_keywords: StringProperty(
-        name="Search",
-        description="Search for these keywords",
-        default="",
-        update=search.search_update
-    )
-    search_style: EnumProperty(
-        name="Style",
-        items=search_model_styles,
-        description="Keywords defining style (realistic, painted, polygonal, other)",
-        default="ANY",
-        update=search.search_update
-    )
-    search_style_other: StringProperty(
-        name="Style",
-        description="Search style - other",
-        default="",
-        update=search.search_update
-    )
-    search_engine: EnumProperty(
-        items=engines,
-        default='CYCLES',
-        description='Output engine',
-        update=search.search_update
-    )
-    search_engine_other: StringProperty(
-        name="Engine",
-        description="Engine not specified by addon",
-        default="",
-        update=search.search_update
-    )
-
-    # CONDITION
-    search_condition: EnumProperty(
-        items=conditions,
-        default='UNSPECIFIED',
-        description='Condition of the object',
-        update=search.search_update
-    )
-
-    search_adult: BoolProperty(
-        name="Adult Content",
-        description="You're adult and agree with searching adult content",
-        default=False,
-        update=search.search_update
-    )
-
-    # DESIGN YEAR
-    search_design_year: BoolProperty(name="Sesigned in Year",
-                                     description="When the object was approximately designed. \n"
-                                                 "Useful for search of historical or future objects",
-                                     default=False,
-                                     update=search.search_update,
-                                     )
-
-    search_design_year_min: IntProperty(name="Minimum Design Year",
-                                        description="Minimum design year",
-                                        default=1950, min=-100000000, max=1000000000,
-                                        update=search.search_update,
-                                        )
-
-    search_design_year_max: IntProperty(name="Maximum Design Year",
-                                        description="Maximum design year",
-                                        default=2017,
-                                        min=0,
-                                        max=10000000,
-                                        update=search.search_update,
-                                        )
-
-    # POLYCOUNT
-    search_polycount: BoolProperty(name="Use Polycount",
-                                   description="Limit polycount",
-                                   default=False,
-                                   update=search.search_update, )
-
-    search_polycount_min: IntProperty(name="Min Polycount",
-                                      description="Minimum poly count",
-                                      default=0,
-                                      min=0,
-                                      max=100000000,
-                                      update=search.search_update, )
-
-    search_polycount_max: IntProperty(name="Max Polycount",
-                                      description="Maximum poly count",
-                                      default=100000000,
-                                      min=0,
-                                      max=100000000,
-                                      update=search.search_update,
-                                      )
-
-    append_method: EnumProperty(
-        name="Import Method",
-        items=(
-            ('LINK_COLLECTION', 'Link', 'Link Collection'),
-            ('APPEND_OBJECTS', 'Append', 'Append as Objects'),
-        ),
-        description="Appended objects are editable in your scene. Linked assets are saved in original files, "
-                    "aren't editable but also don't increase your file size",
-        default="APPEND_OBJECTS"
-    )
-    append_link: EnumProperty(
-        name="How to Attach",
-        items=(
-            ('LINK', 'Link', ''),
-            ('APPEND', 'Append', ''),
-        ),
-        description="choose if the assets will be linked or appended",
-        default="LINK"
-    )
-    import_as: EnumProperty(
-        name="Import as",
-        items=(
-            ('GROUP', 'group', ''),
-            ('INDIVIDUAL', 'objects', ''),
-
-        ),
-        description="choose if the assets will be linked or appended",
-        default="GROUP"
-    )
-    randomize_rotation: BoolProperty(name='Randomize Rotation',
-                                     description="randomize rotation at placement",
-                                     default=False)
-    randomize_rotation_amount: FloatProperty(name="Randomization Max Angle",
-                                             description="maximum angle for random rotation",
-                                             default=math.pi / 36,
-                                             min=0,
-                                             max=2 * math.pi,
-                                             subtype='ANGLE')
-    offset_rotation_amount: FloatProperty(name="Offset Rotation",
-                                          description="offset rotation, hidden prop",
-                                          default=0,
-                                          min=0,
-                                          max=360,
-                                          subtype='ANGLE')
-    offset_rotation_step: FloatProperty(name="Offset Rotation Step",
-                                        description="offset rotation, hidden prop",
-                                        default=math.pi / 2,
-                                        min=0,
-                                        max=180,
-                                        subtype='ANGLE')
-
-    perpendicular_snap: BoolProperty(name='Perpendicular snap',
-                                     description="Limit snapping that is close to perpendicular angles to be perpendicular",
-                                     default=True)
-
-    perpendicular_snap_threshold: FloatProperty(name="Threshold",
-                                                description="Limit perpendicular snap to be below these values",
-                                                default=.25,
-                                                min=0,
-                                                max=.5,
-                                                )
-
-
-class BlenderKitHDRSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
-    search_keywords: StringProperty(
-        name="Search",
-        description="Search for these keywords",
-        default="",
-        update=search.search_update
-    )
-
-    true_hdr: BoolProperty(
-        name='Real HDRs only',
-        description='Search only for real HDRs, this means images that have a range higher than 0-1 in their pixels.',
-        default=True,
-        update=search.search_update
-    )
-
-
-class BlenderKitSceneSearchProps(PropertyGroup, BlenderKitCommonSearchProps):
-    search_keywords: StringProperty(
-        name="Search",
-        description="Search for these keywords",
-        default="",
-        update=search.search_update
-    )
-    search_style: EnumProperty(
-        name="Style",
-        items=search_model_styles,
-        description="Restrict search for style",
-        default="ANY",
-        update=search.search_update
-    )
-    search_style_other: StringProperty(
-        name="Style",
-        description="Search style - other",
-        default="",
-        update=search.search_update
-    )
-    search_engine: EnumProperty(
-        items=engines,
-        default='CYCLES',
-        description='Output engine',
-        update=search.search_update
-    )
-    search_engine_other: StringProperty(
-        name="Engine",
-        description="Engine not specified by addon",
-        default="",
-        update=search.search_update
-    )
-    append_link: EnumProperty(
-        name="Append or link",
-        items=(
-            ('LINK', 'Link', ''),
-            ('APPEND', 'Append', ''),
-        ),
-        description="choose if the scene will be linked or appended",
-        default="APPEND"
-    )
-    switch_after_append: BoolProperty(
-        name='Switch to scene after download',
-        default=True
-    )
-
-
-def fix_subdir(self, context):
-    '''Fixes project subdicrectory settings if people input invalid path.'''
-
-    # pp = pathlib.PurePath(self.project_subdir)
-    pp = self.project_subdir[:]
-    pp = pp.replace('\\', '')
-    pp = pp.replace('/', '')
-    pp = pp.replace(':', '')
-    pp = '//' + pp
-    if self.project_subdir != pp:
-        self.project_subdir = pp
-
-        ui_panels.ui_message(title="Fixed to relative path",
-                             message="This path should be always realative.\n" \
-                                     " It's a directory BlenderKit creates where your .blend is \n " \
-                                     "and uses it for storing assets.")
-
-
-class BlenderKitAddonPreferences(AddonPreferences):
-    # this must match the addon name, use '__package__'
-    # when defining this in a submodule of a python package.
-    bl_idname = __name__
-
-    default_global_dict = paths.default_global_dict()
-
-    enable_oauth = True
-
-    api_key: StringProperty(
-        name="BlenderKit API Key",
-        description="Your blenderkit API Key. Get it from your page on the website",
-        default="",
-        subtype="PASSWORD",
-        update=utils.save_prefs
-    )
-
-    api_key_refresh: StringProperty(
-        name="BlenderKit refresh API Key",
-        description="API key used to refresh the token regularly",
-        default="",
-        subtype="PASSWORD",
-    )
-
-    api_key_timeout: IntProperty(
-        name='api key timeout',
-        description='time where the api key will need to be refreshed',
-        default=0,
-    )
-
-    api_key_life: IntProperty(
-        name='api key life time',
-        description='maximum lifetime of the api key, in seconds',
-        default=0,
-    )
-
-    refresh_in_progress: BoolProperty(
-        name="Api key refresh in progress",
-        description="Api key is currently being refreshed. Don't refresh it again",
-        default=False
-    )
-
-    login_attempt: BoolProperty(
-        name="Login/Signup attempt",
-        description="When this is on, BlenderKit is trying to connect and login",
-        default=False
-    )
-
-    show_on_start: BoolProperty(
-        name="Show assetbar when starting blender",
-        description="Show assetbar when starting blender",
-        default=False
-    )
-
-    tips_on_start: BoolProperty(
-        name="Show tips when starting blender",
-        description="Show tips when starting blender",
-        default=True
-    )
-
-    search_in_header: BoolProperty(
-        name="Show BlenderKit search in 3D view header",
-        description="Show BlenderKit search in 3D view header",
-        default=True
-    )
-
-    global_dir: StringProperty(
-        name="Global Files Directory",
-        description="Global storage for your assets, will use subdirectories for the contents",
-        subtype='DIR_PATH',
-        default=default_global_dict,
-        update=utils.save_prefs
-    )
-
-    project_subdir: StringProperty(
-        name="Project Assets Subdirectory",
-        description="where data will be stored for individual projects",
-        # subtype='DIR_PATH',
-        default="//assets",
-        update=fix_subdir
-    )
-
-    directory_behaviour: EnumProperty(
-        name="Use Directories",
-        items=(
-            ('BOTH', 'Global and subdir',
-             'store files both in global lib and subdirectory of current project. '
-             'Warning - each file can be many times on your harddrive, but helps you keep your projects in one piece'),
-            ('GLOBAL', 'Global',
-             "store downloaded files only in global directory. \n "
-             "This can bring problems when moving your projects, \n"
-             "since assets won't be in subdirectory of current project"),
-            ('LOCAL', 'Local',
-             'store downloaded files only in local directory.\n'
-             ' This can use more bandwidth when you reuse assets in different projects. ')
-
-        ),
-        description="Which directories will be used for storing downloaded data",
-        default="BOTH",
-    )
-    thumbnail_use_gpu: BoolProperty(
-        name="Use GPU for Thumbnails Rendering (For assets upload)",
-        description="By default this is off so you can continue your work without any lag",
-        default=False
-    )
-
-    panel_behaviour: EnumProperty(
-        name="Panels Locations",
-        items=(
-            ('BOTH', 'Both Types',
-             ''),
-            ('UNIFIED', 'Unified 3D View Panel',
-             ""),
-            ('LOCAL', 'Relative to Data',
-             '')
-
-        ),
-        description="Which directories will be used for storing downloaded data",
-        default="UNIFIED",
-    )
-
-    max_assetbar_rows: IntProperty(name="Max Assetbar Rows",
-                                   description="max rows of assetbar in the 3D view",
-                                   default=1,
-                                   min=1,
-                                   max=20)
-
-    thumb_size: IntProperty(name="Assetbar thumbnail Size", default=96, min=-1, max=256)
-
-    #counts usages so it can encourage user after some time to do things.
-    asset_counter: IntProperty(name="Usage Counter",
-                               description="Counts usages so it asks for registration only after reaching a limit",
-                               default=0,
-                               min=0,
-                               max=20000)
-
-    notifications_counter: IntProperty(
-        name='Notifications Counter',
-        description='count users notifications',
-        default=0,
-    )
-    # this is now made obsolete by the new popup upon registration -ensures the user knows about the first search.
-    # first_run: BoolProperty(
-    #     name="First run",
-    #     description="Detects if addon was already registered/run.",
-    #     default=True,
-    #     update=utils.save_prefs
-    # )
-
-    use_timers: BoolProperty(
-        name="Use timers",
-        description="Use timers for BlenderKit. Usefull for debugging since timers seem to be unstable",
-        default=True,
-        update=utils.save_prefs
-    )
-
-    # single_timer: BoolProperty(
-    #     name="Use timers",
-    #     description="Use timers for BlenderKit. Usefull for debugging since timers seem to be unstable",
-    #     default=True,
-    #     update=utils.save_prefs
-    # )
-
-    experimental_features: BoolProperty(
-        name="Enable experimental features",
-        description="Enable all experimental features of BlenderKit. Use at your own risk",
-        default=False,
-        update=utils.save_prefs
-    )
-
-    categories_fix: BoolProperty(
-        name="Enable category fixing mode",
-        description="Enable category fixing mode",
-        default=False,
-        update=utils.save_prefs
-    )
-
-    # allow_proximity : BoolProperty(
-    #     name="allow proximity data reports",
-    #     description="This sends anonymized proximity data \n \
-    #             and allows us to make relations between database objects \n \
-    #              without user interaction",
-    #     default=False
-    # )
-
-    def draw(self, context):
-        layout = self.layout
-        layout.prop(self, "show_on_start")
-
-        if self.api_key.strip() == '':
-            if self.enable_oauth:
-                ui_panels.draw_login_buttons(layout)
-            else:
-                op = layout.operator("wm.url_open", text="Register online and get your API Key",
-                                     icon='QUESTION')
-                op.url = paths.BLENDERKIT_SIGNUP_URL
-        else:
-            if self.enable_oauth:
-                layout.operator("wm.blenderkit_logout", text="Logout",
-                                icon='URL')
-
-        # if not self.enable_oauth:
-        layout.prop(self, "api_key", text='Your API Key')
-        # layout.label(text='After you paste API Key, categories are downloaded, so blender will freeze for a few seconds.')
-        layout.prop(self, "global_dir")
-        layout.prop(self, "project_subdir")
-        # layout.prop(self, "temp_dir")
-        layout.prop(self, "directory_behaviour")
-        # layout.prop(self, "allow_proximity")
-        # layout.prop(self, "panel_behaviour")
-        layout.prop(self, "thumb_size")
-        layout.prop(self, "max_assetbar_rows")
-        layout.prop(self, "tips_on_start")
-        layout.prop(self, "search_in_header")
-        layout.prop(self, "thumbnail_use_gpu")
-
-        if bpy.context.preferences.view.show_developer_ui:
-            layout.prop(self, "use_timers")
-            layout.prop(self, "experimental_features")
-            layout.prop(self, "categories_fix")
-
-
-# # @bpy.app.handlers.persistent
-# def blenderkit_timer():
-#
-#
-# if not user_preferences.use_timers:
-#     search.search_timer()
-#     download.download_timer()
-#     tasks_queue.queue_worker()
-#     bg_blender.bg_update()
-# registration
-classes = (
-
-    BlenderKitAddonPreferences,
-    BlenderKitUIProps,
-
-    BlenderKitModelSearchProps,
-    BlenderKitModelUploadProps,
-
-    BlenderKitSceneSearchProps,
-    BlenderKitSceneUploadProps,
-
-    BlenderKitHDRSearchProps,
-    BlenderKitHDRUploadProps,
-
-    BlenderKitMaterialUploadProps,
-    BlenderKitMaterialSearchProps,
-
-    BlenderKitTextureUploadProps,
-
-    BlenderKitBrushSearchProps,
-    BlenderKitBrushUploadProps,
-
-    BlenderKitRatingProps,
-)
-
-
-
-def register():
-    for cls in classes:
-        bpy.utils.register_class(cls)
-
-    bpy.types.WindowManager.blenderkitUI = PointerProperty(
-        type=BlenderKitUIProps)
-
-    # MODELS
-    bpy.types.WindowManager.blenderkit_models = PointerProperty(
-        type=BlenderKitModelSearchProps)
-    bpy.types.Object.blenderkit = PointerProperty(  # for uploads, not now...
-        type=BlenderKitModelUploadProps)
-    bpy.types.Object.bkit_ratings = PointerProperty(  # for uploads, not now...
-        type=BlenderKitRatingProps)
-
-    # SCENES
-    bpy.types.WindowManager.blenderkit_scene = PointerProperty(
-        type=BlenderKitSceneSearchProps)
-    bpy.types.Scene.blenderkit = PointerProperty(  # for uploads, not now...
-        type=BlenderKitSceneUploadProps)
-    bpy.types.Scene.bkit_ratings = PointerProperty(  # for uploads, not now...
-        type=BlenderKitRatingProps)
-
-    # HDRs
-    bpy.types.WindowManager.blenderkit_HDR = PointerProperty(
-        type=BlenderKitHDRSearchProps)
-    bpy.types.Image.blenderkit = PointerProperty(  # for uploads, not now...
-        type=BlenderKitHDRUploadProps)
-    bpy.types.Image.bkit_ratings = PointerProperty(  # for uploads, not now...
-        type=BlenderKitRatingProps)
-
-    # MATERIALS
-    bpy.types.WindowManager.blenderkit_mat = PointerProperty(
-        type=BlenderKitMaterialSearchProps)
-    bpy.types.Material.blenderkit = PointerProperty(  # for uploads, not now...
-        type=BlenderKitMaterialUploadProps)
-    bpy.types.Material.bkit_ratings = PointerProperty(  # for uploads, not now...
-        type=BlenderKitRatingProps)
-
-    # BRUSHES
-    bpy.types.WindowManager.blenderkit_brush = PointerProperty(
-        type=BlenderKitBrushSearchProps)
-    bpy.types.Brush.blenderkit = PointerProperty(  # for uploads, not now...
-        type=BlenderKitBrushUploadProps)
-    bpy.types.Brush.bkit_ratings = PointerProperty(  # for uploads, not now...
-        type=BlenderKitRatingProps)
-
-    search.register_search()
-    asset_inspector.register_asset_inspector()
-    download.register_download()
-    upload.register_upload()
-    ratings.register_ratings()
-    autothumb.register_thumbnailer()
-    ui.register_ui()
-    icons.register_icons()
-    ui_panels.register_ui_panels()
-    bg_blender.register()
-    utils.load_prefs()
-    overrides.register_overrides()
-    bkit_oauth.register()
-    tasks_queue.register()
-    asset_bar_op.register()
-
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if user_preferences.use_timers and not bpy.app.background:
-        bpy.app.timers.register(check_timers_timer, persistent=True)
-
-    bpy.app.handlers.load_post.append(scene_load)
-    # detect if the user just enabled the addon in preferences, thus enable to run
-    for w in bpy.context.window_manager.windows:
-        for a in w.screen.areas:
-            if a.type == 'PREFERENCES':
-                tasks_queue.add_task((bpy.ops.wm.blenderkit_welcome, ('INVOKE_DEFAULT',)), fake_context=True,
-                                     fake_context_area='PREFERENCES')
-                #save preferences after manually enabling the addon
-                tasks_queue.add_task((bpy.ops.wm.save_userpref, ()), fake_context=False,)
-
-
-def unregister():
-    if bpy.app.timers.is_registered(check_timers_timer):
-        bpy.app.timers.unregister(check_timers_timer)
-    ui_panels.unregister_ui_panels()
-    ui.unregister_ui()
-
-    icons.unregister_icons()
-    search.unregister_search()
-    asset_inspector.unregister_asset_inspector()
-    download.unregister_download()
-    upload.unregister_upload()
-    ratings.unregister_ratings()
-    autothumb.unregister_thumbnailer()
-    bg_blender.unregister()
-    overrides.unregister_overrides()
-    bkit_oauth.unregister()
-    tasks_queue.unregister()
-    asset_bar_op.unregister()
-
-    del bpy.types.WindowManager.blenderkit_models
-    del bpy.types.WindowManager.blenderkit_scene
-    del bpy.types.WindowManager.blenderkit_HDR
-    del bpy.types.WindowManager.blenderkit_brush
-    del bpy.types.WindowManager.blenderkit_mat
-
-    del bpy.types.Scene.blenderkit
-    del bpy.types.Object.blenderkit
-    del bpy.types.Image.blenderkit
-    del bpy.types.Material.blenderkit
-    del bpy.types.Brush.blenderkit
-
-    for cls in classes:
-        bpy.utils.unregister_class(cls)
-
-    bpy.app.handlers.load_post.remove(scene_load)
diff --git a/blenderkit/append_link.py b/blenderkit/append_link.py
deleted file mode 100644
index 6fe710be8de773655f198b506d3a2e26457e0096..0000000000000000000000000000000000000000
--- a/blenderkit/append_link.py
+++ /dev/null
@@ -1,403 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import utils, ui
-
-import bpy
-import uuid
-
-
-def append_brush(file_name, brushname=None, link=False, fake_user=True):
-    '''append a brush'''
-    with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
-        for m in data_from.brushes:
-            if m == brushname or brushname is None:
-                data_to.brushes = [m]
-                brushname = m
-    brush = bpy.data.brushes[brushname]
-    if fake_user:
-        brush.use_fake_user = True
-    return brush
-
-
-def append_material(file_name, matname=None, link=False, fake_user=True):
-    '''append a material type asset'''
-    # first, we have to check if there is a material with same name
-    # in previous step there's check if the imported material
-    # is already in the scene, so we know same name != same material
-
-    mats_before = bpy.data.materials[:]
-    try:
-        with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
-            found = False
-            for m in data_from.materials:
-                if m == matname or matname is None:
-                    data_to.materials = [m]
-                    # print(m, type(m))
-                    matname = m
-                    found = True
-                    break;
-
-            #not found yet? probably some name inconsistency then.
-            if not found and len(data_from.materials)>0:
-                data_to.materials = [data_from.materials[0]]
-                matname = data_from.materials[0]
-                print(f"the material wasn't found under the exact name, appended another one: {matname}")
-            # print('in the appended file the name is ', matname)
-
-    except Exception as e:
-        print(e)
-        print('failed to open the asset file')
-    # we have to find the new material , due to possible name changes
-    mat = None
-    for m in bpy.data.materials:
-        if m not in mats_before:
-            mat = m
-            break;
-    #still not found?
-    if mat is None:
-        mat = bpy.data.materials.get(matname)
-
-    if fake_user:
-        mat.use_fake_user = True
-    return mat
-
-
-def append_scene(file_name, scenename=None, link=False, fake_user=False):
-    '''append a scene type asset'''
-    with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
-        for s in data_from.scenes:
-            if s == scenename or scenename is None:
-                data_to.scenes = [s]
-                scenename = s
-    scene = bpy.data.scenes[scenename]
-    if fake_user:
-        scene.use_fake_user = True
-    # scene has to have a new uuid, so user reports aren't screwed.
-    scene['uuid'] = str(uuid.uuid4())
-
-    #reset ui_props of the scene to defaults:
-    ui_props = bpy.context.window_manager.blenderkitUI
-    ui_props.down_up = 'SEARCH'
-
-    return scene
-
-
-def get_node_sure(node_tree, ntype=''):
-    '''
-    Gets a node of certain type, but creates a new one if not pre
-    '''
-    node = None
-    for n in node_tree.nodes:
-        if ntype == n.bl_rna.identifier:
-            node = n
-            return node
-    if not node:
-        node = node_tree.nodes.new(type=ntype)
-
-    return node
-
-def hdr_swap(name, hdr):
-    '''
-    Try to replace the hdr in current world setup. If this fails, create a new world.
-    :param name: Name of the resulting world (renamse the current one if swap is successfull)
-    :param hdr: Image type
-    :return: None
-    '''
-    w = bpy.context.scene.world
-    if w:
-        w.use_nodes = True
-        w.name = name
-        nt = w.node_tree
-        for n in nt.nodes:
-            if 'ShaderNodeTexEnvironment' == n.bl_rna.identifier:
-                env_node = n
-                env_node.image = hdr
-                return
-    new_hdr_world(name,hdr)
-
-
-def new_hdr_world(name, hdr):
-    '''
-    creates a new world, links in the hdr with mapping node, and links the world to scene
-    :param name: Name of the world datablock
-    :param hdr: Image type
-    :return: None
-    '''
-    w = bpy.data.worlds.new(name=name)
-    w.use_nodes = True
-    bpy.context.scene.world = w
-
-    nt = w.node_tree
-    env_node = nt.nodes.new(type='ShaderNodeTexEnvironment')
-    env_node.image = hdr
-    background = get_node_sure(nt, 'ShaderNodeBackground')
-    tex_coord = get_node_sure(nt, 'ShaderNodeTexCoord')
-    mapping = get_node_sure(nt, 'ShaderNodeMapping')
-
-    nt.links.new(env_node.outputs['Color'], background.inputs['Color'])
-    nt.links.new(tex_coord.outputs['Generated'], mapping.inputs['Vector'])
-    nt.links.new(mapping.outputs['Vector'], env_node.inputs['Vector'])
-    env_node.location.x = -400
-    mapping.location.x = -600
-    tex_coord.location.x = -800
-
-
-def load_HDR(file_name, name):
-    '''Load a HDR into file and link it to scene world. '''
-    already_linked = False
-    for i in bpy.data.images:
-        if i.filepath == file_name:
-            hdr = i
-            already_linked = True
-            break;
-
-    if not already_linked:
-        hdr = bpy.data.images.load(file_name)
-
-    hdr_swap(name, hdr)
-    return hdr
-
-
-def link_collection(file_name, obnames=[], location=(0, 0, 0), link=False, parent = None, **kwargs):
-    '''link an instanced group - model type asset'''
-    sel = utils.selection_get()
-
-    with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
-        scols = []
-        for col in data_from.collections:
-            if col == kwargs['name']:
-                data_to.collections = [col]
-
-    rotation = (0, 0, 0)
-    if kwargs.get('rotation') is not None:
-        rotation = kwargs['rotation']
-
-    bpy.ops.object.empty_add(type='PLAIN_AXES', location=location, rotation=rotation)
-    main_object = bpy.context.view_layer.objects.active
-    main_object.instance_type = 'COLLECTION'
-
-    if parent is not None:
-        main_object.parent = bpy.data.objects.get(parent)
-
-    main_object.matrix_world.translation = location
-
-    for col in bpy.data.collections:
-        if col.library is not None:
-            fp = bpy.path.abspath(col.library.filepath)
-            fp1 = bpy.path.abspath(file_name)
-            if fp == fp1:
-                main_object.instance_collection = col
-                break;
-
-    #sometimes, the lib might already  be without the actual link.
-    if not main_object.instance_collection and kwargs['name']:
-        col = bpy.data.collections.get(kwargs['name'])
-        if col:
-            main_object.instance_collection = col
-
-    main_object.name = main_object.instance_collection.name
-
-    # bpy.ops.wm.link(directory=file_name + "/Collection/", filename=kwargs['name'], link=link, instance_collections=True,
-    #                 autoselect=True)
-    # main_object = bpy.context.view_layer.objects.active
-    # if kwargs.get('rotation') is not None:
-    #     main_object.rotation_euler = kwargs['rotation']
-    # main_object.location = location
-
-    utils.selection_set(sel)
-    return main_object, []
-
-
-def append_particle_system(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs):
-    '''link an instanced group - model type asset'''
-
-    pss = []
-    with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
-        for ps in data_from.particles:
-            pss.append(ps)
-        data_to.particles = pss
-
-    s = bpy.context.scene
-    sel = utils.selection_get()
-
-    target_object = bpy.context.scene.objects.get(kwargs['target_object'])
-    if target_object is not None and target_object.type == 'MESH':
-        target_object.select_set(True)
-        bpy.context.view_layer.objects.active = target_object
-
-        for ps in pss:
-            # now let's tune this ps to the particular objects area:
-            totarea = 0
-            for p in target_object.data.polygons:
-                totarea += p.area
-            count = int(ps.count * totarea)
-
-            if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
-                total_count = count * ps.rendered_child_count
-                disp_count = count * ps.child_nbr
-            else:
-                total_count = count
-
-            bbox_threshold = 25000
-            display_threshold = 200000
-            total_max_threshold = 2000000
-            # emitting too many parent particles just kills blender now.
-
-            #this part tuned child count, we'll leave children to artists only.
-            # if count > total_max_threshold:
-            #     ratio = round(count / total_max_threshold)
-            #
-            #     if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
-            #         ps.rendered_child_count *= ratio
-            #     else:
-            #         ps.child_type = 'INTERPOLATED'
-            #         ps.rendered_child_count = ratio
-            #     count = max(2, int(count / ratio))
-
-            #1st level of optimizaton - switch t bounding boxes.
-            if total_count>bbox_threshold:
-                target_object.display_type = 'BOUNDS'
-            # 2nd level of optimization - reduce percentage of displayed particles.
-            ps.display_percentage = min(ps.display_percentage, max(1, int(100 * display_threshold / total_count)))
-            #here we can also tune down number of children displayed.
-            #set the count
-            ps.count = count
-            #add the modifier
-            bpy.ops.object.particle_system_add()
-            # 3rd level - hide particle system from viewport - is done on the modifier..
-            if total_count > total_max_threshold:
-                target_object.modifiers[-1].show_viewport = False
-
-            target_object.particle_systems[-1].settings = ps
-
-        target_object.select_set(False)
-    utils.selection_set(sel)
-    return target_object, []
-
-
-def append_objects(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs):
-    '''append objects into scene individually'''
-    #simplified version of append
-    if kwargs.get('name'):
-        # by now used for appending into scene
-        scene = bpy.context.scene
-        sel = utils.selection_get()
-        bpy.ops.object.select_all(action='DESELECT')
-
-        path = file_name + "\\Collection\\"
-        collection_name = kwargs.get('name')
-        fc = utils.get_fake_context(bpy.context, area_type='VIEW_3D')
-        bpy.ops.wm.append(fc, filename=collection_name, directory=path)
-
-        return_obs = []
-        to_hidden_collection = []
-        collection = None
-        for ob in bpy.context.scene.objects:
-            if ob.select_get():
-                return_obs.append(ob)
-                if not ob.parent:
-                    main_object = ob
-                    ob.location = location
-                # check for object that should be hidden
-                if ob.users_collection[0].name == collection_name:
-                    collection = ob.users_collection[0]
-                    collection['is_blenderkit_asset'] = True
-
-                else:
-                    to_hidden_collection.append(ob)
-
-        if kwargs.get('rotation'):
-            main_object.rotation_euler = kwargs['rotation']
-
-        if kwargs.get('parent') is not None:
-            main_object.parent = bpy.data.objects[kwargs['parent']]
-            main_object.matrix_world.translation = location
-
-
-        #move objects that should be hidden to a sub collection
-        if len(to_hidden_collection)>0 and collection is not None:
-            hidden_collection_name = collection_name+'_hidden'
-            h_col = bpy.data.collections.new(name = hidden_collection_name)
-            collection.children.link(h_col)
-            for ob in to_hidden_collection:
-                ob.users_collection[0].objects.unlink(ob)
-                h_col.objects.link(ob)
-            utils.exclude_collection(hidden_collection_name)
-
-        bpy.ops.object.select_all(action='DESELECT')
-        utils.selection_set(sel)
-        #let collection also store info that it was created by BlenderKit, for purging reasons
-
-        return main_object, return_obs
-
-    #this is used for uploads:
-    with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
-        sobs = []
-        # for col in data_from.collections:
-        #     if col == kwargs.get('name'):
-        for ob in data_from.objects:
-            if ob in obnames or obnames == []:
-                sobs.append(ob)
-        data_to.objects = sobs
-        # data_to.objects = data_from.objects#[name for name in data_from.objects if name.startswith("house")]
-
-    # link them to scene
-    scene = bpy.context.scene
-    sel = utils.selection_get()
-    bpy.ops.object.select_all(action='DESELECT')
-
-    return_obs = []  # this might not be needed, but better be sure to rewrite the list.
-    main_object = None
-    hidden_objects = []
-    #
-    for obj in data_to.objects:
-        if obj is not None:
-            # if obj.name not in scene.objects:
-            scene.collection.objects.link(obj)
-            if obj.parent is None:
-                obj.location = location
-                main_object = obj
-            obj.select_set(True)
-            # we need to unhide object so make_local op can use those too.
-            if link == True:
-                if obj.hide_viewport:
-                    hidden_objects.append(obj)
-                    obj.hide_viewport = False
-            return_obs.append(obj)
-
-    # Only after all objects are in scene! Otherwise gets broken relationships
-    if link == True:
-        bpy.ops.object.make_local(type='SELECT_OBJECT')
-        for ob in hidden_objects:
-            ob.hide_viewport = True
-
-    if kwargs.get('rotation') is not None:
-        main_object.rotation_euler = kwargs['rotation']
-
-    if kwargs.get('parent') is not None:
-        main_object.parent = bpy.data.objects[kwargs['parent']]
-        main_object.matrix_world.translation = location
-
-    bpy.ops.object.select_all(action='DESELECT')
-
-    utils.selection_set(sel)
-
-
-    return main_object, return_obs
diff --git a/blenderkit/asset_bar_op.py b/blenderkit/asset_bar_op.py
deleted file mode 100644
index 09124f873e9cd311ff18d16bcd7c2f2c32802fde..0000000000000000000000000000000000000000
--- a/blenderkit/asset_bar_op.py
+++ /dev/null
@@ -1,1034 +0,0 @@
-import bpy
-
-from bpy.types import Operator
-
-from blenderkit.bl_ui_widgets.bl_ui_label import *
-from blenderkit.bl_ui_widgets.bl_ui_button import *
-from blenderkit.bl_ui_widgets.bl_ui_image import *
-# from blenderkit.bl_ui_widgets.bl_ui_checkbox import *
-# from blenderkit.bl_ui_widgets.bl_ui_slider import *
-# from blenderkit.bl_ui_widgets.bl_ui_up_down import *
-from blenderkit.bl_ui_widgets.bl_ui_drag_panel import *
-from blenderkit.bl_ui_widgets.bl_ui_draw_op import *
-# from blenderkit.bl_ui_widgets.bl_ui_textbox import *
-import random
-import math
-import time
-
-import blenderkit
-from blenderkit import ui, paths, utils, search, comments_utils
-
-from bpy.props import (
-    IntProperty,
-    BoolProperty,
-    StringProperty
-)
-
-active_area_pointer = 0
-
-
-def get_area_height(self):
-    if type(self.context) != dict:
-        if self.context is None:
-            self.context = bpy.context
-        self.context = self.context.copy()
-    # print(self.context)
-    if self.context.get('area') is not None:
-        return self.context['area'].height
-    # else:
-    #     maxw, maxa, region = utils.get_largest_area()
-    #     if maxa:
-    #         self.context['area'] = maxa
-    #         self.context['window'] = maxw
-    #         self.context['region'] = region
-    #         self.update(self.x,self.y)
-    #
-    #         return self.context['area'].height
-    # print('no area found')
-    return 100
-
-
-BL_UI_Widget.get_area_height = get_area_height
-
-
-def modal_inside(self, context, event):
-    ui_props = bpy.context.window_manager.blenderkitUI
-    if ui_props.turn_off:
-        ui_props.turn_off = False
-        self.finish()
-
-    if self._finished:
-        return {'FINISHED'}
-
-    if context.area:
-        context.area.tag_redraw()
-    else:
-        self.finish()
-        return {'FINISHED'}
-
-    self.update_timer += 1
-
-    if self.update_timer > self.update_timer_limit:
-        self.update_timer = 0
-        # print('timer', time.time())
-        self.update_images()
-
-        # progress bar
-        sr = bpy.context.window_manager.get('search results')
-        ui_scale = bpy.context.preferences.view.ui_scale
-        for asset_button in self.asset_buttons:
-            if sr is not None and len(sr) > asset_button.asset_index:
-                asset_data = sr[asset_button.asset_index]
-
-                if asset_data['downloaded'] > 0:
-                    asset_button.progress_bar.width = int(self.button_size * ui_scale * asset_data['downloaded'] / 100)
-                    asset_button.progress_bar.visible = True
-                else:
-                    asset_button.progress_bar.visible = False
-
-    if self.handle_widget_events(event):
-        return {'RUNNING_MODAL'}
-
-    if event.type in {"ESC"}:
-        self.finish()
-
-    self.mouse_x = event.mouse_region_x
-    self.mouse_y = event.mouse_region_y
-    if event.type == 'WHEELUPMOUSE' and self.panel.is_in_rect(self.mouse_x, self.mouse_y):
-        self.scroll_offset -= 2
-        self.scroll_update()
-        return {'RUNNING_MODAL'}
-
-    elif event.type == 'WHEELDOWNMOUSE' and self.panel.is_in_rect(self.mouse_x, self.mouse_y):
-        self.scroll_offset += 2
-        self.scroll_update()
-        return {'RUNNING_MODAL'}
-
-    if self.check_ui_resized(context) or self.check_new_search_results(context):
-        # print(self.check_ui_resized(context), print(self.check_new_search_results(context)))
-        self.update_ui_size(context)
-        self.update_layout(context, event)
-
-    # this was here to check if sculpt stroke is running, but obviously that didn't help,
-    #  since the RELEASE event is cought by operator and thus there is no way to detect a stroke has ended...
-    if bpy.context.mode in ('SCULPT', 'PAINT_TEXTURE'):
-        if event.type == 'MOUSEMOVE':  # ASSUME THAT SCULPT OPERATOR ACTUALLY STEALS THESE EVENTS,
-            # SO WHEN THERE ARE SOME WE CAN APPEND BRUSH...
-            bpy.context.window_manager['appendable'] = True
-        if event.type == 'LEFTMOUSE':
-            if event.value == 'PRESS':
-                bpy.context.window_manager['appendable'] = False
-    return {"PASS_THROUGH"}
-
-
-def asset_bar_modal(self, context, event):
-    return modal_inside(self, context, event)
-
-
-def asset_bar_invoke(self, context, event):
-    if not self.on_invoke(context, event):
-        return {"CANCELLED"}
-
-    args = (self, context)
-
-    self.register_handlers(args, context)
-
-    self.update_timer_limit = 30
-    self.update_timer = 0
-    # print('adding timer')
-    # self._timer = context.window_manager.event_timer_add(10.0, window=context.window)
-    global active_area_pointer
-    context.window_manager.modal_handler_add(self)
-    self.active_window_pointer = context.window.as_pointer()
-    self.active_area_pointer = context.area.as_pointer()
-    active_area_pointer = context.area.as_pointer()
-    self.active_region_pointer = context.region.as_pointer()
-
-    return {"RUNNING_MODAL"}
-
-
-BL_UI_OT_draw_operator.modal = asset_bar_modal
-BL_UI_OT_draw_operator.invoke = asset_bar_invoke
-
-
-def set_mouse_down_right(self, mouse_down_right_func):
-    self.mouse_down_right_func = mouse_down_right_func
-
-
-def mouse_down_right(self, x, y):
-    if self.is_in_rect(x, y):
-        self.__state = 1
-        try:
-            self.mouse_down_right_func(self)
-        except Exception as e:
-            print(e)
-
-        return True
-
-    return False
-
-
-BL_UI_Button.mouse_down_right = mouse_down_right
-BL_UI_Button.set_mouse_down_right = set_mouse_down_right
-
-asset_bar_operator = None
-
-
-# BL_UI_Button.handle_event = handle_event
-
-def get_tooltip_data(asset_data):
-    gimg = None
-    tooltip_data = asset_data.get('tooltip_data')
-    if tooltip_data is None:
-        author_text = ''
-
-        if bpy.context.window_manager.get('bkit authors') is not None:
-            a = bpy.context.window_manager['bkit authors'].get(asset_data['author']['id'])
-            if a is not None and a != '':
-                if a.get('gravatarImg') is not None:
-                    gimg = utils.get_hidden_image(a['gravatarImg'], a['gravatarHash']).name
-
-                if len(a['firstName']) > 0 or len(a['lastName']) > 0:
-                    author_text = f"by {a['firstName']} {a['lastName']}"
-
-        aname = asset_data['displayName']
-        aname = aname[0].upper() + aname[1:]
-        if len(aname) > 36:
-            aname = f"{aname[:33]}..."
-
-        rc = asset_data.get('ratingsCount')
-        show_rating_threshold = 0
-        rcount = 0
-        quality = '-'
-        if rc:
-            rcount = min(rc.get('quality', 0), rc.get('workingHours', 0))
-        if rcount > show_rating_threshold:
-            quality = str(round(asset_data['ratingsAverage'].get('quality')))
-        tooltip_data = {
-            'aname': aname,
-            'author_text': author_text,
-            'quality': quality,
-            'gimg': gimg
-        }
-        asset_data['tooltip_data'] = tooltip_data
-    gimg = tooltip_data['gimg']
-    if gimg is not None:
-        gimg = bpy.data.images[gimg]
-
-
-class BlenderKitAssetBarOperator(BL_UI_OT_draw_operator):
-    bl_idname = "view3d.blenderkit_asset_bar_widget"
-    bl_label = "BlenderKit asset bar refresh"
-    bl_description = "BlenderKit asset bar refresh"
-    bl_options = {'REGISTER'}
-
-    do_search: BoolProperty(name="Run Search", description='', default=True, options={'SKIP_SAVE'})
-    keep_running: BoolProperty(name="Keep Running", description='', default=True, options={'SKIP_SAVE'})
-    free_only: BoolProperty(name="Free first", description='', default=False, options={'SKIP_SAVE'})
-
-    category: StringProperty(
-        name="Category",
-        description="search only subtree of this category",
-        default="", options={'SKIP_SAVE'})
-
-    tooltip: bpy.props.StringProperty(default='Runs search and displays the asset bar at the same time')
-
-    @classmethod
-    def description(cls, context, properties):
-        return properties.tooltip
-
-    def new_text(self, text, x, y, width=100, height=15, text_size=None, halign='LEFT'):
-        label = BL_UI_Label(x, y, width, height)
-        label.text = text
-        if text_size is None:
-            text_size = 14
-        label.text_size = text_size
-        label.text_color = self.text_color
-        label._halign = halign
-        return label
-
-    def init_tooltip(self):
-        self.tooltip_widgets = []
-        self.tooltip_height = self.tooltip_size
-        self.tooltip_width = self.tooltip_size
-        ui_props = bpy.context.window_manager.blenderkitUI
-        if ui_props.asset_type == 'HDR':
-            self.tooltip_width = self.tooltip_size * 2
-        # total_size = tooltip# + 2 * self.margin
-        self.tooltip_panel = BL_UI_Drag_Panel(0, 0, self.tooltip_width, self.tooltip_height)
-        self.tooltip_panel.bg_color = (0.0, 0.0, 0.0, 0.5)
-        self.tooltip_panel.visible = False
-
-        tooltip_image = BL_UI_Image(0, 0, 1, 1)
-        img_path = paths.get_addon_thumbnail_path('thumbnail_notready.jpg')
-        tooltip_image.set_image(img_path)
-        tooltip_image.set_image_size((self.tooltip_width, self.tooltip_height))
-        tooltip_image.set_image_position((0, 0))
-        self.tooltip_image = tooltip_image
-        self.tooltip_widgets.append(tooltip_image)
-
-        bottom_panel_fraction = 0.15
-        labels_start = self.tooltip_height * (1 - bottom_panel_fraction)
-
-        dark_panel = BL_UI_Widget(0, labels_start, self.tooltip_width, self.tooltip_height * bottom_panel_fraction)
-        dark_panel.bg_color = (0.0, 0.0, 0.0, 0.7)
-        self.tooltip_dark_panel = dark_panel
-        self.tooltip_widgets.append(dark_panel)
-
-        name_label = self.new_text('', self.margin, labels_start + self.margin,
-                                   text_size=self.asset_name_text_size)
-        self.asset_name = name_label
-        self.tooltip_widgets.append(name_label)
-
-        self.gravatar_size = int(self.tooltip_height * bottom_panel_fraction - self.margin)
-
-        authors_name = self.new_text('author', self.tooltip_width - self.gravatar_size - self.margin,
-                                     self.tooltip_height - self.author_text_size - self.margin, labels_start,
-                                     text_size=self.author_text_size, halign='RIGHT')
-        self.authors_name = authors_name
-        self.tooltip_widgets.append(authors_name)
-
-        gravatar_image = BL_UI_Image(self.tooltip_width - self.gravatar_size, self.tooltip_height - self.gravatar_size,
-                                     1, 1)
-        img_path = paths.get_addon_thumbnail_path('thumbnail_notready.jpg')
-        gravatar_image.set_image(img_path)
-        gravatar_image.set_image_size((self.gravatar_size - 1 * self.margin, self.gravatar_size - 1 * self.margin))
-        gravatar_image.set_image_position((0, 0))
-        self.gravatar_image = gravatar_image
-        self.tooltip_widgets.append(gravatar_image)
-
-        quality_star = BL_UI_Image(self.margin, self.tooltip_height - self.margin - self.asset_name_text_size,
-                                   1, 1)
-        img_path = paths.get_addon_thumbnail_path('star_grey.png')
-        quality_star.set_image(img_path)
-        quality_star.set_image_size((self.asset_name_text_size, self.asset_name_text_size))
-        quality_star.set_image_position((0, 0))
-        # self.quality_star = quality_star
-        self.tooltip_widgets.append(quality_star)
-        label = self.new_text('', 2 * self.margin + self.asset_name_text_size,
-                              self.tooltip_height - int(self.asset_name_text_size + self.margin * .5),
-                              text_size=self.asset_name_text_size)
-        self.tooltip_widgets.append(label)
-        self.quality_label = label
-
-        # label = self.new_text('Right click for menu.', self.margin,
-        #                       self.tooltip_height - int(self.author_text_size) - self.margin,
-        #                       text_size=int(self.author_text_size*.7))
-        # self.tooltip_widgets.append(label)
-
-    def hide_tooltip(self):
-        self.tooltip_panel.visible = False
-        for w in self.tooltip_widgets:
-            w.visible = False
-
-    def show_tooltip(self):
-        self.tooltip_panel.visible = True
-        for w in self.tooltip_widgets:
-            w.visible = True
-
-    def show_notifications(self, widget):
-        bpy.ops.wm.show_notifications()
-        if comments_utils.check_notifications_read():
-            widget.visible = False
-
-    def check_new_search_results(self, context):
-        sr = bpy.context.window_manager.get('search results')
-        if not hasattr(self, 'search_results_count'):
-            if not sr:
-                self.search_results_count = 0
-                return True
-
-            self.search_results_count = len(sr)
-
-        if sr is not None and len(sr) != self.search_results_count:
-            self.search_results_count = len(sr)
-            return True
-        return False
-
-    def get_region_size(self, context):
-        # just check the size of region..
-
-        region = context.region
-        area = context.area
-        ui_width = 0
-        tools_width = 0
-        for r in area.regions:
-            if r.type == 'UI':
-                ui_width = r.width
-            if r.type == 'TOOLS':
-                tools_width = r.width
-        total_width = region.width - tools_width - ui_width
-        return total_width, region.height
-
-    def check_ui_resized(self, context):
-        # TODO this should only check if region was resized, not really care about the UI elements size.
-        region_width, region_height = self.get_region_size(context)
-
-        if not hasattr(self, 'total_width'):
-            self.total_width = region_width
-            self.region_height = region_height
-
-        if region_height != self.region_height or region_width != self.total_width:
-            self.region_height = region_height
-            self.total_width = region_width
-            return True
-        return False
-
-    def update_ui_size(self, context):
-
-        if bpy.app.background or not context.area:
-            return
-
-        region = context.region
-        area = context.area
-
-        ui_props = bpy.context.window_manager.blenderkitUI
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        ui_scale = bpy.context.preferences.view.ui_scale
-
-        self.margin = ui_props.bl_rna.properties['margin'].default * ui_scale
-        self.margin = int(9 * ui_scale)
-        self.button_margin = int(0 * ui_scale)
-        self.asset_name_text_size = int(20 * ui_scale)
-        self.author_text_size = int(self.asset_name_text_size * .7 * ui_scale)
-        self.assetbar_margin = int(2 * ui_scale)
-        self.tooltip_size = int(512 * ui_scale)
-
-        if ui_props.asset_type == 'HDR':
-            self.tooltip_width = self.tooltip_size * 2
-        else:
-            self.tooltip_width = self.tooltip_size
-
-        self.thumb_size = user_preferences.thumb_size * ui_scale
-        self.button_size = 2 * self.button_margin + self.thumb_size
-        self.other_button_size = 30 * ui_scale
-        self.icon_size = 24 * ui_scale
-        self.validation_icon_margin = 3 * ui_scale
-        reg_multiplier = 1
-        if not bpy.context.preferences.system.use_region_overlap:
-            reg_multiplier = 0
-
-        ui_width = 0
-        tools_width = 0
-        reg_multiplier = 1
-        if not bpy.context.preferences.system.use_region_overlap:
-            reg_multiplier = 0
-        for r in area.regions:
-            if r.type == 'UI':
-                ui_width = r.width * reg_multiplier
-            if r.type == 'TOOLS':
-                tools_width = r.width * reg_multiplier
-        self.bar_x = tools_width + self.margin + ui_props.bar_x_offset * ui_scale
-        self.bar_end = ui_width + 180 * ui_scale + self.other_button_size
-        self.bar_width = region.width - self.bar_x - self.bar_end
-
-        self.wcount = math.floor((self.bar_width) / (self.button_size))
-
-        self.max_hcount = math.floor(context.window.width / self.button_size)
-        self.max_wcount = user_preferences.max_assetbar_rows
-
-        search_results = bpy.context.window_manager.get('search results')
-        # we need to init all possible thumb previews in advance/
-        # self.hcount = user_preferences.max_assetbar_rows
-        if search_results is not None and self.wcount > 0:
-            self.hcount = min(user_preferences.max_assetbar_rows, math.ceil(len(search_results) / self.wcount))
-            self.hcount = max(self.hcount, 1)
-        else:
-            self.hcount = 1
-
-        self.bar_height = (self.button_size) * self.hcount + 2 * self.assetbar_margin
-        # self.bar_y = region.height - ui_props.bar_y_offset * ui_scale
-        self.bar_y = ui_props.bar_y_offset * ui_scale
-        if ui_props.down_up == 'UPLOAD':
-            self.reports_y = region.height - self.bar_y - 600
-            ui_props.reports_y = region.height - self.bar_y - 600
-            self.reports_x = self.bar_x
-            ui_props.reports_x = self.bar_x
-        else:  # ui.bar_y - ui.bar_height - 100
-
-            self.reports_y = region.height - self.bar_y - self.bar_height - 50
-            ui_props.reports_y = region.height - self.bar_y - self.bar_height - 50
-            self.reports_x = self.bar_x
-            ui_props.reports_x = self.bar_x
-            # print(self.bar_y, self.bar_height, region.height)
-
-    def update_layout(self, context, event):
-        # restarting asset_bar completely since the widgets are too hard to get working with updates.
-
-        self.position_and_hide_buttons()
-        self.scroll_update()
-
-        self.button_close.set_location(self.bar_width - self.other_button_size, -self.other_button_size)
-        if hasattr(self, 'button_notifications'):
-            self.button_notifications.set_location(self.bar_width - self.other_button_size * 2, -self.other_button_size)
-        self.button_scroll_up.set_location(self.bar_width, 0)
-        self.panel.width = self.bar_width
-        self.panel.height = self.bar_height
-
-        self.panel.set_location(self.bar_x, self.panel.y)
-
-        # update Tooltip size
-        if self.tooltip_dark_panel.width != self.tooltip_width:
-            self.tooltip_dark_panel.width = self.tooltip_width
-            self.tooltip_panel.width = self.tooltip_width
-            self.tooltip_image.width = self.tooltip_width
-            self.tooltip_image.set_image_size((self.tooltip_width, self.tooltip_height))
-            self.gravatar_image.set_location(self.tooltip_width - self.gravatar_size,
-                                             self.tooltip_height - self.gravatar_size)
-            self.authors_name.set_location(self.tooltip_width - self.gravatar_size - self.margin,
-                                           self.tooltip_height - self.author_text_size - self.margin)
-
-        # to hide arrows accordingly
-
-    def asset_button_init(self, asset_x, asset_y, button_idx):
-        ui_scale = bpy.context.preferences.view.ui_scale
-
-        button_bg_color = (0.2, 0.2, 0.2, .1)
-        button_hover_color = (0.8, 0.8, 0.8, .2)
-
-        new_button = BL_UI_Button(asset_x, asset_y, self.button_size, self.button_size)
-
-        # asset_data = sr[asset_idx]
-        # iname = blenderkit.utils.previmg_name(asset_idx)
-        # img = bpy.data.images.get(iname)
-
-        new_button.bg_color = button_bg_color
-        new_button.hover_bg_color = button_hover_color
-        new_button.text = ""  # asset_data['name']
-        # if img:
-        #     new_button.set_image(img.filepath)
-
-        new_button.set_image_size((self.thumb_size, self.thumb_size))
-        new_button.set_image_position((self.button_margin, self.button_margin))
-        new_button.button_index = button_idx
-        new_button.search_index = button_idx
-        new_button.set_mouse_down(self.drag_drop_asset)
-        new_button.set_mouse_down_right(self.asset_menu)
-        new_button.set_mouse_enter(self.enter_button)
-        new_button.set_mouse_exit(self.exit_button)
-        new_button.text_input = self.handle_key_input
-        # add validation icon to button
-
-        validation_icon = BL_UI_Image(
-            asset_x + self.button_size - self.icon_size - self.button_margin - self.validation_icon_margin,
-            asset_y + self.button_size - self.icon_size - self.button_margin - self.validation_icon_margin, 0, 0)
-
-        # v_icon = ui.verification_icons[asset_data.get('verificationStatus', 'validated')]
-        # if v_icon is not None:
-        #     img_fp = paths.get_addon_thumbnail_path(v_icon)
-        #     validation_icon.set_image(img_fp)
-        validation_icon.set_image_size((self.icon_size, self.icon_size))
-        validation_icon.set_image_position((0, 0))
-        self.validation_icons.append(validation_icon)
-        new_button.validation_icon = validation_icon
-
-        progress_bar = BL_UI_Widget(asset_x, asset_y + self.button_size - 3, self.button_size, 3)
-        progress_bar.bg_color = (0.0, 1.0, 0.0, 0.3)
-        new_button.progress_bar = progress_bar
-        self.progress_bars.append(progress_bar)
-
-        if utils.profile_is_validator():
-            red_alert = BL_UI_Widget(asset_x, asset_y, self.button_size, self.button_size)
-            red_alert.bg_color = (1.0, 0.0, 0.0, 0.0)
-            red_alert.visible = False
-            new_button.red_alert = red_alert
-            self.red_alerts.append(red_alert)
-        # if result['downloaded'] > 0:
-        #     ui_bgl.draw_rect(x, y, int(ui_props.thumb_size * result['downloaded'] / 100.0), 2, green)
-
-        return new_button
-
-    def init_ui(self):
-        ui_scale = bpy.context.preferences.view.ui_scale
-
-        button_bg_color = (0.2, 0.2, 0.2, .1)
-        button_hover_color = (0.8, 0.8, 0.8, .2)
-
-        self.buttons = []
-        self.asset_buttons = []
-        self.validation_icons = []
-        self.progress_bars = []
-        self.red_alerts = []
-        self.widgets_panel = []
-
-        self.panel = BL_UI_Drag_Panel(0, 0, self.bar_width, self.bar_height)
-        self.panel.bg_color = (0.0, 0.0, 0.0, 0.5)
-
-        # sr = bpy.context.window_manager.get('search results', [])
-        # if sr is not None:
-        # we init max possible buttons.
-        button_idx = 0
-        for x in range(0, self.max_wcount):
-            for y in range(0, self.max_hcount):
-                # asset_x = self.assetbar_margin + a * (self.button_size)
-                # asset_y = self.assetbar_margin + b * (self.button_size)
-                # button_idx = x + y * self.max_wcount
-                asset_idx = button_idx + self.scroll_offset
-                # if asset_idx < len(sr):
-                new_button = self.asset_button_init(0, 0, button_idx)
-                new_button.asset_index = asset_idx
-                self.asset_buttons.append(new_button)
-                button_idx += 1
-
-        self.button_close = BL_UI_Button(self.bar_width - self.other_button_size, -self.other_button_size,
-                                         self.other_button_size,
-                                         self.other_button_size)
-        self.button_close.bg_color = button_bg_color
-        self.button_close.hover_bg_color = button_hover_color
-        self.button_close.text = ""
-        img_fp = paths.get_addon_thumbnail_path('vs_rejected.png')
-        self.button_close.set_image(img_fp)
-        self.button_close.set_mouse_down(self.cancel_press)
-
-        self.widgets_panel.append(self.button_close)
-
-        self.scroll_width = 30
-        self.button_scroll_down = BL_UI_Button(-self.scroll_width, 0, self.scroll_width, self.bar_height)
-        self.button_scroll_down.bg_color = button_bg_color
-        self.button_scroll_down.hover_bg_color = button_hover_color
-        self.button_scroll_down.text = ""
-        self.button_scroll_down.set_image(paths.get_addon_thumbnail_path('arrow_left.png'))
-        self.button_scroll_down.set_image_size((self.scroll_width, self.button_size))
-        self.button_scroll_down.set_image_position((0, int((self.bar_height - self.button_size) / 2)))
-
-        self.button_scroll_down.set_mouse_down(self.scroll_down)
-
-        self.widgets_panel.append(self.button_scroll_down)
-
-        self.button_scroll_up = BL_UI_Button(self.bar_width, 0, self.scroll_width, self.bar_height)
-        self.button_scroll_up.bg_color = button_bg_color
-        self.button_scroll_up.hover_bg_color = button_hover_color
-        self.button_scroll_up.text = ""
-        self.button_scroll_up.set_image(paths.get_addon_thumbnail_path('arrow_right.png'))
-        self.button_scroll_up.set_image_size((self.scroll_width, self.button_size))
-        self.button_scroll_up.set_image_position((0, int((self.bar_height - self.button_size) / 2)))
-
-        self.button_scroll_up.set_mouse_down(self.scroll_up)
-
-        self.widgets_panel.append(self.button_scroll_up)
-
-        # notifications
-        if not comments_utils.check_notifications_read():
-            self.button_notifications = BL_UI_Button(self.bar_width - self.other_button_size * 2,
-                                                     -self.other_button_size, self.other_button_size,
-                                                     self.other_button_size)
-            self.button_notifications.bg_color = button_bg_color
-            self.button_notifications.hover_bg_color = button_hover_color
-            self.button_notifications.text = ""
-            img_fp = paths.get_addon_thumbnail_path('bell.png')
-            self.button_notifications.set_image(img_fp)
-            self.button_notifications.set_mouse_down(self.show_notifications)
-            self.widgets_panel.append(self.button_notifications)
-
-        self.update_images()
-
-    def position_and_hide_buttons(self):
-        # position and layout buttons
-        sr = bpy.context.window_manager.get('search results', [])
-        if sr is None:
-            sr = []
-
-        i = 0
-        for y in range(0, self.hcount):
-            for x in range(0, self.wcount):
-                asset_x = self.assetbar_margin + x * (self.button_size)
-                asset_y = self.assetbar_margin + y * (self.button_size)
-                button_idx = x + y * self.wcount
-                asset_idx = button_idx + self.scroll_offset
-                if len(self.asset_buttons) <= button_idx:
-                    break
-                button = self.asset_buttons[button_idx]
-                button.set_location(asset_x, asset_y)
-                button.validation_icon.set_location(
-                    asset_x + self.button_size - self.icon_size - self.button_margin - self.validation_icon_margin,
-                    asset_y + self.button_size - self.icon_size - self.button_margin - self.validation_icon_margin)
-                button.progress_bar.set_location(asset_x, asset_y + self.button_size - 3)
-                if asset_idx < len(sr):
-                    button.visible = True
-                    button.validation_icon.visible = True
-                    # button.progress_bar.visible = True
-                else:
-                    button.visible = False
-                    button.validation_icon.visible = False
-                    button.progress_bar.visible = False
-                if utils.profile_is_validator():
-                    button.red_alert.set_location(asset_x, asset_y)
-                i += 1
-
-        for a in range(i, len(self.asset_buttons)):
-            button = self.asset_buttons[a]
-            button.visible = False
-            button.validation_icon.visible = False
-            button.progress_bar.visible = False
-
-        self.button_scroll_down.height = self.bar_height
-        self.button_scroll_down.set_image_position((0, int((self.bar_height - self.button_size) / 2)))
-        self.button_scroll_down.height = self.bar_height
-        self.button_scroll_down.set_image_position((0, int((self.bar_height - self.button_size) / 2)))
-
-    def __init__(self):
-        super().__init__()
-
-        self.update_ui_size(bpy.context)
-
-        # todo move all this to update UI size
-        ui_props = bpy.context.window_manager.blenderkitUI
-
-        self.draw_tooltip = False
-        # let's take saved scroll offset and use it to keep scroll between operator runs
-        self.scroll_offset = ui_props.scroll_offset
-
-        self.text_color = (0.9, 0.9, 0.9, 1.0)
-
-        self.init_ui()
-        self.init_tooltip()
-        self.hide_tooltip()
-
-    def setup_widgets(self, context, event):
-        widgets_panel = []
-        widgets_panel.extend(self.widgets_panel)
-        widgets_panel.extend(self.buttons)
-        widgets_panel.extend(self.asset_buttons)
-        widgets_panel.extend(self.validation_icons)
-        widgets_panel.extend(self.progress_bars)
-        widgets_panel.extend(self.red_alerts)
-
-        widgets = [self.panel]
-
-        widgets += widgets_panel
-        widgets.append(self.tooltip_panel)
-        widgets += self.tooltip_widgets
-
-        self.init_widgets(context, widgets)
-        self.panel.add_widgets(widgets_panel)
-        self.tooltip_panel.add_widgets(self.tooltip_widgets)
-
-    def on_invoke(self, context, event):
-
-        self.context = context
-
-        if self.do_search or context.window_manager.get('search results') is None:
-            # TODO: move the search behaviour to separate operator, since asset bar can be already woken up from a timer.
-
-            # we erase search keywords for cateogry search now, since these combinations usually return nothing now.
-            # when the db gets bigger, this can be deleted.
-            if self.category != '':
-                sprops = utils.get_search_props()
-                sprops.search_keywords = ''
-            search.search(category=self.category)
-
-        ui_props = context.window_manager.blenderkitUI
-        if ui_props.assetbar_on:
-            # TODO solve this otehrwise to enable more asset bars?
-
-            # we don't want to run the assetbar many times, that's why it has a switch on/off behaviour,
-            # unless being called with 'keep_running' prop.
-
-            if not self.keep_running:
-                # this sends message to the originally running operator, so it quits, and then it ends this one too.
-                # If it initiated a search, the search will finish in a thread. The switch off procedure is run
-                # by the 'original' operator, since if we get here, it means
-                # same operator is already running.
-                ui_props.turn_off = True
-                # if there was an error, we need to turn off these props so we can restart after 2 clicks
-                ui_props.assetbar_on = False
-
-            else:
-                pass
-            return False
-
-        ui_props.assetbar_on = True
-        global asset_bar_operator
-
-        asset_bar_operator = self
-
-        self.active_index = -1
-
-        self.setup_widgets(context, event)
-        self.position_and_hide_buttons()
-        self.hide_tooltip()
-
-        self.panel.set_location(self.bar_x,
-                                self.bar_y)
-        # to hide arrows accordingly
-        self.scroll_update()
-
-        self.window = context.window
-        self.area = context.area
-        self.scene = bpy.context.scene
-        # global active_window_pointer, active_area_pointer, active_region_pointer
-        # ui.active_window_pointer = self.window.as_pointer()
-        # ui.active_area_pointer = self.area.as_pointer()
-        # ui.active_region_pointer = self.region.as_pointer()
-
-        return True
-
-    def on_finish(self, context):
-        # redraw all areas, since otherwise it stays to hang for some more time.
-        # bpy.types.SpaceView3D.draw_handler_remove(self._handle_2d_tooltip, 'WINDOW')
-        # to pass the operator to validation icons
-        global asset_bar_operator
-        asset_bar_operator = None
-
-        # context.window_manager.event_timer_remove(self._timer)
-
-        scene = bpy.context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        ui_props.assetbar_on = False
-        ui_props.scroll_offset = self.scroll_offset
-
-        wm = bpy.data.window_managers[0]
-
-        for w in wm.windows:
-            for a in w.screen.areas:
-                a.tag_redraw()
-        self._finished = True
-
-    # handlers
-
-    def enter_button(self, widget):
-        # print('enter button', self.active_index, widget.button_index)
-        # print(widget.button_index+ self.scroll_offset, self.active_index)
-        search_index = widget.button_index + self.scroll_offset
-        if search_index < self.search_results_count:
-            self.show_tooltip()
-        # print(self.active_index, search_index)
-        if self.active_index != search_index:
-            self.active_index = search_index
-
-            scene = bpy.context.scene
-            wm = bpy.context.window_manager
-            sr = wm['search results']
-            asset_data = sr[search_index]  # + self.scroll_offset]
-
-            self.draw_tooltip = True
-            # self.tooltip = asset_data['tooltip']
-            ui_props = bpy.context.window_manager.blenderkitUI
-            ui_props.active_index = search_index  # + self.scroll_offset
-
-            img = ui.get_large_thumbnail_image(asset_data)
-            if img:
-                self.tooltip_image.set_image(img.filepath)
-
-            get_tooltip_data(asset_data)
-            an = asset_data['name']
-            max_name_length = 30
-            if len(an) > max_name_length + 3:
-                an = an[:30] + '...'
-            self.asset_name.text = an
-            self.authors_name.text = asset_data['tooltip_data']['author_text']
-            self.quality_label.text = asset_data['tooltip_data']['quality']
-            # print(asset_data['tooltip_data']['quality'])
-            gimg = asset_data['tooltip_data']['gimg']
-            if gimg is not None:
-                gimg = bpy.data.images[gimg]
-            if gimg:
-                self.gravatar_image.set_image(gimg.filepath
-                                              )
-            # print('moving tooltip')
-            properties_width = 0
-            for r in bpy.context.area.regions:
-                if r.type == 'UI':
-                    properties_width = r.width
-            tooltip_x = min(int(widget.x_screen),
-                            int(bpy.context.region.width - self.tooltip_panel.width - properties_width))
-            tooltip_y = int(widget.y_screen + widget.height)
-            # self.init_tooltip()
-            self.tooltip_panel.set_location(tooltip_x, tooltip_y)
-            self.tooltip_panel.layout_widgets()
-            # print(tooltip_x, tooltip_y)
-            # bpy.ops.wm.blenderkit_asset_popup('INVOKE_DEFAULT')
-
-    def exit_button(self, widget):
-        # print(f'exit {widget.search_index} , {self.active_index}')
-        # this condition checks if there wasn't another button already entered, which can happen with small button gaps
-        if self.active_index == widget.button_index + self.scroll_offset:
-            scene = bpy.context.scene
-            ui_props = bpy.context.window_manager.blenderkitUI
-            ui_props.draw_tooltip = False
-            self.draw_tooltip = False
-            self.hide_tooltip()
-        # popup asset card on mouse down
-        # if utils.experimental_enabled():
-        #     h = widget.get_area_height()
-        #     print(h,h-self.mouse_y,self.panel.y_screen, self.panel.y,widget.y_screen, widget.y)
-        # if utils.experimental_enabled() and self.mouse_y<widget.y_screen:
-        #     self.active_index = widget.button_index + self.scroll_offset
-        # bpy.ops.wm.blenderkit_asset_popup('INVOKE_DEFAULT')
-
-    def drag_drop_asset(self, widget):
-        bpy.ops.view3d.asset_drag_drop('INVOKE_DEFAULT', asset_search_index=widget.search_index + self.scroll_offset)
-
-    def cancel_press(self, widget):
-        self.finish()
-
-    def asset_menu(self, widget):
-        self.hide_tooltip()
-        bpy.ops.wm.blenderkit_asset_popup('INVOKE_DEFAULT')
-        # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_asset_menu')
-
-    def search_more(self):
-        sro = bpy.context.window_manager.get('search results orig')
-        if sro is None:
-            return
-        if sro.get('next') is None:
-            return
-        search_props = utils.get_search_props()
-        if search_props.is_searching:
-            return
-
-        blenderkit.search.search(get_next=True)
-
-    def update_validation_icon(self, asset_button, asset_data):
-        if utils.profile_is_validator():
-            ar = bpy.context.window_manager.get('asset ratings')
-            rating = ar.get(asset_data['id'])
-            if rating is not None:
-                rating = rating.to_dict()
-
-            v_icon = ui.verification_icons[asset_data.get('verificationStatus', 'validated')]
-            if v_icon is not None:
-                img_fp = paths.get_addon_thumbnail_path(v_icon)
-                asset_button.validation_icon.set_image(img_fp)
-                asset_button.validation_icon.visible = True
-            elif rating in (None, {}):
-                v_icon = 'star_grey.png'
-                img_fp = paths.get_addon_thumbnail_path(v_icon)
-                asset_button.validation_icon.set_image(img_fp)
-                asset_button.validation_icon.visible = True
-            else:
-                asset_button.validation_icon.visible = False
-        else:
-            if asset_data.get('canDownload', True) == 0:
-                img_fp = paths.get_addon_thumbnail_path('locked.png')
-                asset_button.validation_icon.set_image(img_fp)
-            else:
-                asset_button.validation_icon.visible = False
-
-    def update_images(self):
-        sr = bpy.context.window_manager.get('search results')
-        if not sr:
-            return
-        for asset_button in self.asset_buttons:
-            if asset_button.visible:
-                asset_button.asset_index = asset_button.button_index + self.scroll_offset
-                # print(asset_button.asset_index, len(sr))
-                if asset_button.asset_index < len(sr):
-                    asset_button.visible = True
-
-                    asset_data = sr[asset_button.asset_index]
-                    if asset_data is None:
-                        continue
-                    iname = blenderkit.utils.previmg_name(asset_button.asset_index)
-                    # show indices for debug purposes
-                    # asset_button.text = str(asset_button.asset_index)
-                    img = bpy.data.images.get(iname)
-                    if img is None or len(img.pixels) == 0:
-                        img_filepath = paths.get_addon_thumbnail_path('thumbnail_notready.jpg')
-                    else:
-                        img_filepath = img.filepath
-                    # print(asset_button.button_index, img_filepath)
-
-                    asset_button.set_image(img_filepath)
-                    self.update_validation_icon(asset_button, asset_data)
-
-                    if utils.profile_is_validator() and asset_data['verificationStatus'] == 'uploaded':
-                        over_limit = utils.is_upload_old(asset_data)
-                        if over_limit:
-                            redness = min(over_limit * .05, 0.7)
-                            asset_button.red_alert.bg_color = (1, 0, 0, redness)
-                            asset_button.red_alert.visible = True
-                        else:
-                            asset_button.red_alert.visible = False
-                    elif utils.profile_is_validator():
-                        asset_button.red_alert.visible = False
-            else:
-                asset_button.visible = False
-                asset_button.validation_icon.visible = False
-                if utils.profile_is_validator():
-                    asset_button.red_alert.visible = False
-
-    def scroll_update(self):
-        sr = bpy.context.window_manager.get('search results')
-        sro = bpy.context.window_manager.get('search results orig')
-        # empty results
-        if sr is None:
-            self.button_scroll_down.visible = False
-            self.button_scroll_up.visible = False
-            return
-
-        self.scroll_offset = min(self.scroll_offset, len(sr) - (self.wcount * self.hcount))
-        self.scroll_offset = max(self.scroll_offset, 0)
-        self.update_images()
-
-        # print(sro)
-        if sro['count'] > len(sr) and len(sr) - self.scroll_offset < (self.wcount * self.hcount) + 15:
-            self.search_more()
-
-        if self.scroll_offset == 0:
-            self.button_scroll_down.visible = False
-        else:
-            self.button_scroll_down.visible = True
-
-        if self.scroll_offset >= sro['count'] - (self.wcount * self.hcount):
-            self.button_scroll_up.visible = False
-        else:
-            self.button_scroll_up.visible = True
-
-    def search_by_author(self, asset_index):
-        sr = bpy.context.window_manager['search results']
-        asset_data = sr[asset_index]
-        a = asset_data['author']['id']
-        if a is not None:
-            sprops = utils.get_search_props()
-            sprops.search_keywords = ''
-            sprops.search_verification_status = 'ALL'
-            # utils.p('author:', a)
-            search.search(author_id=a)
-        return True
-
-    def handle_key_input(self, event):
-        if event.type == 'A':
-            self.search_by_author(self.active_index)
-            return True
-        if event.type == 'X' and self.active_index > -1:
-            # delete downloaded files for this asset
-            sr = bpy.context.window_manager['search results']
-            asset_data = sr[self.active_index]
-            print('delete asset from local drive:' + asset_data['name'])
-            paths.delete_asset_debug(asset_data)
-            asset_data['downloaded'] = 0
-            return True
-        if event.type == 'W' and self.active_index > -1:
-            sr = bpy.context.window_manager['search results']
-            asset_data = sr[self.active_index]
-            a = bpy.context.window_manager['bkit authors'].get(asset_data['author']['id'])
-            if a is not None:
-                utils.p('author:', a)
-                if a.get('aboutMeUrl') is not None:
-                    bpy.ops.wm.url_open(url=a['aboutMeUrl'])
-            return True
-        # FastRateMenu
-        if event.type == 'R' and self.active_index > -1:
-            sr = bpy.context.window_manager['search results']
-            asset_data = sr[self.active_index]
-            if not utils.user_is_owner(asset_data=asset_data):
-                bpy.ops.wm.blenderkit_menu_rating_upload(asset_name = asset_data['name'], asset_id =asset_data['id'], asset_type = asset_data['assetType'])
-            return True
-        return False
-
-    def scroll_up(self, widget):
-        self.scroll_offset += self.wcount * self.hcount
-        self.scroll_update()
-
-    def scroll_down(self, widget):
-        self.scroll_offset -= self.wcount * self.hcount
-        self.scroll_update()
-
-
-def register():
-    bpy.utils.register_class(BlenderKitAssetBarOperator)
-
-
-def unregister():
-    bpy.utils.unregister_class(BlenderKitAssetBarOperator)
diff --git a/blenderkit/asset_inspector.py b/blenderkit/asset_inspector.py
deleted file mode 100644
index cbb9517a5f6fa8c745888d023e1aa9ae319d5fdd..0000000000000000000000000000000000000000
--- a/blenderkit/asset_inspector.py
+++ /dev/null
@@ -1,393 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import utils
-
-import bpy
-from object_print3d_utils import operators as ops
-
-RENDER_OBTYPES = ['MESH', 'CURVE', 'SURFACE', 'METABALL', 'TEXT']
-
-
-def check_material(props, mat):
-    e = bpy.context.scene.render.engine
-    shaders = []
-    textures = []
-    props.texture_count = 0
-    props.node_count = 0
-    props.total_megapixels = 0
-    props.is_procedural = True
-
-    if e == 'CYCLES':
-
-        if mat.node_tree is not None:
-            checknodes = mat.node_tree.nodes[:]
-            while len(checknodes) > 0:
-                n = checknodes.pop()
-                props.node_count += 1
-                if n.type == 'GROUP':  # dive deeper here.
-                    checknodes.extend(n.node_tree.nodes)
-                if len(n.outputs) == 1 and n.outputs[0].type == 'SHADER' and n.type != 'GROUP':
-                    if n.type not in shaders:
-                        shaders.append(n.type)
-                if n.type == 'TEX_IMAGE':
-
-                    if n.image is not None:
-                        mattype = 'image based'
-                        props.is_procedural = False
-                        if n.image not in textures:
-                            textures.append(n.image)
-                            props.texture_count += 1
-                            props.total_megapixels += (n.image.size[0] * n.image.size[1])
-
-                            maxres = max(n.image.size[0], n.image.size[1])
-                            props.texture_resolution_max = max(props.texture_resolution_max, maxres)
-                            minres = min(n.image.size[0], n.image.size[1])
-                            if props.texture_resolution_min == 0:
-                                props.texture_resolution_min = minres
-                            else:
-                                props.texture_resolution_min = min(props.texture_resolution_min, minres)
-
-    props.shaders = ''
-    for s in shaders:
-        if s.startswith('BSDF_'):
-            s = s[5:]
-        s = s.lower().replace('_', ' ')
-        props.shaders += (s + ', ')
-
-
-def check_render_engine(props, obs):
-    ob = obs[0]
-    m = None
-
-    e = bpy.context.scene.render.engine
-    mattype = None
-    materials = []
-    shaders = []
-    textures = []
-    props.uv = False
-    props.texture_count = 0
-    props.total_megapixels = 0
-    props.node_count = 0
-    for ob in obs:  # TODO , this is duplicated here for other engines, otherwise this should be more clever.
-        for ms in ob.material_slots:
-            if ms.material is not None:
-                m = ms.material
-                if m.name not in materials:
-                    materials.append(m.name)
-        if ob.type == 'MESH' and len(ob.data.uv_layers) > 0:
-            props.uv = True
-
-    if e == 'BLENDER_RENDER':
-        props.engine = 'BLENDER_INTERNAL'
-    elif e == 'CYCLES':
-
-        props.engine = 'CYCLES'
-
-        for mname in materials:
-            m = bpy.data.materials[mname]
-            if m is not None and m.node_tree is not None:
-                checknodes = m.node_tree.nodes[:]
-                while len(checknodes) > 0:
-                    n = checknodes.pop()
-                    props.node_count +=1
-                    if n.type == 'GROUP':  # dive deeper here.
-                        checknodes.extend(n.node_tree.nodes)
-                    if len(n.outputs) == 1 and n.outputs[0].type == 'SHADER' and n.type != 'GROUP':
-                        if n.type not in shaders:
-                            shaders.append(n.type)
-                    if n.type == 'TEX_IMAGE':
-
-
-                        if n.image is not None and n.image not in textures:
-                            props.is_procedural = False
-                            mattype = 'image based'
-
-                            textures.append(n.image)
-                            props.texture_count += 1
-                            props.total_megapixels += (n.image.size[0] * n.image.size[1])
-
-                            maxres = max(n.image.size[0], n.image.size[1])
-                            props.texture_resolution_max = max(props.texture_resolution_max, maxres)
-                            minres = min(n.image.size[0], n.image.size[1])
-                            if props.texture_resolution_min == 0:
-                                props.texture_resolution_min = minres
-                            else:
-                                props.texture_resolution_min = min(props.texture_resolution_min, minres)
-
-
-        # if mattype == None:
-        #    mattype = 'procedural'
-        # tags['material type'] = mattype
-
-    elif e == 'BLENDER_GAME':
-        props.engine = 'BLENDER_GAME'
-
-    # write to object properties.
-    props.materials = ''
-    props.shaders = ''
-    for m in materials:
-        props.materials += (m + ', ')
-    for s in shaders:
-        if s.startswith('BSDF_'):
-            s = s[5:]
-        s = s.lower()
-        s = s.replace('_', ' ')
-        props.shaders += (s + ', ')
-
-
-def check_printable(props, obs):
-    if len(obs) == 1:
-        check_cls = (
-            ops.Print3DCheckSolid,
-            ops.Print3DCheckIntersections,
-            ops.Print3DCheckDegenerate,
-            ops.Print3DCheckDistorted,
-            ops.Print3DCheckThick,
-            ops.Print3DCheckSharp,
-            # ops.Print3DCheckOverhang,
-        )
-
-        ob = obs[0]
-
-        info = []
-        for cls in check_cls:
-            cls.main_check(ob, info)
-
-        printable = True
-        for item in info:
-            passed = item[0].endswith(' 0')
-            if not passed:
-                # print(item[0])
-                printable = False
-
-        props.printable_3d = printable
-
-
-def check_rig(props, obs):
-    for ob in obs:
-        if ob.type == 'ARMATURE':
-            props.rig = True
-
-
-def check_anim(props, obs):
-    animated = False
-    for ob in obs:
-        if ob.animation_data is not None:
-            a = ob.animation_data.action
-            if a is not None:
-                for c in a.fcurves:
-                    if len(c.keyframe_points) > 1:
-                        animated = True
-
-                        # c.keyframe_points.remove(c.keyframe_points[0])
-    if animated:
-        props.animated = True
-
-
-def check_meshprops(props, obs):
-    ''' checks polycount, manifold, mesh parts (not implemented)'''
-    fc = 0
-    fcr = 0
-    tris = 0
-    quads = 0
-    ngons = 0
-    vc = 0
-
-    edges_counts = {}
-    manifold = True
-
-    for ob in obs:
-        if ob.type == 'MESH' or ob.type == 'CURVE':
-            ob_eval = None
-            if ob.type == 'CURVE':
-                # depsgraph = bpy.context.evaluated_depsgraph_get()
-                # object_eval = ob.evaluated_get(depsgraph)
-                mesh = ob.to_mesh()
-            else:
-                mesh = ob.data
-            fco = len(mesh.polygons)
-            fc += fco
-            vc += len(mesh.vertices)
-            fcor = fco
-            for f in mesh.polygons:
-                # face sides counter
-                if len(f.vertices) == 3:
-                    tris += 1
-                elif len(f.vertices) == 4:
-                    quads += 1
-                elif len(f.vertices) > 4:
-                    ngons += 1
-
-                # manifold counter
-                for i, v in enumerate(f.vertices):
-                    v1 = f.vertices[i - 1]
-                    e = (min(v, v1), max(v, v1))
-                    edges_counts[e] = edges_counts.get(e, 0) + 1
-
-            # all meshes have to be manifold for this to work.
-            manifold = manifold and not any(i in edges_counts.values() for i in [0, 1, 3, 4])
-
-            for m in ob.modifiers:
-                if m.type == 'SUBSURF' or m.type == 'MULTIRES':
-                    fcor *= 4 ** m.render_levels
-                if m.type == 'SOLIDIFY':  # this is rough estimate, not to waste time with evaluating all nonmanifold edges
-                    fcor *= 2
-                if m.type == 'ARRAY':
-                    fcor *= m.count
-                if m.type == 'MIRROR':
-                    fcor *= 2
-                if m.type == 'DECIMATE':
-                    fcor *= m.ratio
-            fcr += fcor
-
-            if ob_eval:
-                ob_eval.to_mesh_clear()
-
-    # write out props
-    props.face_count = fc
-    props.face_count_render = fcr
-    # print(tris, quads, ngons)
-    if quads > 0 and tris == 0 and ngons == 0:
-        props.mesh_poly_type = 'QUAD'
-    elif quads > tris and quads > ngons:
-        props.mesh_poly_type = 'QUAD_DOMINANT'
-    elif tris > quads and tris > quads:
-        props.mesh_poly_type = 'TRI_DOMINANT'
-    elif quads == 0 and tris > 0 and ngons == 0:
-        props.mesh_poly_type = 'TRI'
-    elif ngons > quads and ngons > tris:
-        props.mesh_poly_type = 'NGON'
-    else:
-        props.mesh_poly_type = 'OTHER'
-
-    props.manifold = manifold
-
-
-def countObs(props, obs):
-    ob_types = {}
-    count = len(obs)
-    for ob in obs:
-        otype = ob.type.lower()
-        ob_types[otype] = ob_types.get(otype, 0) + 1
-    props.object_count = count
-
-
-def check_modifiers(props, obs):
-    # modif_mapping = {
-    # }
-    modifiers = []
-    for ob in obs:
-        for m in ob.modifiers:
-            mtype = m.type
-            mtype = mtype.replace('_', ' ')
-            mtype = mtype.lower()
-            # mtype = mtype.capitalize()
-            if mtype not in modifiers:
-                modifiers.append(mtype)
-            if m.type == 'SMOKE':
-                if m.smoke_type == 'FLOW':
-                    smt = m.flow_settings.smoke_flow_type
-                    if smt == 'BOTH' or smt == 'FIRE':
-                        modifiers.append('fire')
-
-    # for mt in modifiers:
-    effectmodifiers = ['soft body', 'fluid simulation', 'particle system', 'collision', 'smoke', 'cloth',
-                       'dynamic paint']
-    for m in modifiers:
-        if m in effectmodifiers:
-            props.simulation = True
-    if ob.rigid_body is not None:
-        props.simulation = True
-        modifiers.append('rigid body')
-    finalstr = ''
-    for m in modifiers:
-        finalstr += m
-        finalstr += ','
-    props.modifiers = finalstr
-
-
-def get_autotags():
-    """ call all analysis functions """
-    ui = bpy.context.window_manager.blenderkitUI
-    if ui.asset_type == 'MODEL':
-        ob = utils.get_active_model()
-        obs = utils.get_hierarchy(ob)
-        props = ob.blenderkit
-        if props.name == "":
-            props.name = ob.name
-
-        # reset some properties here, because they might not get re-filled at all when they aren't needed anymore.
-        props.texture_resolution_max = 0
-        props.texture_resolution_min = 0
-        # disabled printing checking, some 3d print addon bug.
-        # check_printable( props, obs)
-        check_render_engine(props, obs)
-
-        dim, bbox_min, bbox_max = utils.get_dimensions(obs)
-        props.dimensions = dim
-        props.bbox_min = bbox_min
-        props.bbox_max = bbox_max
-
-        check_rig(props, obs)
-        check_anim(props, obs)
-        check_meshprops(props, obs)
-        check_modifiers(props, obs)
-        countObs(props, obs)
-    elif ui.asset_type == 'MATERIAL':
-        # reset some properties here, because they might not get re-filled at all when they aren't needed anymore.
-
-        mat = utils.get_active_asset()
-        props = mat.blenderkit
-        props.texture_resolution_max = 0
-        props.texture_resolution_min = 0
-        check_material(props, mat)
-    elif ui.asset_type == 'HDR':
-        # reset some properties here, because they might not get re-filled at all when they aren't needed anymore.
-
-        hdr = utils.get_active_asset()
-        props = hdr.blenderkit
-        props.texture_resolution_max = max(hdr.size[0],hdr.size[1])
-
-
-class AutoFillTags(bpy.types.Operator):
-    """Fill tags for asset. Now run before upload, no need to interact from user side"""
-    bl_idname = "object.blenderkit_auto_tags"
-    bl_label = "Generate Auto Tags for BlenderKit"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    @classmethod
-    def poll(cls, context):
-        return utils.uploadable_asset_poll()
-
-    def execute(self, context):
-        get_autotags()
-        return {'FINISHED'}
-
-
-def register_asset_inspector():
-    bpy.utils.register_class(AutoFillTags)
-
-
-def unregister_asset_inspector():
-    bpy.utils.unregister_class(AutoFillTags)
-
-
-if __name__ == "__main__":
-    register()
diff --git a/blenderkit/asset_pack_bg.py b/blenderkit/asset_pack_bg.py
deleted file mode 100644
index c59ca08d5d1961d83b5178ef564cb46342fa3686..0000000000000000000000000000000000000000
--- a/blenderkit/asset_pack_bg.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import sys
-import json
-from blenderkit import resolutions
-
-BLENDERKIT_EXPORT_DATA = sys.argv[-1]
-
-if __name__ == "__main__":
-    resolutions.run_bg(sys.argv[-1])
diff --git a/blenderkit/autothumb.py b/blenderkit/autothumb.py
deleted file mode 100644
index 330d31a2f3dafb83d7f75392520352cdbbcdf1d0..0000000000000000000000000000000000000000
--- a/blenderkit/autothumb.py
+++ /dev/null
@@ -1,671 +0,0 @@
-# ##### 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 #####
-
-from blenderkit import paths, utils, bg_blender, ui_panels, icons, tasks_queue, download
-
-import tempfile, os, subprocess, json, sys
-
-import bpy
-from bpy.props import (
-    FloatProperty,
-    IntProperty,
-    EnumProperty,
-    BoolProperty,
-    StringProperty,
-)
-
-BLENDERKIT_EXPORT_DATA_FILE = "data.json"
-
-thumbnail_resolutions = (
-    ('256', '256', ''),
-    ('512', '512', ''),
-    ('1024', '1024 - minimum for public', ''),
-    ('2048', '2048', ''),
-)
-
-thumbnail_angles = (
-    ('DEFAULT', 'default', ''),
-    ('FRONT', 'front', ''),
-    ('SIDE', 'side', ''),
-    ('TOP', 'top', ''),
-)
-
-thumbnail_snap = (
-    ('GROUND', 'ground', ''),
-    ('WALL', 'wall', ''),
-    ('CEILING', 'ceiling', ''),
-    ('FLOAT', 'floating', ''),
-)
-
-
-def get_texture_ui(tpath, iname):
-    tex = bpy.data.textures.get(iname)
-
-    if tpath.startswith('//'):
-        tpath = bpy.path.abspath(tpath)
-
-    if not tex or not tex.image or not tex.image.filepath == tpath:
-        tasks_queue.add_task((utils.get_hidden_image, (tpath, iname)), only_last=True)
-        tasks_queue.add_task((utils.get_hidden_texture, (iname,)), only_last=True)
-        return None
-    return tex
-
-
-def check_thumbnail(props, imgpath):
-    img = utils.get_hidden_image(imgpath, 'upload_preview', force_reload=True)
-    # print(' check thumbnail ', img)
-    if img is not None:  # and img.size[0] == img.size[1] and img.size[0] >= 512 and (
-        # img.file_format == 'JPEG' or img.file_format == 'PNG'):
-        props.has_thumbnail = True
-        props.thumbnail_generating_state = ''
-
-        tex = utils.get_hidden_texture(img.name)
-        # pcoll = icons.icon_collections["previews"]
-        # pcoll.load(img.name, img.filepath, 'IMAGE')
-
-        return img
-    else:
-        props.has_thumbnail = False
-    output = ''
-    if img is None or img.size[0] == 0 or img.filepath.find('thumbnail_notready.jpg') > -1:
-        output += 'No thumbnail or wrong file path\n'
-    else:
-        pass;
-        # this is causing problems on some platforms, don't know why..
-        # if img.size[0] != img.size[1]:
-        #     output += 'image not a square\n'
-        # if img.size[0] < 512:
-        #     output += 'image too small, should be at least 512x512\n'
-        # if img.file_format != 'JPEG' or img.file_format != 'PNG':
-        #     output += 'image has to be a jpeg or png'
-    props.thumbnail_generating_state = output
-
-
-def update_upload_model_preview(self, context):
-    ob = utils.get_active_model()
-    if ob is not None:
-        props = ob.blenderkit
-        imgpath = props.thumbnail
-        img = check_thumbnail(props, imgpath)
-
-
-def update_upload_scene_preview(self, context):
-    s = bpy.context.scene
-    props = s.blenderkit
-    imgpath = props.thumbnail
-    check_thumbnail(props, imgpath)
-
-
-def update_upload_material_preview(self, context):
-    if hasattr(bpy.context, 'active_object') \
-            and bpy.context.view_layer.objects.active is not None \
-            and bpy.context.active_object.active_material is not None:
-        mat = bpy.context.active_object.active_material
-        props = mat.blenderkit
-        imgpath = props.thumbnail
-        check_thumbnail(props, imgpath)
-
-
-def update_upload_brush_preview(self, context):
-    brush = utils.get_active_brush()
-    if brush is not None:
-        props = brush.blenderkit
-        imgpath = bpy.path.abspath(brush.icon_filepath)
-        check_thumbnail(props, imgpath)
-
-
-def start_thumbnailer(self=None, json_args=None, props=None, wait=False, add_bg_process=True):
-    # Prepare to save the file
-
-    binary_path = bpy.app.binary_path
-    script_path = os.path.dirname(os.path.realpath(__file__))
-
-    ext = '.blend'
-
-    tfpath = paths.get_thumbnailer_filepath()
-    datafile = os.path.join(json_args['tempdir'], BLENDERKIT_EXPORT_DATA_FILE)
-    try:
-        with open(datafile, 'w', encoding='utf-8') as s:
-            json.dump(json_args, s, ensure_ascii=False, indent=4)
-
-        proc = subprocess.Popen([
-            binary_path,
-            "--background",
-            "-noaudio",
-            tfpath,
-            "--python", os.path.join(script_path, "autothumb_model_bg.py"),
-            "--", datafile,
-        ], bufsize=1, stdout=subprocess.PIPE, stdin=subprocess.PIPE, creationflags=utils.get_process_flags())
-
-        eval_path_computing = "bpy.data.objects['%s'].blenderkit.is_generating_thumbnail" % json_args['asset_name']
-        eval_path_state = "bpy.data.objects['%s'].blenderkit.thumbnail_generating_state" % json_args['asset_name']
-        eval_path = "bpy.data.objects['%s']" % json_args['asset_name']
-
-        bg_blender.add_bg_process(name = f"{json_args['asset_name']} thumbnailer" ,eval_path_computing=eval_path_computing, eval_path_state=eval_path_state,
-                                  eval_path=eval_path, process_type='THUMBNAILER', process=proc)
-
-
-    except Exception as e:
-        self.report({'WARNING'}, "Error while exporting file: %s" % str(e))
-        return {'FINISHED'}
-
-
-def start_material_thumbnailer(self=None, json_args=None, props=None, wait=False, add_bg_process=True):
-    '''
-
-    Parameters
-    ----------
-    self
-    json_args - all arguments:
-    props - blenderkit upload props with thumbnail settings, to communicate back, if not present, not used.
-    wait - wait for the rendering to finish
-
-    Returns
-    -------
-
-    '''
-    if props:
-        props.is_generating_thumbnail = True
-        props.thumbnail_generating_state = 'starting blender instance'
-
-    binary_path = bpy.app.binary_path
-    script_path = os.path.dirname(os.path.realpath(__file__))
-
-    tfpath = paths.get_material_thumbnailer_filepath()
-    datafile = os.path.join(json_args['tempdir'], BLENDERKIT_EXPORT_DATA_FILE)
-
-    try:
-        with open(datafile, 'w', encoding='utf-8') as s:
-            json.dump(json_args, s, ensure_ascii=False, indent=4)
-
-        proc = subprocess.Popen([
-            binary_path,
-            "--background",
-            "-noaudio",
-            tfpath,
-            "--python", os.path.join(script_path, "autothumb_material_bg.py"),
-            "--", datafile,
-        ], bufsize=1, stdout=subprocess.PIPE, stdin=subprocess.PIPE, creationflags=utils.get_process_flags())
-
-        eval_path_computing = "bpy.data.materials['%s'].blenderkit.is_generating_thumbnail" % json_args['asset_name']
-        eval_path_state = "bpy.data.materials['%s'].blenderkit.thumbnail_generating_state" % json_args['asset_name']
-        eval_path = "bpy.data.materials['%s']" % json_args['asset_name']
-
-        bg_blender.add_bg_process(name=f"{json_args['asset_name']} thumbnailer", eval_path_computing=eval_path_computing,
-                                  eval_path_state=eval_path_state,
-                                  eval_path=eval_path, process_type='THUMBNAILER', process=proc)
-        if props:
-            props.thumbnail_generating_state = 'Saving .blend file'
-
-        if wait:
-            while proc.poll() is None:
-                stdout_data, stderr_data = proc.communicate()
-                print(stdout_data)
-    except Exception as e:
-        if self:
-            self.report({'WARNING'}, "Error while packing file: %s" % str(e))
-        else:
-            print(e)
-        return {'FINISHED'}
-
-
-class GenerateThumbnailOperator(bpy.types.Operator):
-    """Generate Cycles thumbnail for model assets"""
-    bl_idname = "object.blenderkit_generate_thumbnail"
-    bl_label = "BlenderKit Thumbnail Generator"
-    bl_options = {'REGISTER', 'INTERNAL'}
-
-    @classmethod
-    def poll(cls, context):
-        return bpy.context.view_layer.objects.active is not None
-
-    def draw(self, context):
-        ob = bpy.context.active_object
-        while ob.parent is not None:
-            ob = ob.parent
-        props = ob.blenderkit
-        layout = self.layout
-        layout.label(text='thumbnailer settings')
-        layout.prop(props, 'thumbnail_background_lightness')
-        layout.prop(props, 'thumbnail_angle')
-        layout.prop(props, 'thumbnail_snap_to')
-        layout.prop(props, 'thumbnail_samples')
-        layout.prop(props, 'thumbnail_resolution')
-        layout.prop(props, 'thumbnail_denoising')
-        preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        layout.prop(preferences, "thumbnail_use_gpu")
-
-    def execute(self, context):
-        asset = utils.get_active_model()
-        asset.blenderkit.is_generating_thumbnail = True
-        asset.blenderkit.thumbnail_generating_state = 'starting blender instance'
-
-        tempdir = tempfile.mkdtemp()
-        ext = '.blend'
-        filepath = os.path.join(tempdir, "thumbnailer_blenderkit" + ext)
-
-        path_can_be_relative = True
-        file_dir = os.path.dirname(bpy.data.filepath)
-        if file_dir == '':
-            file_dir = tempdir
-            path_can_be_relative = False
-
-        an_slug = paths.slugify(asset.name)
-        thumb_path = os.path.join(file_dir, an_slug)
-        if path_can_be_relative:
-            rel_thumb_path = os.path.join('//', an_slug)
-        else:
-            rel_thumb_path = thumb_path
-
-
-        i = 0
-        while os.path.isfile(thumb_path + '.jpg'):
-            thumb_path = os.path.join(file_dir, an_slug + '_' + str(i).zfill(4))
-            rel_thumb_path = os.path.join('//', an_slug + '_' + str(i).zfill(4))
-            i += 1
-        bkit = asset.blenderkit
-
-        bkit.thumbnail = rel_thumb_path + '.jpg'
-        bkit.thumbnail_generating_state = 'Saving .blend file'
-
-        # if this isn't here, blender crashes.
-        bpy.context.preferences.filepaths.file_preview_type = 'NONE'
-        # save a copy of actual scene but don't interfere with the users models
-
-        bpy.ops.wm.save_as_mainfile(filepath=filepath, compress=False, copy=True)
-        # get all included objects
-        obs = utils.get_hierarchy(asset)
-        obnames = []
-        for ob in obs:
-            obnames.append(ob.name)
-
-        args_dict = {
-            "type": "material",
-            "asset_name": asset.name,
-            "filepath": filepath,
-            "thumbnail_path": thumb_path,
-            "tempdir": tempdir,
-        }
-        thumbnail_args = {
-            "type": "model",
-            "models": str(obnames),
-            "thumbnail_angle": bkit.thumbnail_angle,
-            "thumbnail_snap_to": bkit.thumbnail_snap_to,
-            "thumbnail_background_lightness": bkit.thumbnail_background_lightness,
-            "thumbnail_resolution": bkit.thumbnail_resolution,
-            "thumbnail_samples": bkit.thumbnail_samples,
-            "thumbnail_denoising": bkit.thumbnail_denoising,
-        }
-        args_dict.update(thumbnail_args)
-
-        start_thumbnailer(self,
-                          json_args=args_dict,
-                          props=asset.blenderkit, wait=False)
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-        # if bpy.data.filepath == '':
-        #     ui_panels.ui_message(
-        #         title="Can't render thumbnail",
-        #         message="please save your file first")
-        #
-        #     return {'FINISHED'}
-
-        return wm.invoke_props_dialog(self)
-
-
-class ReGenerateThumbnailOperator(bpy.types.Operator):
-    """
-        Generate default thumbnail with Cycles renderer and upload it.
-        Works also for assets from search results, without being downloaded before
-    """
-    bl_idname = "object.blenderkit_regenerate_thumbnail"
-    bl_label = "BlenderKit Thumbnail Re-generate"
-    bl_options = {'REGISTER', 'INTERNAL'}
-
-    asset_index: IntProperty(name="Asset Index", description='asset index in search results', default=-1)
-
-    thumbnail_background_lightness: FloatProperty(name="Thumbnail Background Lightness",
-                                                  description="set to make your material stand out", default=1.0,
-                                                  min=0.01, max=10)
-
-    thumbnail_angle: EnumProperty(
-        name='Thumbnail Angle',
-        items=thumbnail_angles,
-        default='DEFAULT',
-        description='thumbnailer angle',
-    )
-
-    thumbnail_snap_to: EnumProperty(
-        name='Model Snaps To:',
-        items=thumbnail_snap,
-        default='GROUND',
-        description='typical placing of the interior. Leave on ground for most objects that respect gravity :)',
-    )
-
-    thumbnail_resolution: EnumProperty(
-        name="Resolution",
-        items=thumbnail_resolutions,
-        description="Thumbnail resolution",
-        default="1024",
-    )
-
-    thumbnail_samples: IntProperty(name="Cycles Samples",
-                                   description="cycles samples setting", default=100,
-                                   min=5, max=5000)
-    thumbnail_denoising: BoolProperty(name="Use Denoising",
-                                      description="Use denoising", default=True)
-
-    @classmethod
-    def poll(cls, context):
-        return True  # bpy.context.view_layer.objects.active is not None
-
-    def draw(self, context):
-        props = self
-        layout = self.layout
-        # layout.label('This will re-generate thumbnail and directly upload it to server. You should see your updated thumbnail online depending ')
-        layout.label(text='thumbnailer settings')
-        layout.prop(props, 'thumbnail_background_lightness')
-        layout.prop(props, 'thumbnail_angle')
-        layout.prop(props, 'thumbnail_snap_to')
-        layout.prop(props, 'thumbnail_samples')
-        layout.prop(props, 'thumbnail_resolution')
-        layout.prop(props, 'thumbnail_denoising')
-        preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        layout.prop(preferences, "thumbnail_use_gpu")
-
-    def execute(self, context):
-        if not self.asset_index > -1:
-            return {'CANCELLED'}
-
-        # either get the data from search results
-        sr = bpy.context.window_manager['search results']
-        asset_data = sr[self.asset_index].to_dict()
-
-        tempdir = tempfile.mkdtemp()
-
-        an_slug = paths.slugify(asset_data['name'])
-        thumb_path = os.path.join(tempdir, an_slug)
-
-
-        args_dict = {
-            "type": "material",
-            "asset_name": asset_data['name'],
-            "asset_data": asset_data,
-            # "filepath": filepath,
-            "thumbnail_path": thumb_path,
-            "tempdir": tempdir,
-            "do_download": True,
-            "upload_after_render": True,
-        }
-        thumbnail_args = {
-            "type": "model",
-            "thumbnail_angle": self.thumbnail_angle,
-            "thumbnail_snap_to": self.thumbnail_snap_to,
-            "thumbnail_background_lightness": self.thumbnail_background_lightness,
-            "thumbnail_resolution": self.thumbnail_resolution,
-            "thumbnail_samples": self.thumbnail_samples,
-            "thumbnail_denoising": self.thumbnail_denoising,
-        }
-        args_dict.update(thumbnail_args)
-
-        start_thumbnailer(self,
-                          json_args=args_dict,
-                          wait=False)
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-        # if bpy.data.filepath == '':
-        #     ui_panels.ui_message(
-        #         title="Can't render thumbnail",
-        #         message="please save your file first")
-        #
-        #     return {'FINISHED'}
-
-        return wm.invoke_props_dialog(self)
-
-
-class GenerateMaterialThumbnailOperator(bpy.types.Operator):
-    """Generate default thumbnail with Cycles renderer"""
-    bl_idname = "object.blenderkit_generate_material_thumbnail"
-    bl_label = "BlenderKit Material Thumbnail Generator"
-    bl_options = {'REGISTER', 'INTERNAL'}
-
-    @classmethod
-    def poll(cls, context):
-        return bpy.context.view_layer.objects.active is not None
-
-    def check(self, context):
-        return True
-
-    def draw(self, context):
-        layout = self.layout
-        props = bpy.context.active_object.active_material.blenderkit
-        layout.prop(props, 'thumbnail_generator_type')
-        layout.prop(props, 'thumbnail_scale')
-        layout.prop(props, 'thumbnail_background')
-        if props.thumbnail_background:
-            layout.prop(props, 'thumbnail_background_lightness')
-        layout.prop(props, 'thumbnail_resolution')
-        layout.prop(props, 'thumbnail_samples')
-        layout.prop(props, 'thumbnail_denoising')
-        layout.prop(props, 'adaptive_subdivision')
-        preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        layout.prop(preferences, "thumbnail_use_gpu")
-
-    def execute(self, context):
-        asset = bpy.context.active_object.active_material
-        tempdir = tempfile.mkdtemp()
-        filepath = os.path.join(tempdir, "material_thumbnailer_cycles.blend")
-        # if this isn't here, blender crashes.
-        bpy.context.preferences.filepaths.file_preview_type = 'NONE'
-
-        # save a copy of actual scene but don't interfere with the users models
-        bpy.ops.wm.save_as_mainfile(filepath=filepath, compress=False, copy=True)
-
-        thumb_dir = os.path.dirname(bpy.data.filepath)
-        an_slug = paths.slugify(asset.name)
-
-        thumb_path = os.path.join(thumb_dir, an_slug)
-        rel_thumb_path = os.path.join('//', an_slug)
-
-        # auto increase number of the generated thumbnail.
-        i = 0
-        while os.path.isfile(thumb_path + '.png'):
-            thumb_path = os.path.join(thumb_dir, an_slug + '_' + str(i).zfill(4))
-            rel_thumb_path = os.path.join('//', an_slug + '_' + str(i).zfill(4))
-            i += 1
-
-        asset.blenderkit.thumbnail = rel_thumb_path + '.png'
-        bkit = asset.blenderkit
-
-        args_dict = {
-            "type": "material",
-            "asset_name": asset.name,
-            "filepath": filepath,
-            "thumbnail_path": thumb_path,
-            "tempdir": tempdir,
-        }
-
-        thumbnail_args = {
-            "thumbnail_type": bkit.thumbnail_generator_type,
-            "thumbnail_scale": bkit.thumbnail_scale,
-            "thumbnail_background": bkit.thumbnail_background,
-            "thumbnail_background_lightness": bkit.thumbnail_background_lightness,
-            "thumbnail_resolution": bkit.thumbnail_resolution,
-            "thumbnail_samples": bkit.thumbnail_samples,
-            "thumbnail_denoising": bkit.thumbnail_denoising,
-            "adaptive_subdivision": bkit.adaptive_subdivision,
-            "texture_size_meters": bkit.texture_size_meters,
-        }
-        args_dict.update(thumbnail_args)
-        start_material_thumbnailer(self,
-                                   json_args=args_dict,
-                                   props=asset.blenderkit, wait=False)
-
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-        return wm.invoke_props_dialog(self)
-
-
-class ReGenerateMaterialThumbnailOperator(bpy.types.Operator):
-    """
-        Generate default thumbnail with Cycles renderer and upload it.
-        Works also for assets from search results, without being downloaded before
-    """
-    bl_idname = "object.blenderkit_regenerate_material_thumbnail"
-    bl_label = "BlenderKit Material Thumbnail Re-Generator"
-    bl_options = {'REGISTER', 'INTERNAL'}
-
-    asset_index: IntProperty(name="Asset Index", description='asset index in search results', default=-1)
-
-    thumbnail_scale: FloatProperty(name="Thumbnail Object Size",
-                                   description="Size of material preview object in meters."
-                                               "Change for materials that look better at sizes different than 1m",
-                                   default=1, min=0.00001, max=10)
-    thumbnail_background: BoolProperty(name="Thumbnail Background (for Glass only)",
-                                       description="For refractive materials, you might need a background.\n"
-                                                   "Don't use for other types of materials.\n"
-                                                   "Transparent background is preferred",
-                                       default=False)
-    thumbnail_background_lightness: FloatProperty(name="Thumbnail Background Lightness",
-                                                  description="Set to make your material stand out with enough contrast",
-                                                  default=.9,
-                                                  min=0.00001, max=1)
-    thumbnail_samples: IntProperty(name="Cycles Samples",
-                                   description="Cycles samples", default=100,
-                                   min=5, max=5000)
-    thumbnail_denoising: BoolProperty(name="Use Denoising",
-                                      description="Use denoising", default=True)
-    adaptive_subdivision: BoolProperty(name="Adaptive Subdivide",
-                                       description="Use adaptive displacement subdivision", default=False)
-
-    thumbnail_resolution: EnumProperty(
-        name="Resolution",
-        items=thumbnail_resolutions,
-        description="Thumbnail resolution",
-        default="1024",
-    )
-
-    thumbnail_generator_type: EnumProperty(
-        name="Thumbnail Style",
-        items=(
-            ('BALL', 'Ball', ""),
-            ('BALL_COMPLEX', 'Ball complex', 'Complex ball to highlight edgewear or material thickness'),
-            ('FLUID', 'Fluid', 'Fluid'),
-            ('CLOTH', 'Cloth', 'Cloth'),
-            ('HAIR', 'Hair', 'Hair  ')
-        ),
-        description="Style of asset",
-        default="BALL",
-    )
-
-    @classmethod
-    def poll(cls, context):
-        return True  # bpy.context.view_layer.objects.active is not None
-
-    def check(self, context):
-        return True
-
-    def draw(self, context):
-        layout = self.layout
-        props = self
-        layout.prop(props, 'thumbnail_generator_type')
-        layout.prop(props, 'thumbnail_scale')
-        layout.prop(props, 'thumbnail_background')
-        if props.thumbnail_background:
-            layout.prop(props, 'thumbnail_background_lightness')
-        layout.prop(props, 'thumbnail_resolution')
-        layout.prop(props, 'thumbnail_samples')
-        layout.prop(props, 'thumbnail_denoising')
-        layout.prop(props, 'adaptive_subdivision')
-        preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        layout.prop(preferences, "thumbnail_use_gpu")
-
-    def execute(self, context):
-
-        if not self.asset_index > -1:
-            return {'CANCELLED'}
-
-        # either get the data from search results
-        sr = bpy.context.window_manager['search results']
-        asset_data = sr[self.asset_index].to_dict()
-        an_slug = paths.slugify(asset_data['name'])
-
-        tempdir = tempfile.mkdtemp()
-
-        thumb_path = os.path.join(tempdir,an_slug)
-
-        args_dict = {
-            "type": "material",
-            "asset_name": asset_data['name'],
-            "asset_data": asset_data,
-            "thumbnail_path": thumb_path,
-            "tempdir": tempdir,
-            "do_download": True,
-            "upload_after_render": True,
-        }
-        thumbnail_args = {
-            "thumbnail_type": self.thumbnail_generator_type,
-            "thumbnail_scale": self.thumbnail_scale,
-            "thumbnail_background": self.thumbnail_background,
-            "thumbnail_background_lightness": self.thumbnail_background_lightness,
-            "thumbnail_resolution": self.thumbnail_resolution,
-            "thumbnail_samples": self.thumbnail_samples,
-            "thumbnail_denoising": self.thumbnail_denoising,
-            "adaptive_subdivision": self.adaptive_subdivision,
-            "texture_size_meters": utils.get_param(asset_data, 'textureSizeMeters', 1.0),
-        }
-        args_dict.update(thumbnail_args)
-        start_material_thumbnailer(self,
-                                   json_args=args_dict,
-                                   wait=False)
-
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        # scene = bpy.context.scene
-        # ui_props = bpy.context.window_manager.blenderkitUI
-        # if ui_props.active_index > -1:
-        #     sr = bpy.context.window_manager['search results']
-        #     self.asset_data = dict(sr[ui_props.active_index])
-        # else:
-        #
-        #     active_asset = utils.get_active_asset_by_type(asset_type = self.asset_type)
-        #     self.asset_data = active_asset.get('asset_data')
-
-        wm = context.window_manager
-        return wm.invoke_props_dialog(self)
-
-
-def register_thumbnailer():
-    bpy.utils.register_class(GenerateThumbnailOperator)
-    bpy.utils.register_class(ReGenerateThumbnailOperator)
-    bpy.utils.register_class(GenerateMaterialThumbnailOperator)
-    bpy.utils.register_class(ReGenerateMaterialThumbnailOperator)
-
-
-def unregister_thumbnailer():
-    bpy.utils.unregister_class(GenerateThumbnailOperator)
-    bpy.utils.unregister_class(ReGenerateThumbnailOperator)
-    bpy.utils.unregister_class(GenerateMaterialThumbnailOperator)
-    bpy.utils.unregister_class(ReGenerateMaterialThumbnailOperator)
diff --git a/blenderkit/autothumb_material_bg.py b/blenderkit/autothumb_material_bg.py
deleted file mode 100644
index 37d7c7833b3096389ab5a7207770b49b8376ffea..0000000000000000000000000000000000000000
--- a/blenderkit/autothumb_material_bg.py
+++ /dev/null
@@ -1,171 +0,0 @@
-# ##### 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 #####
-
-
-
-from blenderkit import utils, append_link, bg_blender, upload_bg, download
-
-import sys, json, math, os
-import bpy
-from pathlib import Path
-
-
-BLENDERKIT_EXPORT_DATA = sys.argv[-1]
-
-
-def render_thumbnails():
-    bpy.ops.render.render(write_still=True, animation=False)
-
-
-def unhide_collection(cname):
-    collection = bpy.context.scene.collection.children[cname]
-    collection.hide_viewport = False
-    collection.hide_render = False
-    collection.hide_select = False
-
-
-if __name__ == "__main__":
-    try:
-        bg_blender.progress('preparing thumbnail scene')
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-        with open(BLENDERKIT_EXPORT_DATA, 'r',encoding='utf-8') as s:
-            data = json.load(s)
-            # append_material(file_name, matname = None, link = False, fake_user = True)
-        if data.get('do_download'):
-            #need to save the file, so that asset doesn't get downloaded into addon directory
-            temp_blend_path = os.path.join(data['tempdir'], 'temp.blend')
-
-            # if this isn't here, blender crashes.
-            bpy.context.preferences.filepaths.file_preview_type = 'NONE'
-
-            bpy.ops.wm.save_as_mainfile(filepath=temp_blend_path)
-
-            asset_data = data['asset_data']
-            has_url = download.get_download_url(asset_data, download.get_scene_id(), user_preferences.api_key, tcom=None,
-                                                resolution='blend')
-            if not has_url:
-                bg_blender.progress("couldn't download asset for thumnbail re-rendering")
-                exit()
-            # download first, or rather make sure if it's already downloaded
-            bg_blender.progress('downloading asset')
-            fpath = download.download_asset_file(asset_data)
-            data['filepath'] = fpath
-
-        mat = append_link.append_material(file_name=data['filepath'], matname=data["asset_name"], link=True,
-                                          fake_user=False)
-
-
-        s = bpy.context.scene
-
-        colmapdict = {
-            'BALL': 'Ball',
-            'BALL_COMPLEX': 'Ball complex',
-            'FLUID': 'Fluid',
-            'CLOTH': 'Cloth',
-            'HAIR': 'Hair'
-        }
-        unhide_collection(colmapdict[data["thumbnail_type"]])
-        if data['thumbnail_background']:
-            unhide_collection('Background')
-            bpy.data.materials["bg checker colorable"].node_tree.nodes['input_level'].outputs['Value'].default_value \
-                = data['thumbnail_background_lightness']
-        tscale = data["thumbnail_scale"]
-        scaler = bpy.context.view_layer.objects['scaler']
-        scaler.scale = (tscale, tscale, tscale)
-        utils.activate(scaler)
-        bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
-
-        bpy.context.view_layer.update()
-
-        for ob in bpy.context.visible_objects:
-            if ob.name[:15] == 'MaterialPreview':
-                utils.activate(ob)
-                bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
-
-                ob.material_slots[0].material = mat
-                ob.data.use_auto_texspace = False
-                ob.data.texspace_size.x = 1 #/ tscale
-                ob.data.texspace_size.y = 1 #/ tscale
-                ob.data.texspace_size.z = 1 #/ tscale
-                if data["adaptive_subdivision"] == True:
-                    ob.cycles.use_adaptive_subdivision = True
-
-                else:
-                    ob.cycles.use_adaptive_subdivision = False
-                ts = data['texture_size_meters']
-                if data["thumbnail_type"] in ['BALL', 'BALL_COMPLEX', 'CLOTH']:
-                   utils.automap(ob.name, tex_size = ts / tscale, just_scale = True, bg_exception=True)
-        bpy.context.view_layer.update()
-
-        s.cycles.volume_step_size = tscale * .1
-
-        if user_preferences.thumbnail_use_gpu:
-            bpy.context.scene.cycles.device = 'GPU'
-
-        s.cycles.samples = data['thumbnail_samples']
-        bpy.context.view_layer.cycles.use_denoising = data['thumbnail_denoising']
-
-        # import blender's HDR here
-        hdr_path = Path('datafiles/studiolights/world/interior.exr')
-        bpath = Path(bpy.utils.resource_path('LOCAL'))
-        ipath = bpath / hdr_path
-        ipath = str(ipath)
-
-        # this  stuff is for mac and possibly linux. For blender // means relative path.
-        # for Mac, // means start of absolute path
-        if ipath.startswith('//'):
-            ipath = ipath[1:]
-
-        img = bpy.data.images['interior.exr']
-        img.filepath = ipath
-        img.reload()
-
-        bpy.context.scene.render.resolution_x = int(data['thumbnail_resolution'])
-        bpy.context.scene.render.resolution_y = int(data['thumbnail_resolution'])
-
-        bpy.context.scene.render.filepath = data['thumbnail_path']
-        bg_blender.progress('rendering thumbnail')
-        # bpy.ops.wm.save_as_mainfile(filepath='C:/tmp/test.blend')
-        # fal
-        render_thumbnails()
-        if data.get('upload_after_render') and data.get('asset_data'):
-            bg_blender.progress('uploading thumbnail')
-            preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-            file = {
-                "type": "thumbnail",
-                "index": 0,
-                "file_path": data['thumbnail_path'] + '.png'
-            }
-            upload_data = {
-                "name": data['asset_data']['name'],
-                "token": preferences.api_key,
-                "id": data['asset_data']['id']
-            }
-            upload_bg.upload_file(upload_data, file)
-        bg_blender.progress('background autothumbnailer finished successfully')
-
-
-    except Exception as e:
-        print(e)
-        import traceback
-
-        traceback.print_exc()
-
-        sys.exit(1)
diff --git a/blenderkit/autothumb_model_bg.py b/blenderkit/autothumb_model_bg.py
deleted file mode 100644
index 2ce7683041a7c99494541247cc17275e3043d41c..0000000000000000000000000000000000000000
--- a/blenderkit/autothumb_model_bg.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# ##### 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 #####
-
-
-
-from blenderkit import utils, append_link, bg_blender, download, upload_bg, upload
-
-import sys, json, math, os
-import bpy
-import mathutils
-
-BLENDERKIT_EXPORT_DATA = sys.argv[-1]
-
-
-def get_obnames():
-    with open(BLENDERKIT_EXPORT_DATA, 'r',encoding='utf-8') as s:
-        data = json.load(s)
-    obnames = eval(data['models'])
-    return obnames
-
-
-def center_obs_for_thumbnail(obs):
-    s = bpy.context.scene
-    # obs = bpy.context.selected_objects
-    parent = obs[0]
-    if parent.type == 'EMPTY' and parent.instance_collection is not None:
-        obs = parent.instance_collection.objects[:]
-
-    while parent.parent != None:
-        parent = parent.parent
-    # reset parent rotation, so we see how it really snaps.
-    parent.rotation_euler = (0, 0, 0)
-    bpy.context.view_layer.update()
-    minx, miny, minz, maxx, maxy, maxz = utils.get_bounds_worldspace(obs)
-
-    cx = (maxx - minx) / 2 + minx
-    cy = (maxy - miny) / 2 + miny
-    for ob in s.collection.objects:
-        ob.select_set(False)
-
-    bpy.context.view_layer.objects.active = parent
-    parent.location += mathutils.Vector((-cx, -cy, -minz))
-
-    camZ = s.camera.parent.parent
-    camZ.location.z = (maxz - minz) / 2
-    dx = (maxx - minx)
-    dy = (maxy - miny)
-    dz = (maxz - minz)
-    r = math.sqrt(dx * dx + dy * dy + dz * dz)
-
-    scaler = bpy.context.view_layer.objects['scaler']
-    scaler.scale = (r, r, r)
-    coef = .7
-    r *= coef
-    camZ.scale = (r, r, r)
-    bpy.context.view_layer.update()
-
-
-def render_thumbnails():
-    bpy.ops.render.render(write_still=True, animation=False)
-
-
-if __name__ == "__main__":
-    try:
-        with open(BLENDERKIT_EXPORT_DATA, 'r',encoding='utf-8') as s:
-            data = json.load(s)
-
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-
-        if data.get('do_download'):
-            # if this isn't here, blender crashes.
-            bpy.context.preferences.filepaths.file_preview_type = 'NONE'
-
-            #need to save the file, so that asset doesn't get downloaded into addon directory
-            temp_blend_path = os.path.join(data['tempdir'], 'temp.blend')
-            bpy.ops.wm.save_as_mainfile(filepath = temp_blend_path)
-
-            bg_blender.progress('Downloading asset')
-            asset_data = data['asset_data']
-            has_url = download.get_download_url(asset_data, download.get_scene_id(), user_preferences.api_key, tcom=None,
-                                                resolution='blend')
-            if not has_url == True:
-                bg_blender.progress("couldn't download asset for thumnbail re-rendering")
-            # download first, or rather make sure if it's already downloaded
-            bg_blender.progress('downloading asset')
-            fpath = download.download_asset_file(asset_data)
-            data['filepath'] = fpath
-            main_object, allobs = append_link.link_collection(fpath,
-                                                          location=(0,0,0),
-                                                          rotation=(0,0,0),
-                                                          link=True,
-                                                          name=asset_data['name'],
-                                                          parent=None)
-            allobs = [main_object]
-        else:
-            bg_blender.progress('preparing thumbnail scene')
-
-            obnames = get_obnames()
-            main_object, allobs = append_link.append_objects(file_name=data['filepath'],
-                                                         obnames=obnames,
-                                                             link=True)
-        bpy.context.view_layer.update()
-
-
-        camdict = {
-            'GROUND': 'camera ground',
-            'WALL': 'camera wall',
-            'CEILING': 'camera ceiling',
-            'FLOAT': 'camera float'
-        }
-
-        bpy.context.scene.camera = bpy.data.objects[camdict[data['thumbnail_snap_to']]]
-        center_obs_for_thumbnail(allobs)
-        bpy.context.scene.render.filepath = data['thumbnail_path']
-        if user_preferences.thumbnail_use_gpu:
-            bpy.context.scene.cycles.device = 'GPU'
-
-        fdict = {
-            'DEFAULT': 1,
-            'FRONT': 2,
-            'SIDE': 3,
-            'TOP': 4,
-        }
-        s = bpy.context.scene
-        s.frame_set(fdict[data['thumbnail_angle']])
-
-        snapdict = {
-            'GROUND': 'Ground',
-            'WALL': 'Wall',
-            'CEILING': 'Ceiling',
-            'FLOAT': 'Float'
-        }
-
-        collection = bpy.context.scene.collection.children[snapdict[data['thumbnail_snap_to']]]
-        collection.hide_viewport = False
-        collection.hide_render = False
-        collection.hide_select = False
-
-        main_object.rotation_euler = (0, 0, 0)
-        bpy.data.materials['bkit background'].node_tree.nodes['Value'].outputs['Value'].default_value \
-            = data['thumbnail_background_lightness']
-        s.cycles.samples = data['thumbnail_samples']
-        bpy.context.view_layer.cycles.use_denoising = data['thumbnail_denoising']
-        bpy.context.view_layer.update()
-
-        # import blender's HDR here
-        # hdr_path = Path('datafiles/studiolights/world/interior.exr')
-        # bpath = Path(bpy.utils.resource_path('LOCAL'))
-        # ipath = bpath / hdr_path
-        # ipath = str(ipath)
-
-        # this  stuff is for mac and possibly linux. For blender // means relative path.
-        # for Mac, // means start of absolute path
-        # if ipath.startswith('//'):
-        #     ipath = ipath[1:]
-        #
-        # img = bpy.data.images['interior.exr']
-        # img.filepath = ipath
-        # img.reload()
-
-        bpy.context.scene.render.resolution_x = int(data['thumbnail_resolution'])
-        bpy.context.scene.render.resolution_y = int(data['thumbnail_resolution'])
-
-        bg_blender.progress('rendering thumbnail')
-        render_thumbnails()
-        fpath = data['thumbnail_path'] + '.jpg'
-        if data.get('upload_after_render') and data.get('asset_data'):
-            # try to patch for the sake of older assets where thumbnail update doesn't work for the reasont
-            # that original thumbnail files aren't available.
-            # upload.patch_individual_metadata(data['asset_data']['id'], {}, user_preferences)
-            bg_blender.progress('uploading thumbnail')
-            file = {
-                "type": "thumbnail",
-                "index": 0,
-                "file_path": fpath
-            }
-            upload_data = {
-                "name": data['asset_data']['name'],
-                "token": user_preferences.api_key,
-                "id": data['asset_data']['id']
-            }
-
-            upload_bg.upload_file(upload_data, file)
-
-        bg_blender.progress('background autothumbnailer finished successfully')
-
-    except:
-        import traceback
-
-        traceback.print_exc()
-        sys.exit(1)
diff --git a/blenderkit/bg_blender.py b/blenderkit/bg_blender.py
deleted file mode 100644
index 8495c076ef4d41881b0225bf84049d8ec9840fee..0000000000000000000000000000000000000000
--- a/blenderkit/bg_blender.py
+++ /dev/null
@@ -1,278 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import utils
-
-import bpy
-import sys, threading, os
-import re
-
-from bpy.props import (
-    EnumProperty,
-)
-
-bg_processes = []
-
-
-class threadCom:  # object passed to threads to read background process stdout info
-    ''' Object to pass data between thread and '''
-
-    def __init__(self, eval_path_computing, eval_path_state, eval_path, process_type, proc, location=None, name=''):
-        # self.obname=ob.name
-        self.name = name
-        self.eval_path_computing = eval_path_computing  # property that gets written to.
-        self.eval_path_state = eval_path_state  # property that gets written to.
-        self.eval_path = eval_path  # property that gets written to.
-        self.process_type = process_type
-        self.outtext = ''
-        self.proc = proc
-        self.lasttext = ''
-        self.message = ''  # the message to be sent.
-        self.progress = 0.0
-        self.location = location
-        self.error = False
-        self.log = ''
-
-
-def threadread(tcom):
-    '''reads stdout of background process.
-    this threads basically waits for a stdout line to come in,
-    fills the data, dies.'''
-    found = False
-    while not found:
-        if tcom.proc.poll() is not None:
-            #process terminated
-            return
-        inline = tcom.proc.stdout.readline()
-        # print('readthread', time.time())
-        inline = str(inline)
-        s = inline.find('progress{')
-        if s > -1:
-            e = inline.find('}')
-            tcom.outtext = inline[s + 9:e]
-            found = True
-            if tcom.outtext.find('%') > -1:
-                tcom.progress = float(re.findall('\d+\.\d+|\d+', tcom.outtext)[0])
-            return
-        if s == -1:
-            s = inline.find('Remaining')
-            if s > -1:
-                # e=inline.find('}')
-                tcom.outtext = inline[s: s + 18]
-                found = True
-                return
-        if len(inline) > 3:
-            print(inline, len(inline))
-        # if inline.find('Error'):
-        #    tcom.error = True
-        #     tcom.outtext = inline[2:]
-
-
-def progress(text, n=None):
-    '''function for reporting during the script, works for background operations in the header.'''
-    # for i in range(n+1):
-    # sys.stdout.flush()
-    text = str(text)
-    if n is None:
-        n = ''
-    else:
-        n = ' ' + ' ' + str(int(n * 1000) / 1000) + '% '
-    spaces = ' ' * (len(text) + 55)
-    try:
-        sys.stdout.write('progress{%s%s}\n' % (text, n))
-
-        sys.stdout.flush()
-    except Exception as e:
-        print('background progress reporting race condition')
-        print(e)
-
-
-# @bpy.app.handlers.persistent
-def bg_update():
-    '''monitoring of background process'''
-    text = ''
-    #utils.p('timer search')
-    # utils.p('start bg_blender timer bg_update')
-
-    s = bpy.context.scene
-
-    global bg_processes
-    if len(bg_processes) == 0:
-        # utils.p('end bg_blender timer bg_update')
-
-        return 2
-    #cleanup dead processes first
-    remove_processes = []
-    for p in bg_processes:
-        if p[1].proc.poll() is not None:
-            remove_processes.append(p)
-    for p in remove_processes:
-        bg_processes.remove(p)
-
-    #Parse process output
-    for p in bg_processes:
-        # proc=p[1].proc
-        readthread = p[0]
-        tcom = p[1]
-        if not readthread.is_alive():
-            readthread.join()
-            # readthread.
-            estring = None
-            if tcom.error:
-                estring = tcom.eval_path_computing + ' = False'
-            tcom.lasttext = tcom.outtext
-            if tcom.outtext != '':
-                tcom.outtext = ''
-                text =tcom.lasttext.replace("'","")
-                estring = tcom.eval_path_state + ' = text'
-            # print(tcom.lasttext)
-            if 'finished successfully' in tcom.lasttext:
-                bg_processes.remove(p)
-                estring = tcom.eval_path_computing + ' = False'
-            else:
-                readthread = threading.Thread(target=threadread, args=([tcom]), daemon=True)
-                readthread.start()
-                p[0] = readthread
-            if estring:
-                try:
-                    exec(estring)
-                except Exception as e:
-                    print('Exception while reading from background process')
-                    print(e)
-
-    # if len(bg_processes) == 0:
-    #     bpy.app.timers.unregister(bg_update)
-    if len(bg_processes) > 0:
-        # utils.p('end bg_blender timer bg_update')
-
-        return .3
-    # utils.p('end bg_blender timer bg_update')
-
-    return 1.
-
-
-process_types = (
-    ('UPLOAD', 'Upload', ''),
-    ('THUMBNAILER', 'Thumbnailer', ''),
-)
-
-process_sources = (
-    ('MODEL', 'Model', 'set of objects'),
-    ('SCENE', 'Scene', 'set of scenes'),
-    ('HDR', 'HDR', 'HDR image'),
-    ('MATERIAL', 'Material', 'any .blend Material'),
-    ('TEXTURE', 'Texture', 'a texture, or texture set'),
-    ('BRUSH', 'Brush', 'brush, can be any type of blender brush'),
-)
-
-
-class KillBgProcess(bpy.types.Operator):
-    '''Remove processes in background'''
-    bl_idname = "object.kill_bg_process"
-    bl_label = "Kill Background Process"
-    bl_options = {'REGISTER'}
-
-    process_type: EnumProperty(
-        name="Type",
-        items=process_types,
-        description="Type of process",
-        default="UPLOAD",
-    )
-
-    process_source: EnumProperty(
-        name="Source",
-        items=process_sources,
-        description="Source of process",
-        default="MODEL",
-    )
-
-    def execute(self, context):
-        s = bpy.context.scene
-
-        cls = bpy.ops.object.convert.__class__
-        # first do the easy stuff...TODO all cases.
-        props = utils.get_upload_props()
-        if self.process_type == 'UPLOAD':
-            props.uploading = False
-        if self.process_type == 'THUMBNAILER':
-            props.is_generating_thumbnail = False
-        global blenderkit_bg_process
-        # print('killing', self.process_source, self.process_type)
-        # then go kill the process. this wasn't working for unsetting props and that was the reason for changing to the method above.
-
-        processes = bg_processes
-        for p in processes:
-
-            tcom = p[1]
-            # print(tcom.process_type, self.process_type)
-            if tcom.process_type == self.process_type:
-                source = eval(tcom.eval_path)
-                kill = False
-                #TODO HDR - add killing of process
-                if source.bl_rna.name == 'Object' and self.process_source == 'MODEL':
-                    if source.name == bpy.context.active_object.name:
-                        kill = True
-                if source.bl_rna.name == 'Scene' and self.process_source == 'SCENE':
-                    if source.name == bpy.context.scene.name:
-                        kill = True
-                if source.bl_rna.name == 'Image' and self.process_source == 'HDR':
-                    ui_props = bpy.context.window_manager.blenderkitUI
-                    if source.name == ui_props.hdr_upload_image.name:
-                        kill = False
-
-                if source.bl_rna.name == 'Material' and self.process_source == 'MATERIAL':
-                    if source.name == bpy.context.active_object.active_material.name:
-                        kill = True
-                if source.bl_rna.name == 'Brush' and self.process_source == 'BRUSH':
-                    brush = utils.get_active_brush()
-                    if brush is not None and source.name == brush.name:
-                        kill = True
-                if kill:
-                    estring = tcom.eval_path_computing + ' = False'
-                    exec(estring)
-                    processes.remove(p)
-                    tcom.proc.kill()
-
-        return {'FINISHED'}
-
-
-def add_bg_process(location=None, name=None, eval_path_computing='', eval_path_state='', eval_path='', process_type='',
-                   process=None):
-    '''adds process for monitoring'''
-    global bg_processes
-    tcom = threadCom(eval_path_computing, eval_path_state, eval_path, process_type, process, location, name)
-    readthread = threading.Thread(target=threadread, args=([tcom]), daemon=True)
-    readthread.start()
-
-    bg_processes.append([readthread, tcom])
-    # if not bpy.app.timers.is_registered(bg_update):
-    #     bpy.app.timers.register(bg_update, persistent=True)
-
-
-def register():
-    bpy.utils.register_class(KillBgProcess)
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if user_preferences.use_timers and not bpy.app.background:
-        bpy.app.timers.register(bg_update)
-
-
-def unregister():
-    bpy.utils.unregister_class(KillBgProcess)
-    if bpy.app.timers.is_registered(bg_update):
-        bpy.app.timers.unregister(bg_update)
diff --git a/blenderkit/bkit_oauth.py b/blenderkit/bkit_oauth.py
deleted file mode 100644
index b4e944a37c79cf7fbbd8d304d69e779084b3f661..0000000000000000000000000000000000000000
--- a/blenderkit/bkit_oauth.py
+++ /dev/null
@@ -1,201 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import tasks_queue, utils, paths, search, categories, oauth, ui, ui_panels, colors, reports
-
-import bpy
-
-import threading
-import requests
-import time
-import logging
-
-
-bk_logger = logging.getLogger('blenderkit')
-
-from bpy.props import (
-    BoolProperty,
-)
-
-CLIENT_ID = "IdFRwa3SGA8eMpzhRVFMg5Ts8sPK93xBjif93x0F"
-PORTS = [62485, 65425, 55428, 49452, 35452, 25152, 5152, 1234]
-
-active_authenticator = None
-
-
-def login_thread(signup=False):
-    global active_authenticator
-    r_url = paths.get_oauth_landing_url()
-    url = paths.get_bkit_url()
-    authenticator = oauth.SimpleOAuthAuthenticator(server_url=url, client_id=CLIENT_ID, ports=PORTS)
-    # we store authenticator globally to be able to ping the server if connection fails.
-    active_authenticator = authenticator
-    thread = threading.Thread(target=login, args=([signup, url, r_url, authenticator]), daemon=True)
-    thread.start()
-
-
-def login(signup, url, r_url, authenticator):
-    try:
-        auth_token, refresh_token, oauth_response = authenticator.get_new_token(register=signup, redirect_url=r_url)
-    except Exception as e:
-        tasks_queue.add_task((reports.add_report, (e, 20, colors.RED)))
-
-    bk_logger.debug('tokens retrieved')
-    tasks_queue.add_task((write_tokens, (auth_token, refresh_token, oauth_response)))
-
-
-def refresh_token_thread():
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if len(preferences.api_key_refresh) > 0 and preferences.refresh_in_progress == False:
-        preferences.refresh_in_progress = True
-        url = paths.get_bkit_url()
-        thread = threading.Thread(target=refresh_token, args=([preferences.api_key_refresh, url]), daemon=True)
-        thread.start()
-    else:
-        reports.add_report('Already Refreshing token, will be ready soon. If this fails, please login again in Login panel.')
-
-
-def refresh_token(api_key_refresh, url):
-    authenticator = oauth.SimpleOAuthAuthenticator(server_url=url, client_id=CLIENT_ID, ports=PORTS)
-    auth_token, refresh_token, oauth_response = authenticator.get_refreshed_token(api_key_refresh)
-    if auth_token is not None and refresh_token is not None:
-        tasks_queue.add_task((write_tokens, (auth_token, refresh_token, oauth_response)))
-    return auth_token, refresh_token, oauth_response
-
-
-def write_tokens(auth_token, refresh_token, oauth_response):
-    bk_logger.debug('writing tokens')
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    preferences.api_key_refresh = refresh_token
-    preferences.api_key = auth_token
-    preferences.api_key_timeout = time.time() + oauth_response['expires_in']
-    preferences.api_key_life = oauth_response['expires_in']
-    preferences.login_attempt = False
-    preferences.refresh_in_progress = False
-    props = utils.get_search_props()
-    if props is not None:
-        props.report = ''
-    reports.add_report('BlenderKit Re-Login success')
-    search.get_profile()
-
-    categories.fetch_categories_thread(auth_token, force = False)
-
-
-class RegisterLoginOnline(bpy.types.Operator):
-    """Login online on BlenderKit webpage"""
-
-    bl_idname = "wm.blenderkit_login"
-    bl_label = "BlenderKit login/signup"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    signup: BoolProperty(
-        name="create a new account",
-        description="True for register, otherwise login",
-        default=False,
-        options={'SKIP_SAVE'}
-    )
-
-    message: bpy.props.StringProperty(
-        name="Message",
-        description="",
-        default="You were logged out from BlenderKit.\n Clicking OK takes you to web login. ")
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def draw(self, context):
-        layout = self.layout
-        utils.label_multiline(layout, text=self.message, width = 300)
-
-    def execute(self, context):
-        preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        preferences.login_attempt = True
-        login_thread(self.signup)
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = bpy.context.window_manager
-        preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        preferences.api_key_refresh = ''
-        preferences.api_key = ''
-        return wm.invoke_props_dialog(self)
-
-
-class Logout(bpy.types.Operator):
-    """Logout from BlenderKit immediately"""
-
-    bl_idname = "wm.blenderkit_logout"
-    bl_label = "BlenderKit logout"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def execute(self, context):
-        preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        preferences.login_attempt = False
-        preferences.api_key_refresh = ''
-        preferences.api_key = ''
-        if bpy.context.window_manager.get('bkit profile'):
-            del (bpy.context.window_manager['bkit profile'])
-        return {'FINISHED'}
-
-
-class CancelLoginOnline(bpy.types.Operator):
-    """Cancel login attempt"""
-
-    bl_idname = "wm.blenderkit_login_cancel"
-    bl_label = "BlenderKit login cancel"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def execute(self, context):
-        global active_authenticator
-        preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        preferences.login_attempt = False
-        try:
-            if active_authenticator is not None:
-                requests.get(active_authenticator.redirect_uri)
-                active_authenticator = None
-        except Exception as e:
-            print('stopped login attempt')
-            print(e)
-        return {'FINISHED'}
-
-
-classes = (
-    RegisterLoginOnline,
-    CancelLoginOnline,
-    Logout,
-)
-
-
-def register():
-    for c in classes:
-        bpy.utils.register_class(c)
-
-
-def unregister():
-    for c in classes:
-        bpy.utils.unregister_class(c)
diff --git a/blenderkit/bl_ui_widgets/__init__.py b/blenderkit/bl_ui_widgets/__init__.py
deleted file mode 100644
index a1db444d83da7db5ea6c4a6766df791efa09574d..0000000000000000000000000000000000000000
--- a/blenderkit/bl_ui_widgets/__init__.py
+++ /dev/null
@@ -1,36 +0,0 @@
-bl_info = {
-    "name": "BL UI Widgets",
-    "description": "UI Widgets to draw in the 3D view",
-    "author": "Jayanam",
-    "version": (0, 6, 4, 2),
-    "blender": (2, 80, 0),
-    "location": "View3D",
-    "category": "Object"}
-
-# Blender imports
-import bpy
-
-from bpy.props import *
-
-
-addon_keymaps = []
-
-def register():
-
-    bpy.utils.register_class(DP_OT_draw_operator)
-    kcfg = bpy.context.window_manager.keyconfigs.addon
-    if kcfg:
-        km = kcfg.keymaps.new(name='3D View', space_type='VIEW_3D')
-
-
-        addon_keymaps.append((km, kmi))
-
-def unregister():
-    for km, kmi in addon_keymaps:
-        km.keymap_items.remove(kmi)
-    addon_keymaps.clear()
-
-    bpy.utils.unregister_class(DP_OT_draw_operator)
-
-if __name__ == "__main__":
-    register()
diff --git a/blenderkit/bl_ui_widgets/bl_ui_button.py b/blenderkit/bl_ui_widgets/bl_ui_button.py
deleted file mode 100644
index db81b9f8e0433fcb8e7d5685a75beec4ea2c3150..0000000000000000000000000000000000000000
--- a/blenderkit/bl_ui_widgets/bl_ui_button.py
+++ /dev/null
@@ -1,205 +0,0 @@
-from . bl_ui_widget import *
-
-import blf
-import bpy
-
-class BL_UI_Button(BL_UI_Widget):
-
-    def __init__(self, x, y, width, height):
-        super().__init__(x, y, width, height)
-        self._text_color        = (1.0, 1.0, 1.0, 1.0)
-        self._hover_bg_color    = (0.5, 0.5, 0.5, 1.0)
-        self._select_bg_color   = (0.7, 0.7, 0.7, 1.0)
-
-        self._text = "Button"
-        self._text_size = 16
-        self._textpos = (x, y)
-
-        self.__state = 0
-        self.__image = None
-        self.__image_size = (24, 24)
-        self.__image_position = (4, 2)
-
-    @property
-    def text_color(self):
-        return self._text_color
-
-    @text_color.setter
-    def text_color(self, value):
-        self._text_color = value
-
-    @property
-    def text(self):
-        return self._text
-
-    @text.setter
-    def text(self, value):
-        self._text = value
-
-    @property
-    def text_size(self):
-        return self._text_size
-
-    @text_size.setter
-    def text_size(self, value):
-        self._text_size = value
-
-    @property
-    def hover_bg_color(self):
-        return self._hover_bg_color
-
-    @hover_bg_color.setter
-    def hover_bg_color(self, value):
-        self._hover_bg_color = value
-
-    @property
-    def select_bg_color(self):
-        return self._select_bg_color
-
-    @select_bg_color.setter
-    def select_bg_color(self, value):
-        self._select_bg_color = value
-
-    def set_image_size(self, imgage_size):
-        self.__image_size = imgage_size
-
-    def set_image_position(self, image_position):
-        self.__image_position = image_position
-
-    def set_image(self, rel_filepath):
-        #first try to access the image, for cases where it can get removed
-        try:
-            self.__image
-            self.__image.filepath
-            self.__image.pixels
-        except:
-            self.__image = None
-        try:
-            if self.__image is None or self.__image.filepath != rel_filepath:
-                self.__image = bpy.data.images.load(rel_filepath, check_existing=True)
-                self.__image.gl_load()
-
-            if self.__image and len(self.__image.pixels) == 0:
-                self.__image.reload()
-                self.__image.gl_load()
-
-        except Exception as e:
-            self.__image = None
-
-    def update(self, x, y):
-        super().update(x, y)
-        self._textpos = [x, y]
-
-    def draw(self):
-        if not self._is_visible:
-            return
-        area_height = self.get_area_height()
-
-        self.shader.bind()
-
-        self.set_colors()
-
-        bgl.glEnable(bgl.GL_BLEND)
-
-        self.batch_panel.draw(self.shader)
-
-        self.draw_image()
-
-        bgl.glDisable(bgl.GL_BLEND)
-
-        # Draw text
-        self.draw_text(area_height)
-
-    def set_colors(self):
-        color = self._bg_color
-        text_color = self._text_color
-
-        # pressed
-        if self.__state == 1:
-            color = self._select_bg_color
-
-        # hover
-        elif self.__state == 2:
-            color = self._hover_bg_color
-
-        self.shader.uniform_float("color", color)
-
-    def draw_text(self, area_height):
-        font_id = 1
-        blf.size(font_id, self._text_size, 72)
-        size = blf.dimensions(0, self._text)
-
-        textpos_y = area_height - self._textpos[1] - (self.height + size[1]) / 2.0
-        blf.position(font_id, self._textpos[0] + (self.width - size[0]) / 2.0, textpos_y + 1, 0)
-
-        r, g, b, a = self._text_color
-        blf.color(font_id, r, g, b, a)
-
-        blf.draw(font_id, self._text)
-
-    def draw_image(self):
-        if self.__image is not None:
-            try:
-                y_screen_flip = self.get_area_height() - self.y_screen
-
-                off_x, off_y =  self.__image_position
-                sx, sy = self.__image_size
-
-                # bottom left, top left, top right, bottom right
-                vertices = (
-                            (self.x_screen + off_x, y_screen_flip - off_y),
-                            (self.x_screen + off_x, y_screen_flip - sy - off_y),
-                            (self.x_screen + off_x + sx, y_screen_flip - sy - off_y),
-                            (self.x_screen + off_x + sx, y_screen_flip - off_y))
-
-                self.shader_img = gpu.shader.from_builtin('2D_IMAGE')
-                self.batch_img = batch_for_shader(self.shader_img, 'TRI_FAN',
-                { "pos" : vertices,
-                "texCoord": ((0, 1), (0, 0), (1, 0), (1, 1))
-                },)
-
-                # send image to gpu if it isn't there already
-                if self.__image.gl_load():
-                    raise Exception()
-
-                bgl.glActiveTexture(bgl.GL_TEXTURE0)
-                bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.__image.bindcode)
-
-                self.shader_img.bind()
-                self.shader_img.uniform_int("image", 0)
-                self.batch_img.draw(self.shader_img)
-                return True
-            except:
-                pass
-
-        return False
-
-    def set_mouse_down(self, mouse_down_func):
-        self.mouse_down_func = mouse_down_func
-
-    def mouse_down(self, x, y):
-        if self.is_in_rect(x,y):
-            self.__state = 1
-            try:
-                self.mouse_down_func(self)
-            except Exception as e:
-                print(e)
-
-            return True
-
-        return False
-
-    def mouse_move(self, x, y):
-        if self.is_in_rect(x,y):
-            if(self.__state != 1):
-
-                # hover state
-                self.__state = 2
-        else:
-            self.__state = 0
-
-    def mouse_up(self, x, y):
-        if self.is_in_rect(x,y):
-            self.__state = 2
-        else:
-            self.__state = 0
diff --git a/blenderkit/bl_ui_widgets/bl_ui_drag_panel.py b/blenderkit/bl_ui_widgets/bl_ui_drag_panel.py
deleted file mode 100644
index 1c318babffca0d5a2f66299db461bb6ea291b9e3..0000000000000000000000000000000000000000
--- a/blenderkit/bl_ui_widgets/bl_ui_drag_panel.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from . bl_ui_widget import *
-
-class BL_UI_Drag_Panel(BL_UI_Widget):
-
-    def __init__(self, x, y, width, height):
-        super().__init__(x,y, width, height)
-        self.drag_offset_x = 0
-        self.drag_offset_y = 0
-        self.is_drag = False
-        self.widgets = []
-
-    def set_location(self, x, y):
-        super().set_location(x,y)
-        self.layout_widgets()
-
-    def add_widget(self, widget):
-        self.widgets.append(widget)
-
-    def add_widgets(self, widgets):
-        self.widgets = widgets
-        self.layout_widgets()
-
-
-    def layout_widgets(self):
-        for widget in self.widgets:
-            widget.update(self.x_screen + widget.x, self.y_screen + widget.y)
-
-    def update(self, x, y):
-        super().update(x - self.drag_offset_x, y + self.drag_offset_y)
-
-    def child_widget_focused(self, x, y):
-        for widget in self.widgets:
-            if widget.is_in_rect(x, y):
-                return True
-        return False
-
-    def mouse_down(self, x, y):
-        if self.child_widget_focused(x, y):
-            return False
-
-        if self.is_in_rect(x,y):
-            height = self.get_area_height()
-            self.is_drag = True
-            self.drag_offset_x = x - self.x_screen
-            self.drag_offset_y = y - (height - self.y_screen)
-            return True
-
-        return False
-
-    def mouse_move(self, x, y):
-        if self.is_drag:
-            height = self.get_area_height()
-            self.update(x, height - y)
-            self.layout_widgets()
-
-    def mouse_up(self, x, y):
-        self.is_drag = False
-        self.drag_offset_x = 0
-        self.drag_offset_y = 0
diff --git a/blenderkit/bl_ui_widgets/bl_ui_draw_op.py b/blenderkit/bl_ui_widgets/bl_ui_draw_op.py
deleted file mode 100644
index bc2e9cb53008c6ac98b0c09edda91211d89c3c14..0000000000000000000000000000000000000000
--- a/blenderkit/bl_ui_widgets/bl_ui_draw_op.py
+++ /dev/null
@@ -1,93 +0,0 @@
-import bpy
-
-from bpy.types import Operator
-
-class BL_UI_OT_draw_operator(Operator):
-    bl_idname = "object.bl_ui_ot_draw_operator"
-    bl_label = "bl ui widgets operator"
-    bl_description = "Operator for bl ui widgets"
-    bl_options = {'REGISTER'}
-
-    def __init__(self):
-        self.draw_handle = None
-        self.draw_event  = None
-        self._finished = False
-
-        self.widgets = []
-
-    def init_widgets(self, context, widgets):
-        self.widgets = widgets
-        for widget in self.widgets:
-            widget.init(context)
-
-    def on_invoke(self, context, event):
-        pass
-
-    def on_finish(self, context):
-        self._finished = True
-
-    def invoke(self, context, event):
-
-        self.on_invoke(context, event)
-
-        args = (self, context)
-
-        self.register_handlers(args, context)
-
-        context.window_manager.modal_handler_add(self)
-
-        self.active_window_pointer = context.window.as_pointer()
-        self.active_area_pointer = context.area.as_pointer()
-        self.active_region_pointer = context.region.as_pointer()
-        return {"RUNNING_MODAL"}
-
-    def register_handlers(self, args, context):
-        self.draw_handle = bpy.types.SpaceView3D.draw_handler_add(self.draw_callback_px, args, "WINDOW", "POST_PIXEL")
-        self.draw_event = context.window_manager.event_timer_add(0.1, window=context.window)
-
-    def unregister_handlers(self, context):
-
-        context.window_manager.event_timer_remove(self.draw_event)
-
-        bpy.types.SpaceView3D.draw_handler_remove(self.draw_handle, "WINDOW")
-
-        self.draw_handle = None
-        self.draw_event  = None
-
-    def handle_widget_events(self, event):
-        result = False
-        for widget in self.widgets:
-            if widget.handle_event(event):
-                result = True
-        return result
-
-    def modal(self, context, event):
-
-        if self._finished:
-            return {'FINISHED'}
-
-        if context.area:
-            context.area.tag_redraw()
-
-        if self.handle_widget_events(event):
-            return {'RUNNING_MODAL'}
-
-        if event.type in {"ESC"}:
-            self.finish()
-
-        return {"PASS_THROUGH"}
-
-    def finish(self):
-        self.unregister_handlers(bpy.context)
-        self.on_finish(bpy.context)
-
-	# Draw handler to paint onto the screen
-    def draw_callback_px(self, op, context):
-        try:
-            if context.area.as_pointer() == self.active_area_pointer:
-                for widget in self.widgets:
-                    widget.draw()
-        except:
-            pass;
-        #     context.window_manager.event_timer_remove(self.draw_event)
-        #     bpy.types.SpaceView3D.draw_handler_remove(self.draw_handle, "WINDOW")
\ No newline at end of file
diff --git a/blenderkit/bl_ui_widgets/bl_ui_image.py b/blenderkit/bl_ui_widgets/bl_ui_image.py
deleted file mode 100644
index a11c52c53412786f21f5a4099ea73b39a49f99ca..0000000000000000000000000000000000000000
--- a/blenderkit/bl_ui_widgets/bl_ui_image.py
+++ /dev/null
@@ -1,97 +0,0 @@
-from . bl_ui_widget import *
-
-import blf
-import bpy
-
-class BL_UI_Image(BL_UI_Widget):
-
-    def __init__(self, x, y, width, height):
-        super().__init__(x, y, width, height)
-
-        self.__state = 0
-        self.__image = None
-        self.__image_size = (24, 24)
-        self.__image_position = (4, 2)
-
-    def set_image_size(self, imgage_size):
-        self.__image_size = imgage_size
-
-    def set_image_position(self, image_position):
-        self.__image_position = image_position
-
-    def set_image(self, rel_filepath):
-        try:
-            if self.__image is None or self.__image.filepath != rel_filepath:
-                self.__image = bpy.data.images.load(rel_filepath, check_existing=True)
-                self.__image.gl_load()
-        except:
-            pass
-
-    def update(self, x, y):
-        super().update(x, y)
-
-    def draw(self):
-        if not self._is_visible:
-            return
-
-        area_height = self.get_area_height()
-
-        self.shader.bind()
-
-        bgl.glEnable(bgl.GL_BLEND)
-
-        self.batch_panel.draw(self.shader)
-
-        self.draw_image()
-
-        bgl.glDisable(bgl.GL_BLEND)
-
-
-    def draw_image(self):
-        if self.__image is not None:
-            try:
-                y_screen_flip = self.get_area_height() - self.y_screen
-
-                off_x, off_y =  self.__image_position
-                sx, sy = self.__image_size
-
-                # bottom left, top left, top right, bottom right
-                vertices = (
-                            (self.x_screen + off_x, y_screen_flip - off_y),
-                            (self.x_screen + off_x, y_screen_flip - sy - off_y),
-                            (self.x_screen + off_x + sx, y_screen_flip - sy - off_y),
-                            (self.x_screen + off_x + sx, y_screen_flip - off_y))
-
-                self.shader_img = gpu.shader.from_builtin('2D_IMAGE')
-                self.batch_img = batch_for_shader(self.shader_img, 'TRI_FAN',
-                { "pos" : vertices,
-                "texCoord": ((0, 1), (0, 0), (1, 0), (1, 1))
-                },)
-
-                # send image to gpu if it isn't there already
-                if self.__image.gl_load():
-                    raise Exception()
-
-                bgl.glActiveTexture(bgl.GL_TEXTURE0)
-                bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.__image.bindcode)
-
-                self.shader_img.bind()
-                self.shader_img.uniform_int("image", 0)
-                self.batch_img.draw(self.shader_img)
-                return True
-            except:
-                pass
-
-        return False
-
-    def set_mouse_down(self, mouse_down_func):
-        self.mouse_down_func = mouse_down_func
-
-    def mouse_down(self, x, y):
-        return False
-
-    def mouse_move(self, x, y):
-        return
-
-    def mouse_up(self, x, y):
-        return
diff --git a/blenderkit/bl_ui_widgets/bl_ui_label.py b/blenderkit/bl_ui_widgets/bl_ui_label.py
deleted file mode 100644
index 37ba09f63701b23efb7d8aeca777436a114a51db..0000000000000000000000000000000000000000
--- a/blenderkit/bl_ui_widgets/bl_ui_label.py
+++ /dev/null
@@ -1,72 +0,0 @@
-from . bl_ui_widget import *
-
-import blf
-
-class BL_UI_Label(BL_UI_Widget):
-
-    def __init__(self, x, y, width, height):
-        super().__init__(x, y, width, height)
-
-        self._text_color        = (1.0, 1.0, 1.0, 1.0)
-        self._text = "Label"
-        self._text_size = 16
-        self._ralign = 'LEFT'
-        self._valign = 'TOP'
-
-    @property
-    def text_color(self):
-        return self._text_color
-
-    @text_color.setter
-    def text_color(self, value):
-        self._text_color = value
-
-    @property
-    def text(self):
-        return self._text
-
-    @text.setter
-    def text(self, value):
-        self._text = value
-
-    @property
-    def text_size(self):
-        return self._text_size
-
-    @text_size.setter
-    def text_size(self, value):
-        self._text_size = value
-
-    def is_in_rect(self, x, y):
-        return False
-
-    def draw(self):
-        if not self._is_visible:
-            return
-
-
-        area_height = self.get_area_height()
-
-        font_id = 1
-        blf.size(font_id, self._text_size, 72)
-        size = blf.dimensions(font_id, self._text)
-
-        textpos_y = area_height - self.y_screen - self.height
-
-        r, g, b, a = self._text_color
-        x = self.x_screen
-        y = textpos_y
-        if self._halign != 'LEFT':
-            width, height = blf.dimensions(font_id, self._text)
-            if self._halign == 'RIGHT':
-                x -= width
-            elif self._halign == 'CENTER':
-                x -= width // 2
-            if self._valign == 'CENTER':
-                y -= height // 2
-            # bottom could be here but there's no reason for it
-        blf.position(font_id, x, y, 0)
-
-        blf.color(font_id, r, g, b, a)
-
-        blf.draw(font_id, self._text)
diff --git a/blenderkit/bl_ui_widgets/bl_ui_widget.py b/blenderkit/bl_ui_widgets/bl_ui_widget.py
deleted file mode 100644
index 90fefddf5cde8fc2fc7062982a79a5c9b56a5ced..0000000000000000000000000000000000000000
--- a/blenderkit/bl_ui_widgets/bl_ui_widget.py
+++ /dev/null
@@ -1,195 +0,0 @@
-import gpu
-import bgl
-
-from gpu_extras.batch import batch_for_shader
-
-class BL_UI_Widget:
-
-    def __init__(self, x, y, width, height):
-        self.x = x
-        self.y = y
-        self.x_screen = x
-        self.y_screen = y
-        self.width = width
-        self.height = height
-        self._bg_color = (0.8, 0.8, 0.8, 1.0)
-        self._tag = None
-        self.context = None
-        self.__inrect = False
-        self._mouse_down = False
-        self._mouse_down_right = False
-        self._is_visible = True
-
-    def set_location(self, x, y):
-        self.x = x
-        self.y = y
-        self.x_screen = x
-        self.y_screen = y
-        self.update(x,y)
-
-    @property
-    def bg_color(self):
-        return self._bg_color
-
-    @bg_color.setter
-    def bg_color(self, value):
-        self._bg_color = value
-
-    @property
-    def visible(self):
-        return self._is_visible
-
-    @visible.setter
-    def visible(self, value):
-        self._is_visible = value
-
-    @property
-    def tag(self):
-        return self._tag
-
-    @tag.setter
-    def tag(self, value):
-        self._tag = value
-
-    def draw(self):
-        if not self._is_visible:
-            return
-
-        self.shader.bind()
-        self.shader.uniform_float("color", self._bg_color)
-
-        bgl.glEnable(bgl.GL_BLEND)
-        self.batch_panel.draw(self.shader)
-        bgl.glDisable(bgl.GL_BLEND)
-
-    def init(self, context):
-        self.context = context
-        self.update(self.x, self.y)
-
-    def update(self, x, y):
-
-        area_height = self.get_area_height()
-        self.x_screen = x
-        self.y_screen = y
-
-        indices = ((0, 1, 2), (0, 2, 3))
-
-        y_screen_flip = area_height - self.y_screen
-
-        # bottom left, top left, top right, bottom right
-        vertices = (
-                    (self.x_screen, y_screen_flip),
-                    (self.x_screen, y_screen_flip - self.height),
-                    (self.x_screen + self.width, y_screen_flip - self.height),
-                    (self.x_screen + self.width, y_screen_flip))
-
-        self.shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
-        self.batch_panel = batch_for_shader(self.shader, 'TRIS', {"pos" : vertices}, indices=indices)
-
-    def handle_event(self, event):
-        if not self._is_visible:
-            return False
-        x = event.mouse_region_x
-        y = event.mouse_region_y
-
-        if (event.type == 'LEFTMOUSE'):
-            if (event.value == 'PRESS'):
-                self._mouse_down = True
-                return self.mouse_down(x, y)
-            else:
-                self._mouse_down = False
-                self.mouse_up(x, y)
-
-        elif (event.type == 'RIGHTMOUSE'):
-
-            if (event.value == 'PRESS'):
-                self._mouse_down_right = True
-                return self.mouse_down_right(x, y)
-            else:
-                self._mouse_down_right = False
-                self.mouse_up(x, y)
-
-        elif (event.type == 'MOUSEMOVE'):
-            self.mouse_move(x, y)
-            inrect = self.is_in_rect(x, y)
-
-            # we enter the rect
-            if not self.__inrect and inrect:
-                self.__inrect = True
-                self.mouse_enter(event, x, y)
-
-            # we are leaving the rect
-            elif self.__inrect and not inrect:
-                self.__inrect = False
-                self.mouse_exit(event, x, y)
-
-            return False
-
-        elif event.value == 'PRESS' and self.__inrect and (event.ascii != '' or event.type in self.get_input_keys()):
-
-            return self.text_input(event)
-
-        return False
-
-    def get_input_keys(self)                :
-        return []
-
-    def get_area_height(self):
-        return self.context.area.height
-
-    def is_in_rect(self, x, y):
-        area_height = self.get_area_height()
-
-        widget_y = area_height - self.y_screen
-        if (
-            (self.x_screen <= x <= (self.x_screen + self.width)) and
-            (widget_y >= y >= (widget_y - self.height))
-            ):
-            # print('is in rect!?')
-            # print('area height', area_height)
-            # print ('x sceen ',self.x_screen,'x ', x, 'width', self.width)
-            # print ('widghet y', widget_y,'y', y, 'height',self.height)
-            return True
-
-        return False
-
-    def text_input(self, event):
-        return False
-
-    def mouse_down(self, x, y):
-        return self.is_in_rect(x,y)
-
-    def mouse_down_right(self, x, y):
-        return self.is_in_rect(x,y)
-
-    def mouse_up(self, x, y):
-        pass
-
-    def set_mouse_enter(self, mouse_enter_func):
-        self.mouse_enter_func = mouse_enter_func
-
-    def call_mouse_enter(self):
-        try:
-            if self.mouse_enter_func:
-                self.mouse_enter_func(self)
-        except:
-            pass
-
-    def mouse_enter(self, event, x, y):
-        self.call_mouse_enter()
-
-    def set_mouse_exit(self, mouse_exit_func):
-        self.mouse_exit_func = mouse_exit_func
-
-    def call_mouse_exit(self):
-        try:
-            if self.mouse_exit_func:
-                self.mouse_exit_func(self)
-        except:
-            pass
-
-    def mouse_exit(self, event, x, y):
-        self.call_mouse_exit()
-
-    def mouse_move(self, x, y):
-        pass
diff --git a/blenderkit/blendfiles/cleaned.blend b/blenderkit/blendfiles/cleaned.blend
deleted file mode 100644
index 4ad5f57c2bdbac1d41920fbe66ec6460bd599fb3..0000000000000000000000000000000000000000
Binary files a/blenderkit/blendfiles/cleaned.blend and /dev/null differ
diff --git a/blenderkit/blendfiles/material_thumbnailer_cycles.blend b/blenderkit/blendfiles/material_thumbnailer_cycles.blend
deleted file mode 100644
index 1faa5807d4818aa3ba62084167a92d6b42165574..0000000000000000000000000000000000000000
Binary files a/blenderkit/blendfiles/material_thumbnailer_cycles.blend and /dev/null differ
diff --git a/blenderkit/blendfiles/thumbnailer.blend b/blenderkit/blendfiles/thumbnailer.blend
deleted file mode 100644
index 6903130dc519e495f445a6706f868cda4093c627..0000000000000000000000000000000000000000
Binary files a/blenderkit/blendfiles/thumbnailer.blend and /dev/null differ
diff --git a/blenderkit/categories.py b/blenderkit/categories.py
deleted file mode 100644
index c97c339c220113dfaf451bdfc161cf99620fefe9..0000000000000000000000000000000000000000
--- a/blenderkit/categories.py
+++ /dev/null
@@ -1,274 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import paths, utils, tasks_queue, rerequests, ui, colors, reports
-
-import requests
-import json
-import os
-import bpy
-import time
-
-import shutil
-import threading
-import logging
-
-bk_logger = logging.getLogger('blenderkit')
-
-
-def count_to_parent(parent):
-    for c in parent['children']:
-        count_to_parent(c)
-        parent['assetCount'] += c['assetCount']
-
-
-def fix_category_counts(categories):
-    for c in categories:
-        count_to_parent(c)
-
-
-def filter_category(category):
-    ''' filter categories with no assets, so they aren't shown in search panel'''
-    if category['assetCount'] < 1:
-        return True
-    else:
-        to_remove = []
-        for c in category['children']:
-            if filter_category(c):
-                to_remove.append(c)
-        for c in to_remove:
-            category['children'].remove(c)
-
-
-def filter_categories(categories):
-    for category in categories:
-        filter_category(category)
-
-
-def get_category_path(categories, category):
-    '''finds the category in all possible subcategories and returns the path to it'''
-    category_path = []
-    check_categories = categories[:]
-    parents = {}
-    while len(check_categories) > 0:
-        ccheck = check_categories.pop()
-        #        print(ccheck['name'])
-        if not ccheck.get('children'):
-            continue
-
-        for ch in ccheck['children']:
-            #                print(ch['name'])
-            parents[ch['slug']] = ccheck['slug']
-
-            if ch['slug'] == category:
-                category_path = [ch['slug']]
-                slug = ch['slug']
-                while parents.get(slug):
-                    slug = parents.get(slug)
-                    category_path.insert(0, slug)
-                return category_path
-            check_categories.append(ch)
-    return category_path
-
-def get_category_name_path(categories, category):
-    '''finds the category in all possible subcategories and returns the path to it'''
-    category_path = []
-    check_categories = categories[:]
-    parents = {}
-    # utils.pprint(categories)
-    while len(check_categories) > 0:
-        ccheck = check_categories.pop()
-        #        print(ccheck['name'])
-        if not ccheck.get('children'):
-            continue
-
-        for ch in ccheck['children']:
-            #                print(ch['name'])
-            parents[ch['slug']] = ccheck
-
-            if ch['slug'] == category:
-                category_path = [ch['name']]
-                slug = ch['slug']
-                while parents.get(slug):
-                    parent = parents.get(slug)
-                    slug = parent['slug']
-
-                    category_path.insert(0, parent['name'])
-                return category_path
-            check_categories.append(ch)
-    return category_path
-
-def get_category(categories, cat_path=()):
-    for category in cat_path:
-        for c in categories:
-            if c['slug'] == category:
-                categories = c['children']
-                if category == cat_path[-1]:
-                    return (c)
-                break;
-
-
-# def get_upload_asset_type(self):
-#     typemapper = {
-#         bpy.types.Object.blenderkit: 'model',
-#         bpy.types.Scene.blenderkit: 'scene',
-#         bpy.types.Image.blenderkit: 'hdr',
-#         bpy.types.Material.blenderkit: 'material',
-#         bpy.types.Brush.blenderkit: 'brush'
-#     }
-#     asset_type = typemapper[type(self)]
-#     return asset_type
-
-def update_category_enums(self, context):
-    '''Fixes if lower level is empty - sets it to None, because enum value can be higher.'''
-    enums = get_subcategory_enums(self, context)
-    if enums[0][0] == 'NONE' and self.subcategory != 'NONE':
-        self.subcategory = 'NONE'
-
-
-def update_subcategory_enums(self, context):
-    '''Fixes if lower level is empty - sets it to None, because enum value can be higher.'''
-    enums = get_subcategory1_enums(self, context)
-    if enums[0][0] == 'NONE' and self.subcategory1 != 'NONE':
-        self.subcategory1 = 'NONE'
-
-
-def get_category_enums(self, context):
-    wm = bpy.context.window_manager
-    props = bpy.context.window_manager.blenderkitUI
-    asset_type = props.asset_type.lower()
-    # asset_type = self.asset_type#get_upload_asset_type(self)
-    asset_categories = get_category(wm['bkit_categories'], cat_path=(asset_type,))
-    items = []
-    for c in asset_categories['children']:
-        items.append((c['slug'], c['name'], c['description']))
-    if len(items) == 0:
-        items.append(('NONE', '', 'no categories on this level defined'))
-    return items
-
-
-def get_subcategory_enums(self, context):
-    wm = bpy.context.window_manager
-    props = bpy.context.window_manager.blenderkitUI
-    asset_type = props.asset_type.lower()
-    items = []
-    if self.category != '':
-        asset_categories = get_category(wm['bkit_categories'], cat_path=(asset_type, self.category,))
-        for c in asset_categories['children']:
-            items.append((c['slug'], c['name'], c['description']))
-    if len(items) == 0:
-        items.append(('NONE', '', 'no categories on this level defined'))
-    # print('subcategory', items)
-    return items
-
-
-def get_subcategory1_enums(self, context):
-    wm = bpy.context.window_manager
-    props = bpy.context.window_manager.blenderkitUI
-    asset_type = props.asset_type.lower()
-    items = []
-    if self.category != '' and self.subcategory != '':
-        asset_categories = get_category(wm['bkit_categories'], cat_path=(asset_type, self.category, self.subcategory,))
-        if asset_categories:
-            for c in asset_categories['children']:
-                items.append((c['slug'], c['name'], c['description']))
-    if len(items) == 0:
-        items.append(('NONE', '', 'no categories on this level defined'))
-    return items
-
-
-def copy_categories():
-    # this creates the categories system on only
-    tempdir = paths.get_temp_dir()
-    categories_filepath = os.path.join(tempdir, 'categories.json')
-    if not os.path.exists(categories_filepath):
-        source_path = paths.get_addon_file(subpath='data' + os.sep + 'categories.json')
-        # print('attempt to copy categories from: %s to %s' % (categories_filepath, source_path))
-        try:
-            shutil.copy(source_path, categories_filepath)
-        except:
-            print("couldn't copy categories file")
-
-
-def load_categories():
-    copy_categories()
-    tempdir = paths.get_temp_dir()
-    categories_filepath = os.path.join(tempdir, 'categories.json')
-
-    wm = bpy.context.window_manager
-    try:
-        with open(categories_filepath, 'r', encoding='utf-8') as catfile:
-            wm['bkit_categories'] = json.load(catfile)
-
-        wm['active_category'] = {
-            'MODEL': ['model'],
-            'SCENE': ['scene'],
-            'HDR': ['hdr'],
-            'MATERIAL': ['material'],
-            'BRUSH': ['brush'],
-        }
-    except:
-        print('categories failed to read')
-
-
-#
-catfetch_counter = 0
-
-
-def fetch_categories(API_key, force=False):
-    url = paths.get_api_url() + 'categories/'
-
-    headers = utils.get_headers(API_key)
-
-    tempdir = paths.get_temp_dir()
-    categories_filepath = os.path.join(tempdir, 'categories.json')
-    if os.path.exists(categories_filepath):
-        catfile_age = time.time() - os.path.getmtime(categories_filepath)
-    else:
-        catfile_age = 10000000
-
-    # global catfetch_counter
-    # catfetch_counter += 1
-    # bk_logger.debug('fetching categories: ', catfetch_counter)
-    # bk_logger.debug('age of cat file', catfile_age)
-    try:
-        # read categories only once per day maximum, or when forced to do so.
-        if catfile_age > 86400 or force:
-            bk_logger.debug('requesting categories from server')
-            r = rerequests.get(url, headers=headers)
-            rdata = r.json()
-            categories = rdata['results']
-            fix_category_counts(categories)
-            # filter_categories(categories) #TODO this should filter categories for search, but not for upload. by now off.
-            with open(categories_filepath, 'w', encoding='utf-8') as s:
-                json.dump(categories, s, ensure_ascii=False, indent=4)
-        tasks_queue.add_task((load_categories, ()))
-    except Exception as e:
-        t = 'BlenderKit failed to download fresh categories from the server'
-        tasks_queue.add_task((reports.add_report(),(t, 15, colors.RED)))
-        bk_logger.debug(t)
-        bk_logger.exception(e)
-        if not os.path.exists(categories_filepath):
-            source_path = paths.get_addon_file(subpath='data' + os.sep + 'categories.json')
-            shutil.copy(source_path, categories_filepath)
-
-
-def fetch_categories_thread(API_key, force=False):
-    cat_thread = threading.Thread(target=fetch_categories, args=([API_key, force]), daemon=True)
-    cat_thread.start()
diff --git a/blenderkit/colors.py b/blenderkit/colors.py
deleted file mode 100644
index fe2fb1ac96148c2e889edbf929368162f66c6d53..0000000000000000000000000000000000000000
--- a/blenderkit/colors.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# ##### 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 #####
-
-# this module defines color palette for BlenderKit UI
-
-WHITE = (1, 1, 1, .9)
-
-TEXT = (.9, .9, .9, .6)
-GREEN = (.9, 1, .9, .6)
-RED = (1, .5, .5, .8)
diff --git a/blenderkit/comments_utils.py b/blenderkit/comments_utils.py
deleted file mode 100644
index 654bbb54f8574da652ad7842e05cfe2cbe30c9d3..0000000000000000000000000000000000000000
--- a/blenderkit/comments_utils.py
+++ /dev/null
@@ -1,232 +0,0 @@
-# ##### 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 #####
-
-# mainly update functions and callbacks for ratings properties, here to avoid circular imports.
-import bpy
-from blenderkit import utils, paths, tasks_queue, rerequests
-
-import threading
-import requests
-import logging
-
-bk_logger = logging.getLogger('blenderkit')
-
-
-def upload_comment_thread(url, comment='', api_key=None):
-    ''' Upload rating thread function / disconnected from blender data.'''
-    headers = utils.get_headers(api_key)
-
-    bk_logger.debug('upload comment ' + comment)
-
-    # rating_url = url + rating_name + '/'
-    data = {
-        "content_type": "",
-        "object_pk": "",
-        "timestamp": "",
-        "security_hash": "",
-        "honeypot": "",
-        "name": "",
-        "email": "",
-        "url": "",
-        "comment": comment,
-        "followup": False,
-        "reply_to": None
-    }
-
-    # try:
-    r = rerequests.put(url, data=data, verify=True, headers=headers)
-    # print(r)
-    # print(dir(r))
-    # print(r.text)
-    # except requests.exceptions.RequestException as e:
-    #     print('ratings upload failed: %s' % str(e))
-
-
-def upload_comment_flag_thread( asset_id = '', comment_id='', flag='like', api_key=None):
-    ''' Upload rating thread function / disconnected from blender data.'''
-    headers = utils.get_headers(api_key)
-
-    bk_logger.debug('upload comment flag' + str(comment_id))
-
-    # rating_url = url + rating_name + '/'
-    data = {
-        "comment": comment_id,
-        "flag": flag,
-    }
-    url = paths.get_api_url() + 'comments/feedback/'
-
-    # try:
-    r = rerequests.post(url, data=data, verify=True, headers=headers)
-    # print(r.text)
-
-    #here it's important we read back, so likes are updated accordingly:
-    get_comments(asset_id, api_key)
-
-
-def send_comment_flag_to_thread(asset_id = '', comment_id='', flag='like', api_key = None):
-    '''Sens rating into thread rating, main purpose is for tasks_queue.
-    One function per property to avoid lost data due to stashing.'''
-    thread = threading.Thread(target=upload_comment_flag_thread, args=(asset_id, comment_id, flag, api_key))
-    thread.start()
-
-def send_comment_to_thread(url, comment, api_key):
-    '''Sens rating into thread rating, main purpose is for tasks_queue.
-    One function per property to avoid lost data due to stashing.'''
-    thread = threading.Thread(target=upload_comment_thread, args=(url, comment, api_key))
-    thread.start()
-
-
-def store_comments_local(asset_id, comments):
-    context = bpy.context
-    ac = context.window_manager.get('asset comments', {})
-    ac[asset_id] = comments
-    context.window_manager['asset comments'] = ac
-
-
-def get_comments_local(asset_id):
-    context = bpy.context
-    context.window_manager['asset comments'] = context.window_manager.get('asset comments', {})
-    comments = context.window_manager['asset comments'].get(asset_id)
-    if comments:
-        return comments
-    return None
-
-def get_comments_thread(asset_id, api_key):
-    thread = threading.Thread(target=get_comments, args=([asset_id, api_key]), daemon=True)
-    thread.start()
-
-def get_comments(asset_id, api_key):
-    '''
-    Retrieve comments  from BlenderKit server. Can be run from a thread
-    Parameters
-    ----------
-    asset_id
-    headers
-
-    Returns
-    -------
-    ratings - dict of type:value ratings
-    '''
-    headers = utils.get_headers(api_key)
-
-    url = paths.get_api_url() + 'comments/assets-uuidasset/' + asset_id + '/'
-    params = {}
-    r = rerequests.get(url, params=params, verify=True, headers=headers)
-    if r is None:
-        return
-    # print(r.status_code)
-    if r.status_code == 200:
-        rj = r.json()
-        # store comments - send them to task queue
-        # print('retrieved comments')
-        # print(rj)
-        tasks_queue.add_task((store_comments_local, (asset_id, rj['results'])))
-
-        # if len(rj['results'])==0:
-        #     # store empty ratings too, so that server isn't checked repeatedly
-        #     tasks_queue.add_task((store_rating_local_empty,(asset_id,)))
-        # return ratings
-
-
-def store_notifications_count_local(all_count):
-    '''Store total count of notifications on server in preferences'''
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    user_preferences.notifications_counter = all_count
-
-def store_notifications_local(notifications):
-    '''Store notifications in Blender'''
-    bpy.context.window_manager['bkit notifications'] = notifications
-
-def count_all_notifications():
-    '''Return count of all notifications on server'''
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    return user_preferences.notifications_counter
-
-
-def check_notifications_read():
-    '''checks if all notifications were already read, and removes them if so'''
-    notifications = bpy.context.window_manager.get('bkit notifications')
-    if notifications is None or notifications.get('count') == 0:
-        return True
-    for n in notifications['results']:
-        if n['unread'] == 1:
-            return False
-    bpy.context.window_manager['bkit notifications'] = None
-    return True
-
-def get_notifications_thread(api_key, all_count = 1000):
-    thread = threading.Thread(target=get_notifications, args=([api_key, all_count]), daemon=True)
-    thread.start()
-
-def get_notifications(api_key, all_count = 1000):
-    '''
-    Retrieve notifications from BlenderKit server. Can be run from a thread.
-
-    Parameters
-    ----------
-    api_key
-    all_count
-
-    Returns
-    -------
-    '''
-    headers = utils.get_headers(api_key)
-
-    params = {}
-
-    url = paths.get_api_url() + 'notifications/all_count/'
-    r = rerequests.get(url, params=params, verify=True, headers=headers)
-    if r.status_code ==200:
-        rj = r.json()
-        # print(rj)
-        # no new notifications?
-        if all_count >= rj['allCount']:
-            tasks_queue.add_task((store_notifications_count_local, ([rj['allCount']])))
-
-            return
-    url = paths.get_api_url() + 'notifications/unread/'
-    r = rerequests.get(url, params=params, verify=True, headers=headers)
-    if r is None:
-        return
-    if r.status_code == 200:
-        rj = r.json()
-        # store notifications - send them to task queue
-        tasks_queue.add_task((store_notifications_local, ([rj])))
-
-def mark_notification_read_thread(api_key, notification_id):
-    thread = threading.Thread(target=mark_notification_read, args=([api_key, notification_id]), daemon=True)
-    thread.start()
-
-def mark_notification_read(api_key, notification_id):
-    '''
-    mark notification as read
-    '''
-    headers = utils.get_headers(api_key)
-
-    url = paths.get_api_url() + f'notifications/mark-as-read/{notification_id}/'
-    params = {}
-    r = rerequests.get(url, params=params, verify=True, headers=headers)
-    if r is None:
-        return
-    # print(r.text)
-    # if r.status_code == 200:
-    #     rj = r.json()
-    #     # store notifications - send them to task queue
-    #     print(rj)
-    #     tasks_queue.add_task((mark_notification_read_local, ([notification_id])))
-
diff --git a/blenderkit/data/categories.json b/blenderkit/data/categories.json
deleted file mode 100644
index 376d26d4d1d9fe7e6fd3c51939413048b5f3cd6d..0000000000000000000000000000000000000000
--- a/blenderkit/data/categories.json
+++ /dev/null
@@ -1,6176 +0,0 @@
-[
-    {
-        "name": "brush",
-        "slug": "brush",
-        "active": true,
-        "thumbnail": null,
-        "thumbnailWidth": null,
-        "thumbnailHeight": null,
-        "order": 0,
-        "alternateTitle": "brush",
-        "alternateUrl": "",
-        "description": "",
-        "metaKeywords": "",
-        "metaExtra": "",
-        "children": [
-            {
-                "name": "anatomy",
-                "slug": "anatomy-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "anatomy",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 10,
-                "assetCountCumulative": 10
-            },
-            {
-                "name": "animal",
-                "slug": "animal-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "animal",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 5,
-                "assetCountCumulative": 5
-            },
-            {
-                "name": "art",
-                "slug": "art-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "art",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 3,
-                "assetCountCumulative": 3
-            },
-            {
-                "name": "clothing",
-                "slug": "clothing-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "clothing",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 10,
-                "assetCountCumulative": 10
-            },
-            {
-                "name": "crack",
-                "slug": "crack",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "crack",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 0,
-                "assetCountCumulative": 0
-            },
-            {
-                "name": "cut",
-                "slug": "cut",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "cut",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 2,
-                "assetCountCumulative": 2
-            },
-            {
-                "name": "damage",
-                "slug": "damage",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "damage",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 4,
-                "assetCountCumulative": 4
-            },
-            {
-                "name": "dirt",
-                "slug": "dirt-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "dirt",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 2,
-                "assetCountCumulative": 2
-            },
-            {
-                "name": "fabric",
-                "slug": "fabric-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "fabric",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 8,
-                "assetCountCumulative": 8
-            },
-            {
-                "name": "geometric",
-                "slug": "geometric",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "geometric",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 5,
-                "assetCountCumulative": 5
-            },
-            {
-                "name": "human",
-                "slug": "human-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "human",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 7,
-                "assetCountCumulative": 7
-            },
-            {
-                "name": "industrial",
-                "slug": "industrial-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "industrial",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 12,
-                "assetCountCumulative": 12
-            },
-            {
-                "name": "landscape",
-                "slug": "landscape-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "landscape",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 25,
-                "assetCountCumulative": 25
-            },
-            {
-                "name": "misc",
-                "slug": "misc",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "misc",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 10,
-                "assetCountCumulative": 10
-            },
-            {
-                "name": "nature",
-                "slug": "nature-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "nature",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 0,
-                "assetCountCumulative": 0
-            },
-            {
-                "name": "pattern",
-                "slug": "pattern",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "pattern",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 8,
-                "assetCountCumulative": 8
-            },
-            {
-                "name": "rock",
-                "slug": "rock-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "rock",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 8,
-                "assetCountCumulative": 8
-            },
-            {
-                "name": "rust",
-                "slug": "rust-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "rust",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 0,
-                "assetCountCumulative": 0
-            },
-            {
-                "name": "sculpture",
-                "slug": "sculpture-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "sculpture",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 3,
-                "assetCountCumulative": 3
-            },
-            {
-                "name": "stitches",
-                "slug": "stitches",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "stitches",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 10,
-                "assetCountCumulative": 10
-            },
-            {
-                "name": "stone",
-                "slug": "stone-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "stone",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 0,
-                "assetCountCumulative": 0
-            },
-            {
-                "name": "tree",
-                "slug": "tree-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "tree",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 5,
-                "assetCountCumulative": 5
-            },
-            {
-                "name": "wood",
-                "slug": "wood-brush",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "wood",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 0,
-                "assetCountCumulative": 0
-            }
-        ],
-        "assetCount": 137,
-        "assetCountCumulative": 137
-    },
-    {
-        "name": "HDR",
-        "slug": "hdr",
-        "active": true,
-        "thumbnail": null,
-        "thumbnailWidth": null,
-        "thumbnailHeight": null,
-        "order": 0,
-        "alternateTitle": "HDR",
-        "alternateUrl": "",
-        "description": "",
-        "metaKeywords": "",
-        "metaExtra": "",
-        "children": [
-            {
-                "name": "Indoor",
-                "slug": "indoor",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Indoor",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Industrial",
-                        "slug": "hdr-industrial",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Industrial",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 63,
-                        "assetCountCumulative": 63
-                    },
-                    {
-                        "name": "Public",
-                        "slug": "hdr-public",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Public",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 31,
-                        "assetCountCumulative": 31
-                    },
-                    {
-                        "name": "Residential",
-                        "slug": "residential",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Residential",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 85,
-                        "assetCountCumulative": 85
-                    },
-                    {
-                        "name": "Studio",
-                        "slug": "hdr-studio",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Studio",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 13,
-                        "assetCountCumulative": 13
-                    }
-                ],
-                "assetCount": 447,
-                "assetCountCumulative": 447
-            },
-            {
-                "name": "Outdoor",
-                "slug": "hdr-outdoor",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Outdoor",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Nature",
-                        "slug": "hdr-nature",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Nature",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 41,
-                        "assetCountCumulative": 41
-                    },
-                    {
-                        "name": "Urban",
-                        "slug": "hdr-urban",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Urban",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 80,
-                        "assetCountCumulative": 80
-                    }
-                ],
-                "assetCount": 121,
-                "assetCountCumulative": 121
-            }
-        ],
-        "assetCount": 580,
-        "assetCountCumulative": 580
-    },
-    {
-        "name": "material",
-        "slug": "material",
-        "active": true,
-        "thumbnail": null,
-        "thumbnailWidth": null,
-        "thumbnailHeight": null,
-        "order": 0,
-        "alternateTitle": "materials",
-        "alternateUrl": "",
-        "description": "",
-        "metaKeywords": "",
-        "metaExtra": "",
-        "children": [
-            {
-                "name": "animal",
-                "slug": "animal-material",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "animal",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 51,
-                "assetCountCumulative": 51
-            },
-            {
-                "name": "asphalt",
-                "slug": "asphalt",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "asphalt",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 58,
-                "assetCountCumulative": 58
-            },
-            {
-                "name": "bricks",
-                "slug": "bricks",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "bricks",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 93,
-                "assetCountCumulative": 93
-            },
-            {
-                "name": "ceramic",
-                "slug": "ceramic",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "ceramic",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 30,
-                "assetCountCumulative": 30
-            },
-            {
-                "name": "concrete",
-                "slug": "concrete",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "concrete",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 132,
-                "assetCountCumulative": 132
-            },
-            {
-                "name": "dirt",
-                "slug": "dirt",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "dirt",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 37,
-                "assetCountCumulative": 37
-            },
-            {
-                "name": "fabric",
-                "slug": "fabric",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "fabric",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 205,
-                "assetCountCumulative": 205
-            },
-            {
-                "name": "floor",
-                "slug": "floor",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "floor",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 72,
-                "assetCountCumulative": 72
-            },
-            {
-                "name": "food",
-                "slug": "food-material",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "food",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 44,
-                "assetCountCumulative": 44
-            },
-            {
-                "name": "fx",
-                "slug": "fx",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "fx",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 54,
-                "assetCountCumulative": 54
-            },
-            {
-                "name": "glass",
-                "slug": "glass",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "glass",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 73,
-                "assetCountCumulative": 73
-            },
-            {
-                "name": "grass",
-                "slug": "grass",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "grass",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 15,
-                "assetCountCumulative": 15
-            },
-            {
-                "name": "ground",
-                "slug": "ground-material",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "ground",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 134,
-                "assetCountCumulative": 134
-            },
-            {
-                "name": "human",
-                "slug": "human",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "human",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 5,
-                "assetCountCumulative": 5
-            },
-            {
-                "name": "ice",
-                "slug": "ice",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "ice",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 28,
-                "assetCountCumulative": 28
-            },
-            {
-                "name": "leather",
-                "slug": "leather",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "leather",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 88,
-                "assetCountCumulative": 88
-            },
-            {
-                "name": "liquid",
-                "slug": "liquid",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "liquid",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 25,
-                "assetCountCumulative": 25
-            },
-            {
-                "name": "marble",
-                "slug": "marble",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "marble",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 14,
-                "assetCountCumulative": 14
-            },
-            {
-                "name": "metal",
-                "slug": "metal",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "metal",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 349,
-                "assetCountCumulative": 349
-            },
-            {
-                "name": "organic",
-                "slug": "organic",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "organic",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 50,
-                "assetCountCumulative": 50
-            },
-            {
-                "name": "ornaments",
-                "slug": "ornaments",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "ornaments",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 40,
-                "assetCountCumulative": 40
-            },
-            {
-                "name": "paper",
-                "slug": "paper",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "paper",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 64,
-                "assetCountCumulative": 64
-            },
-            {
-                "name": "paving",
-                "slug": "paving",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "paving",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 51,
-                "assetCountCumulative": 51
-            },
-            {
-                "name": "plaster",
-                "slug": "plaster",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "plaster",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 76,
-                "assetCountCumulative": 76
-            },
-            {
-                "name": "plastic",
-                "slug": "plastic",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "plastic",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 77,
-                "assetCountCumulative": 77
-            },
-            {
-                "name": "rock",
-                "slug": "rock",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "rock",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 55,
-                "assetCountCumulative": 55
-            },
-            {
-                "name": "roofing",
-                "slug": "roofing",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "roofing",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 24,
-                "assetCountCumulative": 24
-            },
-            {
-                "name": "rubber",
-                "slug": "rubber",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "rubber",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 12,
-                "assetCountCumulative": 12
-            },
-            {
-                "name": "rust",
-                "slug": "rust",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "rust",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 25,
-                "assetCountCumulative": 25
-            },
-            {
-                "name": "sand",
-                "slug": "sand",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "sand",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 28,
-                "assetCountCumulative": 28
-            },
-            {
-                "name": "soil",
-                "slug": "soil",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "soil",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 13,
-                "assetCountCumulative": 13
-            },
-            {
-                "name": "stone",
-                "slug": "stone",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "stone",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 153,
-                "assetCountCumulative": 153
-            },
-            {
-                "name": "tech",
-                "slug": "tech",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "tech",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 115,
-                "assetCountCumulative": 115
-            },
-            {
-                "name": "tiles",
-                "slug": "tiles",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "tiles",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 164,
-                "assetCountCumulative": 164
-            },
-            {
-                "name": "wood",
-                "slug": "wood",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "wood",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 351,
-                "assetCountCumulative": 351
-            }
-        ],
-        "assetCount": 2805,
-        "assetCountCumulative": 2805
-    },
-    {
-        "name": "model",
-        "slug": "model",
-        "active": true,
-        "thumbnail": null,
-        "thumbnailWidth": null,
-        "thumbnailHeight": null,
-        "order": 0,
-        "alternateTitle": "model",
-        "alternateUrl": "",
-        "description": "",
-        "metaKeywords": "",
-        "metaExtra": "",
-        "children": [
-            {
-                "name": "Architecture",
-                "slug": "architecture",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Architecture",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Building",
-                        "slug": "building",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Building",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Commercial",
-                                "slug": "public",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Commercial",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 39,
-                                "assetCountCumulative": 39
-                            },
-                            {
-                                "name": "Historic",
-                                "slug": "historic",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Historic",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 15,
-                                "assetCountCumulative": 15
-                            },
-                            {
-                                "name": "Other",
-                                "slug": "stadium",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Other",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 12,
-                                "assetCountCumulative": 12
-                            },
-                            {
-                                "name": "Private",
-                                "slug": "house",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Private",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 31,
-                                "assetCountCumulative": 31
-                            },
-                            {
-                                "name": "Sci-fi",
-                                "slug": "sci-fi",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Sci-fi",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            }
-                        ],
-                        "assetCount": 112,
-                        "assetCountCumulative": 112
-                    },
-                    {
-                        "name": "Door",
-                        "slug": "door",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Door",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 124,
-                        "assetCountCumulative": 124
-                    },
-                    {
-                        "name": "Exterior element",
-                        "slug": "exterior",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Exterior element",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Bench",
-                                "slug": "bench",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Bench",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 55,
-                                "assetCountCumulative": 55
-                            },
-                            {
-                                "name": "Facade element",
-                                "slug": "facade-element",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Facade element",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 58,
-                                "assetCountCumulative": 58
-                            },
-                            {
-                                "name": "Fence",
-                                "slug": "fence",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Fence",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 32,
-                                "assetCountCumulative": 32
-                            },
-                            {
-                                "name": "Fountain",
-                                "slug": "fountain",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Fountain",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 4,
-                                "assetCountCumulative": 4
-                            },
-                            {
-                                "name": "Other",
-                                "slug": "exterior-other",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Other",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 147,
-                                "assetCountCumulative": 147
-                            },
-                            {
-                                "name": "Playground",
-                                "slug": "playground",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Playground",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 8,
-                                "assetCountCumulative": 8
-                            },
-                            {
-                                "name": "Swimming pool",
-                                "slug": "swimming-pool",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Swimming pool",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 7,
-                                "assetCountCumulative": 7
-                            },
-                            {
-                                "name": "Urban Environment",
-                                "slug": "cityspace",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Urban Environment",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 67,
-                                "assetCountCumulative": 67
-                            }
-                        ],
-                        "assetCount": 384,
-                        "assetCountCumulative": 384
-                    },
-                    {
-                        "name": "Floor Covering",
-                        "slug": "floor-covering",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Floor Covering",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 5,
-                        "assetCountCumulative": 5
-                    },
-                    {
-                        "name": "Molding / Carving",
-                        "slug": "molding-carving",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Molding / Carving",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 1,
-                        "assetCountCumulative": 1
-                    },
-                    {
-                        "name": "Other",
-                        "slug": "elements",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Other",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 64,
-                        "assetCountCumulative": 64
-                    },
-                    {
-                        "name": "Scenes",
-                        "slug": "landmark",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Scenes",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 5,
-                        "assetCountCumulative": 5
-                    },
-                    {
-                        "name": "Stairs",
-                        "slug": "stairs",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Stairs",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 23,
-                        "assetCountCumulative": 23
-                    },
-                    {
-                        "name": "Structure",
-                        "slug": "street",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Structure",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 51,
-                        "assetCountCumulative": 51
-                    },
-                    {
-                        "name": "Wall Panel",
-                        "slug": "wall-panel",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Wall Panel",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "3D Panel",
-                                "slug": "3d-panel",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "3D Panel",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 4,
-                                "assetCountCumulative": 4
-                            },
-                            {
-                                "name": "Stone Panel",
-                                "slug": "stone-panel",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Stone Panel",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 2,
-                                "assetCountCumulative": 2
-                            },
-                            {
-                                "name": "Upholstery Panel",
-                                "slug": "upholstery-panel",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Upholstery Panel",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            },
-                            {
-                                "name": "Wood Panel",
-                                "slug": "wood-panel",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Wood Panel",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 4,
-                                "assetCountCumulative": 4
-                            }
-                        ],
-                        "assetCount": 11,
-                        "assetCountCumulative": 11
-                    },
-                    {
-                        "name": "Window",
-                        "slug": "window",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Window",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 67,
-                        "assetCountCumulative": 67
-                    }
-                ],
-                "assetCount": 849,
-                "assetCountCumulative": 849
-            },
-            {
-                "name": "Character",
-                "slug": "character",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Character",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Anatomy",
-                        "slug": "anatomy",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Anatomy",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Full Body",
-                                "slug": "full-body",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Full Body",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 4,
-                                "assetCountCumulative": 4
-                            },
-                            {
-                                "name": "Head",
-                                "slug": "head",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Head",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 9,
-                                "assetCountCumulative": 9
-                            },
-                            {
-                                "name": "Internal organ",
-                                "slug": "internal-organ",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Internal organ",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            },
-                            {
-                                "name": "Limbs",
-                                "slug": "limbs",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Limbs",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Musculature",
-                                "slug": "musculature",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Musculature",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Skeleton",
-                                "slug": "skeleton",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Skeleton",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 2,
-                                "assetCountCumulative": 2
-                            }
-                        ],
-                        "assetCount": 16,
-                        "assetCountCumulative": 16
-                    },
-                    {
-                        "name": "Animal",
-                        "slug": "animal-nature",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Animal",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Bird",
-                                "slug": "bird",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Bird",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            },
-                            {
-                                "name": "Dinosaur",
-                                "slug": "dinosaur",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Dinosaur",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Fish",
-                                "slug": "fish",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Fish",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            },
-                            {
-                                "name": "Insect",
-                                "slug": "insect",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Insect",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 6,
-                                "assetCountCumulative": 6
-                            },
-                            {
-                                "name": "Mammal",
-                                "slug": "mammal",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Mammal",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 12,
-                                "assetCountCumulative": 12
-                            },
-                            {
-                                "name": "Other",
-                                "slug": "animal",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Other",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 2,
-                                "assetCountCumulative": 2
-                            },
-                            {
-                                "name": "Reptile",
-                                "slug": "reptile",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Reptile",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            }
-                        ],
-                        "assetCount": 25,
-                        "assetCountCumulative": 25
-                    },
-                    {
-                        "name": "Clothing",
-                        "slug": "clothing",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Clothing",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Accessories",
-                                "slug": "clothing-accessories",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Accessories",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 22,
-                                "assetCountCumulative": 22
-                            },
-                            {
-                                "name": "Footwear",
-                                "slug": "footwear",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Footwear",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 25,
-                                "assetCountCumulative": 25
-                            },
-                            {
-                                "name": "Headwear",
-                                "slug": "headwear",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Headwear",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 15,
-                                "assetCountCumulative": 15
-                            },
-                            {
-                                "name": "Lingerie",
-                                "slug": "lingerie",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Lingerie",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Man Clothing",
-                                "slug": "man-clothing",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Man Clothing",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 10,
-                                "assetCountCumulative": 10
-                            },
-                            {
-                                "name": "Woman Clothing",
-                                "slug": "woman-clothing",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Woman Clothing",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 14,
-                                "assetCountCumulative": 14
-                            }
-                        ],
-                        "assetCount": 87,
-                        "assetCountCumulative": 87
-                    },
-                    {
-                        "name": "Humanoids",
-                        "slug": "people",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Humanoids",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Child",
-                                "slug": "child",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Child",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 6,
-                                "assetCountCumulative": 6
-                            },
-                            {
-                                "name": "Fantasy Hero",
-                                "slug": "fantasy",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Fantasy Hero",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 17,
-                                "assetCountCumulative": 17
-                            },
-                            {
-                                "name": "Medical",
-                                "slug": "humanoids-medical",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Medical",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Men",
-                                "slug": "man",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Men",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 27,
-                                "assetCountCumulative": 27
-                            },
-                            {
-                                "name": "Military",
-                                "slug": "humanoids-military",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Military",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 3,
-                                "assetCountCumulative": 3
-                            },
-                            {
-                                "name": "Police",
-                                "slug": "police",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Police",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            },
-                            {
-                                "name": "Sci-Fi",
-                                "slug": "sci-fi-character",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Sci-Fi",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 12,
-                                "assetCountCumulative": 12
-                            },
-                            {
-                                "name": "Sports",
-                                "slug": "humanoids-sports",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Sports",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Women",
-                                "slug": "woman",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Women",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 18,
-                                "assetCountCumulative": 18
-                            }
-                        ],
-                        "assetCount": 84,
-                        "assetCountCumulative": 84
-                    },
-                    {
-                        "name": "Monster / Creature",
-                        "slug": "monster-creature",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Monster / Creature",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 5,
-                        "assetCountCumulative": 5
-                    },
-                    {
-                        "name": "Robot",
-                        "slug": "robot",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Robot",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 16,
-                        "assetCountCumulative": 16
-                    }
-                ],
-                "assetCount": 233,
-                "assetCountCumulative": 233
-            },
-            {
-                "name": "Decoration",
-                "slug": "decoration",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Decoration",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Bag / Suitcase",
-                        "slug": "bag-case",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Bag / Suitcase",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 22,
-                        "assetCountCumulative": 22
-                    },
-                    {
-                        "name": "Bed sheet",
-                        "slug": "bed-sheet",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Bed sheet",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 0,
-                        "assetCountCumulative": 0
-                    },
-                    {
-                        "name": "Blanket",
-                        "slug": "blanket",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Blanket",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 0,
-                        "assetCountCumulative": 0
-                    },
-                    {
-                        "name": "Book",
-                        "slug": "literature",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Book",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 69,
-                        "assetCountCumulative": 69
-                    },
-                    {
-                        "name": "Carpet",
-                        "slug": "carpet",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Carpet",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 35,
-                        "assetCountCumulative": 35
-                    },
-                    {
-                        "name": "Clock / Watch",
-                        "slug": "design",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Clock / Watch",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 42,
-                        "assetCountCumulative": 42
-                    },
-                    {
-                        "name": "Curtain",
-                        "slug": "curtain",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Curtain",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 35,
-                        "assetCountCumulative": 35
-                    },
-                    {
-                        "name": "Decoration Set",
-                        "slug": "photo",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Decoration Set",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 45,
-                        "assetCountCumulative": 45
-                    },
-                    {
-                        "name": "Fabrics",
-                        "slug": "fabrics",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Fabrics",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 10,
-                        "assetCountCumulative": 10
-                    },
-                    {
-                        "name": "Fireplace",
-                        "slug": "fireplace",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Fireplace",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 29,
-                        "assetCountCumulative": 29
-                    },
-                    {
-                        "name": "Food / Drinks",
-                        "slug": "food-drink",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Food / Drinks",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Beverage",
-                                "slug": "drink",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Beverage",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 100,
-                                "assetCountCumulative": 100
-                            },
-                            {
-                                "name": "Food",
-                                "slug": "food",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Food",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 62,
-                                "assetCountCumulative": 62
-                            },
-                            {
-                                "name": "Fruit / Vegetable",
-                                "slug": "fruitvegetable",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Fruit/Vegetable",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 71,
-                                "assetCountCumulative": 71
-                            },
-                            {
-                                "name": "Kitchenware",
-                                "slug": "container",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Kitchenware",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 164,
-                                "assetCountCumulative": 164
-                            },
-                            {
-                                "name": "Other",
-                                "slug": "drugs",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Other",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 14,
-                                "assetCountCumulative": 14
-                            },
-                            {
-                                "name": "Sweets / Dessert",
-                                "slug": "sweetsdessert",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Sweets/Dessert",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 26,
-                                "assetCountCumulative": 26
-                            },
-                            {
-                                "name": "Tableware set",
-                                "slug": "tableware-set",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Tableware set",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 157,
-                                "assetCountCumulative": 157
-                            }
-                        ],
-                        "assetCount": 599,
-                        "assetCountCumulative": 599
-                    },
-                    {
-                        "name": "Holiday Decoration",
-                        "slug": "supplies",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Holiday Decoration",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 38,
-                        "assetCountCumulative": 38
-                    },
-                    {
-                        "name": "Mirror",
-                        "slug": "mirror",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Mirror",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 50,
-                        "assetCountCumulative": 50
-                    },
-                    {
-                        "name": "Miscellaneous",
-                        "slug": "art",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Miscellaneous",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 272,
-                        "assetCountCumulative": 272
-                    },
-                    {
-                        "name": "Money",
-                        "slug": "money",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Money",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 21,
-                        "assetCountCumulative": 21
-                    },
-                    {
-                        "name": "Other textile",
-                        "slug": "other-textile",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Other textile",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 20,
-                        "assetCountCumulative": 20
-                    },
-                    {
-                        "name": "Picture",
-                        "slug": "painting",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Picture",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 160,
-                        "assetCountCumulative": 160
-                    },
-                    {
-                        "name": "Pillow",
-                        "slug": "pillow",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Pillow",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 56,
-                        "assetCountCumulative": 56
-                    },
-                    {
-                        "name": "Sculpture",
-                        "slug": "sculpture",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Sculpture",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 110,
-                        "assetCountCumulative": 110
-                    },
-                    {
-                        "name": "Vase",
-                        "slug": "drawing",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Vase",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 132,
-                        "assetCountCumulative": 132
-                    }
-                ],
-                "assetCount": 1749,
-                "assetCountCumulative": 1749
-            },
-            {
-                "name": "Industrial",
-                "slug": "industrial",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Industrial",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Container",
-                        "slug": "container-industrial",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Container",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 83,
-                        "assetCountCumulative": 83
-                    },
-                    {
-                        "name": "Equipment",
-                        "slug": "utility-industrial",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Equipment",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 17,
-                        "assetCountCumulative": 17
-                    },
-                    {
-                        "name": "Machinery",
-                        "slug": "machine",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Machinery",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 23,
-                        "assetCountCumulative": 23
-                    },
-                    {
-                        "name": "Other",
-                        "slug": "agriculture",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Other",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 50,
-                        "assetCountCumulative": 50
-                    },
-                    {
-                        "name": "Parts",
-                        "slug": "construction",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Parts",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 81,
-                        "assetCountCumulative": 81
-                    },
-                    {
-                        "name": "Sign",
-                        "slug": "communication",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Sign",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 36,
-                        "assetCountCumulative": 36
-                    },
-                    {
-                        "name": "Tools",
-                        "slug": "tool",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Tools",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Handtools",
-                                "slug": "handtools",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Handtools",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 34,
-                                "assetCountCumulative": 34
-                            },
-                            {
-                                "name": "Powertools",
-                                "slug": "powertools",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Powertools",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 16,
-                                "assetCountCumulative": 16
-                            }
-                        ],
-                        "assetCount": 50,
-                        "assetCountCumulative": 50
-                    }
-                ],
-                "assetCount": 340,
-                "assetCountCumulative": 340
-            },
-            {
-                "name": "Interior",
-                "slug": "interior",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Interior",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Armchair",
-                        "slug": "furniture",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Armchair",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 223,
-                        "assetCountCumulative": 223
-                    },
-                    {
-                        "name": "Bathroom furniture",
-                        "slug": "bathroom",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Bathroom furniture",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Accessories",
-                                "slug": "utility",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Accessories",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 93,
-                                "assetCountCumulative": 93
-                            },
-                            {
-                                "name": "Bathhub",
-                                "slug": "bathhub",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Bathhub",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 19,
-                                "assetCountCumulative": 19
-                            },
-                            {
-                                "name": "Faucet",
-                                "slug": "bathroomfurniture-faucet",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Faucet",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 21,
-                                "assetCountCumulative": 21
-                            },
-                            {
-                                "name": "Furniture Set",
-                                "slug": "bathroomfurniture-furniture-set",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Furniture Set",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 19,
-                                "assetCountCumulative": 19
-                            },
-                            {
-                                "name": "Laundry",
-                                "slug": "laundry",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Laundry",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 11,
-                                "assetCountCumulative": 11
-                            },
-                            {
-                                "name": "Shower",
-                                "slug": "shower",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Shower",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 21,
-                                "assetCountCumulative": 21
-                            },
-                            {
-                                "name": "Toilet / Bidet",
-                                "slug": "toilet-bidet",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Toilet / Bidet",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 19,
-                                "assetCountCumulative": 19
-                            },
-                            {
-                                "name": "Towel rail",
-                                "slug": "towel-rail",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Towel rail",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 10,
-                                "assetCountCumulative": 10
-                            },
-                            {
-                                "name": "Wash Basin",
-                                "slug": "wash-basin",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Wash Basin",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 35,
-                                "assetCountCumulative": 35
-                            }
-                        ],
-                        "assetCount": 255,
-                        "assetCountCumulative": 255
-                    },
-                    {
-                        "name": "Bed",
-                        "slug": "bed",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Bed",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 57,
-                        "assetCountCumulative": 57
-                    },
-                    {
-                        "name": "Cabinets",
-                        "slug": "cabinets",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Cabinets",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Bookcase",
-                                "slug": "bookcase",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Bookcase",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 31,
-                                "assetCountCumulative": 31
-                            },
-                            {
-                                "name": "Commode",
-                                "slug": "commode",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Commode",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 108,
-                                "assetCountCumulative": 108
-                            },
-                            {
-                                "name": "Shelving",
-                                "slug": "shelving",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Shelving",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 103,
-                                "assetCountCumulative": 103
-                            },
-                            {
-                                "name": "TV Cabinets",
-                                "slug": "tv-cabinets",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "TV Cabinets",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 43,
-                                "assetCountCumulative": 43
-                            }
-                        ],
-                        "assetCount": 327,
-                        "assetCountCumulative": 327
-                    },
-                    {
-                        "name": "Chair",
-                        "slug": "chair",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Chair",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Bar Chair",
-                                "slug": "bar-chair",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Bar Chair",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 72,
-                                "assetCountCumulative": 72
-                            },
-                            {
-                                "name": "Regular Chair",
-                                "slug": "regular-chair",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Regular Chair",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 265,
-                                "assetCountCumulative": 265
-                            }
-                        ],
-                        "assetCount": 364,
-                        "assetCountCumulative": 364
-                    },
-                    {
-                        "name": "Console",
-                        "slug": "bedroom",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Console",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 39,
-                        "assetCountCumulative": 39
-                    },
-                    {
-                        "name": "Dressing Table",
-                        "slug": "living-room",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Dressing Table",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 13,
-                        "assetCountCumulative": 13
-                    },
-                    {
-                        "name": "Kids furniture",
-                        "slug": "kids-room",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Kids furniture",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Bed",
-                                "slug": "kidsfurniture-bed",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Bed",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 14,
-                                "assetCountCumulative": 14
-                            },
-                            {
-                                "name": "Chair",
-                                "slug": "kidsfurniture-chair",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Chair",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 3,
-                                "assetCountCumulative": 3
-                            },
-                            {
-                                "name": "Furniture Set",
-                                "slug": "furniture-set",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Furniture Set",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 8,
-                                "assetCountCumulative": 8
-                            },
-                            {
-                                "name": "Miscellaneous",
-                                "slug": "miscellaneous",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Miscellaneous",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 13,
-                                "assetCountCumulative": 13
-                            },
-                            {
-                                "name": "Table",
-                                "slug": "tablechair",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Table",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            },
-                            {
-                                "name": "Toy",
-                                "slug": "toy",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Toy",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 37,
-                                "assetCountCumulative": 37
-                            },
-                            {
-                                "name": "Wardrobe",
-                                "slug": "kidsfurniture-wardrobe",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Wardrobe",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 4,
-                                "assetCountCumulative": 4
-                            }
-                        ],
-                        "assetCount": 82,
-                        "assetCountCumulative": 82
-                    },
-                    {
-                        "name": "Kitchen Furniture",
-                        "slug": "kitchen",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Kitchen Furniture",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Faucet",
-                                "slug": "faucet",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Faucet",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 33,
-                                "assetCountCumulative": 33
-                            },
-                            {
-                                "name": "Kitchen Appliance",
-                                "slug": "kitchen-appliance",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Kitchen Appliance",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 126,
-                                "assetCountCumulative": 126
-                            },
-                            {
-                                "name": "Kitchen Set",
-                                "slug": "kitchen-set",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Kitchen Set",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 43,
-                                "assetCountCumulative": 43
-                            },
-                            {
-                                "name": "Sink",
-                                "slug": "sink",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Sink",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 18,
-                                "assetCountCumulative": 18
-                            },
-                            {
-                                "name": "Storage",
-                                "slug": "storage",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Storage",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 127,
-                                "assetCountCumulative": 127
-                            }
-                        ],
-                        "assetCount": 361,
-                        "assetCountCumulative": 361
-                    },
-                    {
-                        "name": "Lights",
-                        "slug": "lighting",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Lights",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Ceiling Light",
-                                "slug": "ceiling-light",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Ceiling Light",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 187,
-                                "assetCountCumulative": 187
-                            },
-                            {
-                                "name": "Floor Lamp",
-                                "slug": "floor-lamp",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Floor Lamp",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 57,
-                                "assetCountCumulative": 57
-                            },
-                            {
-                                "name": "IES Light",
-                                "slug": "ies-light",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "IES Light",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 10,
-                                "assetCountCumulative": 10
-                            },
-                            {
-                                "name": "Industrial Light",
-                                "slug": "industrial-light",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Industrial Light",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 19,
-                                "assetCountCumulative": 19
-                            },
-                            {
-                                "name": "Outdoor Light",
-                                "slug": "outdoor-light",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Outdoor Light",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 36,
-                                "assetCountCumulative": 36
-                            },
-                            {
-                                "name": "Table Lamp",
-                                "slug": "table-lamps",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Table Lamp",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 99,
-                                "assetCountCumulative": 99
-                            },
-                            {
-                                "name": "Wall Light",
-                                "slug": "wall-light",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Wall Light",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 51,
-                                "assetCountCumulative": 51
-                            }
-                        ],
-                        "assetCount": 480,
-                        "assetCountCumulative": 480
-                    },
-                    {
-                        "name": "Office Furniture",
-                        "slug": "office",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Office Furniture",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Chair",
-                                "slug": "office-chair",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Chair",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 26,
-                                "assetCountCumulative": 26
-                            },
-                            {
-                                "name": "Desk",
-                                "slug": "desk",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Desk",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 63,
-                                "assetCountCumulative": 63
-                            },
-                            {
-                                "name": "Stationery",
-                                "slug": "stationery",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Stationery",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 52,
-                                "assetCountCumulative": 52
-                            },
-                            {
-                                "name": "Storage",
-                                "slug": "office-storage",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Storage",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 32,
-                                "assetCountCumulative": 32
-                            },
-                            {
-                                "name": "Table",
-                                "slug": "office-table",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Table",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            }
-                        ],
-                        "assetCount": 186,
-                        "assetCountCumulative": 186
-                    },
-                    {
-                        "name": "Outdoor Furniture",
-                        "slug": "outdoor-furniture",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Outdoor Furniture",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 36,
-                        "assetCountCumulative": 36
-                    },
-                    {
-                        "name": "Pouf",
-                        "slug": "pouf",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Pouf",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 43,
-                        "assetCountCumulative": 43
-                    },
-                    {
-                        "name": "Restaurant / Bar",
-                        "slug": "restaurant-bar",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Restaurant / Bar",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 40,
-                        "assetCountCumulative": 40
-                    },
-                    {
-                        "name": "Seating Set",
-                        "slug": "seating",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Seating Set",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Chair-table Set",
-                                "slug": "chair-table-set",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Chair-table Set",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 18,
-                                "assetCountCumulative": 18
-                            },
-                            {
-                                "name": "Sofa-table Set",
-                                "slug": "sofa-table-set",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Sofa-table Set",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 5,
-                                "assetCountCumulative": 5
-                            }
-                        ],
-                        "assetCount": 31,
-                        "assetCountCumulative": 31
-                    },
-                    {
-                        "name": "Shopping / Retail",
-                        "slug": "shopping-retail",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Shopping / Retail",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 3,
-                        "assetCountCumulative": 3
-                    },
-                    {
-                        "name": "Sideboard / Drawers Chest",
-                        "slug": "hall",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Sideboard / Drawers Chest",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 124,
-                        "assetCountCumulative": 124
-                    },
-                    {
-                        "name": "Sofa",
-                        "slug": "sofa",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Sofa",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 208,
-                        "assetCountCumulative": 208
-                    },
-                    {
-                        "name": "Table",
-                        "slug": "table",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Table",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 444,
-                        "assetCountCumulative": 444
-                    },
-                    {
-                        "name": "Wardrobe",
-                        "slug": "wardrobe",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Wardrobe",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 62,
-                        "assetCountCumulative": 62
-                    }
-                ],
-                "assetCount": 3378,
-                "assetCountCumulative": 3378
-            },
-            {
-                "name": "Military",
-                "slug": "military",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Military",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Aircraft",
-                        "slug": "air",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Aircraft",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 15,
-                        "assetCountCumulative": 15
-                    },
-                    {
-                        "name": "Vehicles",
-                        "slug": "ground",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Vehicles",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 4,
-                        "assetCountCumulative": 4
-                    },
-                    {
-                        "name": "Watercraft",
-                        "slug": "naval",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Watercraft",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 1,
-                        "assetCountCumulative": 1
-                    },
-                    {
-                        "name": "Weapon / Armor",
-                        "slug": "weapon",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Weapon / Armor",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Historic",
-                                "slug": "historic-military",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Historic",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 67,
-                                "assetCountCumulative": 67
-                            },
-                            {
-                                "name": "Modern",
-                                "slug": "equipment",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Modern",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 47,
-                                "assetCountCumulative": 47
-                            },
-                            {
-                                "name": "Sci-Fi",
-                                "slug": "military-sci-fi",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Sci-Fi",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 22,
-                                "assetCountCumulative": 22
-                            }
-                        ],
-                        "assetCount": 144,
-                        "assetCountCumulative": 144
-                    }
-                ],
-                "assetCount": 164,
-                "assetCountCumulative": 164
-            },
-            {
-                "name": "Nature",
-                "slug": "nature",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Nature",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Atmosphere",
-                        "slug": "atmosphere",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Atmosphere",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Cloud",
-                                "slug": "weather",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Cloud",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 3,
-                                "assetCountCumulative": 3
-                            },
-                            {
-                                "name": "Fog",
-                                "slug": "fog",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Fog",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Smoke / Fire",
-                                "slug": "smoke-fire",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Smoke / Fire",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 2,
-                                "assetCountCumulative": 2
-                            },
-                            {
-                                "name": "Wind Setup",
-                                "slug": "wind-setup",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Wind Setup",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            }
-                        ],
-                        "assetCount": 5,
-                        "assetCountCumulative": 5
-                    },
-                    {
-                        "name": "Grass",
-                        "slug": "nature-grass",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Grass",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 30,
-                        "assetCountCumulative": 30
-                    },
-                    {
-                        "name": "Landscape",
-                        "slug": "landscape-nature",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Landscape",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Environment Elements",
-                                "slug": "environment-elements",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Environment Elements",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 128,
-                                "assetCountCumulative": 128
-                            },
-                            {
-                                "name": "Terrain",
-                                "slug": "landscape",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Terrain",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 26,
-                                "assetCountCumulative": 26
-                            }
-                        ],
-                        "assetCount": 155,
-                        "assetCountCumulative": 155
-                    },
-                    {
-                        "name": "Plant",
-                        "slug": "plant",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Plant",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Bouquet",
-                                "slug": "bouquet",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Bouquet",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 12,
-                                "assetCountCumulative": 12
-                            },
-                            {
-                                "name": "Fitowall",
-                                "slug": "fitowall",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Fitowall",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 4,
-                                "assetCountCumulative": 4
-                            },
-                            {
-                                "name": "Indoor",
-                                "slug": "nature-indoor",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Indoor",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 109,
-                                "assetCountCumulative": 109
-                            },
-                            {
-                                "name": "Outdoor",
-                                "slug": "nature-outdoor",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Outdoor",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 73,
-                                "assetCountCumulative": 73
-                            }
-                        ],
-                        "assetCount": 201,
-                        "assetCountCumulative": 201
-                    },
-                    {
-                        "name": "Tree",
-                        "slug": "tree",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Tree",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 246,
-                        "assetCountCumulative": 246
-                    }
-                ],
-                "assetCount": 638,
-                "assetCountCumulative": 638
-            },
-            {
-                "name": "Science",
-                "slug": "science",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Science",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Lab Equipment",
-                        "slug": "medicine",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Lab Equipment",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 15,
-                        "assetCountCumulative": 15
-                    },
-                    {
-                        "name": "Medical Equipment",
-                        "slug": "medical",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Medical Equipment",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 8,
-                        "assetCountCumulative": 8
-                    },
-                    {
-                        "name": "Microbiology",
-                        "slug": "microbiology",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Microbiology",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 6,
-                        "assetCountCumulative": 6
-                    },
-                    {
-                        "name": "Miscellaneous",
-                        "slug": "science-miscellaneous",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Miscellaneous",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 21,
-                        "assetCountCumulative": 21
-                    },
-                    {
-                        "name": "Pharmacy",
-                        "slug": "pharmacy",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Pharmacy",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 10,
-                        "assetCountCumulative": 10
-                    }
-                ],
-                "assetCount": 60,
-                "assetCountCumulative": 60
-            },
-            {
-                "name": "Space",
-                "slug": "space",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Space",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Miscellaneous",
-                        "slug": "sci-fi-space",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Miscellaneous",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 6,
-                        "assetCountCumulative": 6
-                    },
-                    {
-                        "name": "Planet",
-                        "slug": "planets",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Planet",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 31,
-                        "assetCountCumulative": 31
-                    },
-                    {
-                        "name": "Satellite",
-                        "slug": "satellite",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Satellite",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 3,
-                        "assetCountCumulative": 3
-                    },
-                    {
-                        "name": "Spacecraft",
-                        "slug": "spacecraft",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Spacecraft",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 23,
-                        "assetCountCumulative": 23
-                    },
-                    {
-                        "name": "Station",
-                        "slug": "astronomy",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Station",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 0,
-                        "assetCountCumulative": 0
-                    }
-                ],
-                "assetCount": 63,
-                "assetCountCumulative": 63
-            },
-            {
-                "name": "Sport / Hobby",
-                "slug": "sports",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Sport / Hobby",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Fishing",
-                        "slug": "outdoor",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Fishing",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 0,
-                        "assetCountCumulative": 0
-                    },
-                    {
-                        "name": "Gym",
-                        "slug": "individual",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Gym",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 43,
-                        "assetCountCumulative": 43
-                    },
-                    {
-                        "name": "Hobby Accessories",
-                        "slug": "team",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Hobby Accessories",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 21,
-                        "assetCountCumulative": 21
-                    },
-                    {
-                        "name": "Miscellaneous",
-                        "slug": "exercise",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Miscellaneous",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 30,
-                        "assetCountCumulative": 30
-                    },
-                    {
-                        "name": "Music",
-                        "slug": "music",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Music",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Accessories",
-                                "slug": "accessories",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Accessories",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 22,
-                                "assetCountCumulative": 22
-                            },
-                            {
-                                "name": "Instruments",
-                                "slug": "instruments",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Instruments",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 36,
-                                "assetCountCumulative": 36
-                            },
-                            {
-                                "name": "Stage",
-                                "slug": "stage",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Stage",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 2,
-                                "assetCountCumulative": 2
-                            },
-                            {
-                                "name": "Studio",
-                                "slug": "studio",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Studio",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            }
-                        ],
-                        "assetCount": 65,
-                        "assetCountCumulative": 65
-                    },
-                    {
-                        "name": "Sport",
-                        "slug": "extreme",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Sport",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 50,
-                        "assetCountCumulative": 50
-                    }
-                ],
-                "assetCount": 209,
-                "assetCountCumulative": 209
-            },
-            {
-                "name": "Technology",
-                "slug": "technology",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Technology",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Audio Devices",
-                        "slug": "audio",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Audio Devices",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 79,
-                        "assetCountCumulative": 79
-                    },
-                    {
-                        "name": "Computer",
-                        "slug": "computer",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Computer",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Components / Hardware",
-                                "slug": "components-hardware",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Components / Hardware",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 88,
-                                "assetCountCumulative": 88
-                            },
-                            {
-                                "name": "Desktop",
-                                "slug": "desktop",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Desktop",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 16,
-                                "assetCountCumulative": 16
-                            },
-                            {
-                                "name": "Game Console",
-                                "slug": "game-console",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Game Console",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 15,
-                                "assetCountCumulative": 15
-                            },
-                            {
-                                "name": "Keyboard",
-                                "slug": "keyboard",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Keyboard",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 11,
-                                "assetCountCumulative": 11
-                            },
-                            {
-                                "name": "Laptop",
-                                "slug": "laptop",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Laptop",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 17,
-                                "assetCountCumulative": 17
-                            },
-                            {
-                                "name": "Monitor",
-                                "slug": "monitor",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Monitor",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 12,
-                                "assetCountCumulative": 12
-                            },
-                            {
-                                "name": "Mouse",
-                                "slug": "mouse",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Mouse",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 6,
-                                "assetCountCumulative": 6
-                            },
-                            {
-                                "name": "Peripheral",
-                                "slug": "peripheral",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Peripheral",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 10,
-                                "assetCountCumulative": 10
-                            }
-                        ],
-                        "assetCount": 180,
-                        "assetCountCumulative": 180
-                    },
-                    {
-                        "name": "Devices",
-                        "slug": "devices",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Devices",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Celullar Phone",
-                                "slug": "celullar-phone",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Celullar Phone",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 4,
-                                "assetCountCumulative": 4
-                            },
-                            {
-                                "name": "Corded Phone",
-                                "slug": "corded-phone",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Corded Phone",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 6,
-                                "assetCountCumulative": 6
-                            },
-                            {
-                                "name": "Smartphone",
-                                "slug": "phone",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Smartphone",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 23,
-                                "assetCountCumulative": 23
-                            },
-                            {
-                                "name": "Smart Watch",
-                                "slug": "smart-watch",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Smart Watch",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Tablet",
-                                "slug": "tablet",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Tablet",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 6,
-                                "assetCountCumulative": 6
-                            }
-                        ],
-                        "assetCount": 39,
-                        "assetCountCumulative": 39
-                    },
-                    {
-                        "name": "Household Appliances",
-                        "slug": "household-appliances",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Household Appliances",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 50,
-                        "assetCountCumulative": 50
-                    },
-                    {
-                        "name": "Miscellaneous",
-                        "slug": "industrial-exterior",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Miscellaneous",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 170,
-                        "assetCountCumulative": 170
-                    },
-                    {
-                        "name": "Photography",
-                        "slug": "photography",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Photography",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 20,
-                        "assetCountCumulative": 20
-                    },
-                    {
-                        "name": "Robotics",
-                        "slug": "ai",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Robotics",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 47,
-                        "assetCountCumulative": 47
-                    },
-                    {
-                        "name": "Video devices",
-                        "slug": "video",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Video devices",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 21,
-                        "assetCountCumulative": 21
-                    }
-                ],
-                "assetCount": 606,
-                "assetCountCumulative": 606
-            },
-            {
-                "name": "Transport",
-                "slug": "vehicle",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Transport",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Aircraft",
-                        "slug": "aircraft",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Aircraft",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Accessories / Part",
-                                "slug": "part-aircraft",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Accessories / Part",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 4,
-                                "assetCountCumulative": 4
-                            },
-                            {
-                                "name": "Air Baloon",
-                                "slug": "air-baloon",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Air Baloon",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Airplane",
-                                "slug": "commercial",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Airplane",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 3,
-                                "assetCountCumulative": 3
-                            },
-                            {
-                                "name": "Drone",
-                                "slug": "drone",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Drone",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 3,
-                                "assetCountCumulative": 3
-                            },
-                            {
-                                "name": "Glider",
-                                "slug": "glider",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Glider",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Helicopter",
-                                "slug": "helicopter",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Helicopter",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 3,
-                                "assetCountCumulative": 3
-                            },
-                            {
-                                "name": "Historic Plane",
-                                "slug": "historic-aircraft",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Historic Plane",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Private Jet",
-                                "slug": "private",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Private Jet",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Seaplane",
-                                "slug": "jet",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Seaplane",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            }
-                        ],
-                        "assetCount": 16,
-                        "assetCountCumulative": 16
-                    },
-                    {
-                        "name": "Bicycle",
-                        "slug": "bicycle",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Bicycle",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 9,
-                        "assetCountCumulative": 9
-                    },
-                    {
-                        "name": "Car",
-                        "slug": "car",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Car",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Buggy",
-                                "slug": "buggy",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Buggy",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 2,
-                                "assetCountCumulative": 2
-                            },
-                            {
-                                "name": "Concept",
-                                "slug": "concept",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Concept",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 17,
-                                "assetCountCumulative": 17
-                            },
-                            {
-                                "name": "Historical",
-                                "slug": "historic-vehicle",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Historical",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 14,
-                                "assetCountCumulative": 14
-                            },
-                            {
-                                "name": "Luxury / Supercar",
-                                "slug": "luxury-supercar",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Luxury / Supercar",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 27,
-                                "assetCountCumulative": 27
-                            },
-                            {
-                                "name": "Racing",
-                                "slug": "racing",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Racing",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 2,
-                                "assetCountCumulative": 2
-                            },
-                            {
-                                "name": "Sci-Fi",
-                                "slug": "transport-sci-fi",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Sci-Fi",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 4,
-                                "assetCountCumulative": 4
-                            },
-                            {
-                                "name": "Standard",
-                                "slug": "standard",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Standard",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 40,
-                                "assetCountCumulative": 40
-                            }
-                        ],
-                        "assetCount": 112,
-                        "assetCountCumulative": 112
-                    },
-                    {
-                        "name": "Emergency",
-                        "slug": "emergency",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Emergency",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Ambulance",
-                                "slug": "ambulance",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Ambulance",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Fire Department",
-                                "slug": "fire-department",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Fire Department",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Police",
-                                "slug": "transport-police",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Police",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            }
-                        ],
-                        "assetCount": 1,
-                        "assetCountCumulative": 1
-                    },
-                    {
-                        "name": "Heavy Vehicle",
-                        "slug": "heavy-vehicle",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Heavy Vehicle",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Industrial",
-                                "slug": "industrial-vehicle",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Industrial",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 4,
-                                "assetCountCumulative": 4
-                            },
-                            {
-                                "name": "Trailer",
-                                "slug": "trailer",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Trailer",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Truck",
-                                "slug": "truck",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Truck",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 3,
-                                "assetCountCumulative": 3
-                            },
-                            {
-                                "name": "Van",
-                                "slug": "van",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Van",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 2,
-                                "assetCountCumulative": 2
-                            }
-                        ],
-                        "assetCount": 10,
-                        "assetCountCumulative": 10
-                    },
-                    {
-                        "name": "Motocycle",
-                        "slug": "motorcycle",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Motocycle",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Historical",
-                                "slug": "historical",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Historical",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Sport",
-                                "slug": "sport",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Sport",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Standard",
-                                "slug": "transport-standard",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Standard",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 2,
-                                "assetCountCumulative": 2
-                            }
-                        ],
-                        "assetCount": 2,
-                        "assetCountCumulative": 2
-                    },
-                    {
-                        "name": "Public Transport",
-                        "slug": "public-transport",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Public Transport",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Bus",
-                                "slug": "bus",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Bus",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 2,
-                                "assetCountCumulative": 2
-                            },
-                            {
-                                "name": "Taxi",
-                                "slug": "taxi",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Taxi",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            }
-                        ],
-                        "assetCount": 2,
-                        "assetCountCumulative": 2
-                    },
-                    {
-                        "name": "Railed vehicle",
-                        "slug": "railed-vehicle",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Railed vehicle",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Cargo",
-                                "slug": "cargo",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Cargo",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            },
-                            {
-                                "name": "Passenger",
-                                "slug": "train",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Passenger",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 3,
-                                "assetCountCumulative": 3
-                            }
-                        ],
-                        "assetCount": 5,
-                        "assetCountCumulative": 5
-                    },
-                    {
-                        "name": "Small Electric Vehicles",
-                        "slug": "small-electric-vehicles",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Small Electric Vehicles",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 0,
-                        "assetCountCumulative": 0
-                    },
-                    {
-                        "name": "Vehicle Parts",
-                        "slug": "part-vehicle",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Vehicle Parts",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 167,
-                        "assetCountCumulative": 167
-                    },
-                    {
-                        "name": "Watercraft",
-                        "slug": "watercraft",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Watercraft",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [
-                            {
-                                "name": "Accessories / Part",
-                                "slug": "part-watercraft",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Accessories / Part",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Boat",
-                                "slug": "recreational",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Boat",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 4,
-                                "assetCountCumulative": 4
-                            },
-                            {
-                                "name": "Hovercraft",
-                                "slug": "hovercraft",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Hovercraft",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            },
-                            {
-                                "name": "Ship",
-                                "slug": "industrial-watercraft",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Ship",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            },
-                            {
-                                "name": "Submarine",
-                                "slug": "historic-watercraft",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Submarine",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 0,
-                                "assetCountCumulative": 0
-                            },
-                            {
-                                "name": "Yacht",
-                                "slug": "personal",
-                                "active": true,
-                                "thumbnail": null,
-                                "thumbnailWidth": null,
-                                "thumbnailHeight": null,
-                                "order": 0,
-                                "alternateTitle": "Yacht",
-                                "alternateUrl": "",
-                                "description": "",
-                                "metaKeywords": "",
-                                "metaExtra": "",
-                                "children": [],
-                                "assetCount": 1,
-                                "assetCountCumulative": 1
-                            }
-                        ],
-                        "assetCount": 7,
-                        "assetCountCumulative": 7
-                    }
-                ],
-                "assetCount": 334,
-                "assetCountCumulative": 334
-            }
-        ],
-        "assetCount": 8630,
-        "assetCountCumulative": 8630
-    },
-    {
-        "name": "Scene",
-        "slug": "scene",
-        "active": true,
-        "thumbnail": null,
-        "thumbnailWidth": null,
-        "thumbnailHeight": null,
-        "order": 0,
-        "alternateTitle": "scene",
-        "alternateUrl": "",
-        "description": "",
-        "metaKeywords": "",
-        "metaExtra": "",
-        "children": [
-            {
-                "name": "Indoor",
-                "slug": "scene-indoor",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Indoor",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 38,
-                "assetCountCumulative": 38
-            },
-            {
-                "name": "Outdoor",
-                "slug": "scene-outdoor",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Outdoor",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [],
-                "assetCount": 8,
-                "assetCountCumulative": 8
-            },
-            {
-                "name": "templates",
-                "slug": "templates",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "templates",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "brush templates",
-                        "slug": "brush-templates",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "brush templates",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 4,
-                        "assetCountCumulative": 4
-                    }
-                ],
-                "assetCount": 4,
-                "assetCountCumulative": 4
-            }
-        ],
-        "assetCount": 50,
-        "assetCountCumulative": 50
-    },
-    {
-        "name": "texture",
-        "slug": "texture",
-        "active": true,
-        "thumbnail": null,
-        "thumbnailWidth": null,
-        "thumbnailHeight": null,
-        "order": 0,
-        "alternateTitle": "texture",
-        "alternateUrl": "",
-        "description": "",
-        "metaKeywords": "",
-        "metaExtra": "",
-        "children": [
-            {
-                "name": "Animals",
-                "slug": "animals",
-                "active": true,
-                "thumbnail": null,
-                "thumbnailWidth": null,
-                "thumbnailHeight": null,
-                "order": 0,
-                "alternateTitle": "Animals",
-                "alternateUrl": "",
-                "description": "",
-                "metaKeywords": "",
-                "metaExtra": "",
-                "children": [
-                    {
-                        "name": "Mammals",
-                        "slug": "mammals",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Mammals",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 0,
-                        "assetCountCumulative": 0
-                    },
-                    {
-                        "name": "Plants",
-                        "slug": "plants",
-                        "active": true,
-                        "thumbnail": null,
-                        "thumbnailWidth": null,
-                        "thumbnailHeight": null,
-                        "order": 0,
-                        "alternateTitle": "Plants",
-                        "alternateUrl": "",
-                        "description": "",
-                        "metaKeywords": "",
-                        "metaExtra": "",
-                        "children": [],
-                        "assetCount": 0,
-                        "assetCountCumulative": 0
-                    }
-                ],
-                "assetCount": 0,
-                "assetCountCumulative": 12
-            }
-        ],
-        "assetCount": 0,
-        "assetCountCumulative": 0
-    }
-]
\ No newline at end of file
diff --git a/blenderkit/download.py b/blenderkit/download.py
deleted file mode 100644
index 7fda06a2c52b7a8cdac9ae9afa34cbeed46ace54..0000000000000000000000000000000000000000
--- a/blenderkit/download.py
+++ /dev/null
@@ -1,1467 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import paths, append_link, utils, ui, colors, tasks_queue, rerequests, resolutions, ui_panels, search, reports
-
-import threading
-import time
-import requests
-import shutil, sys, os
-import uuid
-import copy
-import logging
-
-bk_logger = logging.getLogger('blenderkit')
-
-import bpy
-from bpy.props import (
-    IntProperty,
-    FloatProperty,
-    FloatVectorProperty,
-    StringProperty,
-    EnumProperty,
-    BoolProperty,
-    PointerProperty,
-)
-from bpy.app.handlers import persistent
-
-download_threads = []
-
-
-def check_missing():
-    '''checks for missing files, and possibly starts re-download of these into the scene'''
-    s = bpy.context.scene
-    # missing libs:
-    # TODO: put these into a panel and let the user decide if these should be downloaded.
-    missing = []
-    for l in bpy.data.libraries:
-        fp = l.filepath
-        if fp.startswith('//'):
-            fp = bpy.path.abspath(fp)
-        if not os.path.exists(fp) and l.get('asset_data') is not None:
-            missing.append(l)
-
-    # print('missing libraries', missing)
-
-    for l in missing:
-        asset_data = l['asset_data']
-
-        downloaded = check_existing(asset_data, resolution=asset_data.get('resolution'))
-        if downloaded:
-            try:
-                l.reload()
-            except:
-                download(l['asset_data'], redownload=True)
-        else:
-            download(l['asset_data'], redownload=True)
-
-
-def check_unused():
-    '''find assets that have been deleted from scene but their library is still present.'''
-    # this is obviously broken. Blender should take care of the extra data automaticlaly
-    # first clean up collections
-    for c in bpy.data.collections:
-        if len(c.all_objects) == 0 and c.get('is_blenderkit_asset'):
-            bpy.data.collections.remove(c)
-    return;
-    used_libs = []
-    for ob in bpy.data.objects:
-        if ob.instance_collection is not None and ob.instance_collection.library is not None:
-            # used_libs[ob.instance_collection.name] = True
-            if ob.instance_collection.library not in used_libs:
-                used_libs.append(ob.instance_collection.library)
-
-        for ps in ob.particle_systems:
-            set = ps.settings
-            if ps.settings.render_type == 'GROUP' \
-                    and ps.settings.instance_collection is not None \
-                    and ps.settings.instance_collection.library not in used_libs:
-                used_libs.append(ps.settings.instance_collection)
-
-    for l in bpy.data.libraries:
-        if l not in used_libs and l.getn('asset_data'):
-            print('attempt to remove this library: ', l.filepath)
-            # have to unlink all groups, since the file is a 'user' even if the groups aren't used at all...
-            for user_id in l.users_id:
-                if type(user_id) == bpy.types.Collection:
-                    bpy.data.collections.remove(user_id)
-            l.user_clear()
-
-
-@persistent
-def scene_save(context):
-    ''' does cleanup of blenderkit props and sends a message to the server about assets used.'''
-    # TODO this can be optimized by merging these 2 functions, since both iterate over all objects.
-    if not bpy.app.background:
-        check_unused()
-        report_usages()
-
-
-@persistent
-def scene_load(context):
-    '''restart broken downloads on scene load'''
-    t = time.time()
-    s = bpy.context.scene
-    global download_threads
-    download_threads = []
-
-    # commenting this out - old restore broken download on scene start. Might come back if downloads get recorded in scene
-    # reset_asset_ids = {}
-    # reset_obs = {}
-    # for ob in bpy.context.scene.collection.objects:
-    #     if ob.name[:12] == 'downloading ':
-    #         obn = ob.name
-    #
-    #         asset_data = ob['asset_data']
-    #
-    #         # obn.replace('#', '')
-    #         # if asset_data['id'] not in reset_asset_ids:
-    #
-    #         if reset_obs.get(asset_data['id']) is None:
-    #             reset_obs[asset_data['id']] = [obn]
-    #             reset_asset_ids[asset_data['id']] = asset_data
-    #         else:
-    #             reset_obs[asset_data['id']].append(obn)
-    # for asset_id in reset_asset_ids:
-    #     asset_data = reset_asset_ids[asset_id]
-    #     done = False
-    #     if check_existing(asset_data, resolution = should be here):
-    #         for obname in reset_obs[asset_id]:
-    #             downloader = s.collection.objects[obname]
-    #             done = try_finished_append(asset_data,
-    #                                        model_location=downloader.location,
-    #                                        model_rotation=downloader.rotation_euler)
-    #
-    #     if not done:
-    #         downloading = check_downloading(asset_data)
-    #         if not downloading:
-    #             print('redownloading %s' % asset_data['name'])
-    #             download(asset_data, downloaders=reset_obs[asset_id], delete=True)
-
-    # check for group users that have been deleted, remove the groups /files from the file...
-    # TODO scenes fixing part... download the assets not present on drive,
-    # and erase from scene linked files that aren't used in the scene.
-    # print('continue downlaods ', time.time() - t)
-    t = time.time()
-    check_missing()
-    # print('missing check', time.time() - t)
-
-
-def get_scene_id():
-    '''gets scene id and possibly also generates a new one'''
-    bpy.context.scene['uuid'] = bpy.context.scene.get('uuid', str(uuid.uuid4()))
-    return bpy.context.scene['uuid']
-
-
-def report_usages():
-    '''report the usage of assets to the server.'''
-    mt = time.time()
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    api_key = user_preferences.api_key
-    sid = get_scene_id()
-    headers = utils.get_headers(api_key)
-    url = paths.get_api_url() + paths.BLENDERKIT_REPORT_URL
-
-    assets = {}
-    asset_obs = []
-    scene = bpy.context.scene
-    asset_usages = {}
-
-    for ob in scene.collection.objects:
-        if ob.get('asset_data') != None:
-            asset_obs.append(ob)
-
-    for ob in asset_obs:
-        asset_data = ob['asset_data']
-        abid = asset_data['assetBaseId']
-
-        if assets.get(abid) is None:
-            asset_usages[abid] = {'count': 1}
-            assets[abid] = asset_data
-        else:
-            asset_usages[abid]['count'] += 1
-
-    # brushes
-    for b in bpy.data.brushes:
-        if b.get('asset_data') != None:
-            abid = b['asset_data']['assetBaseId']
-            asset_usages[abid] = {'count': 1}
-            assets[abid] = b['asset_data']
-    # materials
-    for ob in scene.collection.objects:
-        for ms in ob.material_slots:
-            m = ms.material
-
-            if m is not None and m.get('asset_data') is not None:
-
-                abid = m['asset_data']['assetBaseId']
-                if assets.get(abid) is None:
-                    asset_usages[abid] = {'count': 1}
-                    assets[abid] = m['asset_data']
-                else:
-                    asset_usages[abid]['count'] += 1
-
-    assets_list = []
-    assets_reported = scene.get('assets reported', {})
-
-    new_assets_count = 0
-    for k in asset_usages.keys():
-        if k not in assets_reported.keys():
-            data = asset_usages[k]
-            list_item = {
-                'asset': k,
-                'usageCount': data['count'],
-                'proximitySet': data.get('proximity', [])
-            }
-            assets_list.append(list_item)
-            new_assets_count += 1
-        if k not in assets_reported.keys():
-            assets_reported[k] = True
-
-    scene['assets reported'] = assets_reported
-
-    if new_assets_count == 0:
-        bk_logger.debug('no new assets were added')
-        return;
-    usage_report = {
-        'scene': sid,
-        'reportType': 'save',
-        'assetusageSet': assets_list
-    }
-
-    au = scene.get('assets used', {})
-    ad = scene.get('assets deleted', {})
-
-    ak = assets.keys()
-    for k in au.keys():
-        if k not in ak:
-            ad[k] = au[k]
-        else:
-            if k in ad:
-                ad.pop(k)
-
-    # scene['assets used'] = {}
-    for k in ak:  # rewrite assets used.
-        scene['assets used'][k] = assets[k]
-
-    ###########check ratings herer too:
-    scene['assets rated'] = scene.get('assets rated', {})
-    for k in assets.keys():
-        scene['assets rated'][k] = scene['assets rated'].get(k, False)
-    thread = threading.Thread(target=utils.requests_post_thread, args=(url, usage_report, headers))
-    thread.start()
-    mt = time.time() - mt
-    # print('report generation:                ', mt)
-
-
-def udpate_asset_data_in_dicts(asset_data):
-    '''
-    updates asset data in all relevant dictionaries, after a threaded download task \
-    - where the urls were retrieved, and now they can be reused
-    Parameters
-    ----------
-    asset_data - data coming back from thread, thus containing also download urls
-    '''
-    scene = bpy.context.scene
-    scene['assets used'] = scene.get('assets used', {})
-    scene['assets used'][asset_data['assetBaseId']] = asset_data.copy()
-
-    scene['assets rated'] = scene.get('assets rated', {})
-    id = asset_data['assetBaseId']
-    scene['assets rated'][id] = scene['assets rated'].get(id, False)
-    sr = bpy.context.window_manager['search results']
-    if not sr:
-        return;
-    for i, r in enumerate(sr):
-        if r['assetBaseId'] == asset_data['assetBaseId']:
-            for f in asset_data['files']:
-                if f.get('url'):
-                    for f1 in r['files']:
-                        if f1['fileType'] == f['fileType']:
-                            f1['url'] = f['url']
-
-
-def append_asset(asset_data, **kwargs):  # downloaders=[], location=None,
-    '''Link asset to the scene.
-
-
-    '''
-    file_names = paths.get_download_filepaths(asset_data, kwargs['resolution'])
-    props = None
-    #####
-    # how to do particle  drop:
-    # link the group we are interested in( there are more groups in File!!!! , have to get the correct one!)
-    s = bpy.context.scene
-    wm = bpy.context.window_manager
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-    if user_preferences.api_key == '':
-        user_preferences.asset_counter += 1
-
-    if asset_data['assetType'] == 'scene':
-        sprops = wm.blenderkit_scene
-
-        scene = append_link.append_scene(file_names[0], link=sprops.append_link == 'LINK', fake_user=False)
-        # print('scene appended')
-        if scene is not None:
-            props = scene.blenderkit
-            asset_main = scene
-            if sprops.switch_after_append:
-                bpy.context.window_manager.windows[0].scene = scene
-
-    if asset_data['assetType'] == 'hdr':
-        hdr = append_link.load_HDR(file_name=file_names[0], name=asset_data['name'])
-        props = hdr.blenderkit
-        asset_main = hdr
-
-    if asset_data['assetType'] == 'model':
-        downloaders = kwargs.get('downloaders')
-        sprops = wm.blenderkit_models
-        # TODO this is here because combinations of linking objects or appending groups are rather not-usefull
-        if sprops.append_method == 'LINK_COLLECTION':
-            sprops.append_link = 'LINK'
-            sprops.import_as = 'GROUP'
-        else:
-            sprops.append_link = 'APPEND'
-            sprops.import_as = 'INDIVIDUAL'
-
-        # copy for override
-        al = sprops.append_link
-        # set consistency for objects already in scene, otherwise this literally breaks blender :)
-        ain, resolution = asset_in_scene(asset_data)
-        # this is commented out since it already happens in start_download function.
-        # if resolution:
-        #     kwargs['resolution'] = resolution
-        # override based on history
-        if ain is not False:
-            if ain == 'LINKED':
-                al = 'LINK'
-            else:
-                al = 'APPEND'
-                if asset_data['assetType'] == 'model':
-                    source_parent = get_asset_in_scene(asset_data)
-                    if source_parent:
-                        asset_main, new_obs = duplicate_asset(source=source_parent, **kwargs)
-                        asset_main.location = kwargs['model_location']
-                        asset_main.rotation_euler = kwargs['model_rotation']
-                        # this is a case where asset is already in scene and should be duplicated instead.
-                        # there is a big chance that the duplication wouldn't work perfectly(hidden or unselectable objects)
-                        # so here we need to check and return if there was success
-                        # also, if it was successful, no other operations are needed , basically all asset data is already ready from the original asset
-                        if new_obs:
-                            # update here assets rated/used because there might be new download urls?
-                            udpate_asset_data_in_dicts(asset_data)
-                            bpy.ops.wm.undo_push_context(message='add %s to scene' % asset_data['name'])
-
-                            return
-
-        # first get conditions for append link
-        link = al == 'LINK'
-        # then append link
-        if downloaders:
-            for downloader in downloaders:
-                # this cares for adding particle systems directly to target mesh, but I had to block it now,
-                # because of the sluggishnes of it. Possibly re-enable when it's possible to do this faster?
-                if 'particle_plants' in asset_data['tags']:
-                    append_link.append_particle_system(file_names[-1],
-                                                       target_object=kwargs['target_object'],
-                                                       rotation=downloader['rotation'],
-                                                       link=False,
-                                                       name=asset_data['name'])
-                    return
-
-                if link:
-                    asset_main, new_obs = append_link.link_collection(file_names[-1],
-                                                                      location=downloader['location'],
-                                                                      rotation=downloader['rotation'],
-                                                                      link=link,
-                                                                      name=asset_data['name'],
-                                                                      parent=kwargs.get('parent'))
-
-                else:
-
-                    asset_main, new_obs = append_link.append_objects(file_names[-1],
-                                                                     location=downloader['location'],
-                                                                     rotation=downloader['rotation'],
-                                                                     link=link,
-                                                                     name=asset_data['name'],
-                                                                     parent=kwargs.get('parent'))
-                if asset_main.type == 'EMPTY' and link:
-                    bmin = asset_data['bbox_min']
-                    bmax = asset_data['bbox_max']
-                    size_min = min(1.0, (bmax[0] - bmin[0] + bmax[1] - bmin[1] + bmax[2] - bmin[2]) / 3)
-                    asset_main.empty_display_size = size_min
-
-        elif kwargs.get('model_location') is not None:
-            if link:
-                asset_main, new_obs = append_link.link_collection(file_names[-1],
-                                                                  location=kwargs['model_location'],
-                                                                  rotation=kwargs['model_rotation'],
-                                                                  link=link,
-                                                                  name=asset_data['name'],
-                                                                  parent=kwargs.get('parent'))
-            else:
-                asset_main, new_obs = append_link.append_objects(file_names[-1],
-                                                                 location=kwargs['model_location'],
-                                                                 rotation=kwargs['model_rotation'],
-                                                                 link=link,
-                                                                 name=asset_data['name'],
-                                                                 parent=kwargs.get('parent'))
-
-            # scale Empty for assets, so they don't clutter the scene.
-            if asset_main.type == 'EMPTY' and link:
-                bmin = asset_data['bbox_min']
-                bmax = asset_data['bbox_max']
-                size_min = min(1.0, (bmax[0] - bmin[0] + bmax[1] - bmin[1] + bmax[2] - bmin[2]) / 3)
-                asset_main.empty_display_size = size_min
-
-        if link:
-            group = asset_main.instance_collection
-
-            lib = group.library
-            lib['asset_data'] = asset_data
-
-    elif asset_data['assetType'] == 'brush':
-        # TODO if already in scene, should avoid reappending.
-        inscene = False
-        for b in bpy.data.brushes:
-
-            if b.blenderkit.id == asset_data['id']:
-                inscene = True
-                brush = b
-                break;
-        if not inscene:
-            brush = append_link.append_brush(file_names[-1], link=False, fake_user=False)
-
-            thumbnail_name = asset_data['thumbnail'].split(os.sep)[-1]
-            tempdir = paths.get_temp_dir('brush_search')
-            thumbpath = os.path.join(tempdir, thumbnail_name)
-            asset_thumbs_dir = paths.get_download_dirs('brush')[0]
-            asset_thumb_path = os.path.join(asset_thumbs_dir, thumbnail_name)
-            shutil.copy(thumbpath, asset_thumb_path)
-            brush.icon_filepath = asset_thumb_path
-
-        if bpy.context.view_layer.objects.active.mode == 'SCULPT':
-            bpy.context.tool_settings.sculpt.brush = brush
-        elif bpy.context.view_layer.objects.active.mode == 'TEXTURE_PAINT':  # could be just else, but for future possible more types...
-            bpy.context.tool_settings.image_paint.brush = brush
-        # TODO set brush by by asset data(user can be downloading while switching modes.)
-
-        # bpy.context.tool_settings.image_paint.brush = brush
-        props = brush.blenderkit
-        asset_main = brush
-
-    elif asset_data['assetType'] == 'material':
-        inscene = False
-        sprops = wm.blenderkit_mat
-
-        for m in bpy.data.materials:
-            if m.blenderkit.id == asset_data['id']:
-                inscene = True
-                material = m
-                break;
-        if not inscene:
-            link = sprops.append_method == 'LINK'
-            material = append_link.append_material(file_names[-1], link=link, fake_user=False)
-        target_object = bpy.data.objects[kwargs['target_object']]
-
-        if len(target_object.material_slots) == 0:
-            target_object.data.materials.append(material)
-        else:
-            target_object.material_slots[kwargs['material_target_slot']].material = material
-
-        asset_main = material
-
-    asset_data['resolution'] = kwargs['resolution']
-    udpate_asset_data_in_dicts(asset_data)
-
-    asset_main['asset_data'] = asset_data  # TODO remove this??? should write to blenderkit Props?
-    asset_main.blenderkit.asset_base_id = asset_data['assetBaseId']
-    asset_main.blenderkit.id = asset_data['id']
-
-    bpy.ops.wm.undo_push_context(message='add %s to scene' % asset_data['name'])
-    # moving reporting to on save.
-    # report_use_success(asset_data['id'])
-
-
-def replace_resolution_linked(file_paths, asset_data):
-    # replace one asset resolution for another.
-    # this is the much simpler case
-    #  - find the library,
-    #  - replace the path and name of the library, reload.
-    file_name = os.path.basename(file_paths[-1])
-
-    for l in bpy.data.libraries:
-        if not l.get('asset_data'):
-            continue;
-        if not l['asset_data']['assetBaseId'] == asset_data['assetBaseId']:
-            continue;
-
-        bk_logger.debug('try to re-link library')
-
-        if not os.path.isfile(file_paths[-1]):
-            bk_logger.debug('library file doesnt exist')
-            break;
-        l.filepath = os.path.join(os.path.dirname(l.filepath), file_name)
-        l.name = file_name
-        udpate_asset_data_in_dicts(asset_data)
-
-
-def replace_resolution_appended(file_paths, asset_data, resolution):
-    # In this case the texture paths need to be replaced.
-    # Find the file path pattern that is present in texture paths
-    # replace the pattern with the new one.
-    file_name = os.path.basename(file_paths[-1])
-
-    new_filename_pattern = os.path.splitext(file_name)[0]
-    all_patterns = []
-    for suff in paths.resolution_suffix.values():
-        pattern = f"{asset_data['id']}{os.sep}textures{suff}{os.sep}"
-        all_patterns.append(pattern)
-    new_pattern = f"{asset_data['id']}{os.sep}textures{paths.resolution_suffix[resolution]}{os.sep}"
-
-    # replace the pattern with the new one.
-    # print(existing_filename_patterns)
-    # print(new_filename_pattern)
-    # print('existing images:')
-    for i in bpy.data.images:
-
-        for old_pattern in all_patterns:
-            if i.filepath.find(old_pattern) > -1:
-                fp = i.filepath.replace(old_pattern, new_pattern)
-                fpabs = bpy.path.abspath(fp)
-                if not os.path.exists(fpabs):
-                    # this currently handles .png's that have been swapped to .jpg's during resolution generation process.
-                    # should probably also handle .exr's and similar others.
-                    # bk_logger.debug('need to find a replacement')
-                    base, ext = os.path.splitext(fp)
-                    if resolution == 'blend' and i.get('original_extension'):
-                        fp = base + i.get('original_extension')
-                    elif ext in ('.png', '.PNG'):
-                        fp = base + '.jpg'
-                i.filepath = fp
-                i.filepath_raw = fp  # bpy.path.abspath(fp)
-                for pf in i.packed_files:
-                    pf.filepath = fp
-                i.reload()
-    udpate_asset_data_in_dicts(asset_data)
-
-
-# @bpy.app.handlers.persistent
-def download_timer():
-    # TODO might get moved to handle all blenderkit stuff, not to slow down.
-    '''
-    check for running and finished downloads.
-    Running downloads get checked for progress which is passed to UI.
-    Finished downloads are processed and linked/appended to scene.
-     '''
-    global download_threads
-    # utils.p('start download timer')
-
-    # bk_logger.debug('timer download')
-
-    if len(download_threads) == 0:
-        # utils.p('end download timer')
-
-        return 2
-    s = bpy.context.scene
-    for threaddata in download_threads:
-        t = threaddata[0]
-        asset_data = threaddata[1]
-        tcom = threaddata[2]
-
-        progress_bars = []
-        downloaders = []
-
-        if t.is_alive():  # set downloader size
-            sr = bpy.context.window_manager.get('search results')
-            if sr is not None:
-                for r in sr:
-                    if asset_data['id'] == r['id']:
-                        r['downloaded'] = 0.5  # tcom.progress
-        if not t.is_alive():
-            if tcom.error:
-                sprops = utils.get_search_props()
-                sprops.report = tcom.report
-                download_threads.remove(threaddata)
-                # utils.p('end download timer')
-
-                return
-            file_paths = paths.get_download_filepaths(asset_data, tcom.passargs['resolution'])
-
-            if len(file_paths) == 0:
-                bk_logger.debug('library names not found in asset data after download')
-                download_threads.remove(threaddata)
-                break;
-
-            wm = bpy.context.window_manager
-
-            at = asset_data['assetType']
-            if ((bpy.context.mode == 'OBJECT' and \
-                 (at == 'model' or at == 'material'))) \
-                    or ((at == 'brush') \
-                        and wm.get('appendable') == True) or at == 'scene' or at == 'hdr':
-                # don't do this stuff in editmode and other modes, just wait...
-                download_threads.remove(threaddata)
-
-                # duplicate file if the global and subdir are used in prefs
-                if len(file_paths) == 2:  # todo this should try to check if both files exist and are ok.
-                    utils.copy_asset(file_paths[0], file_paths[1])
-                    # shutil.copyfile(file_paths[0], file_paths[1])
-
-                bk_logger.debug('appending asset')
-                # progress bars:
-
-                # we need to check if mouse isn't down, which means an operator can be running.
-                # Especially for sculpt mode, where appending a brush during a sculpt stroke causes crasehes
-                #
-
-                if tcom.passargs.get('redownload'):
-                    # handle lost libraries here:
-                    for l in bpy.data.libraries:
-                        if l.get('asset_data') is not None and l['asset_data']['id'] == asset_data['id']:
-                            l.filepath = file_paths[-1]
-                            l.reload()
-
-                if tcom.passargs.get('replace_resolution'):
-                    # try to relink
-                    # HDRs are always swapped, so their swapping is handled without the replace_resolution option
-
-                    ain, resolution = asset_in_scene(asset_data)
-
-                    if ain == 'LINKED':
-                        replace_resolution_linked(file_paths, asset_data)
-
-
-                    elif ain == 'APPENDED':
-                        replace_resolution_appended(file_paths, asset_data, tcom.passargs['resolution'])
-
-
-
-                else:
-                    done = try_finished_append(asset_data, **tcom.passargs)
-                    if not done:
-                        at = asset_data['assetType']
-                        tcom.passargs['retry_counter'] = tcom.passargs.get('retry_counter', 0) + 1
-                        download(asset_data, **tcom.passargs)
-
-                    if bpy.context.window_manager['search results'] is not None and done:
-                        for sres in bpy.context.window_manager['search results']:
-                            if asset_data['id'] == sres['id']:
-                                sres['downloaded'] = 100
-
-                bk_logger.debug('finished download thread')
-    # utils.p('end download timer')
-
-    return .5
-
-
-def delete_unfinished_file(file_name):
-    '''
-    Deletes download if it wasn't finished. If the folder it's containing is empty, it also removes the directory
-    Parameters
-    ----------
-    file_name
-
-    Returns
-    -------
-    None
-    '''
-    try:
-        os.remove(file_name)
-    except Exception as e:
-        print(e)
-    asset_dir = os.path.dirname(file_name)
-    if len(os.listdir(asset_dir)) == 0:
-        os.rmdir(asset_dir)
-    return
-
-
-def download_asset_file(asset_data, resolution='blend', api_key=''):
-    # this is a simple non-threaded way to download files for background resolution genenration tool
-    file_names = paths.get_download_filepaths(asset_data, resolution)  # prefer global dir if possible.
-    if len(file_names) == 0:
-        return None
-
-    file_name = file_names[0]
-
-    if check_existing(asset_data, resolution=resolution):
-        # this sends the thread for processing, where another check should occur, since the file might be corrupted.
-        bk_logger.debug('not downloading, already in db')
-        return file_name
-
-    download_canceled = False
-
-    with open(file_name, "wb") as f:
-        print("Downloading %s" % file_name)
-        headers = utils.get_headers(api_key)
-        res_file_info, resolution = paths.get_res_file(asset_data, resolution)
-        response = requests.get(res_file_info['url'], stream=True)
-        total_length = response.headers.get('Content-Length')
-
-        if total_length is None or int(total_length) < 1000:  # no content length header
-            download_canceled = True
-            print(response.content)
-        else:
-            total_length = int(total_length)
-            dl = 0
-            last_percent = 0
-            percent = 0
-            for data in response.iter_content(chunk_size=4096 * 10):
-                dl += len(data)
-
-                # the exact output you're looking for:
-                fs_str = utils.files_size_to_text(total_length)
-
-                percent = int(dl * 100 / total_length)
-                if percent > last_percent:
-                    last_percent = percent
-                    # sys.stdout.write('\r')
-                    # sys.stdout.write(f'Downloading {asset_data['name']} {fs_str} {percent}% ')  # + int(dl * 50 / total_length) * 'x')
-                    print(
-                        f'Downloading {asset_data["name"]} {fs_str} {percent}% ')  # + int(dl * 50 / total_length) * 'x')
-                    # sys.stdout.flush()
-
-                # print(int(dl*50/total_length)*'x'+'\r')
-                f.write(data)
-    if download_canceled:
-        delete_unfinished_file(file_name)
-        return None
-
-    return file_name
-
-
-class Downloader(threading.Thread):
-    def __init__(self, asset_data, tcom, scene_id, api_key, resolution='blend'):
-        super(Downloader, self).__init__()
-        self.asset_data = asset_data
-        self.tcom = tcom
-        self.scene_id = scene_id
-        self.api_key = api_key
-        self.resolution = resolution
-        self._stop_event = threading.Event()
-
-    def stop(self):
-        self._stop_event.set()
-
-    def stopped(self):
-        return self._stop_event.is_set()
-
-    # def main_download_thread(asset_data, tcom, scene_id, api_key):
-    def run(self):
-        '''try to download file from blenderkit'''
-        # utils.p('start downloader thread')
-        asset_data = self.asset_data
-        tcom = self.tcom
-        scene_id = self.scene_id
-        api_key = self.api_key
-        tcom.report = 'Looking for asset'
-        # TODO get real link here...
-        has_url = get_download_url(asset_data, scene_id, api_key, resolution=self.resolution, tcom=tcom)
-
-        if not has_url:
-            tasks_queue.add_task(
-                (reports.add_report, ('Failed to obtain download URL for %s.' % asset_data['name'], 5, colors.RED)))
-            return;
-        if tcom.error:
-            return
-        # only now we can check if the file already exists. This should have 2 levels, for materials and for brushes
-        # different than for the non free content. delete is here when called after failed append tries.
-
-        if check_existing(asset_data, resolution=self.resolution) and not tcom.passargs.get('delete'):
-            # this sends the thread for processing, where another check should occur, since the file might be corrupted.
-            tcom.downloaded = 100
-            bk_logger.debug('not downloading, trying to append again')
-            return
-
-        file_name = paths.get_download_filepaths(asset_data, self.resolution)[0]  # prefer global dir if possible.
-        # for k in asset_data:
-        #    print(asset_data[k])
-        if self.stopped():
-            bk_logger.debug('stopping download: ' + asset_data['name'])
-            return
-
-        download_canceled = False
-        with open(file_name, "wb") as f:
-            bk_logger.debug("Downloading %s" % file_name)
-            headers = utils.get_headers(api_key)
-            res_file_info, self.resolution = paths.get_res_file(asset_data, self.resolution)
-            response = requests.get(res_file_info['url'], stream=True)
-            total_length = response.headers.get('Content-Length')
-            if total_length is None:  # no content length header
-                print('no content length')
-                print(response.content)
-                tcom.report = response.content
-                download_canceled = True
-            else:
-                # bk_logger.debug(total_length)
-                if int(total_length) < 1000:  # means probably no file returned.
-                    tasks_queue.add_task((reports.add_report, (response.content, 20, colors.RED)))
-
-                    tcom.report = response.content
-
-                tcom.file_size = int(total_length)
-                fsmb = tcom.file_size // (1024 * 1024)
-                fskb = tcom.file_size % 1024
-                if fsmb == 0:
-                    t = '%iKB' % fskb
-                else:
-                    t = ' %iMB' % fsmb
-
-                tcom.report = f'Downloading {t} {self.resolution}'
-
-                dl = 0
-                totdata = []
-                for data in response.iter_content(chunk_size=4096 * 32):  # crashed here... why? investigate:
-                    dl += len(data)
-                    tcom.downloaded = dl
-                    tcom.progress = int(100 * tcom.downloaded / tcom.file_size)
-                    f.write(data)
-                    if self.stopped():
-                        bk_logger.debug('stopping download: ' + asset_data['name'])
-                        download_canceled = True
-                        break
-
-        if download_canceled:
-            delete_unfinished_file(file_name)
-            return
-        # unpack the file immediately after download
-
-        tcom.report = f'Unpacking files'
-        self.asset_data['resolution'] = self.resolution
-        resolutions.send_to_bg(self.asset_data, file_name, command='unpack')
-        # utils.p('end downloader thread')
-
-
-class ThreadCom:  # object passed to threads to read background process stdout info
-    def __init__(self):
-        self.file_size = 1000000000000000  # property that gets written to.
-        self.downloaded = 0
-        self.lasttext = ''
-        self.error = False
-        self.report = ''
-        self.progress = 0.0
-        self.passargs = {}
-
-
-def download(asset_data, **kwargs):
-    '''start the download thread'''
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    api_key = user_preferences.api_key
-    scene_id = get_scene_id()
-
-    tcom = ThreadCom()
-    tcom.passargs = kwargs
-
-    if kwargs.get('retry_counter', 0) > 3:
-        sprops = utils.get_search_props()
-        report = f"Maximum retries exceeded for {asset_data['name']}"
-        sprops.report = report
-        reports.add_report(report, 5, colors.RED)
-
-        bk_logger.debug(sprops.report)
-        return
-
-    # incoming data can be either directly dict from python, or blender id property
-    # (recovering failed downloads on reload)
-    if type(asset_data) == dict:
-        asset_data = copy.deepcopy(asset_data)
-    else:
-        asset_data = asset_data.to_dict()
-    readthread = Downloader(asset_data, tcom, scene_id, api_key, resolution=kwargs['resolution'])
-    readthread.start()
-
-    global download_threads
-    download_threads.append(
-        [readthread, asset_data, tcom])
-
-
-def check_downloading(asset_data, **kwargs):
-    ''' check if an asset is already downloading, if yes, just make a progress bar with downloader object.'''
-    global download_threads
-
-    downloading = False
-
-    for p in download_threads:
-        p_asset_data = p[1]
-        if p_asset_data['id'] == asset_data['id']:
-            at = asset_data['assetType']
-            if at in ('model', 'material'):
-                downloader = {'location': kwargs['model_location'],
-                              'rotation': kwargs['model_rotation']}
-                p[2].passargs['downloaders'].append(downloader)
-            downloading = True
-
-    return downloading
-
-
-def check_existing(asset_data, resolution='blend', can_return_others=False):
-    ''' check if the object exists on the hard drive'''
-    fexists = False
-
-    if asset_data.get('files') == None:
-        # this is because of some very odl files where asset data had no files structure.
-        return False
-
-    file_names = paths.get_download_filepaths(asset_data, resolution, can_return_others=can_return_others)
-
-    bk_logger.debug('check if file already exists' + str(file_names))
-    if len(file_names) == 2:
-        # TODO this should check also for failed or running downloads.
-        # If download is running, assign just the running thread. if download isn't running but the file is wrong size,
-        #  delete file and restart download (or continue downoad? if possible.)
-        if os.path.isfile(file_names[0]):  # and not os.path.isfile(file_names[1])
-            utils.copy_asset(file_names[0], file_names[1])
-        elif not os.path.isfile(file_names[0]) and os.path.isfile(
-                file_names[1]):  # only in case of changed settings or deleted/moved global dict.
-            utils.copy_asset(file_names[1], file_names[0])
-
-    if len(file_names) > 0 and os.path.isfile(file_names[0]):
-        fexists = True
-    return fexists
-
-
-def try_finished_append(asset_data, **kwargs):  # location=None, material_target=None):
-    ''' try to append asset, if not successfully delete source files.
-     This means probably wrong download, so download should restart'''
-    file_names = paths.get_download_filepaths(asset_data, kwargs['resolution'])
-    done = False
-    bk_logger.debug('try to append already existing asset')
-    if len(file_names) > 0:
-        if os.path.isfile(file_names[-1]):
-            kwargs['name'] = asset_data['name']
-            try:
-                append_asset(asset_data, **kwargs)
-                done = True
-            except Exception as e:
-                # TODO: this should distinguis if the appending failed (wrong file)
-                # or something else happened(shouldn't delete the files)
-                print(e)
-                done = False
-                for f in file_names:
-                    try:
-                        os.remove(f)
-                    except Exception as e:
-                        # e = sys.exc_info()[0]
-                        print(e)
-                        pass;
-                return done
-
-    return done
-
-
-def get_asset_in_scene(asset_data):
-    '''tries to find an appended copy of particular asset and duplicate it - so it doesn't have to be appended again.'''
-    scene = bpy.context.scene
-    for ob in bpy.context.scene.objects:
-        ad1 = ob.get('asset_data')
-        if not ad1:
-            continue
-        if ad1.get('assetBaseId') == asset_data['assetBaseId']:
-            return ob
-    return None
-
-
-def check_all_visible(obs):
-    '''checks all objects are visible, so they can be manipulated/copied.'''
-    for ob in obs:
-        if not ob.visible_get():
-            return False
-    return True
-
-
-def check_selectible(obs):
-    '''checks if all objects can be selected and selects them if possible.
-     this isn't only select_hide, but all possible combinations of collections e.t.c. so hard to check otherwise.'''
-    for ob in obs:
-        ob.select_set(True)
-        if not ob.select_get():
-            return False
-    return True
-
-
-def duplicate_asset(source, **kwargs):
-    '''
-    Duplicate asset when it's already appended in the scene,
-    so that blender's append doesn't create duplicated data.
-     '''
-    bk_logger.debug('duplicate asset instead')
-    # we need to save selection
-    sel = utils.selection_get()
-    bpy.ops.object.select_all(action='DESELECT')
-
-    # check visibility
-    obs = utils.get_hierarchy(source)
-    if not check_all_visible(obs):
-        return None
-    # check selectability and select in one run
-    if not check_selectible(obs):
-        return None
-
-    # duplicate the asset objects
-    bpy.ops.object.duplicate(linked=True)
-
-    nobs = bpy.context.selected_objects[:]
-    # get asset main object
-    for ob in nobs:
-        if ob.parent not in nobs:
-            asset_main = ob
-            break
-
-    # in case of replacement,there might be a paarent relationship that can be restored
-    if kwargs.get('parent'):
-        parent = bpy.data.objects[kwargs['parent']]
-        asset_main.parent = parent  # even if parent is None this is ok without if condition
-    else:
-        asset_main.parent = None
-    # restore original selection
-    utils.selection_set(sel)
-    return asset_main, nobs
-
-
-def asset_in_scene(asset_data):
-    '''checks if the asset is already in scene. If yes, modifies asset data so the asset can be reached again.'''
-    scene = bpy.context.scene
-    au = scene.get('assets used', {})
-
-    id = asset_data['assetBaseId']
-    if id in au.keys():
-        ad = au[id]
-        if ad.get('files'):
-            for fi in ad['files']:
-                if fi.get('file_name') != None:
-
-                    for fi1 in asset_data['files']:
-                        if fi['fileType'] == fi1['fileType']:
-                            fi1['file_name'] = fi['file_name']
-                            fi1['url'] = fi['url']
-
-                            # browse all collections since linked collections can have same name.
-                            if asset_data['assetType'] == 'MODEL':
-                                for c in bpy.data.collections:
-                                    if c.name == ad['name']:
-                                        # there can also be more linked collections with same name, we need to check id.
-                                        if c.library and c.library.get('asset_data') and c.library['asset_data'][
-                                            'assetBaseId'] == id:
-                                            print('asset linked')
-                                            return 'LINKED', ad.get('resolution')
-                            elif asset_data['assetType'] == 'MATERIAL':
-                                for m in bpy.data.materials:
-                                    if not m.get('asset_data'):
-                                        continue
-                                    if m['asset_data']['assetBaseId'] == asset_data[
-                                        'assetBaseId'] and bpy.context.active_object.active_material.library:
-                                        return 'LINKED', ad.get('resolution')
-
-                            print('asset appended')
-                            return 'APPENDED', ad.get('resolution')
-    return False, None
-
-
-def fprint(text):
-    print('###################################################################################')
-    print('\n\n\n')
-    print(text)
-    print('\n\n\n')
-    print('###################################################################################')
-
-
-def get_download_url(asset_data, scene_id, api_key, tcom=None, resolution='blend'):
-    ''''retrieves the download url. The server checks if user can download the item.'''
-    mt = time.time()
-    utils.pprint('getting download url')
-
-    headers = utils.get_headers(api_key)
-
-    data = {
-        'scene_uuid': scene_id
-    }
-    r = None
-
-    res_file_info, resolution = paths.get_res_file(asset_data, resolution)
-
-    try:
-        r = rerequests.get(res_file_info['downloadUrl'], params=data, headers=headers)
-    except Exception as e:
-        print(e)
-        if tcom is not None:
-            tcom.error = True
-    if r == None:
-        if tcom is not None:
-            tcom.report = 'Connection Error'
-            tcom.error = True
-        return 'Connection Error'
-
-    if r.status_code < 400:
-        data = r.json()
-        url = data['filePath']
-
-        res_file_info['url'] = url
-        res_file_info['file_name'] = paths.extract_filename_from_url(url)
-
-        # print(res_file_info, url)
-        print(url)
-        return True
-
-    # let's print it into UI
-    tasks_queue.add_task((reports.add_report, (str(r), 10, colors.RED)))
-
-    if r.status_code == 403:
-        report = 'You need Full plan to get this item.'
-        # r1 = 'All materials and brushes are available for free. Only users registered to Standard plan can use all models.'
-        # tasks_queue.add_task((reports.add_report, (r1, 5, colors.RED)))
-        if tcom is not None:
-            tcom.report = report
-            tcom.error = True
-
-    if r.status_code == 404:
-        report = 'Url not found - 404.'
-        # r1 = 'All materials and brushes are available for free. Only users registered to Standard plan can use all models.'
-        if tcom is not None:
-            tcom.report = report
-            tcom.error = True
-
-    elif r.status_code >= 500:
-        # bk_logger.debug(r.text)
-        if tcom is not None:
-            tcom.report = 'Server error'
-            tcom.error = True
-    return False
-
-
-def start_download(asset_data, **kwargs):
-    '''
-    check if file isn't downloading or doesn't exist, then start new download
-    '''
-    # first check if the asset is already in scene. We can use that asset without checking with server
-    ain, resolution = asset_in_scene(asset_data)
-    # quota_ok = ain is not False
-
-    # if resolution:
-    #     kwargs['resolution'] = resolution
-    # otherwise, check on server
-
-    s = bpy.context.scene
-    done = False
-    # is the asseet being currently downloaded?
-    downloading = check_downloading(asset_data, **kwargs)
-    if not downloading:
-        # check if there are files already. This check happens 2x once here(for free assets),
-        # once in thread(for non-free)
-        fexists = check_existing(asset_data, resolution=kwargs['resolution'])
-        bk_logger.debug('does file exist?' + str(fexists))
-        bk_logger.debug('asset is in scene' + str(ain))
-        if ain and not kwargs.get('replace_resolution'):
-            # this goes to appending asset - where it should duplicate the original asset already in scene.
-            done = try_finished_append(asset_data, **kwargs)
-        # else:
-        #     props = utils.get_search_props()
-        #     props.report = str('asset ')
-        if not done:
-            at = asset_data['assetType']
-            if at in ('model', 'material'):
-                downloader = {'location': kwargs['model_location'],
-                              'rotation': kwargs['model_rotation']}
-                download(asset_data, downloaders=[downloader], **kwargs)
-
-            else:
-                download(asset_data, **kwargs)
-
-
-asset_types = (
-    ('MODEL', 'Model', 'set of objects'),
-    ('SCENE', 'Scene', 'scene'),
-    ('HDR', 'Hdr', 'hdr'),
-    ('MATERIAL', 'Material', 'any .blend Material'),
-    ('TEXTURE', 'Texture', 'a texture, or texture set'),
-    ('BRUSH', 'Brush', 'brush, can be any type of blender brush'),
-    ('ADDON', 'Addon', 'addnon'),
-)
-
-
-class BlenderkitKillDownloadOperator(bpy.types.Operator):
-    """Kill a download"""
-    bl_idname = "scene.blenderkit_download_kill"
-    bl_label = "BlenderKit Kill Asset Download"
-    bl_options = {'REGISTER', 'INTERNAL'}
-
-    thread_index: IntProperty(name="Thread index", description='index of the thread to kill', default=-1)
-
-    def execute(self, context):
-        global download_threads
-        td = download_threads[self.thread_index]
-        download_threads.remove(td)
-        td[0].stop()
-        return {'FINISHED'}
-
-
-def available_resolutions_callback(self, context):
-    '''
-    Returns
-    checks active asset for available resolutions and offers only those available
-    TODO: this currently returns always the same list of resolutions, make it actually work
-    '''
-    # print('callback called', self.asset_data)
-    pat_items = (
-        ('512', '512', '', 1),
-        ('1024', '1024', '', 2),
-        ('2048', '2048', '', 3),
-        ('4096', '4096', '', 4),
-        ('8192', '8192', '', 5),
-    )
-    items = []
-    for item in pat_items:
-        if int(self.max_resolution) >= int(item[0]):
-            items.append(item)
-    items.append(('ORIGINAL', 'Original', '', 6))
-    return items
-
-
-def show_enum_values(obj, prop_name):
-    print([item.identifier for item in obj.bl_rna.properties[prop_name].enum_items])
-
-
-class BlenderkitDownloadOperator(bpy.types.Operator):
-    """Download and link asset to scene. Only link if asset already available locally"""
-    bl_idname = "scene.blenderkit_download"
-    bl_label = "Download"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    # asset_type: EnumProperty(
-    #     name="Type",
-    #     items=asset_types,
-    #     description="Type of download",
-    #     default="MODEL",
-    # )
-    asset_index: IntProperty(name="Asset Index", description='asset index in search results', default=-1)
-
-    asset_base_id: StringProperty(
-        name="Asset base Id",
-        description="Asset base id, used instead of search result index",
-        default="")
-
-    target_object: StringProperty(
-        name="Target Object",
-        description="Material or object target for replacement",
-        default="")
-
-    material_target_slot: IntProperty(name="Asset Index", description='asset index in search results', default=0)
-    model_location: FloatVectorProperty(name='Asset Location', default=(0, 0, 0))
-    model_rotation: FloatVectorProperty(name='Asset Rotation', default=(0, 0, 0))
-
-    replace: BoolProperty(name='Replace', description='replace selection with the asset', default=False)
-
-    replace_resolution: BoolProperty(name='Replace resolution', description='replace resolution of the active asset',
-                                     default=False)
-
-    invoke_resolution: BoolProperty(name='Replace resolution popup',
-                                    description='pop up to ask which resolution to download', default=False)
-    invoke_scene_settings: BoolProperty(name='Scene import settings popup',
-                                        description='pop up scene import settings', default=False)
-
-    resolution: EnumProperty(
-        items=available_resolutions_callback,
-        default=512,
-        description='Replace resolution'
-    )
-
-    # needs to be passed to the operator to not show all resolution possibilities
-    max_resolution: IntProperty(
-        name="Max resolution",
-        description="",
-        default=0)
-    # has_res_0_5k: BoolProperty(name='512',
-    #                                 description='', default=False)
-
-    cast_parent: StringProperty(
-        name="Particles Target Object",
-        description="",
-        default="")
-
-    # close_window: BoolProperty(name='Close window',
-    #                            description='Try to close the window below mouse before download',
-    #                            default=False)
-    # @classmethod
-    # def poll(cls, context):
-    #     return bpy.context.window_manager.BlenderKitModelThumbnails is not ''
-    tooltip: bpy.props.StringProperty(
-        default='Download and link asset to scene. Only link if asset already available locally')
-
-    @classmethod
-    def description(cls, context, properties):
-        return properties.tooltip
-
-    def get_asset_data(self, context):
-        # get asset data - it can come from scene, or from search results.
-        s = bpy.context.scene
-
-        if self.asset_index > -1:
-            # either get the data from search results
-            sr = bpy.context.window_manager['search results']
-            asset_data = sr[
-                self.asset_index].to_dict()  # TODO CHECK ALL OCCURRENCES OF PASSING BLENDER ID PROPS TO THREADS!
-            asset_base_id = asset_data['assetBaseId']
-        else:
-            # or from the scene.
-            asset_base_id = self.asset_base_id
-
-            au = s.get('assets used')
-            if au == None:
-                s['assets used'] = {}
-            if asset_base_id in s.get('assets used'):
-                # already used assets have already download link and especially file link.
-                asset_data = s['assets used'][asset_base_id].to_dict()
-            else:
-                # when not in scene nor in search results, we need to get it from the server
-                params = {
-                    'asset_base_id': self.asset_base_id
-                }
-                preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-                results = search.get_search_simple(params, page_size=1, max_results=1,
-                                                   api_key=preferences.api_key)
-                asset_data = search.parse_result(results[0])
-
-        return asset_data
-
-    def execute(self, context):
-        sprops = utils.get_search_props()
-
-        self.asset_data = self.get_asset_data(context)
-
-        # print('after getting asset data')
-        # print(self.asset_base_id)
-
-        atype = self.asset_data['assetType']
-        if bpy.context.mode != 'OBJECT' and (
-                atype == 'model' or atype == 'material') and bpy.context.view_layer.objects.active is not None:
-            bpy.ops.object.mode_set(mode='OBJECT')
-
-        if self.resolution == 0 or self.resolution == '':
-            resolution = sprops.resolution
-        else:
-            resolution = self.resolution
-
-        resolution = resolutions.resolution_props_to_server[resolution]
-        if self.replace:  # cleanup first, assign later.
-            obs = utils.get_selected_replace_adepts()
-            # print(obs)
-            for ob in obs:
-                # print('replace attempt ', ob.name)
-                if self.asset_base_id != '':
-                    # this is for a case when replace is called from a panel,
-                    # this uses active object as replacement source instead of target.
-                    if ob.get('asset_data') is not None and \
-                            (ob['asset_data']['assetBaseId'] == self.asset_base_id and ob['asset_data'][
-                                'resolution'] == resolution):
-                        # print('skipping this one')
-                        continue;
-                parent = ob.parent
-                if parent:
-                    parent = ob.parent.name  # after this, parent is either name or None.
-
-                kwargs = {
-                    'cast_parent': self.cast_parent,
-                    'target_object': ob.name,
-                    'material_target_slot': ob.active_material_index,
-                    'model_location': tuple(ob.matrix_world.translation),
-                    'model_rotation': tuple(ob.matrix_world.to_euler()),
-                    'replace': True,
-                    'replace_resolution': False,
-                    'parent': parent,
-                    'resolution': resolution
-                }
-                # TODO - move this After download, not before, so that the replacement
-                utils.delete_hierarchy(ob)
-                start_download(self.asset_data, **kwargs)
-        else:
-            # replace resolution needs to replace all instances of the resolution in the scene
-            # and deleting originals has to be thus done after the downlaod
-
-            kwargs = {
-                'cast_parent': self.cast_parent,
-                'target_object': self.target_object,
-                'material_target_slot': self.material_target_slot,
-                'model_location': tuple(self.model_location),
-                'model_rotation': tuple(self.model_rotation),
-                'replace': False,
-                'replace_resolution': self.replace_resolution,
-                'resolution': resolution
-            }
-
-            start_download(self.asset_data, **kwargs)
-        return {'FINISHED'}
-
-    def draw(self, context):
-        layout = self.layout
-        if self.invoke_resolution:
-            layout.prop(self, 'resolution', expand=True, icon_only=False)
-        if self.invoke_scene_settings:
-            ui_panels.draw_scene_import_settings(self, context)
-
-    def invoke(self, context, event):
-        # if self.close_window:
-        #     context.window.cursor_warp(event.mouse_x-1000, event.mouse_y - 1000);
-
-        # print(self.asset_base_id)
-        wm = context.window_manager
-        # only make a pop up in case of switching resolutions
-        if self.invoke_resolution:
-            # show_enum_values(self, 'resolution')
-            self.asset_data = self.get_asset_data(context)
-            sprops = utils.get_search_props()
-
-            # set initial resolutions enum activation
-            if sprops.resolution != 'ORIGINAL' and int(sprops.resolution) <= int(self.max_resolution):
-                self.resolution = sprops.resolution
-            elif int(self.max_resolution) > 0:
-                self.resolution = str(self.max_resolution)
-            else:
-                self.resolution = 'ORIGINAL'
-            return wm.invoke_props_dialog(self)
-
-        if self.invoke_scene_settings:
-            return wm.invoke_props_dialog(self)
-        # if self.close_window:
-        #     time.sleep(0.1)
-        #     context.area.tag_redraw()
-        #     time.sleep(0.1)
-        #
-        #     context.window.cursor_warp(event.mouse_x, event.mouse_y);
-
-        return self.execute(context)
-
-
-def register_download():
-    bpy.utils.register_class(BlenderkitDownloadOperator)
-    bpy.utils.register_class(BlenderkitKillDownloadOperator)
-    bpy.app.handlers.load_post.append(scene_load)
-    bpy.app.handlers.save_pre.append(scene_save)
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if user_preferences.use_timers and not bpy.app.background:
-        bpy.app.timers.register(download_timer)
-
-
-def unregister_download():
-    bpy.utils.unregister_class(BlenderkitDownloadOperator)
-    bpy.utils.unregister_class(BlenderkitKillDownloadOperator)
-    bpy.app.handlers.load_post.remove(scene_load)
-    bpy.app.handlers.save_pre.remove(scene_save)
-    if bpy.app.timers.is_registered(download_timer):
-        bpy.app.timers.unregister(download_timer)
diff --git a/blenderkit/icons.py b/blenderkit/icons.py
deleted file mode 100644
index 379062edd5076de1d82723ef4e20e4a67f519a3b..0000000000000000000000000000000000000000
--- a/blenderkit/icons.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# ##### 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 #####
-
-
-import os
-import bpy
-
-# We can store multiple preview collections here,
-# however in this example we only store "main"
-icon_collections = {}
-
-icons_read = {
-    'fp.png': 'free',
-    'flp.png': 'full',
-    'trophy.png': 'trophy',
-    'dumbbell.png': 'dumbbell',
-    'cc0.png': 'cc0',
-    'royalty_free.png': 'royalty_free',
-    'filter.png': 'filter',
-    'filter_active.png': 'filter_active',
-    'bell.png': 'bell',
-}
-
-verification_icons = {
-    'vs_ready.png':'ready',
-    'vs_deleted.png':'deleted' ,
-    'vs_uploaded.png': 'uploaded',
-    'vs_uploading.png': 'uploading',
-    'vs_on_hold.png': 'on_hold',
-    'vs_validated.png': 'validated',
-    'vs_rejected.png': 'rejected'
-
-}
-
-icons_read.update(verification_icons)
-
-def register_icons():
-    # Note that preview collections returned by bpy.utils.previews
-    # are regular py objects - you can use them to store custom data.
-    import bpy.utils.previews
-    pcoll = bpy.utils.previews.new()
-
-    # path to the folder where the icon is
-    # the path is calculated relative to this py file inside the addon folder
-    icons_dir = os.path.join(os.path.dirname(__file__), "thumbnails")
-
-    # load a preview thumbnail of a file and store in the previews collection
-    for ir in icons_read.keys():
-        pcoll.load(icons_read[ir], os.path.join(icons_dir, ir), 'IMAGE')
-
-        # iprev = pcoll.new(icons_read[ir])
-        # img = bpy.data.images.load(os.path.join(icons_dir, ir))
-        # iprev.image_size = (img.size[0], img.size[1])
-        # iprev.image_pixels_float = img.pixels[:]
-
-    icon_collections["main"] = pcoll
-    icon_collections["previews"] = bpy.utils.previews.new()
-
-
-def unregister_icons():
-    for pcoll in icon_collections.values():
-        bpy.utils.previews.remove(pcoll)
-    icon_collections.clear()
diff --git a/blenderkit/image_utils.py b/blenderkit/image_utils.py
deleted file mode 100644
index b17878c3ce8f4ec7d87e192bc821ba0697a13c4e..0000000000000000000000000000000000000000
--- a/blenderkit/image_utils.py
+++ /dev/null
@@ -1,505 +0,0 @@
-import bpy
-import os
-import time
-
-
-def get_orig_render_settings():
-    rs = bpy.context.scene.render
-    ims = rs.image_settings
-
-    vs = bpy.context.scene.view_settings
-
-    orig_settings = {
-        'file_format': ims.file_format,
-        'quality': ims.quality,
-        'color_mode': ims.color_mode,
-        'compression': ims.compression,
-        'exr_codec': ims.exr_codec,
-        'view_transform': vs.view_transform
-    }
-    return orig_settings
-
-
-def set_orig_render_settings(orig_settings):
-    rs = bpy.context.scene.render
-    ims = rs.image_settings
-    vs = bpy.context.scene.view_settings
-
-    ims.file_format = orig_settings['file_format']
-    ims.quality = orig_settings['quality']
-    ims.color_mode = orig_settings['color_mode']
-    ims.compression = orig_settings['compression']
-    ims.exr_codec = orig_settings['exr_codec']
-
-    vs.view_transform = orig_settings['view_transform']
-
-
-def img_save_as(img, filepath='//', file_format='JPEG', quality=90, color_mode='RGB', compression=15,
-                view_transform='Raw', exr_codec='DWAA'):
-    '''Uses Blender 'save render' to save images - BLender isn't really able so save images with other methods correctly.'''
-
-    ors = get_orig_render_settings()
-
-    rs = bpy.context.scene.render
-    vs = bpy.context.scene.view_settings
-
-    ims = rs.image_settings
-    ims.file_format = file_format
-    ims.quality = quality
-    ims.color_mode = color_mode
-    ims.compression = compression
-    ims.exr_codec = exr_codec
-    vs.view_transform = view_transform
-
-    img.save_render(filepath=bpy.path.abspath(filepath), scene=bpy.context.scene)
-
-    set_orig_render_settings(ors)
-
-
-def set_colorspace(img, colorspace):
-    '''sets image colorspace, but does so in a try statement, because some people might actually replace the default
-    colorspace settings, and it literally can't be guessed what these people use, even if it will mostly be the filmic addon.
-    '''
-    try:
-        if colorspace == 'Non-Color':
-            img.colorspace_settings.is_data = True
-        else:
-            img.colorspace_settings.name = colorspace
-    except:
-        print(f'Colorspace {colorspace} not found.')
-
-def analyze_image_is_true_hdr(image):
-    import numpy
-    scene = bpy.context.scene
-    ui_props = bpy.context.window_manager.blenderkitUI
-    size = image.size
-    imageWidth = size[0]
-    imageHeight = size[1]
-    tempBuffer = numpy.empty(imageWidth * imageHeight * 4, dtype=numpy.float32)
-    image.pixels.foreach_get(tempBuffer)
-    image.blenderkit.true_hdr = numpy.amax(tempBuffer) > 1.05
-
-def generate_hdr_thumbnail():
-    import numpy
-    scene = bpy.context.scene
-    ui_props = bpy.context.window_manager.blenderkitUI
-    hdr_image = ui_props.hdr_upload_image  # bpy.data.images.get(ui_props.hdr_upload_image)
-
-    base, ext = os.path.splitext(hdr_image.filepath)
-    thumb_path = base + '.jpg'
-    thumb_name = os.path.basename(thumb_path)
-
-    max_thumbnail_size = 2048
-    size = hdr_image.size
-    ratio = size[0] / size[1]
-
-    imageWidth = size[0]
-    imageHeight = size[1]
-    thumbnailWidth = min(size[0], max_thumbnail_size)
-    thumbnailHeight = min(size[1], int(max_thumbnail_size / ratio))
-
-    tempBuffer = numpy.empty(imageWidth * imageHeight * 4, dtype=numpy.float32)
-    inew = bpy.data.images.new(thumb_name, imageWidth, imageHeight, alpha=False, float_buffer=False)
-
-    hdr_image.pixels.foreach_get(tempBuffer)
-
-    hdr_image.blenderkit.true_hdr = numpy.amax(tempBuffer) > 1.05
-
-    inew.filepath = thumb_path
-    set_colorspace(inew, 'Linear')
-    inew.pixels.foreach_set(tempBuffer)
-
-    bpy.context.view_layer.update()
-    if thumbnailWidth < imageWidth:
-        inew.scale(thumbnailWidth, thumbnailHeight)
-
-    img_save_as(inew, filepath=inew.filepath)
-
-
-def find_color_mode(image):
-    if not isinstance(image, bpy.types.Image):
-        raise (TypeError)
-    else:
-        depth_mapping = {
-            8: 'BW',
-            24: 'RGB',
-            32: 'RGBA',  # can also be bw.. but image.channels doesn't work.
-            96: 'RGB',
-            128: 'RGBA',
-        }
-        return depth_mapping.get(image.depth, 'RGB')
-
-
-def find_image_depth(image):
-    if not isinstance(image, bpy.types.Image):
-        raise (TypeError)
-    else:
-        depth_mapping = {
-            8: '8',
-            24: '8',
-            32: '8',  # can also be bw.. but image.channels doesn't work.
-            96: '16',
-            128: '16',
-        }
-        return depth_mapping.get(image.depth, '8')
-
-
-def can_erase_alpha(na):
-    alpha = na[3::4]
-    alpha_sum = alpha.sum()
-    if alpha_sum == alpha.size:
-        print('image can have alpha erased')
-    # print(alpha_sum, alpha.size)
-    return alpha_sum == alpha.size
-
-
-def is_image_black(na):
-    r = na[::4]
-    g = na[1::4]
-    b = na[2::4]
-
-    rgbsum = r.sum() + g.sum() + b.sum()
-
-    # print('rgb sum', rgbsum, r.sum(), g.sum(), b.sum())
-    if rgbsum == 0:
-        print('image can have alpha channel dropped')
-    return rgbsum == 0
-
-
-def is_image_bw(na):
-    r = na[::4]
-    g = na[1::4]
-    b = na[2::4]
-
-    rg_equal = r == g
-    gb_equal = g == b
-    rgbequal = rg_equal.all() and gb_equal.all()
-    if rgbequal:
-        print('image is black and white, can have channels reduced')
-
-    return rgbequal
-
-
-def numpytoimage(a, iname, width=0, height=0, channels=3):
-    t = time.time()
-    foundimage = False
-
-    for image in bpy.data.images:
-
-        if image.name[:len(iname)] == iname and image.size[0] == a.shape[0] and image.size[1] == a.shape[1]:
-            i = image
-            foundimage = True
-    if not foundimage:
-        if channels == 4:
-            bpy.ops.image.new(name=iname, width=width, height=height, color=(0, 0, 0, 1), alpha=True,
-                              generated_type='BLANK', float=True)
-        if channels == 3:
-            bpy.ops.image.new(name=iname, width=width, height=height, color=(0, 0, 0), alpha=False,
-                              generated_type='BLANK', float=True)
-
-    i = None
-
-    for image in bpy.data.images:
-        # print(image.name[:len(iname)],iname, image.size[0],a.shape[0],image.size[1],a.shape[1])
-        if image.name[:len(iname)] == iname and image.size[0] == width and image.size[1] == height:
-            i = image
-    if i is None:
-        i = bpy.data.images.new(iname, width, height, alpha=False, float_buffer=False, stereo3d=False, is_data=False,
-                                tiled=False)
-
-    # dropping this re-shaping code -  just doing flat array for speed and simplicity
-    #    d = a.shape[0] * a.shape[1]
-    #    a = a.swapaxes(0, 1)
-    #    a = a.reshape(d)
-    #    a = a.repeat(channels)
-    #    a[3::4] = 1
-    i.pixels.foreach_set(a)  # this gives big speedup!
-    print('\ntime ' + str(time.time() - t))
-    return i
-
-
-def imagetonumpy_flat(i):
-    t = time.time()
-
-    import numpy
-
-    width = i.size[0]
-    height = i.size[1]
-    # print(i.channels)
-
-    size = width * height * i.channels
-    na = numpy.empty(size, numpy.float32)
-    i.pixels.foreach_get(na)
-
-    # dropping this re-shaping code -  just doing flat array for speed and simplicity
-    #    na = na[::4]
-    #    na = na.reshape(height, width, i.channels)
-    #    na = na.swapaxnes(0, 1)
-
-    # print('\ntime of image to numpy ' + str(time.time() - t))
-    return na
-
-
-def imagetonumpy(i):
-    t = time.time()
-
-    import numpy as np
-
-    width = i.size[0]
-    height = i.size[1]
-    # print(i.channels)
-
-    size = width * height * i.channels
-    na = np.empty(size, np.float32)
-    i.pixels.foreach_get(na)
-
-    # dropping this re-shaping code -  just doing flat array for speed and simplicity
-    # na = na[::4]
-    na = na.reshape(height, width, i.channels)
-    na = na.swapaxes(0, 1)
-
-    # print('\ntime of image to numpy ' + str(time.time() - t))
-    return na
-
-
-def downscale(i):
-    minsize = 128
-
-    sx, sy = i.size[:]
-    sx = round(sx / 2)
-    sy = round(sy / 2)
-    if sx > minsize and sy > minsize:
-        i.scale(sx, sy)
-
-
-def get_rgb_mean(i):
-    '''checks if normal map values are ok.'''
-    import numpy
-
-    na = imagetonumpy_flat(i)
-
-    r = na[::4]
-    g = na[1::4]
-    b = na[2::4]
-
-    rmean = r.mean()
-    gmean = g.mean()
-    bmean = b.mean()
-
-    rmedian = numpy.median(r)
-    gmedian = numpy.median(g)
-    bmedian = numpy.median(b)
-
-    #    return(rmedian,gmedian, bmedian)
-    return (rmean, gmean, bmean)
-
-
-def check_nmap_mean_ok(i):
-    '''checks if normal map values are in standard range.'''
-
-    rmean, gmean, bmean = get_rgb_mean(i)
-
-    # we could/should also check blue, but some ogl substance exports have 0-1, while 90% nmaps have 0.5 - 1.
-    nmap_ok = 0.45 < rmean < 0.55 and .45 < gmean < .55
-
-    return nmap_ok
-
-
-def check_nmap_ogl_vs_dx(i, mask=None, generated_test_images=False):
-    '''
-    checks if normal map is directX or OpenGL.
-    Returns - String value - DirectX and OpenGL
-    '''
-    import numpy
-    width = i.size[0]
-    height = i.size[1]
-
-    rmean, gmean, bmean = get_rgb_mean(i)
-
-    na = imagetonumpy(i)
-
-    if mask:
-        mask = imagetonumpy(mask)
-
-    red_x_comparison = numpy.zeros((width, height), numpy.float32)
-    green_y_comparison = numpy.zeros((width, height), numpy.float32)
-
-    if generated_test_images:
-        red_x_comparison_img = numpy.empty((width, height, 4), numpy.float32)  # images for debugging purposes
-        green_y_comparison_img = numpy.empty((width, height, 4), numpy.float32)  # images for debugging purposes
-
-    ogl = numpy.zeros((width, height), numpy.float32)
-    dx = numpy.zeros((width, height), numpy.float32)
-
-    if generated_test_images:
-        ogl_img = numpy.empty((width, height, 4), numpy.float32)  # images for debugging purposes
-        dx_img = numpy.empty((width, height, 4), numpy.float32)  # images for debugging purposes
-
-    for y in range(0, height):
-        for x in range(0, width):
-            # try to mask with UV mask image
-            if mask is None or mask[x, y, 3] > 0:
-
-                last_height_x = ogl[max(x - 1, 0), min(y, height - 1)]
-                last_height_y = ogl[max(x, 0), min(y - 1, height - 1)]
-
-                diff_x = ((na[x, y, 0] - rmean) / ((na[x, y, 2] - 0.5)))
-                diff_y = ((na[x, y, 1] - gmean) / ((na[x, y, 2] - 0.5)))
-                calc_height = (last_height_x + last_height_y) \
-                              - diff_x - diff_y
-                calc_height = calc_height / 2
-                ogl[x, y] = calc_height
-                if generated_test_images:
-                    rgb = calc_height * .1 + .5
-                    ogl_img[x, y] = [rgb, rgb, rgb, 1]
-
-                # green channel
-                last_height_x = dx[max(x - 1, 0), min(y, height - 1)]
-                last_height_y = dx[max(x, 0), min(y - 1, height - 1)]
-
-                diff_x = ((na[x, y, 0] - rmean) / ((na[x, y, 2] - 0.5)))
-                diff_y = ((na[x, y, 1] - gmean) / ((na[x, y, 2] - 0.5)))
-                calc_height = (last_height_x + last_height_y) \
-                              - diff_x + diff_y
-                calc_height = calc_height / 2
-                dx[x, y] = calc_height
-                if generated_test_images:
-                    rgb = calc_height * .1 + .5
-                    dx_img[x, y] = [rgb, rgb, rgb, 1]
-
-    ogl_std = ogl.std()
-    dx_std = dx.std()
-
-    # print(mean_ogl, mean_dx)
-    # print(max_ogl, max_dx)
-    print(ogl_std, dx_std)
-    print(i.name)
-    #    if abs(mean_ogl) > abs(mean_dx):
-    if abs(ogl_std) > abs(dx_std):
-        print('this is probably a DirectX texture')
-    else:
-        print('this is probably an OpenGL texture')
-
-    if generated_test_images:
-        # red_x_comparison_img = red_x_comparison_img.swapaxes(0,1)
-        # red_x_comparison_img = red_x_comparison_img.flatten()
-        #
-        # green_y_comparison_img = green_y_comparison_img.swapaxes(0,1)
-        # green_y_comparison_img = green_y_comparison_img.flatten()
-        #
-        # numpytoimage(red_x_comparison_img, 'red_' + i.name, width=width, height=height, channels=1)
-        # numpytoimage(green_y_comparison_img, 'green_' + i.name, width=width, height=height, channels=1)
-
-        ogl_img = ogl_img.swapaxes(0, 1)
-        ogl_img = ogl_img.flatten()
-
-        dx_img = dx_img.swapaxes(0, 1)
-        dx_img = dx_img.flatten()
-
-        numpytoimage(ogl_img, 'OpenGL', width=width, height=height, channels=1)
-        numpytoimage(dx_img, 'DirectX', width=width, height=height, channels=1)
-
-    if abs(ogl_std) > abs(dx_std):
-        return 'DirectX'
-    return 'OpenGL'
-
-
-def make_possible_reductions_on_image(teximage, input_filepath, do_reductions=False, do_downscale=False):
-    '''checks the image and saves it to drive with possibly reduced channels.
-    Also can remove the image from the asset if the image is pure black
-    - it finds it's usages and replaces the inputs where the image is used
-    with zero/black color.
-    currently implemented file type conversions:
-    PNG->JPG
-    '''
-    colorspace = teximage.colorspace_settings.name
-    teximage.colorspace_settings.name = 'Non-Color'
-    # teximage.colorspace_settings.name = 'sRGB' color correction mambo jambo.
-
-    JPEG_QUALITY = 90
-    # is_image_black(na)
-    # is_image_bw(na)
-
-    rs = bpy.context.scene.render
-    ims = rs.image_settings
-
-    orig_file_format = ims.file_format
-    orig_quality = ims.quality
-    orig_color_mode = ims.color_mode
-    orig_compression = ims.compression
-    orig_depth = ims.color_depth
-
-    # if is_image_black(na):
-    #     # just erase the image from the asset here, no need to store black images.
-    #     pass;
-
-    # fp = teximage.filepath
-
-    # setup  image depth, 8 or 16 bit.
-    # this should normally divide depth with number of channels, but blender always states that number of channels is 4, even if there are only 3
-
-    print(teximage.name)
-    print(teximage.depth)
-    print(teximage.channels)
-
-    bpy.context.scene.display_settings.display_device = 'None'
-
-    image_depth = find_image_depth(teximage)
-
-    ims.color_mode = find_color_mode(teximage)
-    # image_depth = str(max(min(int(teximage.depth / 3), 16), 8))
-    print('resulting depth set to:', image_depth)
-
-    fp = input_filepath
-    if do_reductions:
-        na = imagetonumpy_flat(teximage)
-
-        if can_erase_alpha(na):
-            print(teximage.file_format)
-            if teximage.file_format == 'PNG':
-                print('changing type of image to JPG')
-                base, ext = os.path.splitext(fp)
-                teximage['original_extension'] = ext
-
-                fp = fp.replace('.png', '.jpg')
-                fp = fp.replace('.PNG', '.jpg')
-
-                teximage.name = teximage.name.replace('.png', '.jpg')
-                teximage.name = teximage.name.replace('.PNG', '.jpg')
-
-                teximage.file_format = 'JPEG'
-                ims.quality = JPEG_QUALITY
-                ims.color_mode = 'RGB'
-
-            if is_image_bw(na):
-                ims.color_mode = 'BW'
-
-    ims.file_format = teximage.file_format
-    ims.color_depth = image_depth
-
-    # all pngs with max compression
-    if ims.file_format == 'PNG':
-        ims.compression = 100
-    # all jpgs brought to reasonable quality
-    if ims.file_format == 'JPG':
-        ims.quality = JPEG_QUALITY
-
-    if do_downscale:
-        downscale(teximage)
-
-    # it's actually very important not to try to change the image filepath and packed file filepath before saving,
-    # blender tries to re-pack the image after writing to image.packed_image.filepath and reverts any changes.
-    teximage.save_render(filepath=bpy.path.abspath(fp), scene=bpy.context.scene)
-    if len(teximage.packed_files) > 0:
-        teximage.unpack(method='REMOVE')
-    teximage.filepath = fp
-    teximage.filepath_raw = fp
-    teximage.reload()
-
-    teximage.colorspace_settings.name = colorspace
-
-    ims.file_format = orig_file_format
-    ims.quality = orig_quality
-    ims.color_mode = orig_color_mode
-    ims.compression = orig_compression
-    ims.color_depth = orig_depth
diff --git a/blenderkit/oauth.py b/blenderkit/oauth.py
deleted file mode 100644
index ad45ef6e7dce7b08e0dc4872fe640600ba509b0a..0000000000000000000000000000000000000000
--- a/blenderkit/oauth.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# ##### 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 #####
-
-
-import json
-import webbrowser
-from http.server import BaseHTTPRequestHandler, HTTPServer
-from urllib.parse import parse_qs, quote as urlquote, urlparse
-
-import requests
-
-
-class PortsBlockedException(Exception):
-    pass
-
-
-class SimpleOAuthAuthenticator(object):
-    def __init__(self, server_url, client_id, ports):
-        self.server_url = server_url
-        self.client_id = client_id
-        self.ports = ports
-
-    def _get_tokens(self, authorization_code=None, refresh_token=None, grant_type="authorization_code"):
-        data = {
-            "grant_type": grant_type,
-            "state": "random_state_string",
-            "client_id": self.client_id,
-            "scopes": "read write",
-        }
-        if hasattr(self, 'redirect_uri'):
-            data["redirect_uri"] = self.redirect_uri
-        if authorization_code:
-            data['code'] = authorization_code
-        if refresh_token:
-            data['refresh_token'] = refresh_token
-
-        response = requests.post(
-            '%s/o/token/' % self.server_url,
-            data=data
-        )
-        if response.status_code != 200:
-            print("error retrieving refresh tokens %s" % response.status_code)
-            print(response.content)
-            return None, None, None
-
-        response_json = json.loads(response.content)
-        refresh_token = response_json['refresh_token']
-        access_token = response_json['access_token']
-        return access_token, refresh_token, response_json
-
-    def get_new_token(self, register=True, redirect_url=None):
-        class HTTPServerHandler(BaseHTTPRequestHandler):
-            html_template = '<html>%(head)s<h1>%(message)s</h1></html>'
-
-            def do_GET(self):
-                self.send_response(200)
-                self.send_header('Content-type', 'text/html')
-                self.end_headers()
-                if 'code' in self.path:
-                    self.auth_code = self.path.split('=')[1]
-                    # Display to the user that they no longer need the browser window
-                    if redirect_url:
-                        redirect_string = (
-                            '<head><meta http-equiv="refresh" content="0;url=%(redirect_url)s"></head>'
-                            '<script> window.location.href="%(redirect_url)s"; </script>' % {'redirect_url': redirect_url}
-                        )
-                    else:
-                        redirect_string = ""
-                    self.wfile.write(bytes(self.html_template % {'head': redirect_string, 'message': 'You may now close this window.'}, 'utf-8'))
-                    qs = parse_qs(urlparse(self.path).query)
-                    self.server.authorization_code = qs['code'][0]
-                else:
-                    self.wfile.write(bytes(self.html_template % {'head': '', 'message': 'Authorization failed.'}, 'utf-8'))
-
-        for port in self.ports:
-            try:
-                httpServer = HTTPServer(('localhost', port), HTTPServerHandler)
-            except Exception as e:
-                print(f"Port {port}: {e}")
-                continue
-            break
-        else:
-            print("All available ports are blocked")
-            raise PortsBlockedException(f"All available ports are blocked: {self.ports}")
-        print(f"Choosen port {port}")
-        self.redirect_uri = f"http://localhost:{port}/consumer/exchange/"
-        authorize_url = (
-            "/o/authorize?client_id=%s&state=random_state_string&response_type=code&"
-            "redirect_uri=%s" % (self.client_id, self.redirect_uri)
-        )
-        if register:
-            authorize_url = "%s/accounts/register/?next=%s" % (self.server_url, urlquote(authorize_url))
-        else:
-            authorize_url = "%s%s" % (self.server_url, authorize_url)
-        webbrowser.open_new(authorize_url)
-
-        httpServer.handle_request()
-        authorization_code = httpServer.authorization_code
-        return self._get_tokens(authorization_code=authorization_code)
-
-    def get_refreshed_token(self, refresh_token):
-        return self._get_tokens(refresh_token=refresh_token, grant_type="refresh_token")
diff --git a/blenderkit/overrides.py b/blenderkit/overrides.py
deleted file mode 100644
index 03872d70efe9eadde9d972f52128d38d66169d1c..0000000000000000000000000000000000000000
--- a/blenderkit/overrides.py
+++ /dev/null
@@ -1,300 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import utils
-
-import bpy, mathutils
-from bpy.types import (
-    Operator)
-
-
-def getNodes(nt, node_type='OUTPUT_MATERIAL'):
-    chnodes = nt.nodes[:]
-    nodes = []
-    while len(chnodes) > 0:
-        n = chnodes.pop()
-        if n.type == node_type:
-            nodes.append(n)
-        if n.type == 'GROUP':
-            chnodes.extend(n.node_tree.nodes)
-    return nodes
-
-
-def getShadersCrawl(nt, chnodes):
-    shaders = []
-    done_nodes = chnodes[:]
-
-    while len(chnodes) > 0:
-        check_node = chnodes.pop()
-        is_shader = False
-        for o in check_node.outputs:
-            if o.type == 'SHADER':
-                is_shader = True
-        for i in check_node.inputs:
-            if i.type == 'SHADER':
-                is_shader = False  # this is for mix nodes and group inputs..
-                if len(i.links) > 0:
-                    for l in i.links:
-                        fn = l.from_node
-                        if fn not in done_nodes:
-                            done_nodes.append(fn)
-                            chnodes.append(fn)
-                            if fn.type == 'GROUP':
-                                group_outputs = getNodes(fn.node_tree, node_type='GROUP_OUTPUT')
-                                shaders.extend(getShadersCrawl(fn.node_tree, group_outputs))
-
-        if check_node.type == 'GROUP':
-            is_shader = False
-
-        if is_shader:
-            shaders.append((check_node, nt))
-
-    return (shaders)
-
-
-def addColorCorrectors(material):
-    nt = material.node_tree
-    output = getNodes(nt, 'OUTPUT_MATERIAL')[0]
-    shaders = getShadersCrawl(nt, [output])
-
-    correctors = []
-    for shader, nt in shaders:
-
-        if shader.type != 'BSDF_TRANSPARENT':  # exclude transparent for color tweaks
-            for i in shader.inputs:
-                if i.type == 'RGBA':
-                    if len(i.links) > 0:
-                        l = i.links[0]
-                        if not (l.from_node.type == 'GROUP' and l.from_node.node_tree.name == 'bkit_asset_tweaker'):
-                            from_socket = l.from_socket
-                            to_socket = l.to_socket
-
-                            g = nt.nodes.new(type='ShaderNodeGroup')
-                            g.node_tree = bpy.data.node_groups['bkit_asset_tweaker']
-                            g.location = shader.location
-                            g.location.x -= 100
-
-                            nt.links.new(from_socket, g.inputs[0])
-                            nt.links.new(g.outputs[0], to_socket)
-                        else:
-                            g = l.from_node
-                        tweakers.append(g)
-                    else:
-                        g = nt.nodes.new(type='ShaderNodeGroup')
-                        g.node_tree = bpy.data.node_groups['bkit_asset_tweaker']
-                        g.location = shader.location
-                        g.location.x -= 100
-
-                        nt.links.new(g.outputs[0], i)
-                        correctors.append(g)
-
-
-# def modelProxy():
-#     utils.p('No proxies in Blender anymore')
-#     return False
-#
-#     s = bpy.context.scene
-#     ao = bpy.context.active_object
-#     if utils.is_linked_asset(ao):
-#         utils.activate(ao)
-#
-#         g = ao.instance_collection
-#
-#         rigs = []
-#
-#         for ob in g.objects:
-#             if ob.type == 'ARMATURE':
-#                 rigs.append(ob)
-#
-#         if len(rigs) == 1:
-#
-#             ao.instance_collection = None
-#             bpy.ops.object.duplicate()
-#             new_ao = bpy.context.view_layer.objects.active
-#             new_ao.instance_collection = g
-#             new_ao.empty_display_type = 'SPHERE'
-#             new_ao.empty_display_size *= 0.1
-#
-#             # bpy.ops.object.proxy_make(object=rigs[0].name)
-#             proxy = bpy.context.active_object
-#             bpy.context.view_layer.objects.active = ao
-#             ao.select_set(True)
-#             new_ao.select_set(True)
-#             new_ao.use_extra_recalc_object = True
-#             new_ao.use_extra_recalc_data = True
-#             bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)
-#             return True
-#         else:  # TODO report this to ui
-#             utils.p('not sure what to proxify')
-#     return False
-
-
-eevee_transp_nodes = [
-    'BSDF_GLASS',
-    'BSDF_REFRACTION',
-    'BSDF_TRANSPARENT',
-    'PRINCIPLED_VOLUME',
-    'VOLUME_ABSORPTION',
-    'VOLUME_SCATTER'
-]
-
-
-def ensure_eevee_transparency(m):
-    ''' ensures alpha for transparent materials when the user didn't set it up correctly'''
-    # if the blend mode is opaque, it means user probably ddidn't know or forgot to
-    # set up material properly
-    if m.blend_method == 'OPAQUE':
-        alpha = False
-        for n in m.node_tree.nodes:
-            if n.type in eevee_transp_nodes:
-                alpha = True
-            elif n.type == 'BSDF_PRINCIPLED':
-                i = n.inputs['Transmission']
-                if i.default_value > 0 or len(i.links) > 0:
-                    alpha = True
-        if alpha:
-            m.blend_method = 'HASHED'
-            m.shadow_method = 'HASHED'
-
-
-class BringToScene(Operator):
-    """Bring linked object hierarchy to scene and make it editable"""
-
-    bl_idname = "object.blenderkit_bring_to_scene"
-    bl_label = "BlenderKit bring objects to scene"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    @classmethod
-    def poll(cls, context):
-        return bpy.context.view_layer.objects.active is not None
-
-    def execute(self, context):
-
-        s = bpy.context.scene
-        sobs = s.collection.all_objects
-        aob = bpy.context.active_object
-        dg = aob.instance_collection
-        vlayer = bpy.context.view_layer
-        instances_emptys = []
-
-        # first, find instances of this collection in the scene
-        for ob in sobs:
-            if ob.instance_collection == dg and ob not in instances_emptys:
-                instances_emptys.append(ob)
-                ob.instance_collection = None
-                ob.instance_type = 'NONE'
-        # dg.make_local
-        parent = None
-        obs = []
-        for ob in dg.objects:
-            dg.objects.unlink(ob)
-            try:
-                s.collection.objects.link(ob)
-                ob.select_set(True)
-                obs.append(ob)
-                if ob.parent == None:
-                    parent = ob
-                    bpy.context.view_layer.objects.active = parent
-            except Exception as e:
-                print(e)
-
-        bpy.ops.object.make_local(type='ALL')
-
-        for i, ob in enumerate(obs):
-            if ob.name in vlayer.objects:
-                obs[i] = vlayer.objects[ob.name]
-                try:
-                    ob.select_set(True)
-                except Exception as e:
-                    print('failed to select an object from the collection, getting a replacement.')
-                    print(e)
-
-        related = []
-
-        for i, ob in enumerate(instances_emptys):
-            if i > 0:
-                bpy.ops.object.duplicate(linked=True)
-
-            related.append([ob, bpy.context.active_object, mathutils.Vector(bpy.context.active_object.scale)])
-
-        for relation in related:
-            bpy.ops.object.select_all(action='DESELECT')
-            bpy.context.view_layer.objects.active = relation[0]
-            relation[0].select_set(True)
-            relation[1].select_set(True)
-            relation[1].matrix_world = relation[0].matrix_world
-            relation[1].scale.x = relation[2].x * relation[0].scale.x
-            relation[1].scale.y = relation[2].y * relation[0].scale.y
-            relation[1].scale.z = relation[2].z * relation[0].scale.z
-            bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)
-
-        return {'FINISHED'}
-
-
-# class ModelProxy(Operator):
-#     """Attempt to create proxy armature from the asset"""
-#     bl_idname = "object.blenderkit_make_proxy"
-#     bl_label = "BlenderKit Make Proxy"
-#
-#     @classmethod
-#     def poll(cls, context):
-#         return bpy.context.view_layer.objects.active is not None
-#
-#     def execute(self, context):
-#         result = modelProxy()
-#         if not result:
-#             self.report({'INFO'}, 'No proxy made.There is no armature or more than one in the model.')
-#         return {'FINISHED'}
-
-
-class ColorCorrector(Operator):
-    """Add color corector to the asset. """
-    bl_idname = "object.blenderkit_color_corrector"
-    bl_label = "Add color corrector"
-
-    @classmethod
-    def poll(cls, context):
-        return bpy.context.view_layer.objects.active is not None
-
-    def execute(self, context):
-        ao = bpy.context.active_object
-        g = ao.instance_collection
-        ao['color correctors'] = []
-        mats = []
-
-        for o in g.objects:
-            for ms in o.material_slots:
-                if ms.material not in mats:
-                    mats.append(ms.material)
-        for mat in mats:
-            correctors = addColorCorrectors(mat)
-
-        return 'FINISHED'
-
-
-def register_overrides():
-    bpy.utils.register_class(BringToScene)
-    # bpy.utils.register_class(ModelProxy)
-    bpy.utils.register_class(ColorCorrector)
-
-
-def unregister_overrides():
-    bpy.utils.unregister_class(BringToScene)
-    # bpy.utils.unregister_class(ModelProxy)
-    bpy.utils.unregister_class(ColorCorrector)
diff --git a/blenderkit/paths.py b/blenderkit/paths.py
deleted file mode 100644
index 0170ae7b56f7f557794406038ed33218f98895dd..0000000000000000000000000000000000000000
--- a/blenderkit/paths.py
+++ /dev/null
@@ -1,407 +0,0 @@
-# ##### 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 #####
-
-import bpy, os, sys, tempfile, shutil
-from blenderkit import tasks_queue, ui, utils, reports
-
-_presets = os.path.join(bpy.utils.user_resource('SCRIPTS'), "presets")
-BLENDERKIT_LOCAL = "http://localhost:8001"
-BLENDERKIT_MAIN = "https://www.blenderkit.com"
-BLENDERKIT_DEVEL = "https://devel.blenderkit.com"
-BLENDERKIT_API = "/api/v1/"
-BLENDERKIT_REPORT_URL = "usage_report/"
-BLENDERKIT_USER_ASSETS = "/my-assets"
-BLENDERKIT_PLANS = "/plans/pricing/"
-BLENDERKIT_MANUAL = "https://youtu.be/pSay3yaBWV0"
-BLENDERKIT_MODEL_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/upload/"
-BLENDERKIT_MATERIAL_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/uploading-material/"
-BLENDERKIT_BRUSH_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/uploading-brush/"
-BLENDERKIT_HDR_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/uploading-hdr/"
-BLENDERKIT_SCENE_UPLOAD_INSTRUCTIONS_URL = "https://www.blenderkit.com/docs/uploading-scene/"
-BLENDERKIT_LOGIN_URL = "https://www.blenderkit.com/accounts/login"
-BLENDERKIT_OAUTH_LANDING_URL = "/oauth-landing/"
-BLENDERKIT_SIGNUP_URL = "https://www.blenderkit.com/accounts/register"
-BLENDERKIT_SETTINGS_FILENAME = os.path.join(_presets, "bkit.json")
-
-
-def cleanup_old_folders():
-    '''function to clean up any historical folders for BlenderKit. By now removes the temp folder.'''
-    orig_temp = os.path.join(os.path.expanduser('~'), 'blenderkit_data', 'temp')
-    if os.path.isdir(orig_temp):
-        try:
-            shutil.rmtree(orig_temp)
-        except Exception as e:
-            print(e)
-            print("couldn't delete old temp directory")
-
-
-def get_bkit_url():
-    # bpy.app.debug_value = 2
-    d = bpy.app.debug_value
-    # d = 2
-    if d == 1:
-        url = BLENDERKIT_LOCAL
-    elif d == 2:
-        url = BLENDERKIT_DEVEL
-    else:
-        url = BLENDERKIT_MAIN
-    return url
-
-
-def find_in_local(text=''):
-    fs = []
-    for p, d, f in os.walk('.'):
-        for file in f:
-            if text in file:
-                fs.append(file)
-    return fs
-
-
-def get_api_url():
-    return get_bkit_url() + BLENDERKIT_API
-
-
-def get_oauth_landing_url():
-    return get_bkit_url() + BLENDERKIT_OAUTH_LANDING_URL
-
-
-def get_author_gallery_url(author_id):
-    return f'{get_bkit_url()}/asset-gallery?query=author_id:{author_id}'
-
-def get_asset_gallery_url(asset_id):
-    return f'{get_bkit_url()}/asset-gallery-detail/{asset_id}/'
-
-def default_global_dict():
-    from os.path import expanduser
-    home = expanduser("~")
-    return home + os.sep + 'blenderkit_data'
-
-
-def get_categories_filepath():
-    tempdir = get_temp_dir()
-    return os.path.join(tempdir, 'categories.json')
-
-dirs_exist_dict = {}#cache these results since this is used very often
-# this causes the function to fail if user deletes the directory while blender is running,
-# but comes back when blender is restarted.
-def get_temp_dir(subdir=None):
-
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    #first try cached results
-    if subdir is not None:
-        d = dirs_exist_dict.get(subdir)
-        if d is not None:
-            return d
-    else:
-        d = dirs_exist_dict.get('top')
-        if d is not None:
-            return d
-
-    # tempdir = user_preferences.temp_dir
-    tempdir = os.path.join(tempfile.gettempdir(), 'bkit_temp')
-    if tempdir.startswith('//'):
-        tempdir = bpy.path.abspath(tempdir)
-    try:
-        if not os.path.exists(tempdir):
-            os.makedirs(tempdir)
-        dirs_exist_dict['top'] = tempdir
-
-        if subdir is not None:
-            tempdir = os.path.join(tempdir, subdir)
-            if not os.path.exists(tempdir):
-                os.makedirs(tempdir)
-            dirs_exist_dict[subdir] = tempdir
-
-        cleanup_old_folders()
-    except:
-        tasks_queue.add_task((reports.add_report, ('Cache directory not found. Resetting Cache folder path.',)))
-
-        p = default_global_dict()
-        if p == user_preferences.global_dir:
-            message = 'Global dir was already default, plese set a global directory in addon preferences to a dir where you have write permissions.'
-            tasks_queue.add_task((reports.add_report, (message,)))
-            return None
-        user_preferences.global_dir = p
-        tempdir = get_temp_dir(subdir=subdir)
-    return tempdir
-
-
-
-def get_download_dirs(asset_type):
-    ''' get directories where assets will be downloaded'''
-    subdmapping = {'brush': 'brushes', 'texture': 'textures', 'model': 'models', 'scene': 'scenes',
-                   'material': 'materials', 'hdr':'hdrs'}
-
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    dirs = []
-    if user_preferences.directory_behaviour == 'BOTH' or 'GLOBAL':
-        ddir = user_preferences.global_dir
-        if ddir.startswith('//'):
-            ddir = bpy.path.abspath(ddir)
-        if not os.path.exists(ddir):
-            os.makedirs(ddir)
-
-        subd = subdmapping[asset_type]
-        subdir = os.path.join(ddir, subd)
-        if not os.path.exists(subdir):
-            os.makedirs(subdir)
-        dirs.append(subdir)
-    if (
-            user_preferences.directory_behaviour == 'BOTH' or user_preferences.directory_behaviour == 'LOCAL') and bpy.data.is_saved:  # it's important local get's solved as second, since for the linking process only last filename will be taken. For download process first name will be taken and if 2 filenames were returned, file will be copied to the 2nd path.
-        ddir = user_preferences.project_subdir
-        if ddir.startswith('//'):
-            ddir = bpy.path.abspath(ddir)
-            if not os.path.exists(ddir):
-                os.makedirs(ddir)
-
-        subd = subdmapping[asset_type]
-
-        subdir = os.path.join(ddir, subd)
-        if not os.path.exists(subdir):
-            os.makedirs(subdir)
-        dirs.append(subdir)
-
-    return dirs
-
-
-def slugify(slug):
-    """
-    Normalizes string, converts to lowercase, removes non-alpha characters,
-    and converts spaces to hyphens.
-    """
-    import unicodedata, re
-    slug = slug.lower()
-
-    characters = '<>:"/\\|?\*., ()#'
-    for ch in characters:
-        slug = slug.replace(ch, '_')
-    # import re
-    # slug = unicodedata.normalize('NFKD', slug)
-    # slug = slug.encode('ascii', 'ignore').lower()
-    slug = re.sub(r'[^a-z0-9]+.- ', '-', slug).strip('-')
-    slug = re.sub(r'[-]+', '-', slug)
-    slug = re.sub(r'/', '_', slug)
-    slug = re.sub(r'\\\'\"', '_', slug)
-    if len(slug)>50:
-        slug = slug[:50]
-    return slug
-
-
-def extract_filename_from_url(url):
-    # print(url)
-    if url is not None:
-        imgname = url.split('/')[-1]
-        imgname = imgname.split('?')[0]
-        return imgname
-    return ''
-
-
-resolution_suffix = {
-    'blend': '',
-    'resolution_0_5K': '_05k',
-    'resolution_1K': '_1k',
-    'resolution_2K': '_2k',
-    'resolution_4K': '_4k',
-    'resolution_8K': '_8k',
-}
-resolutions = {
-    'resolution_0_5K': 512,
-    'resolution_1K': 1024,
-    'resolution_2K': 2048,
-    'resolution_4K': 4096,
-    'resolution_8K': 8192,
-}
-
-
-def round_to_closest_resolution(res):
-    rdist = 1000000
-    #    while res/2>1:
-    #        p2res*=2
-    #        res = res/2
-    #        print(p2res, res)
-    for rkey in resolutions:
-        # print(resolutions[rkey], rdist)
-        d = abs(res - resolutions[rkey])
-        if d < rdist:
-            rdist = d
-            p2res = rkey
-
-    return p2res
-
-
-def get_res_file(asset_data, resolution, find_closest_with_url = False):
-    '''
-    Returns closest resolution that current asset can offer.
-    If there are no resolutions, return orig file.
-    If orig file is requested, return it.
-    params
-    asset_data
-    resolution - ideal resolution
-    find_closest_with_url:
-        returns only resolutions that already containt url in the asset data, used in scenes where asset is/was already present.
-    Returns:
-        resolution file
-        resolution, so that other processess can pass correctly which resolution is downloaded.
-    '''
-    orig = None
-    res = None
-    closest = None
-    target_resolution = resolutions.get(resolution)
-    mindist = 100000000
-
-    for f in asset_data['files']:
-        if f['fileType'] == 'blend':
-            orig = f
-            if resolution == 'blend':
-                #orig file found, return.
-                return orig , 'blend'
-
-        if f['fileType'] == resolution:
-            #exact match found, return.
-            return f, resolution
-        # find closest resolution if the exact match won't be found.
-        rval = resolutions.get(f['fileType'])
-        if rval and target_resolution:
-            rdiff = abs(target_resolution - rval)
-            if rdiff < mindist:
-                closest = f
-                mindist = rdiff
-                # print('\n\n\n\n\n\n\n\n')
-                # print(closest)
-                # print('\n\n\n\n\n\n\n\n')
-    if not res and not closest:
-        # utils.pprint(f'will download blend instead of resolution {resolution}')
-        return orig , 'blend'
-    # utils.pprint(f'found closest resolution {closest["fileType"]} instead of the requested {resolution}')
-    return closest, closest['fileType']
-
-def server_2_local_filename(asset_data, filename):
-    '''
-    Convert file name on server to file name local.
-    This should get replaced
-    '''
-    # print(filename)
-    fn = filename.replace('blend_', '')
-    fn = fn.replace('resolution_', '')
-    # print('after replace ', fn)
-    n = slugify(asset_data['name']) + '_' + fn
-    return n
-
-def get_texture_directory(asset_data, resolution = 'blend'):
-    tex_dir_path = f"//textures{resolution_suffix[resolution]}{os.sep}"
-    return tex_dir_path
-
-def get_download_filepaths(asset_data, resolution='blend', can_return_others = False):
-    '''Get all possible paths of the asset and resolution. Usually global and local directory.'''
-    dirs = get_download_dirs(asset_data['assetType'])
-    res_file, resolution = get_res_file(asset_data, resolution, find_closest_with_url = can_return_others)
-    name_slug = slugify(asset_data['name'])
-    asset_folder_name = f"{name_slug}_{asset_data['id']}"
-
-    # utils.pprint('get download filenames ', dict(res_file))
-    file_names = []
-
-    if not res_file:
-        return file_names
-    # fn = asset_data['file_name'].replace('blend_', '')
-    if res_file.get('url') is not None:
-        #Tweak the names a bit:
-        # remove resolution and blend words in names
-        #
-        fn = extract_filename_from_url(res_file['url'])
-        n = server_2_local_filename(asset_data,fn)
-        for d in dirs:
-            asset_folder_path = os.path.join(d,asset_folder_name)
-            if not os.path.exists(asset_folder_path):
-                os.makedirs(asset_folder_path)
-
-            file_name = os.path.join(asset_folder_path, n)
-            file_names.append(file_name)
-
-    utils.p('file paths', file_names)
-    return file_names
-
-
-def delete_asset_debug(asset_data):
-    '''TODO fix this for resolutions - should get ALL files from ALL resolutions.'''
-    from blenderkit import download
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    api_key = user_preferences.api_key
-
-    download.get_download_url(asset_data, download.get_scene_id(), api_key)
-
-    file_names = get_download_filepaths(asset_data)
-    for f in file_names:
-        asset_dir = os.path.dirname(f)
-
-        if os.path.isdir(asset_dir):
-
-            try:
-                print(asset_dir)
-                shutil.rmtree(asset_dir)
-            except:
-                e = sys.exc_info()[0]
-                print(e)
-                pass;
-
-
-def get_clean_filepath():
-    script_path = os.path.dirname(os.path.realpath(__file__))
-    subpath = "blendfiles" + os.sep + "cleaned.blend"
-    cp = os.path.join(script_path, subpath)
-    return cp
-
-
-def get_thumbnailer_filepath():
-    script_path = os.path.dirname(os.path.realpath(__file__))
-    # fpath = os.path.join(p, subpath)
-    subpath = "blendfiles" + os.sep + "thumbnailer.blend"
-    return os.path.join(script_path, subpath)
-
-
-def get_material_thumbnailer_filepath():
-    script_path = os.path.dirname(os.path.realpath(__file__))
-    # fpath = os.path.join(p, subpath)
-    subpath = "blendfiles" + os.sep + "material_thumbnailer_cycles.blend"
-    return os.path.join(script_path, subpath)
-    """
-    for p in bpy.utils.script_paths():
-        testfname= os.path.join(p, subpath)#p + '%saddons%sobject_fracture%sdata.blend' % (s,s,s)
-        if os.path.isfile( testfname):
-            fname=testfname
-            return(fname)
-    return None
-    """
-
-
-def get_addon_file(subpath=''):
-    script_path = os.path.dirname(os.path.realpath(__file__))
-    # fpath = os.path.join(p, subpath)
-    return os.path.join(script_path, subpath)
-
-script_path = os.path.dirname(os.path.realpath(__file__))
-
-def get_addon_thumbnail_path(name):
-    global script_path
-    # fpath = os.path.join(p, subpath)
-    ext = name.split('.')[-1]
-    next = ''
-    if not (ext == 'jpg' or ext == 'png'):  # already has ext?
-        next = '.jpg'
-    subpath = "thumbnails" + os.sep + name + next
-    return os.path.join(script_path, subpath)
diff --git a/blenderkit/ratings.py b/blenderkit/ratings.py
deleted file mode 100644
index 3baabb5bd97764f8bea68de14e04a6d48b662c66..0000000000000000000000000000000000000000
--- a/blenderkit/ratings.py
+++ /dev/null
@@ -1,297 +0,0 @@
-# ##### 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 #####
-
-from blenderkit import paths, utils, rerequests, tasks_queue, ratings_utils, icons
-
-import bpy
-import requests, threading
-import logging
-
-bk_logger = logging.getLogger('blenderkit')
-
-from bpy.props import (
-    IntProperty,
-    FloatProperty,
-    StringProperty,
-    EnumProperty,
-    BoolProperty,
-    PointerProperty,
-)
-from bpy.types import (
-    Operator,
-    Panel,
-)
-
-
-def pretty_print_POST(req):
-    """
-    pretty print a request
-    """
-    print('{}\n{}\n{}\n\n{}'.format(
-        '-----------START-----------',
-        req.method + ' ' + req.url,
-        '\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
-        req.body,
-    ))
-
-
-def upload_review_thread(url, reviews, headers):
-    r = rerequests.put(url, data=reviews, verify=True, headers=headers)
-
-    # except requests.exceptions.RequestException as e:
-    #     print('reviews upload failed: %s' % str(e))
-
-
-
-def upload_rating(asset):
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    api_key = user_preferences.api_key
-    headers = utils.get_headers(api_key)
-
-    bkit_ratings = asset.bkit_ratings
-    # print('rating asset', asset_data['name'], asset_data['assetBaseId'])
-    url = paths.get_api_url() + 'assets/' + asset['asset_data']['id'] + '/rating/'
-
-    ratings = [
-
-    ]
-
-    if bkit_ratings.rating_quality > 0.1:
-        ratings = (('quality', bkit_ratings.rating_quality),)
-        tasks_queue.add_task((ratings_utils.send_rating_to_thread_quality, (url, ratings, headers)), wait=2.5,
-                             only_last=True)
-    if bkit_ratings.rating_work_hours > 0.1:
-        ratings = (('working_hours', round(bkit_ratings.rating_work_hours, 1)),)
-        tasks_queue.add_task((ratings_utils.send_rating_to_thread_work_hours, (url, ratings, headers)), wait=2.5,
-                             only_last=True)
-
-    thread = threading.Thread(target=ratings_utils.upload_rating_thread, args=(url, ratings, headers))
-    thread.start()
-
-    url = paths.get_api_url() + 'assets/' + asset['asset_data']['id'] + '/review'
-
-    reviews = {
-        'reviewText': bkit_ratings.rating_compliments,
-        'reviewTextProblems': bkit_ratings.rating_problems,
-    }
-    if not (bkit_ratings.rating_compliments == '' and bkit_ratings.rating_compliments == ''):
-        thread = threading.Thread(target=upload_review_thread, args=(url, reviews, headers))
-        thread.start()
-
-    # the info that the user rated an item is stored in the scene
-    s = bpy.context.scene
-    s['assets rated'] = s.get('assets rated', {})
-    if bkit_ratings.rating_quality > 0.1 and bkit_ratings.rating_work_hours > 0.1:
-        s['assets rated'][asset['asset_data']['assetBaseId']] = True
-
-
-def get_assets_for_rating():
-    '''
-    gets assets from scene that could/should be rated by the user.
-    TODO this is only a draft.
-
-    '''
-    assets = []
-    for ob in bpy.context.scene.objects:
-        if ob.get('asset_data'):
-            assets.append(ob)
-    for m in bpy.data.materials:
-        if m.get('asset_data'):
-            assets.append(m)
-    for b in bpy.data.brushes:
-        if b.get('asset_data'):
-            assets.append(b)
-    return assets
-
-
-asset_types = (
-    ('MODEL', 'Model', 'set of objects'),
-    ('SCENE', 'Scene', 'scene'),
-    ('HDR', 'HDR', 'hdr'),
-    ('MATERIAL', 'Material', 'any .blend Material'),
-    ('TEXTURE', 'Texture', 'a texture, or texture set'),
-    ('BRUSH', 'Brush', 'brush, can be any type of blender brush'),
-    ('ADDON', 'Addon', 'addnon'),
-)
-
-
-# TODO drop this operator, not needed anymore.
-class UploadRatingOperator(bpy.types.Operator):
-    """Upload rating to the web db"""
-    bl_idname = "object.blenderkit_rating_upload"
-    bl_label = "Send Rating"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    # type of upload - model, material, textures, e.t.c.
-    # asset_type: EnumProperty(
-    #     name="Type",
-    #     items=asset_types,
-    #     description="Type of asset",
-    #     default="MODEL",
-    # )
-
-    # @classmethod
-    # def poll(cls, context):
-    #    return bpy.context.active_object != None and bpy.context.active_object.get('asset_id') is not None
-    def draw(self, context):
-        layout = self.layout
-        layout.label(text='Rating sent to server. Thanks for rating!')
-
-    def execute(self, context):
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-        asset = utils.get_active_asset()
-        upload_rating(asset)
-        return wm.invoke_props_dialog(self)
-
-
-def draw_ratings_menu(self, context, layout):
-    pcoll = icons.icon_collections["main"]
-
-    profile_name = ''
-    profile = bpy.context.window_manager.get('bkit profile')
-    if profile and len(profile['user']['firstName']) > 0:
-        profile_name = ' ' + profile['user']['firstName']
-
-    col = layout.column()
-    # layout.template_icon_view(bkit_ratings, property, show_labels=False, scale=6.0, scale_popup=5.0)
-    row = col.row()
-    row.label(text='Quality:', icon='SOLO_ON')
-    row = col.row()
-    row.label(text='Please help the community by rating quality:')
-
-    row = col.row()
-    row.prop(self, 'rating_quality_ui', expand=True, icon_only=True, emboss=False)
-    if self.rating_quality > 0:
-        # row = col.row()
-
-        row.label(text=f'    Thanks{profile_name}!', icon='FUND')
-    # row.label(text=str(self.rating_quality))
-    col.separator()
-    col.separator()
-
-    row = col.row()
-    row.label(text='Complexity:', icon_value=pcoll['dumbbell'].icon_id)
-    row = col.row()
-    row.label(text=f"How many hours did this {self.asset_type} save you?")
-
-    if utils.profile_is_validator():
-        row = col.row()
-        row.prop(self, 'rating_work_hours')
-
-    if self.asset_type in ('model', 'scene'):
-        row = col.row()
-
-        row.prop(self, 'rating_work_hours_ui', expand=True, icon_only=False, emboss=True)
-        if float(self.rating_work_hours_ui) > 100:
-            utils.label_multiline(col,
-                                  text=f"\nThat's huge! please be sure to give such rating only to godly {self.asset_type}s.\n",
-                                  width=500)
-        elif float(self.rating_work_hours_ui) > 18:
-            col.separator()
-
-            utils.label_multiline(col,
-                                  text=f"\nThat's a lot! please be sure to give such rating only to amazing {self.asset_type}s.\n",
-                                  width=500)
-
-
-    elif self.asset_type == 'hdr':
-        row = col.row()
-        row.prop(self, 'rating_work_hours_ui_1_10', expand=True, icon_only=False, emboss=True)
-    else:
-        row = col.row()
-        row.prop(self, 'rating_work_hours_ui_1_5', expand=True, icon_only=False, emboss=True)
-
-    if self.rating_work_hours > 0:
-        row = col.row()
-        row.label(text=f'Thanks{profile_name}, you are amazing!', icon='FUND')
-
-
-class FastRateMenu(Operator, ratings_utils.RatingsProperties):
-    """Rating of the assets , also directly from the asset bar - without need to download assets"""
-    bl_idname = "wm.blenderkit_menu_rating_upload"
-    bl_label = "Ratings"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    @classmethod
-    def poll(cls, context):
-        scene = bpy.context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        return True;
-
-    def draw(self, context):
-        layout = self.layout
-        draw_ratings_menu(self, context, layout)
-
-    def execute(self, context):
-        scene = bpy.context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        #get asset id
-        if ui_props.active_index > -1:
-            sr = bpy.context.window_manager['search results']
-            asset_data = dict(sr[ui_props.active_index])
-            self.asset_id = asset_data['id']
-            self.asset_type = asset_data['assetType']
-
-        if self.asset_id == '':
-            return {'CANCELLED'}
-
-        wm = context.window_manager
-
-        self.prefill_ratings()
-
-        if self.asset_type in ('model', 'scene'):
-            # spawn a wider one for validators for the enum buttons
-            return wm.invoke_popup(self, width=500)
-        else:
-            return wm.invoke_popup(self)
-
-
-def rating_menu_draw(self, context):
-    layout = self.layout
-
-    ui_props = context.window_manager.blenderkitUI
-    sr = bpy.context.window_manager['search results']
-
-    asset_search_index = ui_props.active_index
-    if asset_search_index > -1:
-        asset_data = dict(sr['results'][asset_search_index])
-
-    col = layout.column()
-    layout.label(text='Admin rating Tools:')
-    col.operator_context = 'INVOKE_DEFAULT'
-
-    op = col.operator('wm.blenderkit_menu_rating_upload', text='Add Rating')
-    op.asset_id = asset_data['id']
-    op.asset_name = asset_data['name']
-    op.asset_type = asset_data['assetType']
-
-
-def register_ratings():
-    bpy.utils.register_class(UploadRatingOperator)
-    bpy.utils.register_class(FastRateMenu)
-    # bpy.types.OBJECT_MT_blenderkit_asset_menu.append(rating_menu_draw)
-
-
-def unregister_ratings():
-    pass;
-    # bpy.utils.unregister_class(StarRatingOperator)
-    bpy.utils.unregister_class(UploadRatingOperator)
-    bpy.utils.unregister_class(FastRateMenu)
diff --git a/blenderkit/ratings_utils.py b/blenderkit/ratings_utils.py
deleted file mode 100644
index 798d5c7eac20f79738c320e838fb444b290499ff..0000000000000000000000000000000000000000
--- a/blenderkit/ratings_utils.py
+++ /dev/null
@@ -1,367 +0,0 @@
-# ##### 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 #####
-
-# mainly update functions and callbacks for ratings properties, here to avoid circular imports.
-import bpy
-from blenderkit import utils, paths, tasks_queue, rerequests
-
-from bpy.props import (
-    IntProperty,
-    FloatProperty,
-    FloatVectorProperty,
-    StringProperty,
-    EnumProperty,
-    BoolProperty,
-    PointerProperty,
-)
-
-import threading
-import requests
-import logging
-
-bk_logger = logging.getLogger('blenderkit')
-
-
-def upload_rating_thread(url, ratings, headers):
-    ''' Upload rating thread function / disconnected from blender data.'''
-    bk_logger.debug('upload rating ' + url + str(ratings))
-    for rating_name, score in ratings:
-        if (score != -1 and score != 0):
-            rating_url = url + rating_name + '/'
-            data = {
-                "score": score,  # todo this kind of mixing is too much. Should have 2 bkit structures, upload, use
-            }
-
-            try:
-                r = rerequests.put(rating_url, data=data, verify=True, headers=headers)
-
-            except requests.exceptions.RequestException as e:
-                print('ratings upload failed: %s' % str(e))
-
-
-def send_rating_to_thread_quality(url, ratings, headers):
-    '''Sens rating into thread rating, main purpose is for tasks_queue.
-    One function per property to avoid lost data due to stashing.'''
-    thread = threading.Thread(target=upload_rating_thread, args=(url, ratings, headers))
-    thread.start()
-
-
-def send_rating_to_thread_work_hours(url, ratings, headers):
-    '''Sens rating into thread rating, main purpose is for tasks_queue.
-    One function per property to avoid lost data due to stashing.'''
-    thread = threading.Thread(target=upload_rating_thread, args=(url, ratings, headers))
-    thread.start()
-
-
-def store_rating_local_empty(asset_id):
-    context = bpy.context
-    ar = context.window_manager['asset ratings']
-    ar[asset_id] = ar.get(asset_id, {})
-
-
-def store_rating_local(asset_id, type='quality', value=0):
-    context = bpy.context
-    ar   = context.window_manager['asset ratings']
-    ar[asset_id] = ar.get(asset_id, {})
-    ar[asset_id][type] = value
-
-
-def get_rating(asset_id, headers):
-    '''
-    Retrieve ratings from BlenderKit server. Can be run from a thread
-    Parameters
-    ----------
-    asset_id
-    headers
-
-    Returns
-    -------
-    ratings - dict of type:value ratings
-    '''
-    url = paths.get_api_url() + 'assets/' + asset_id + '/rating/'
-    params = {}
-    r = rerequests.get(url, params=params, verify=True, headers=headers)
-    if r is None:
-        return
-    if r.status_code == 200:
-        rj = r.json()
-        ratings = {}
-        # print(rj)
-        # store ratings - send them to task queue
-        for r in rj['results']:
-            ratings[r['ratingType']] = r['score']
-            tasks_queue.add_task((store_rating_local,(asset_id, r['ratingType'], r['score'])))
-            # store_rating_local(asset_id, type = r['ratingType'], value = r['score'])
-
-        if len(rj['results'])==0:
-            # store empty ratings too, so that server isn't checked repeatedly
-            tasks_queue.add_task((store_rating_local_empty,(asset_id,)))
-        # return ratings
-
-
-def get_rating_local(asset_id):
-    context = bpy.context
-    context.window_manager['asset ratings'] = context.window_manager.get('asset ratings', {})
-    rating = context.window_manager['asset ratings'].get(asset_id)
-    if rating:
-        return rating.to_dict()
-    return None
-
-
-def update_ratings_quality(self, context):
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    api_key = user_preferences.api_key
-
-    headers = utils.get_headers(api_key)
-
-    if not (hasattr(self, 'rating_quality')):
-        # first option is for rating of assets that are from scene
-        asset = self.id_data
-        bkit_ratings = asset.bkit_ratings
-        asset_id = asset['asset_data']['id']
-    else:
-        # this part is for operator rating:
-        bkit_ratings = self
-        asset_id = self.asset_id
-
-    if bkit_ratings.rating_quality > 0.1:
-        url = paths.get_api_url() + f'assets/{asset_id}/rating/'
-
-        store_rating_local(asset_id, type='quality', value=bkit_ratings.rating_quality)
-
-        ratings = [('quality', bkit_ratings.rating_quality)]
-        tasks_queue.add_task((send_rating_to_thread_quality, (url, ratings, headers)), wait=2.5, only_last=True)
-
-
-def update_ratings_work_hours(self, context):
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    api_key = user_preferences.api_key
-    headers = utils.get_headers(api_key)
-    if not (hasattr(self, 'rating_work_hours')):
-        # first option is for rating of assets that are from scene
-        asset = self.id_data
-        bkit_ratings = asset.bkit_ratings
-        asset_id = asset['asset_data']['id']
-    else:
-        # this part is for operator rating:
-        bkit_ratings = self
-        asset_id = self.asset_id
-
-    if bkit_ratings.rating_work_hours > 0.45:
-        url = paths.get_api_url() + f'assets/{asset_id}/rating/'
-
-        store_rating_local(asset_id, type='working_hours', value=bkit_ratings.rating_work_hours)
-
-        ratings = [('working_hours', round(bkit_ratings.rating_work_hours, 1))]
-        tasks_queue.add_task((send_rating_to_thread_work_hours, (url, ratings, headers)), wait=2.5, only_last=True)
-
-
-def update_quality_ui(self, context):
-    '''Converts the _ui the enum into actual quality number.'''
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if user_preferences.api_key == '':
-        # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
-        # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
-        # return
-        bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
-                                    message='Please login/signup to rate assets. Clicking OK takes you to web login.')
-        # self.rating_quality_ui = '0'
-    self.rating_quality = int(self.rating_quality_ui)
-
-
-def update_ratings_work_hours_ui(self, context):
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if user_preferences.api_key == '':
-        # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
-        # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
-        # return
-        bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
-                                    message='Please login/signup to rate assets. Clicking OK takes you to web login.')
-        # self.rating_work_hours_ui = '0'
-    self.rating_work_hours = float(self.rating_work_hours_ui)
-
-
-def update_ratings_work_hours_ui_1_5(self, context):
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if user_preferences.api_key == '':
-        # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
-        # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
-        # return
-        bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
-                                    message='Please login/signup to rate assets. Clicking OK takes you to web login.')
-        # self.rating_work_hours_ui_1_5 = '0'
-    self.rating_work_hours = float(self.rating_work_hours_ui_1_5)
-
-
-def update_ratings_work_hours_ui_1_10(self, context):
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if user_preferences.api_key == '':
-        # ui_panels.draw_not_logged_in(self, message='Please login/signup to rate assets.')
-        # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_login_menu')
-        # return
-        bpy.ops.wm.blenderkit_login('INVOKE_DEFAULT',
-                                    message='Please login/signup to rate assets. Clicking OK takes you to web login.')
-        # self.rating_work_hours_ui_1_5 = '0'
-    # print('updating 1-5')
-    # print(float(self.rating_work_hours_ui_1_5))
-    self.rating_work_hours = float(self.rating_work_hours_ui_1_10)
-
-
-def stars_enum_callback(self, context):
-    '''regenerates the enum property used to display rating stars, so that there are filled/empty stars correctly.'''
-    items = []
-    for a in range(0, 10):
-        if self.rating_quality < a + 1:
-            icon = 'SOLO_OFF'
-        else:
-            icon = 'SOLO_ON'
-        # has to have something before the number in the value, otherwise fails on registration.
-        items.append((f'{a + 1}', f'{a + 1}', '', icon, a + 1))
-    return items
-
-
-class RatingsProperties():
-    message: StringProperty(
-        name="message",
-        description="message",
-        default="Rating asset",
-        options={'SKIP_SAVE'})
-
-    asset_id: StringProperty(
-        name="Asset Base Id",
-        description="Unique id of the asset (hidden)",
-        default="",
-        options={'SKIP_SAVE'})
-
-    asset_name: StringProperty(
-        name="Asset Name",
-        description="Name of the asset (hidden)",
-        default="",
-        options={'SKIP_SAVE'})
-
-    asset_type: StringProperty(
-        name="Asset type",
-        description="asset type",
-        default="",
-        options={'SKIP_SAVE'})
-
-    rating_quality: IntProperty(name="Quality",
-                                description="quality of the material",
-                                default=0,
-                                min=-1, max=10,
-                                update=update_ratings_quality,
-                                options={'SKIP_SAVE'})
-
-    # the following enum is only to ease interaction - enums support 'drag over' and enable to draw the stars easily.
-    rating_quality_ui: EnumProperty(name='rating_quality_ui',
-                                    items=stars_enum_callback,
-                                    description='Rating stars 0 - 10',
-                                    default=0,
-                                    update=update_quality_ui,
-                                    options={'SKIP_SAVE'})
-
-    rating_work_hours: FloatProperty(name="Work Hours",
-                                     description="How many hours did this work take?",
-                                     default=0.00,
-                                     min=0.0, max=300,
-                                     update=update_ratings_work_hours,
-                                     options={'SKIP_SAVE'}
-                                     )
-
-    high_rating_warning = "This is a high rating, please be sure to give such rating only to amazing assets"
-
-    possible_wh_values = [0,.5,1,2,3,4,5,6,8,10,15,20,30,50,100,150,200,250]
-    items_models = [('0', '0', ''),
-                    ('.5', '0.5', ''),
-                    ('1', '1', ''),
-                    ('2', '2', ''),
-                    ('3', '3', ''),
-                    ('4', '4', ''),
-                    ('5', '5', ''),
-                    ('6', '6', ''),
-                    ('8', '8', ''),
-                    ('10', '10', ''),
-                    ('15', '15', ''),
-                    ('20', '20', ''),
-                    ('30', '30', high_rating_warning),
-                    ('50', '50', high_rating_warning),
-                    ('100', '100', high_rating_warning),
-                    ('150', '150', high_rating_warning),
-                    ('200', '200', high_rating_warning),
-                    ('250', '250', high_rating_warning),
-                    ]
-    rating_work_hours_ui: EnumProperty(name="Work Hours",
-                                       description="How many hours did this work take?",
-                                       items=items_models,
-                                       default='0', update=update_ratings_work_hours_ui,
-                                       options={'SKIP_SAVE'}
-                                       )
-    possible_wh_values_1_5 = [0,.2, .5,1,2,3,4,5]
-
-    items_1_5 = [('0', '0', ''),
-                 ('.2', '0.2', ''),
-                 ('.5', '0.5', ''),
-                 ('1', '1', ''),
-                 ('2', '2', ''),
-                 ('3', '3', ''),
-                 ('4', '4', ''),
-                 ('5', '5', '')
-                 ]
-    rating_work_hours_ui_1_5: EnumProperty(name="Work Hours",
-                                           description="How many hours did this work take?",
-                                           items=items_1_5,
-                                           default='0',
-                                           update=update_ratings_work_hours_ui_1_5,
-                                           options={'SKIP_SAVE'}
-                                           )
-    possible_wh_values_1_10 = [0,1,2,3,4,5,6,7,8,9,10]
-
-    items_1_10= [('0', '0', ''),
-       ('1', '1', ''),
-       ('2', '2', ''),
-       ('3', '3', ''),
-       ('4', '4', ''),
-       ('5', '5', ''),
-       ('6', '6', ''),
-       ('7', '7', ''),
-       ('8', '8', ''),
-       ('9', '9', ''),
-       ('10', '10', '')
-       ]
-    rating_work_hours_ui_1_10: EnumProperty(name="Work Hours",
-                                            description="How many hours did this work take?",
-                                            items= items_1_10,
-                                            default='0',
-                                            update=update_ratings_work_hours_ui_1_10,
-                                            options={'SKIP_SAVE'}
-                                            )
-
-    def prefill_ratings(self):
-        # pre-fill ratings
-        ratings = get_rating_local(self.asset_id)
-        if ratings and ratings.get('quality'):
-            self.rating_quality = ratings['quality']
-        if ratings and ratings.get('working_hours'):
-            wh = int(ratings['working_hours'])
-            whs = str(wh)
-            if wh in self.possible_wh_values:
-                self.rating_work_hours_ui = whs
-            if wh < 6 and wh in self.possible_wh_values_1_5:
-                self.rating_work_hours_ui_1_5 = whs
-            if wh < 11 and wh in self.possible_wh_values_1_10:
-                self.rating_work_hours_ui_1_10 = whs
diff --git a/blenderkit/reports.py b/blenderkit/reports.py
deleted file mode 100644
index 7a45586383be9bd26f187a56cb4a108e771ecf6e..0000000000000000000000000000000000000000
--- a/blenderkit/reports.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# ##### 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 #####
-
-import time
-import bpy
-from blenderkit import colors, asset_bar_op, ui_bgl, utils
-
-reports = []
-
-
-def add_report(text='', timeout=5, color=colors.GREEN):
-    global reports
-    # check for same reports and just make them longer by the timeout.
-    for old_report in reports:
-        if old_report.text == text:
-            old_report.timeout = old_report.age + timeout
-            return
-    report = Report(text=text,  timeout=timeout, color=color)
-    reports.append(report)
-
-
-class Report():
-    def __init__(self, area_pointer=0, text='', timeout=5, color=(.5, 1, .5, 1)):
-        self.text = text
-        self.timeout = timeout
-        self.start_time = time.time()
-        self.color = color
-        self.draw_color = color
-        self.age = 0
-        if asset_bar_op.active_area_pointer == 0:
-            w, a, r = utils.get_largest_area(area_type='VIEW_3D')
-
-            self.active_area_pointer = a.as_pointer()
-        else:
-            self.active_area_pointer = asset_bar_op.active_area_pointer
-
-    def fade(self):
-        fade_time = 1
-        self.age = time.time() - self.start_time
-        if self.age + fade_time > self.timeout:
-            alpha_multiplier = (self.timeout - self.age) / fade_time
-            self.draw_color = (self.color[0], self.color[1], self.color[2], self.color[3] * alpha_multiplier)
-            if self.age > self.timeout:
-                global reports
-                try:
-                    reports.remove(self)
-                except Exception as e:
-                    pass;
-
-    def draw(self, x, y):
-        if (bpy.context.area is not None and bpy.context.area.as_pointer() == self.active_area_pointer):
-            ui_bgl.draw_text(self.text, x, y + 8, 16, self.draw_color)
diff --git a/blenderkit/rerequests.py b/blenderkit/rerequests.py
deleted file mode 100644
index 2a8adc417d58599baacd034fdc43e55f3b1483da..0000000000000000000000000000000000000000
--- a/blenderkit/rerequests.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import ui, utils, paths, tasks_queue, bkit_oauth, reports
-
-import requests
-import bpy
-import logging
-
-bk_logger = logging.getLogger('rerequests')
-
-
-class FakeResponse():
-    def __init__(self, text='', status_code = 400):
-        self.text = text
-        self.status_code = status_code
-    def json(self):
-        return {}
-
-def rerequest(method, url, recursion=0, **kwargs):
-    # first get any additional args from kwargs
-    immediate = False
-    if kwargs.get('immediate'):
-        immediate = kwargs['immediate']
-        kwargs.pop('immediate')
-    # first normal attempt
-    try:
-        response = requests.request(method, url, **kwargs)
-    except Exception as e:
-        print(e)
-        tasks_queue.add_task((reports.add_report, (
-            'Connection error.', 10)))
-        return FakeResponse()
-
-    bk_logger.debug(url + str(kwargs))
-    bk_logger.debug(response.status_code)
-
-    if response.status_code == 401:
-        try:
-            rdata = response.json()
-        except:
-            rdata = {}
-
-        tasks_queue.add_task((reports.add_report, (method + ' request Failed.' + str(rdata.get('detail')),)))
-
-        if rdata.get('detail') == 'Invalid token.':
-            user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-            if user_preferences.api_key != '':
-                if user_preferences.enable_oauth and user_preferences.api_key_refresh != '':
-                    tasks_queue.add_task((reports.add_report, (
-                        'refreshing token. If this fails, please login in BlenderKit Login panel.', 10)))
-                    refresh_url = paths.get_bkit_url()
-                    auth_token, refresh_token, oauth_response = bkit_oauth.refresh_token(
-                        user_preferences.api_key_refresh, refresh_url)
-
-                    # bk_logger.debug(auth_token, refresh_token)
-                    if auth_token is not None:
-                        if immediate == True:
-                            # this can write tokens occasionally into prefs. used e.g. in upload. Only possible
-                            #  in non-threaded tasks
-                            bpy.context.preferences.addons['blenderkit'].preferences.api_key = auth_token
-                            bpy.context.preferences.addons['blenderkit'].preferences.api_key_refresh = refresh_token
-                        else:
-                            tasks_queue.add_task((bkit_oauth.write_tokens, (auth_token, refresh_token, oauth_response)))
-
-                        kwargs['headers'] = utils.get_headers(auth_token)
-                        response = requests.request(method, url, **kwargs)
-                        bk_logger.debug('reresult', response.status_code)
-                        if response.status_code >= 400:
-                            bk_logger.debug('reresult', response.text)
-                            tasks_queue.add_task((reports.add_report, (
-                                response.text, 10)))
-
-                    else:
-                        tasks_queue.add_task((reports.add_report, (
-                            'Refreshing token failed.Please login manually.', 10)))
-                        # tasks_queue.add_task((bkit_oauth.write_tokens, ('', '', '')))
-                        tasks_queue.add_task((bpy.ops.wm.blenderkit_login, ('INVOKE_DEFAULT',)), fake_context=True)
-    return response
-
-
-def get(url, **kwargs):
-    response = rerequest('get', url, **kwargs)
-    return response
-
-
-def post(url, **kwargs):
-    response = rerequest('post', url, **kwargs)
-    return response
-
-
-def put(url, **kwargs):
-    response = rerequest('put', url, **kwargs)
-    return response
-
-
-def patch(url, **kwargs):
-    response = rerequest('patch', url, **kwargs)
-    return response
diff --git a/blenderkit/resolutions.py b/blenderkit/resolutions.py
deleted file mode 100644
index 23aa939d047eda62aeec33a83a645764c36bf196..0000000000000000000000000000000000000000
--- a/blenderkit/resolutions.py
+++ /dev/null
@@ -1,716 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import paths, append_link, bg_blender, utils, download, search, rerequests, upload_bg, image_utils
-
-import sys, json, os, time
-import subprocess
-import tempfile
-import bpy
-import requests
-import math
-import threading
-
-resolutions = {
-    'resolution_0_5K': 512,
-    'resolution_1K': 1024,
-    'resolution_2K': 2048,
-    'resolution_4K': 4096,
-    'resolution_8K': 8192,
-}
-rkeys = list(resolutions.keys())
-
-resolution_props_to_server = {
-
-    '512': 'resolution_0_5K',
-    '1024': 'resolution_1K',
-    '2048': 'resolution_2K',
-    '4096': 'resolution_4K',
-    '8192': 'resolution_8K',
-    'ORIGINAL': 'blend',
-}
-
-
-def get_current_resolution():
-    actres = 0
-    for i in bpy.data.images:
-        if i.name != 'Render Result':
-            actres = max(actres, i.size[0], i.size[1])
-    return actres
-
-
-def save_image_safely(teximage, filepath):
-    '''
-    Blender makes it really hard to save images...
-    Would be worth investigating PIL or similar instead
-    Parameters
-    ----------
-    teximage
-
-    Returns
-    -------
-
-    '''
-    JPEG_QUALITY = 98
-
-    rs = bpy.context.scene.render
-    ims = rs.image_settings
-
-    orig_file_format = ims.file_format
-    orig_quality = ims.quality
-    orig_color_mode = ims.color_mode
-    orig_compression = ims.compression
-
-    ims.file_format = teximage.file_format
-    if teximage.file_format == 'PNG':
-        ims.color_mode = 'RGBA'
-    elif teximage.channels == 3:
-        ims.color_mode = 'RGB'
-    else:
-        ims.color_mode = 'BW'
-
-    # all pngs with max compression
-    if ims.file_format == 'PNG':
-        ims.compression = 100
-    # all jpgs brought to reasonable quality
-    if ims.file_format == 'JPG':
-        ims.quality = JPEG_QUALITY
-    # it's actually very important not to try to change the image filepath and packed file filepath before saving,
-    # blender tries to re-pack the image after writing to image.packed_image.filepath and reverts any changes.
-    teximage.save_render(filepath=bpy.path.abspath(filepath), scene=bpy.context.scene)
-
-    teximage.filepath = filepath
-    for packed_file in teximage.packed_files:
-        packed_file.filepath = filepath
-    teximage.filepath_raw = filepath
-    teximage.reload()
-
-    ims.file_format = orig_file_format
-    ims.quality = orig_quality
-    ims.color_mode = orig_color_mode
-    ims.compression = orig_compression
-
-
-def extxchange_to_resolution(filepath):
-    base, ext = os.path.splitext(filepath)
-    if ext in ('.png', '.PNG'):
-        ext = 'jpg'
-
-
-
-
-
-
-def upload_resolutions(files, asset_data):
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-    upload_data = {
-        "name": asset_data['name'],
-        "token": preferences.api_key,
-        "id": asset_data['id']
-    }
-
-    uploaded = upload_bg.upload_files(upload_data, files)
-
-    if uploaded:
-        bg_blender.progress('upload finished successfully')
-    else:
-        bg_blender.progress('upload failed.')
-
-
-def unpack_asset(data):
-    utils.p('unpacking asset')
-    asset_data = data['asset_data']
-    # utils.pprint(asset_data)
-
-    blend_file_name = os.path.basename(bpy.data.filepath)
-    ext = os.path.splitext(blend_file_name)[1]
-
-    resolution = asset_data.get('resolution', 'blend')
-    # TODO - passing resolution inside asset data might not be the best solution
-    tex_dir_path = paths.get_texture_directory(asset_data, resolution=resolution)
-    tex_dir_abs = bpy.path.abspath(tex_dir_path)
-    if not os.path.exists(tex_dir_abs):
-        try:
-            os.mkdir(tex_dir_abs)
-        except Exception as e:
-            print(e)
-    bpy.data.use_autopack = False
-    for image in bpy.data.images:
-        if image.name != 'Render Result':
-            # suffix = paths.resolution_suffix(data['suffix'])
-            fp = get_texture_filepath(tex_dir_path, image, resolution=resolution)
-            utils.p('unpacking file', image.name)
-            utils.p(image.filepath, fp)
-
-            for pf in image.packed_files:
-                pf.filepath = fp  # bpy.path.abspath(fp)
-            image.filepath = fp  # bpy.path.abspath(fp)
-            image.filepath_raw = fp  # bpy.path.abspath(fp)
-            # image.save()
-            if len(image.packed_files) > 0:
-                # image.unpack(method='REMOVE')
-                image.unpack(method='WRITE_ORIGINAL')
-
-    #mark asset browser asset
-    data_block = None
-    if asset_data['assetType'] == 'model':
-        for ob in bpy.data.objects:
-            if ob.parent is None and ob in bpy.context.visible_objects:
-                ob.asset_mark()
-        # for c in bpy.data.collections:
-        #     if c.get('asset_data') is not None:
-        #         c.asset_mark()
-        #         data_block = c
-    elif asset_data['assetType'] == 'material':
-        for m in bpy.data.materials:
-            m.asset_mark()
-            data_block = m
-    elif asset_data['assetType'] == 'scene':
-        bpy.context.scene.asset_mark()
-    elif asset_data['assetType'] =='brush':
-        for b in bpy.data.brushes:
-            if b.get('asset_data') is not None:
-                b.asset_mark()
-                data_block = b
-    if data_block is not None:
-        tags = data_block.asset_data.tags
-        for t in tags:
-            tags.remove(t)
-        tags.new('description: ' + asset_data['description'])
-        tags.new('tags: ' + ','.join(asset_data['tags']))
-    #
-    # if this isn't here, blender crashes when saving file.
-    bpy.context.preferences.filepaths.file_preview_type = 'NONE'
-
-    bpy.ops.wm.save_as_mainfile(filepath = bpy.data.filepath, compress=False)
-    # now try to delete the .blend1 file
-    try:
-
-        os.remove(bpy.data.filepath + '1')
-    except Exception as e:
-        print(e)
-
-
-def patch_asset_empty(asset_id, api_key):
-    '''
-        This function patches the asset for the purpose of it getting a reindex.
-        Should be removed once this is fixed on the server and
-        the server is able to reindex after uploads of resolutions
-        Returns
-        -------
-    '''
-    upload_data = {
-    }
-    url = paths.get_api_url() + 'assets/' + str(asset_id) + '/'
-    headers = utils.get_headers(api_key)
-    try:
-        r = rerequests.patch(url, json=upload_data, headers=headers, verify=True)  # files = files,
-    except requests.exceptions.RequestException as e:
-        print(e)
-        return {'CANCELLED'}
-    return {'FINISHED'}
-
-
-def reduce_all_images(target_scale=1024):
-    for img in bpy.data.images:
-        if img.name != 'Render Result':
-            print('scaling ', img.name, img.size[0], img.size[1])
-            # make_possible_reductions_on_image(i)
-            if max(img.size) > target_scale:
-                ratio = float(target_scale) / float(max(img.size))
-                print(ratio)
-                # i.save()
-                fp = '//tempimagestorage'
-                # print('generated filename',fp)
-                # for pf in img.packed_files:
-                #     pf.filepath = fp  # bpy.path.abspath(fp)
-
-                img.filepath = fp
-                img.filepath_raw = fp
-                print(int(img.size[0] * ratio), int(img.size[1] * ratio))
-                img.scale(int(img.size[0] * ratio), int(img.size[1] * ratio))
-                img.update()
-                # img.save()
-                # img.reload()
-                img.pack()
-
-
-def get_texture_filepath(tex_dir_path, image, resolution='blend'):
-    image_file_name = bpy.path.basename(image.filepath)
-    if image_file_name == '':
-        image_file_name = image.name.split('.')[0]
-
-    suffix = paths.resolution_suffix[resolution]
-
-    fp = os.path.join(tex_dir_path, image_file_name)
-    # check if there is allready an image with same name and thus also assigned path
-    # (can happen easily with genearted tex sets and more materials)
-    done = False
-    fpn = fp
-    i = 0
-    while not done:
-        is_solo = True
-        for image1 in bpy.data.images:
-            if image != image1 and image1.filepath == fpn:
-                is_solo = False
-                fpleft, fpext = os.path.splitext(fp)
-                fpn = fpleft + str(i).zfill(3) + fpext
-                i += 1
-        if is_solo:
-            done = True
-
-    return fpn
-
-
-def generate_lower_resolutions_hdr(asset_data, fpath):
-    '''generates lower resolutions for HDR images'''
-    hdr = bpy.data.images.load(fpath)
-    actres = max(hdr.size[0], hdr.size[1])
-    p2res = paths.round_to_closest_resolution(actres)
-    original_filesize = os.path.getsize(fpath) # for comparison on the original level
-    i = 0
-    finished = False
-    files = []
-    while not finished:
-        dirn = os.path.dirname(fpath)
-        fn_strip, ext = os.path.splitext(fpath)
-        ext = '.exr'
-        if i>0:
-            image_utils.downscale(hdr)
-
-
-        hdr_resolution_filepath = fn_strip + paths.resolution_suffix[p2res] + ext
-        image_utils.img_save_as(hdr, filepath=hdr_resolution_filepath, file_format='OPEN_EXR', quality=20, color_mode='RGB', compression=15,
-                    view_transform='Raw', exr_codec = 'DWAA')
-
-        if os.path.exists(hdr_resolution_filepath):
-            reduced_filesize = os.path.getsize(hdr_resolution_filepath)
-
-        # compare file sizes
-        print(f'HDR size was reduced from {original_filesize} to {reduced_filesize}')
-        if reduced_filesize < original_filesize:
-            # this limits from uploaidng especially same-as-original resolution files in case when there is no advantage.
-            # usually however the advantage can be big also for same as original resolution
-            files.append({
-                "type": p2res,
-                "index": 0,
-                "file_path": hdr_resolution_filepath
-            })
-
-            print('prepared resolution file: ', p2res)
-
-        if rkeys.index(p2res) == 0:
-            finished = True
-        else:
-            p2res = rkeys[rkeys.index(p2res) - 1]
-        i+=1
-
-    print('uploading resolution files')
-    upload_resolutions(files, asset_data)
-
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    patch_asset_empty(asset_data['id'], preferences.api_key)
-
-
-def generate_lower_resolutions(data):
-    asset_data = data['asset_data']
-    actres = get_current_resolution()
-    # first let's skip procedural assets
-    base_fpath = bpy.data.filepath
-
-    s = bpy.context.scene
-
-    print('current resolution of the asset ', actres)
-    if actres > 0:
-        p2res = paths.round_to_closest_resolution(actres)
-        orig_res = p2res
-        print(p2res)
-        finished = False
-        files = []
-        # now skip assets that have lowest possible resolution already
-        if p2res != [0]:
-            original_textures_filesize = 0
-            for i in bpy.data.images:
-                abspath = bpy.path.abspath(i.filepath)
-                if os.path.exists(abspath):
-                    original_textures_filesize += os.path.getsize(abspath)
-
-            while not finished:
-
-                blend_file_name = os.path.basename(base_fpath)
-
-                dirn = os.path.dirname(base_fpath)
-                fn_strip, ext = os.path.splitext(blend_file_name)
-
-                fn = fn_strip + paths.resolution_suffix[p2res] + ext
-                fpath = os.path.join(dirn, fn)
-
-                tex_dir_path = paths.get_texture_directory(asset_data, resolution=p2res)
-
-                tex_dir_abs = bpy.path.abspath(tex_dir_path)
-                if not os.path.exists(tex_dir_abs):
-                    os.mkdir(tex_dir_abs)
-
-                reduced_textures_filessize = 0
-                for i in bpy.data.images:
-                    if i.name != 'Render Result':
-
-                        print('scaling ', i.name, i.size[0], i.size[1])
-                        fp = get_texture_filepath(tex_dir_path, i, resolution=p2res)
-
-                        if p2res == orig_res:
-                            # first, let's link the image back to the original one.
-                            i['blenderkit_original_path'] = i.filepath
-                            # first round also makes reductions on the image, while keeping resolution
-                            image_utils.make_possible_reductions_on_image(i, fp, do_reductions=True, do_downscale=False)
-
-                        else:
-                            # lower resolutions only downscale
-                            image_utils.make_possible_reductions_on_image(i, fp, do_reductions=False, do_downscale=True)
-
-                        abspath = bpy.path.abspath(i.filepath)
-                        if os.path.exists(abspath):
-                            reduced_textures_filessize += os.path.getsize(abspath)
-
-                        i.pack()
-                # save
-                print(fpath)
-                # if this isn't here, blender crashes.
-                bpy.context.preferences.filepaths.file_preview_type = 'NONE'
-
-                # save the file
-                bpy.ops.wm.save_as_mainfile(filepath=fpath, compress=True, copy=True)
-                # compare file sizes
-                print(f'textures size was reduced from {original_textures_filesize} to {reduced_textures_filessize}')
-                if reduced_textures_filessize < original_textures_filesize:
-                    # this limits from uploaidng especially same-as-original resolution files in case when there is no advantage.
-                    # usually however the advantage can be big also for same as original resolution
-                    files.append({
-                        "type": p2res,
-                        "index": 0,
-                        "file_path": fpath
-                    })
-
-                print('prepared resolution file: ', p2res)
-                if rkeys.index(p2res) == 0:
-                    finished = True
-                else:
-                    p2res = rkeys[rkeys.index(p2res) - 1]
-            print('uploading resolution files')
-            upload_resolutions(files, data['asset_data'])
-            preferences = bpy.context.preferences.addons['blenderkit'].preferences
-            patch_asset_empty(data['asset_data']['id'], preferences.api_key)
-        return
-
-
-def regenerate_thumbnail_material(data):
-    # this should re-generate material thumbnail and re-upload it.
-    # first let's skip procedural assets
-    base_fpath = bpy.data.filepath
-    blend_file_name = os.path.basename(base_fpath)
-    bpy.ops.mesh.primitive_cube_add()
-    aob = bpy.context.active_object
-    bpy.ops.object.material_slot_add()
-    aob.material_slots[0].material = bpy.data.materials[0]
-    props = aob.active_material.blenderkit
-    props.thumbnail_generator_type = 'BALL'
-    props.thumbnail_background = False
-    props.thumbnail_resolution = '256'
-    # layout.prop(props, 'thumbnail_generator_type')
-    # layout.prop(props, 'thumbnail_scale')
-    # layout.prop(props, 'thumbnail_background')
-    # if props.thumbnail_background:
-    #     layout.prop(props, 'thumbnail_background_lightness')
-    # layout.prop(props, 'thumbnail_resolution')
-    # layout.prop(props, 'thumbnail_samples')
-    # layout.prop(props, 'thumbnail_denoising')
-    # layout.prop(props, 'adaptive_subdivision')
-    # preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    # layout.prop(preferences, "thumbnail_use_gpu")
-    # TODO: here it should call start_material_thumbnailer , but with the wait property on, so it can upload afterwards.
-    bpy.ops.object.blenderkit_generate_material_thumbnail()
-    time.sleep(130)
-    # save
-    # this does the actual job
-
-    return
-
-
-def assets_db_path():
-    dpath = os.path.dirname(bpy.data.filepath)
-    fpath = os.path.join(dpath, 'all_assets.json')
-    return fpath
-
-
-def get_assets_search():
-    # bpy.app.debug_value = 2
-
-    results = []
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    url = paths.get_api_url() + 'search/all'
-    i = 0
-    while url is not None:
-        headers = utils.get_headers(preferences.api_key)
-        print('fetching assets from assets endpoint')
-        print(url)
-        retries = 0
-        while retries < 3:
-            r = rerequests.get(url, headers=headers)
-
-            try:
-                adata = r.json()
-                url = adata.get('next')
-                print(i)
-                i += 1
-            except Exception as e:
-                print(e)
-                print('failed to get next')
-                if retries == 2:
-                    url = None
-            if adata.get('results') != None:
-                results.extend(adata['results'])
-                retries = 3
-            print(f'fetched page {i}')
-            retries += 1
-
-    fpath = assets_db_path()
-    with open(fpath, 'w', encoding = 'utf-8') as s:
-        json.dump(results, s, ensure_ascii=False, indent=4)
-
-
-def get_assets_for_resolutions(page_size=100, max_results=100000000):
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-    dpath = os.path.dirname(bpy.data.filepath)
-    filepath = os.path.join(dpath, 'assets_for_resolutions.json')
-    params = {
-        'order': '-created',
-        'textureResolutionMax_gte': '100',
-        #    'last_resolution_upload_lt':'2020-9-01'
-    }
-    search.get_search_simple(params, filepath=filepath, page_size=page_size, max_results=max_results,
-                             api_key=preferences.api_key)
-    return filepath
-
-
-def get_materials_for_validation(page_size=100, max_results=100000000):
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    dpath = os.path.dirname(bpy.data.filepath)
-    filepath = os.path.join(dpath, 'materials_for_validation.json')
-    params = {
-        'order': '-created',
-        'asset_type': 'material',
-        'verification_status': 'uploaded'
-    }
-    search.get_search_simple(params, filepath=filepath, page_size=page_size, max_results=max_results,
-                             api_key=preferences.api_key)
-    return filepath
-
-
-
-
-def load_assets_list(filepath):
-    if os.path.exists(filepath):
-        with open(filepath, 'r', encoding='utf-8') as s:
-            assets = json.load(s)
-    return assets
-
-
-def check_needs_resolutions(a):
-    if a['verificationStatus'] == 'validated' and a['assetType'] in ('material', 'model', 'scene', 'hdr'):
-        # the search itself now picks the right assets so there's no need to filter more than asset types.
-        # TODO needs to check first if the upload date is older than resolution upload date, for that we need resolution upload date.
-        for f in a['files']:
-            if f['fileType'].find('resolution') > -1:
-                return False
-
-        return True
-    return False
-
-
-def download_asset(asset_data, resolution='blend', unpack=False, api_key=''):
-    '''
-    Download an asset non-threaded way.
-    Parameters
-    ----------
-    asset_data - search result from elastic or assets endpoints from API
-
-    Returns
-    -------
-    path to the resulting asset file or None if asset isn't accessible
-    '''
-
-    has_url = download.get_download_url(asset_data, download.get_scene_id(), api_key, tcom=None,
-                                        resolution='blend')
-    if has_url:
-        fpath = download.download_asset_file(asset_data, api_key = api_key)
-        if fpath and unpack and asset_data['assetType'] != 'hdr':
-            send_to_bg(asset_data, fpath, command='unpack', wait=True)
-        return fpath
-
-    return None
-
-
-def generate_resolution_thread(asset_data, api_key):
-    '''
-    A thread that downloads file and only then starts an instance of Blender that generates the resolution
-    Parameters
-    ----------
-    asset_data
-
-    Returns
-    -------
-
-    '''
-
-    fpath = download_asset(asset_data, unpack=True, api_key=api_key)
-
-    if fpath:
-        if asset_data['assetType'] != 'hdr':
-            print('send to bg ', fpath)
-            proc = send_to_bg(asset_data, fpath, command='generate_resolutions', wait=True);
-        else:
-            generate_lower_resolutions_hdr(asset_data, fpath)
-        # send_to_bg by now waits for end of the process.
-        # time.sleep((5))
-
-
-def iterate_for_resolutions(filepath, process_count=12, api_key='', do_checks = True):
-    ''' iterate through all assigned assets, check for those which need generation and send them to res gen'''
-    assets = load_assets_list(filepath)
-    print(len(assets))
-    threads = []
-    for asset_data in assets:
-        asset_data = search.parse_result(asset_data)
-        if asset_data is not None:
-
-            if not do_checks or check_needs_resolutions(asset_data):
-                print('downloading and generating resolution for  %s' % asset_data['name'])
-                # this is just a quick hack for not using original dirs in blendrkit...
-                generate_resolution_thread(asset_data, api_key)
-                # thread = threading.Thread(target=generate_resolution_thread, args=(asset_data, api_key))
-                # thread.start()
-                #
-                # threads.append(thread)
-                # print('processes ', len(threads))
-                # while len(threads) > process_count - 1:
-                #     for t in threads:
-                #         if not t.is_alive():
-                #             threads.remove(t)
-                #         break;
-                # else:
-                #     print(f'Failed to generate resolution:{asset_data["name"]}')
-            else:
-                print('not generated resolutions:', asset_data['name'])
-
-
-def send_to_bg(asset_data, fpath, command='generate_resolutions', wait=True):
-    '''
-    Send varioust task to a new blender instance that runs and closes after finishing the task.
-    This function waits until the process finishes.
-    The function tries to set the same bpy.app.debug_value in the instance of Blender that is run.
-    Parameters
-    ----------
-    asset_data
-    fpath - file that will be processed
-    command - command which should be run in background.
-
-    Returns
-    -------
-    None
-    '''
-    data = {
-        'fpath': fpath,
-        'debug_value': bpy.app.debug_value,
-        'asset_data': asset_data,
-        'command': command,
-    }
-    binary_path = bpy.app.binary_path
-    tempdir = tempfile.mkdtemp()
-    datafile = os.path.join(tempdir + 'resdata.json')
-    script_path = os.path.dirname(os.path.realpath(__file__))
-    with open(datafile, 'w', encoding = 'utf-8') as s:
-        json.dump(data, s,  ensure_ascii=False, indent=4)
-
-    print('opening Blender instance to do processing - ', command)
-
-    if wait:
-        proc = subprocess.run([
-            binary_path,
-            "--background",
-            "-noaudio",
-            fpath,
-            "--python", os.path.join(script_path, "resolutions_bg.py"),
-            "--", datafile
-        ], bufsize=1, stdout=sys.stdout, stdin=subprocess.PIPE, creationflags=utils.get_process_flags())
-
-    else:
-        # TODO this should be fixed to allow multithreading.
-        proc = subprocess.Popen([
-            binary_path,
-            "--background",
-            "-noaudio",
-            fpath,
-            "--python", os.path.join(script_path, "resolutions_bg.py"),
-            "--", datafile
-        ], bufsize=1, stdout=subprocess.PIPE, stdin=subprocess.PIPE, creationflags=utils.get_process_flags())
-        return proc
-
-
-def write_data_back(asset_data):
-    '''ensures that the data in the resolution file is the same as in the database.'''
-    pass;
-
-
-def run_bg(datafile):
-    print('background file operation')
-    with open(datafile, 'r',encoding='utf-8') as f:
-        data = json.load(f)
-    bpy.app.debug_value = data['debug_value']
-    write_data_back(data['asset_data'])
-    if data['command'] == 'generate_resolutions':
-        generate_lower_resolutions(data)
-    elif data['command'] == 'unpack':
-        unpack_asset(data)
-    elif data['command'] == 'regen_thumbnail':
-        regenerate_thumbnail_material(data)
-
-# load_assets_list()
-# generate_lower_resolutions()
-# class TestOperator(bpy.types.Operator):
-#     """Tooltip"""
-#     bl_idname = "object.test_anything"
-#     bl_label = "Test Operator"
-#
-#     @classmethod
-#     def poll(cls, context):
-#         return True
-#
-#     def execute(self, context):
-#         iterate_for_resolutions()
-#         return {'FINISHED'}
-#
-#
-# def register():
-#     bpy.utils.register_class(TestOperator)
-#
-#
-# def unregister():
-#     bpy.utils.unregister_class(TestOperator)
diff --git a/blenderkit/resolutions_bg.py b/blenderkit/resolutions_bg.py
deleted file mode 100644
index c59ca08d5d1961d83b5178ef564cb46342fa3686..0000000000000000000000000000000000000000
--- a/blenderkit/resolutions_bg.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import sys
-import json
-from blenderkit import resolutions
-
-BLENDERKIT_EXPORT_DATA = sys.argv[-1]
-
-if __name__ == "__main__":
-    resolutions.run_bg(sys.argv[-1])
diff --git a/blenderkit/search.py b/blenderkit/search.py
deleted file mode 100644
index cf5068f42d515feedea5de46895842104c4dffe2..0000000000000000000000000000000000000000
--- a/blenderkit/search.py
+++ /dev/null
@@ -1,1685 +0,0 @@
-# ##### 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 #####
-
-from blenderkit import paths, utils, categories, ui, colors, bkit_oauth, version_checker, tasks_queue, rerequests, \
-    resolutions, image_utils, ratings_utils, comments_utils, reports
-
-import blenderkit
-from bpy.app.handlers import persistent
-
-from bpy.props import (  # TODO only keep the ones actually used when cleaning
-    IntProperty,
-    FloatProperty,
-    FloatVectorProperty,
-    StringProperty,
-    EnumProperty,
-    BoolProperty,
-    PointerProperty,
-)
-from bpy.types import (
-    Operator,
-    Panel,
-    AddonPreferences,
-    PropertyGroup,
-    UIList
-)
-
-import requests, os, random
-import time
-import threading
-import platform
-import bpy
-import copy
-import json
-import math
-import unicodedata
-import urllib
-import queue
-import logging
-
-bk_logger = logging.getLogger('blenderkit')
-
-search_start_time = 0
-prev_time = 0
-
-
-def check_errors(rdata):
-    if rdata.get('statusCode') and int(rdata.get('statusCode')) > 299:
-        utils.p(rdata)
-        if rdata.get('detail') == 'Invalid token.':
-            user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-            if user_preferences.api_key != '':
-                if user_preferences.enable_oauth:
-                    bkit_oauth.refresh_token_thread()
-                return False, rdata.get('detail')
-            return False, 'Use login panel to connect your profile.'
-        else:
-            return False, rdata.get('detail')
-    if rdata.get('statusCode') is None and rdata.get('results') is None:
-        return False, 'Connection error'
-    return True, ''
-
-
-search_threads = []
-thumb_workers_sml = []
-thumb_workers_full = []
-thumb_sml_download_threads = queue.Queue()
-thumb_full_download_threads = queue.Queue()
-reports_queue = queue.Queue()
-all_thumbs_loaded = True
-
-rtips_string = """YYou can disable tips in the add-on preferences.
-Ratings help us distribute funds to creators.
-Creators also gain credits for free assets from subscribers.
-Click or drag model or material in scene to link/append 
-Right click in the asset bar for more options
-Use Append in import settings if you want to edit downloaded objects. 
-Please rate responsively and plentifully. This helps us distribute rewards to the authors.
-All materials are free.
-Storage for public assets is unlimited.
-Locked models are available if you subscribe to Full plan.
-Login to upload your own models, materials or brushes.
-Use 'A' key over the asset bar to search assets by the same author.
-Use semicolon - ; to hide or show the AssetBar.
-Support the authors by subscribing to Full plan.
-Use the W key over the asset bar to open the Author's webpage.
-Use the R key for fast rating of assets.
-Use the X key to delete the asset from your hard drive.
-"""
-rtips = rtips_string.splitlines()
-
-
-def refresh_token_timer():
-    ''' this timer gets run every time the token needs refresh. It refreshes tokens and also categories.'''
-    utils.p('refresh timer')
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    fetch_server_data()
-    categories.load_categories()
-
-    return max(3600, user_preferences.api_key_life - 3600)
-
-
-def refresh_notifications_timer():
-    ''' this timer gets notifications.'''
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    fetch_server_data()
-    all_notifications_count = comments_utils.count_all_notifications()
-    comments_utils.get_notifications_thread(preferences.api_key, all_count = all_notifications_count)
-    return 7200
-
-
-def update_ad(ad):
-    if not ad.get('assetBaseId'):
-        try:
-            ad['assetBaseId'] = ad['asset_base_id']  # this should stay ONLY for compatibility with older scenes
-            ad['assetType'] = ad['asset_type']  # this should stay ONLY for compatibility with older scenes
-            ad['verificationStatus'] = ad[
-                'verification_status']  # this should stay ONLY for compatibility with older scenes
-            ad['author'] = {}
-            ad['author']['id'] = ad['author_id']  # this should stay ONLY for compatibility with older scenes
-            ad['canDownload'] = ad['can_download']  # this should stay ONLY for compatibility with older scenes
-        except Exception as e:
-            bk_logger.error('BlenderKit failed to update older asset data')
-    return ad
-
-
-def update_assets_data():  # updates assets data on scene load.
-    '''updates some properties that were changed on scenes with older assets.
-    The properties were mainly changed from snake_case to CamelCase to fit the data that is coming from the server.
-    '''
-    data = bpy.data
-
-    datablocks = [
-        bpy.data.objects,
-        bpy.data.materials,
-        bpy.data.brushes,
-    ]
-    for dtype in datablocks:
-        for block in dtype:
-            if block.get('asset_data') != None:
-                update_ad(block['asset_data'])
-
-    dicts = [
-        'assets used',
-        # 'assets rated',# assets rated stores only true/false, not asset data.
-    ]
-    for s in bpy.data.scenes:
-        for bkdict in dicts:
-
-            d = s.get(bkdict)
-            if not d:
-                continue;
-
-            for asset_id in d.keys():
-                update_ad(d[asset_id])
-                # bpy.context.scene['assets used'][ad] = ad
-
-
-def purge_search_results():
-    ''' clean up search results on save/load.'''
-
-    s = bpy.context.scene
-
-    sr_props = [
-        'search results',
-        'search results orig',
-    ]
-    asset_types = ['model', 'material', 'scene', 'hdr', 'brush']
-    for at in asset_types:
-        sr_props.append('bkit {at} search')
-        sr_props.append('bkit {at} search orig')
-    for sr_prop in sr_props:
-        if s.get(sr_prop):
-            del (s[sr_prop])
-
-
-@persistent
-def scene_load(context):
-    '''
-    Loads categories , checks timers registration, and updates scene asset data.
-    Should (probably)also update asset data from server (after user consent)
-    '''
-    wm = bpy.context.window_manager
-    purge_search_results()
-    fetch_server_data()
-    categories.load_categories()
-    if not bpy.app.timers.is_registered(refresh_token_timer) and not bpy.app.background:
-        bpy.app.timers.register(refresh_token_timer, persistent=True, first_interval=36000)
-    # if utils.experimental_enabled() and not bpy.app.timers.is_registered(
-    #         refresh_notifications_timer) and not bpy.app.background:
-    #     bpy.app.timers.register(refresh_notifications_timer, persistent=True, first_interval=5)
-
-    update_assets_data()
-
-
-def fetch_server_data():
-    ''' download categories , profile, and refresh token if needed.'''
-    if not bpy.app.background:
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        api_key = user_preferences.api_key
-        # Only refresh new type of tokens(by length), and only one hour before the token timeouts.
-        if user_preferences.enable_oauth and \
-                len(user_preferences.api_key) < 38 and len(user_preferences.api_key) > 0 and \
-                user_preferences.api_key_timeout < time.time() + 3600:
-            bkit_oauth.refresh_token_thread()
-        if api_key != '' and bpy.context.window_manager.get('bkit profile') == None:
-            get_profile()
-        if bpy.context.window_manager.get('bkit_categories') is None:
-            categories.fetch_categories_thread(api_key, force=False)
-        # all_notifications_count = comments_utils.count_all_notifications()
-        # comments_utils.get_notifications_thread(api_key, all_count = all_notifications_count)
-
-first_time = True
-first_search_parsing = True
-last_clipboard = ''
-
-
-def check_clipboard():
-    '''
-    Checks clipboard for an exact string containing asset ID.
-    The string is generated on www.blenderkit.com as for example here:
-    https://www.blenderkit.com/get-blenderkit/54ff5c85-2c73-49e9-ba80-aec18616a408/
-    '''
-
-    # clipboard monitoring to search assets from web
-    if platform.system() != 'Linux':
-        global last_clipboard
-        if bpy.context.window_manager.clipboard != last_clipboard:
-            last_clipboard = bpy.context.window_manager.clipboard
-            instr = 'asset_base_id:'
-            # first check if contains asset id, then asset type
-            if last_clipboard[:len(instr)] == instr:
-                atstr = 'asset_type:'
-                ati = last_clipboard.find(atstr)
-                # this only checks if the asset_type keyword is there but let's the keywords update function do the parsing.
-                if ati > -1:
-                    search_props = utils.get_search_props()
-                    search_props.search_keywords = last_clipboard
-                    # don't run search after this - assigning to keywords runs the search_update function.
-
-
-def parse_result(r):
-    '''
-    needed to generate some extra data in the result(by now)
-    Parameters
-    ----------
-    r - search result, also called asset_data
-    '''
-    scene = bpy.context.scene
-
-    # TODO remove this fix when filesSize is fixed.
-    # this is a temporary fix for too big numbers from the server.
-    # try:
-    #     r['filesSize'] = int(r['filesSize'] / 1024)
-    # except:
-    #     utils.p('asset with no files-size')
-    asset_type = r['assetType']
-    if len(r['files']) > 0:  # TODO remove this condition so all assets are parsed.
-        get_author(r)
-
-        r['available_resolutions'] = []
-        allthumbs = []
-        durl, tname, small_tname = '', '', ''
-
-        if r['assetType'] == 'hdr':
-            tname = paths.extract_filename_from_url(r['thumbnailLargeUrlNonsquared'])
-        else:
-            tname = paths.extract_filename_from_url(r['thumbnailMiddleUrl'])
-        small_tname = paths.extract_filename_from_url(r['thumbnailSmallUrl'])
-        allthumbs.append(tname)  # TODO just first thumb is used now.
-        # if r['fileType'] == 'thumbnail':
-        #     tname = paths.extract_filename_from_url(f['fileThumbnailLarge'])
-        #     small_tname = paths.extract_filename_from_url(f['fileThumbnail'])
-        #     allthumbs.append(tname)  # TODO just first thumb is used now.
-
-        for f in r['files']:
-            # if f['fileType'] == 'thumbnail':
-            #     tname = paths.extract_filename_from_url(f['fileThumbnailLarge'])
-            #     small_tname = paths.extract_filename_from_url(f['fileThumbnail'])
-            #     allthumbs.append(tname)  # TODO just first thumb is used now.
-
-            if f['fileType'] == 'blend':
-                durl = f['downloadUrl'].split('?')[0]
-                # fname = paths.extract_filename_from_url(f['filePath'])
-
-            if f['fileType'].find('resolution') > -1:
-                r['available_resolutions'].append(resolutions.resolutions[f['fileType']])
-
-        # code for more thumbnails
-        # tdict = {}
-        # for i, t in enumerate(allthumbs):
-        #     tdict['thumbnail_%i'] = t
-
-        r['max_resolution'] = 0
-        if r['available_resolutions']:  # should check only for non-empty sequences
-            r['max_resolution'] = max(r['available_resolutions'])
-
-        # tooltip = generate_tooltip(r)
-        # for some reason, the id was still int on some occurances. investigate this.
-        r['author']['id'] = str(r['author']['id'])
-
-        # some helper props, but generally shouldn't be renaming/duplifiying original properties,
-        # so blender's data is same as on server.
-        asset_data = {'thumbnail': tname,
-                      'thumbnail_small': small_tname,
-                      # 'tooltip': tooltip,
-
-                      }
-        asset_data['downloaded'] = 0
-
-        # parse extra params needed for blender here
-        params = r['dictParameters']  # utils.params_to_dict(r['parameters'])
-
-        if asset_type == 'model':
-            if params.get('boundBoxMinX') != None:
-                bbox = {
-                    'bbox_min': (
-                        float(params['boundBoxMinX']),
-                        float(params['boundBoxMinY']),
-                        float(params['boundBoxMinZ'])),
-                    'bbox_max': (
-                        float(params['boundBoxMaxX']),
-                        float(params['boundBoxMaxY']),
-                        float(params['boundBoxMaxZ']))
-                }
-
-            else:
-                bbox = {
-                    'bbox_min': (-.5, -.5, 0),
-                    'bbox_max': (.5, .5, 1)
-                }
-            asset_data.update(bbox)
-        if asset_type == 'material':
-            asset_data['texture_size_meters'] = params.get('textureSizeMeters', 1.0)
-
-        # asset_data.update(tdict)
-
-        au = scene.get('assets used', {})
-        if au == {}:
-            scene['assets used'] = au
-        if r['assetBaseId'] in au.keys():
-            asset_data['downloaded'] = 100
-            # transcribe all urls already fetched from the server
-            r_previous = au[r['assetBaseId']]
-            if r_previous.get('files'):
-                for f in r_previous['files']:
-                    if f.get('url'):
-                        for f1 in r['files']:
-                            if f1['fileType'] == f['fileType']:
-                                f1['url'] = f['url']
-
-        # attempt to switch to use original data gradually, since the parsing as itself should become obsolete.
-        asset_data.update(r)
-        return asset_data
-
-
-# @bpy.app.handlers.persistent
-def search_timer():
-    # this makes a first search after opening blender. showing latest assets.
-    # utils.p('timer search')
-    # utils.p('start search timer')
-    global first_time
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if first_time and not bpy.app.background:  # first time
-
-        first_time = False
-        if preferences.show_on_start:
-            # TODO here it should check if there are some results, and only open assetbar if this is the case, not search.
-            # if bpy.context.window_manager.get('search results') is None:
-            search()
-            # preferences.first_run = False
-        if preferences.tips_on_start:
-            utils.get_largest_area()
-            ui.update_ui_size(ui.active_area_pointer, ui.active_region_pointer)
-            reports.add_report(text='BlenderKit Tip: ' + random.choice(rtips), timeout=12, color=colors.GREEN)
-        # utils.p('end search timer')
-
-        return 3.0
-
-    # if preferences.first_run:
-    #     search()
-    #     preferences.first_run = False
-
-    # check_clipboard()
-
-    # finish loading thumbs from queues
-    global all_thumbs_loaded
-    if not all_thumbs_loaded:
-        ui_props = bpy.context.window_manager.blenderkitUI
-        search_name = f'bkit {ui_props.asset_type.lower()} search'
-        wm = bpy.context.window_manager
-        if wm.get(search_name) is not None:
-            all_loaded = True
-            for ri, r in enumerate(wm[search_name]):
-                if not r.get('thumb_small_loaded'):
-                    preview_loaded = load_preview(r, ri)
-                    all_loaded = all_loaded and preview_loaded
-
-            all_thumbs_loaded = all_loaded
-
-    global search_threads, first_search_parsing
-    if len(search_threads) == 0:
-        # utils.p('end search timer')
-        props = utils.get_search_props()
-        props.is_searching = False
-        return 1.0
-    # don't do anything while dragging - this could switch asset during drag, and make results list length different,
-    # causing a lot of throuble.
-    if bpy.context.window_manager.blenderkitUI.dragging:
-        # utils.p('end search timer')
-
-        return 0.5
-
-    for thread in search_threads:
-        # TODO this doesn't check all processes when one gets removed,
-        # but most of the time only one is running anyway
-        if not thread[0].is_alive():
-
-            #check for notifications only for users that actually use the add-on
-            if first_search_parsing:
-                first_search_parsing = False
-                all_notifications_count = comments_utils.count_all_notifications()
-                comments_utils.get_notifications_thread(preferences.api_key, all_count=all_notifications_count)
-                if utils.experimental_enabled() and not bpy.app.timers.is_registered(
-                        refresh_notifications_timer) and not bpy.app.background:
-                    bpy.app.timers.register(refresh_notifications_timer, persistent=True, first_interval=5)
-
-            search_threads.remove(thread)  #
-            icons_dir = thread[1]
-            scene = bpy.context.scene
-            # these 2 lines should update the previews enum and set the first result as active.
-            wm = bpy.context.window_manager
-            asset_type = thread[2]
-
-            props = utils.get_search_props()
-            search_name = f'bkit {asset_type} search'
-
-            if not thread[0].params.get('get_next'):
-                # wm[search_name] = []
-                result_field = []
-            else:
-                result_field = []
-                for r in wm[search_name]:
-                    result_field.append(r.to_dict())
-
-            global reports_queue
-
-            while not reports_queue.empty():
-                props.report = str(reports_queue.get())
-                # utils.p('end search timer')
-
-                return .2
-
-            rdata = thread[0].result
-
-            ok, error = check_errors(rdata)
-            if ok:
-                ui_props = bpy.context.window_manager.blenderkitUI
-                orig_len = len(result_field)
-
-                for ri, r in enumerate(rdata['results']):
-                    asset_data = parse_result(r)
-                    if asset_data != None:
-                        result_field.append(asset_data)
-                        all_thumbs_loaded = all_thumbs_loaded and load_preview(asset_data, ri + orig_len)
-
-                # Get ratings from BlenderKit server
-                user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-                api_key = user_preferences.api_key
-                headers = utils.get_headers(api_key)
-                if utils.profile_is_validator():
-                    for r in rdata['results']:
-                        if ratings_utils.get_rating_local(r['id']) is None:
-                            rating_thread = threading.Thread(target=ratings_utils.get_rating, args=([r['id'], headers]),
-                                                             daemon=True)
-                            rating_thread.start()
-
-                wm[search_name] = result_field
-                wm['search results'] = result_field
-
-                # rdata=['results']=[]
-                wm[search_name + ' orig'] = rdata
-                wm['search results orig'] = rdata
-
-                if len(result_field) < ui_props.scroll_offset or not (thread[0].params.get('get_next')):
-                    # jump back
-                    ui_props.scroll_offset = 0
-                props.search_error = False
-                props.report = f"Found {wm['search results orig']['count']} results."
-                if len(wm['search results']) == 0:
-                    tasks_queue.add_task((reports.add_report, ('No matching results found.',)))
-                else:
-                    tasks_queue.add_task((reports.add_report, (f"Found {wm['search results orig']['count']} results.",)))
-                # undo push
-                # bpy.ops.wm.undo_push_context(message='Get BlenderKit search')
-                # show asset bar automatically, but only on first page - others are loaded also when asset bar is hidden.
-                if not ui_props.assetbar_on and not thread[0].params.get('get_next'):
-                    bpy.ops.object.run_assetbar_fix_context()
-
-            else:
-                bk_logger.error(error)
-                props.report = error
-                props.search_error = True
-
-            props.is_searching = False
-            # print('finished search thread')
-            mt('preview loading finished')
-    # utils.p('end search timer')
-    if not all_thumbs_loaded:
-        return .1
-    return .3
-
-
-def load_preview(asset, index):
-    # FIRST START SEARCH
-    props = bpy.context.window_manager.blenderkitUI
-    directory = paths.get_temp_dir('%s_search' % props.asset_type.lower())
-
-    tpath = os.path.join(directory, asset['thumbnail_small'])
-    if not asset['thumbnail_small'] or asset['thumbnail_small'] == '' or not os.path.exists(tpath):
-        # tpath = paths.get_addon_thumbnail_path('thumbnail_notready.jpg')
-        asset['thumb_small_loaded'] = False
-
-    iname = utils.previmg_name(index)
-
-    # if os.path.exists(tpath):  # sometimes we are unlucky...
-    img = bpy.data.images.get(iname)
-
-    if img is None or len(img.pixels) == 0:
-        if not os.path.exists(tpath):
-            return False
-        # wrap into try statement since sometimes
-        try:
-            img = bpy.data.images.load(tpath)
-
-            img.name = iname
-            if len(img.pixels)>0:
-                return True
-        except:
-            pass
-        return False
-    elif img.filepath != tpath:
-        if not os.path.exists(tpath):
-            # unload loaded previews from previous results
-            bpy.data.images.remove(img)
-            return False
-        # had to add this check for autopacking files...
-        if bpy.data.use_autopack and img.packed_file is not None:
-            img.unpack(method='USE_ORIGINAL')
-        img.filepath = tpath
-        try:
-            img.reload()
-        except:
-            return False
-
-    if asset['assetType'] == 'hdr':
-        # to display hdr thumbnails correctly, we use non-color, otherwise looks shifted
-        image_utils.set_colorspace(img, 'Non-Color')
-    else:
-        image_utils.set_colorspace(img, 'sRGB')
-    asset['thumb_small_loaded'] = True
-    return True
-
-
-def load_previews():
-    scene = bpy.context.scene
-    # FIRST START SEARCH
-    props = bpy.context.window_manager.blenderkitUI
-    directory = paths.get_temp_dir('%s_search' % props.asset_type.lower())
-    s = bpy.context.scene
-    results = bpy.context.window_manager.get('search results')
-    #
-    if results is not None:
-        i = 0
-        for r in results:
-            load_preview(r, i)
-            i += 1
-
-
-#  line splitting for longer texts...
-def split_subs(text, threshold=40):
-    if text == '':
-        return []
-    # temporarily disable this, to be able to do this in drawing code
-
-    text = text.rstrip()
-    text = text.replace('\r\n', '\n')
-
-    lines = []
-
-    while len(text) > threshold:
-        # first handle if there's an \n line ending
-        i_rn = text.find('\n')
-        if 1 < i_rn < threshold:
-            i = i_rn
-            text = text.replace('\n', '', 1)
-        else:
-            i = text.rfind(' ', 0, threshold)
-            i1 = text.rfind(',', 0, threshold)
-            i2 = text.rfind('.', 0, threshold)
-            i = max(i, i1, i2)
-            if i <= 0:
-                i = threshold
-        lines.append(text[:i])
-        text = text[i:]
-    lines.append(text)
-    return lines
-
-
-def list_to_str(input):
-    output = ''
-    for i, text in enumerate(input):
-        output += text
-        if i < len(input) - 1:
-            output += ', '
-    return output
-
-
-def writeblock(t, input, width=40):  # for longer texts
-    dlines = split_subs(input, threshold=width)
-    for i, l in enumerate(dlines):
-        t += '%s\n' % l
-    return t
-
-
-def writeblockm(tooltip, mdata, key='', pretext=None, width=40):  # for longer texts
-    if mdata.get(key) == None:
-        return tooltip
-    else:
-        intext = mdata[key]
-        if type(intext) == list:
-            intext = list_to_str(intext)
-        if type(intext) == float:
-            intext = round(intext, 3)
-        intext = str(intext)
-        if intext.rstrip() == '':
-            return tooltip
-        if pretext == None:
-            pretext = key
-        if pretext != '':
-            pretext = pretext + ': '
-        text = pretext + intext
-        dlines = split_subs(text, threshold=width)
-        for i, l in enumerate(dlines):
-            tooltip += '%s\n' % l
-
-    return tooltip
-
-
-def has(mdata, prop):
-    if mdata.get(prop) is not None and mdata[prop] is not None and mdata[prop] is not False:
-        return True
-    else:
-        return False
-
-
-def generate_tooltip(mdata):
-    col_w = 40
-    if type(mdata['parameters']) == list:
-        mparams = utils.params_to_dict(mdata['parameters'])
-    else:
-        mparams = mdata['parameters']
-    t = ''
-    t = writeblock(t, mdata['displayName'], width=int(col_w * .6))
-    # t += '\n'
-
-    # t = writeblockm(t, mdata, key='description', pretext='', width=col_w)
-    return t
-
-
-def get_random_tip():
-    t = ''
-    tip = 'Tip: ' + random.choice(rtips)
-    t = writeblock(t, tip)
-    return t
-
-
-def generate_author_textblock(adata):
-    t = ''
-
-    if adata not in (None, ''):
-        col_w = 2000
-        if len(adata['firstName'] + adata['lastName']) > 0:
-            t = '%s %s\n' % (adata['firstName'], adata['lastName'])
-            t += '\n'
-            if adata.get('aboutMe') is not None:
-                t = writeblockm(t, adata, key='aboutMe', pretext='', width=col_w)
-    return t
-
-
-def download_image(session, url, filepath):
-    r = None
-    try:
-        r = session.get(url, stream=False)
-    except Exception as e:
-        bk_logger.error('Thumbnail download failed')
-        bk_logger.error(str(e))
-    if r and r.status_code == 200:
-        with open(filepath, 'wb') as f:
-            f.write(r.content)
-
-
-def thumb_download_worker(queue_sml, queue_full):
-    # print('thumb downloader', self.url)
-    # utils.p('start thumbdownloader thread')
-    while 1:
-        session = None
-        # start a session only for single search usually, if users starts scrolling, the session might last longer if
-        # queue gets filled.
-        if not queue_sml.empty() or not queue_full.empty():
-            if session is None:
-                session = requests.Session()
-            while not queue_sml.empty():
-                # first empty the small thumbs queue
-                url, filepath = queue_sml.get()
-                download_image(session, url, filepath)
-            exit_full = False
-            # download full resolution image, but only if no small thumbs are waiting. If there are small
-            while not queue_full.empty() and queue_sml.empty():
-                url, filepath = queue_full.get()
-                download_image(session, url, filepath)
-
-        if queue_sml.empty() and queue_full.empty():
-            if session is not None:
-                session.close()
-                session = None
-            time.sleep(.5)
-
-
-def write_gravatar(a_id, gravatar_path):
-    '''
-    Write down gravatar path, as a result of thread-based gravatar image download.
-    This should happen on timer in queue.
-    '''
-    # print('write author', a_id, type(a_id))
-    authors = bpy.context.window_manager['bkit authors']
-    if authors.get(a_id) is not None:
-        adata = authors.get(a_id)
-        adata['gravatarImg'] = gravatar_path
-
-
-def fetch_gravatar(adata = None):
-
-    '''
-    Gets avatars from blenderkit server
-    Parameters
-    ----------
-    adata - author data from elastic search result
-
-    '''
-    # utils.p('fetch gravatar')
-    # print(adata)
-    # fetch new avatars if available already
-    if adata.get('avatar128') is not None:
-        avatar_path = paths.get_temp_dir(subdir='bkit_g/') + adata['id'] + '.jpg'
-        if os.path.exists(avatar_path):
-            tasks_queue.add_task((write_gravatar, (adata['id'], avatar_path)))
-            return;
-
-        url = paths.get_bkit_url() + adata['avatar128']
-        r = rerequests.get(url, stream=False)
-        # print(r.body)
-        if r.status_code == 200:
-            # print(url)
-            # print(r.headers['content-disposition'])
-            with open(avatar_path, 'wb') as f:
-                f.write(r.content)
-            tasks_queue.add_task((write_gravatar, (adata['id'], avatar_path)))
-        elif r.status_code == '404':
-            adata['avatar128'] = None
-            utils.p('avatar for author not available.')
-        return
-
-    # older gravatar code
-    if adata.get('gravatarHash') is not None:
-        gravatar_path = paths.get_temp_dir(subdir='bkit_g/') + adata['gravatarHash'] + '.jpg'
-
-        if os.path.exists(gravatar_path):
-            tasks_queue.add_task((write_gravatar, (adata['id'], gravatar_path)))
-            return;
-
-        url = "https://www.gravatar.com/avatar/" + adata['gravatarHash'] + '?d=404'
-        r = rerequests.get(url, stream=False)
-        if r.status_code == 200:
-            with open(gravatar_path, 'wb') as f:
-                f.write(r.content)
-            tasks_queue.add_task((write_gravatar, (adata['id'], gravatar_path)))
-        elif r.status_code == '404':
-            adata['gravatarHash'] = None
-            utils.p('gravatar for author not available.')
-
-
-fetching_gravatars = {}
-
-
-def get_author(r):
-    ''' Writes author info (now from search results) and fetches gravatar if needed.
-    this is now tweaked to be able to get authors from
-    '''
-    global fetching_gravatars
-
-    a_id = str(r['author']['id'])
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    authors = bpy.context.window_manager.get('bkit authors', {})
-    if authors == {}:
-        bpy.context.window_manager['bkit authors'] = authors
-    a = authors.get(a_id)
-    if a is None:  # or a is '' or (a.get('gravatarHash') is not None and a.get('gravatarImg') is None):
-        a = r['author']
-        a['id'] = a_id
-        a['tooltip'] = generate_author_textblock(a)
-
-        authors[a_id] = a
-        if fetching_gravatars.get(a['id']) is None:
-            fetching_gravatars[a['id']] = True
-
-        thread = threading.Thread(target=fetch_gravatar, args=(a.copy(),), daemon=True)
-        thread.start()
-    return a
-
-
-def write_profile(adata):
-    utils.p('writing profile information')
-    user = adata['user']
-    # we have to convert to MiB here, numbers too big for python int type
-    if user.get('sumAssetFilesSize') is not None:
-        user['sumAssetFilesSize'] /= (1024 * 1024)
-    if user.get('sumPrivateAssetFilesSize') is not None:
-        user['sumPrivateAssetFilesSize'] /= (1024 * 1024)
-    if user.get('remainingPrivateQuota') is not None:
-        user['remainingPrivateQuota'] /= (1024 * 1024)
-
-    if adata.get('canEditAllAssets') is True:
-        user['exmenu'] = True
-    else:
-        user['exmenu'] = False
-
-    bpy.context.window_manager['bkit profile'] = adata
-
-
-def request_profile(api_key):
-    a_url = paths.get_api_url() + 'me/'
-    headers = utils.get_headers(api_key)
-    r = rerequests.get(a_url, headers=headers)
-    adata = r.json()
-    if adata.get('user') is None:
-        utils.p(adata)
-        utils.p('getting profile failed')
-        return None
-    return adata
-
-
-def fetch_profile(api_key):
-    utils.p('fetch profile')
-    try:
-        adata = request_profile(api_key)
-        if adata is not None:
-            tasks_queue.add_task((write_profile, (adata,)))
-    except Exception as e:
-        bk_logger.error(e)
-
-
-def get_profile():
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    a = bpy.context.window_manager.get('bkit profile')
-    thread = threading.Thread(target=fetch_profile, args=(preferences.api_key,), daemon=True)
-    thread.start()
-
-    return a
-
-
-def query_to_url(query={}, params={}):
-    # build a new request
-    url = paths.get_api_url() + 'search/'
-
-    # build request manually
-    # TODO use real queries
-    requeststring = '?query='
-    #
-    if query.get('query') not in ('', None):
-        requeststring += query['query'].lower()
-    for i, q in enumerate(query):
-        if q != 'query':
-            requeststring += '+'
-            requeststring += q + ':' + str(query[q]).lower()
-
-    # add dict_parameters to make results smaller
-    # result ordering: _score - relevance, score - BlenderKit score
-    order = []
-    if params['free_first']:
-        order = ['-is_free', ]
-    if query.get('query') is None and query.get('category_subtree') == None:
-        # assumes no keywords and no category, thus an empty search that is triggered on start.
-        # orders by last core file upload
-        if query.get('verification_status') == 'uploaded':
-            # for validators, sort uploaded from oldest
-            order.append('created')
-        else:
-            order.append('-last_upload')
-    elif query.get('author_id') is not None and utils.profile_is_validator():
-
-        order.append('-created')
-    else:
-        if query.get('category_subtree') is not None:
-            order.append('-score,_score')
-        else:
-            order.append('_score')
-    if requeststring.find('+order:') == -1:
-        requeststring += '+order:' + ','.join(order)
-    requeststring += '&dict_parameters=1'
-
-    requeststring += '&page_size=' + str(params['page_size'])
-    requeststring += '&addon_version=%s' % params['addon_version']
-    if params.get('scene_uuid') is not None:
-        requeststring += '&scene_uuid=%s' % params['scene_uuid']
-    # print('params', params)
-    urlquery = url + requeststring
-    return urlquery
-
-
-def parse_html_formated_error(text):
-    report = text[text.find('<title>') + 7: text.find('</title>')]
-
-    return report
-
-
-class Searcher(threading.Thread):
-    query = None
-
-    def __init__(self, query, params, tempdir='', headers=None, urlquery=''):
-        super(Searcher, self).__init__()
-        self.query = query
-        self.params = params
-        self._stop_event = threading.Event()
-        self.result = {}
-        self.tempdir = tempdir
-        self.headers = headers
-        self.urlquery = urlquery
-
-    def stop(self):
-        self._stop_event.set()
-
-    def stopped(self):
-        return self._stop_event.is_set()
-
-    def run(self):
-        global reports_queue, thumb_sml_download_threads, thumb_full_download_threads
-
-        maxthreads = 50
-        query = self.query
-        params = self.params
-
-        t = time.time()
-        # utils.p('start search thread')
-
-        mt('search thread started')
-        # tempdir = paths.get_temp_dir('%s_search' % query['asset_type'])
-        # json_filepath = os.path.join(tempdir, '%s_searchresult.json' % query['asset_type'])
-
-        rdata = {}
-        rdata['results'] = []
-
-        try:
-            utils.p(self.urlquery)
-            r = rerequests.get(self.urlquery, headers=self.headers)  # , params = rparameters)
-        except requests.exceptions.RequestException as e:
-            bk_logger.error(e)
-            reports_queue.put(str(e))
-            # utils.p('end search thread')
-
-            return
-
-        mt('search response is back ')
-        try:
-            rdata = r.json()
-        except Exception as e:
-            if hasattr(r, 'text'):
-                error_description = parse_html_formated_error(r.text)
-                reports_queue.put(error_description)
-                tasks_queue.add_task((reports.add_report, (error_description, 10, colors.RED)))
-
-            bk_logger.error(e)
-            return
-        mt('data parsed ')
-        if not rdata.get('results'):
-            # utils.pprint(rdata)
-            # if the result was converted to json and didn't return results,
-            # it means it's a server error that has a clear message.
-            # That's why it gets processed in the update timer, where it can be passed in messages to user.
-            self.result = rdata
-            # utils.p('end search thread')
-
-            return
-        # print('number of results: ', len(rdata.get('results', [])))
-        if self.stopped():
-            utils.p('stopping search : ' + str(query))
-            # utils.p('end search thread')
-
-            return
-
-        mt('search finished')
-        i = 0
-
-        thumb_small_urls = []
-        thumb_small_filepaths = []
-        thumb_full_urls = []
-        thumb_full_filepaths = []
-        # END OF PARSING
-        for d in rdata.get('results', []):
-            thumb_small_urls.append(d["thumbnailSmallUrl"])
-            imgname = paths.extract_filename_from_url(d['thumbnailSmallUrl'])
-            imgpath = os.path.join(self.tempdir, imgname)
-            thumb_small_filepaths.append(imgpath)
-
-            if d["assetType"] == 'hdr':
-                larege_thumb_url = d['thumbnailLargeUrlNonsquared']
-
-            else:
-                larege_thumb_url = d['thumbnailMiddleUrl']
-
-            thumb_full_urls.append(larege_thumb_url)
-            imgname = paths.extract_filename_from_url(larege_thumb_url)
-            imgpath = os.path.join(self.tempdir, imgname)
-            thumb_full_filepaths.append(imgpath)
-
-            # for f in d['files']:
-            #     # TODO move validation of published assets to server, too manmy checks here.
-            #     if f['fileType'] == 'thumbnail' and f['fileThumbnail'] != None and f['fileThumbnailLarge'] != None:
-            #         if f['fileThumbnail'] == None:
-            #             f['fileThumbnail'] = 'NONE'
-            #         if f['fileThumbnailLarge'] == None:
-            #             f['fileThumbnailLarge'] = 'NONE'
-            #
-            #         thumb_small_urls.append(f['fileThumbnail'])
-            #         thumb_full_urls.append(f['fileThumbnailLarge'])
-            #
-            #         imgname = paths.extract_filename_from_url(f['fileThumbnail'])
-            #         imgpath = os.path.join(self.tempdir, imgname)
-            #         thumb_small_filepaths.append(imgpath)
-            #
-            #         imgname = paths.extract_filename_from_url(f['fileThumbnailLarge'])
-            #         imgpath = os.path.join(self.tempdir, imgname)
-            #         thumb_full_filepaths.append(imgpath)
-
-        sml_thbs = zip(thumb_small_filepaths, thumb_small_urls)
-        full_thbs = zip(thumb_full_filepaths, thumb_full_urls)
-
-        # we save here because a missing thumbnail check is in the previous loop
-        # we can also prepend previous results. These have downloaded thumbnails already...
-
-        self.result = rdata
-
-        if self.stopped():
-            utils.p('stopping search : ' + str(query))
-            # utils.p('end search thread')
-            return
-
-        # this loop handles downloading of small thumbnails
-        for imgpath, url in sml_thbs:
-            if not os.path.exists(imgpath):
-                thumb_sml_download_threads.put((url, imgpath))
-
-        if self.stopped():
-            utils.p('stopping search : ' + str(query))
-            # utils.p('end search thread')
-            return
-
-        if self.stopped():
-            # utils.p('end search thread')
-
-            utils.p('stopping search : ' + str(query))
-            return
-
-        # start downloading full thumbs in the end
-        tsession = requests.Session()
-
-        for imgpath, url in full_thbs:
-            if not os.path.exists(imgpath):
-                thumb_full_download_threads.put((url, imgpath))
-        # utils.p('end search thread')
-        mt('thumbnails finished')
-
-
-def build_query_common(query, props):
-    '''add shared parameters to query'''
-    query_common = {}
-    if props.search_keywords != '':
-        # keywords = urllib.parse.urlencode(props.search_keywords)
-        keywords = props.search_keywords.replace('&', '%26')
-        query_common["query"] = keywords
-
-    if props.search_verification_status != 'ALL' and utils.profile_is_validator():
-        query_common['verification_status'] = props.search_verification_status.lower()
-
-    if props.unrated_only and utils.profile_is_validator():
-        query["quality_count"] = 0
-
-    if props.search_file_size:
-        query_common["files_size_gte"] = props.search_file_size_min * 1024 * 1024
-        query_common["files_size_lte"] = props.search_file_size_max * 1024 * 1024
-
-    if props.quality_limit > 0:
-        query["quality_gte"] = props.quality_limit
-
-    query.update(query_common)
-
-
-def build_query_model():
-    '''use all search input to request results from server'''
-
-    props = bpy.context.window_manager.blenderkit_models
-    query = {
-        "asset_type": 'model',
-        # "engine": props.search_engine,
-        # "adult": props.search_adult,
-    }
-    if props.search_style != 'ANY':
-        if props.search_style != 'OTHER':
-            query["model_style"] = props.search_style
-        else:
-            query["model_style"] = props.search_style_other
-
-    # the 'free_only' parametr gets moved to the search command and is used for ordering the assets as free first
-    # if props.free_only:
-    #     query["is_free"] = True
-
-    if props.search_condition != 'UNSPECIFIED':
-        query["condition"] = props.search_condition
-
-    if props.search_design_year:
-        query["designYear_gte"] = props.search_design_year_min
-        query["designYear_lte"] = props.search_design_year_max
-    if props.search_polycount:
-        query["faceCount_gte"] = props.search_polycount_min
-        query["faceCount_lte"] = props.search_polycount_max
-    if props.search_texture_resolution:
-        query["textureResolutionMax_gte"] = props.search_texture_resolution_min
-        query["textureResolutionMax_lte"] = props.search_texture_resolution_max
-
-    build_query_common(query, props)
-
-    return query
-
-
-def build_query_scene():
-    '''use all search input to request results from server'''
-
-    props = bpy.context.window_manager.blenderkit_scene
-    query = {
-        "asset_type": 'scene',
-        # "engine": props.search_engine,
-        # "adult": props.search_adult,
-    }
-    build_query_common(query, props)
-    return query
-
-
-def build_query_HDR():
-    '''use all search input to request results from server'''
-
-    props = bpy.context.window_manager.blenderkit_HDR
-    query = {
-        "asset_type": 'hdr',
-
-        # "engine": props.search_engine,
-        # "adult": props.search_adult,
-    }
-    if props.true_hdr:
-        query["trueHDR"] = props.true_hdr
-    build_query_common(query, props)
-    return query
-
-
-def build_query_material():
-    props = bpy.context.window_manager.blenderkit_mat
-    query = {
-        "asset_type": 'material',
-
-    }
-    # if props.search_engine == 'NONE':
-    #     query["engine"] = ''
-    # if props.search_engine != 'OTHER':
-    #     query["engine"] = props.search_engine
-    # else:
-    #     query["engine"] = props.search_engine_other
-    if props.search_style != 'ANY':
-        if props.search_style != 'OTHER':
-            query["style"] = props.search_style
-        else:
-            query["style"] = props.search_style_other
-    if props.search_procedural == 'TEXTURE_BASED':
-        # todo this procedural hack should be replaced with the parameter
-        query["textureResolutionMax_gte"] = 0
-        # query["procedural"] = False
-        if props.search_texture_resolution:
-            query["textureResolutionMax_gte"] = props.search_texture_resolution_min
-            query["textureResolutionMax_lte"] = props.search_texture_resolution_max
-
-
-
-    elif props.search_procedural == "PROCEDURAL":
-        # todo this procedural hack should be replaced with the parameter
-        query["files_size_lte"] = 1024 * 1024
-        # query["procedural"] = True
-
-    build_query_common(query, props)
-
-    return query
-
-
-def build_query_texture():
-    props = bpy.context.scene.blenderkit_tex
-    query = {
-        "asset_type": 'texture',
-
-    }
-
-    if props.search_style != 'ANY':
-        if props.search_style != 'OTHER':
-            query["search_style"] = props.search_style
-        else:
-            query["search_style"] = props.search_style_other
-
-    build_query_common(query, props)
-
-    return query
-
-
-def build_query_brush():
-    props = bpy.context.window_manager.blenderkit_brush
-
-    brush_type = ''
-    if bpy.context.sculpt_object is not None:
-        brush_type = 'sculpt'
-
-    elif bpy.context.image_paint_object:  # could be just else, but for future p
-        brush_type = 'texture_paint'
-
-    query = {
-        "asset_type": 'brush',
-
-        "mode": brush_type
-    }
-
-    build_query_common(query, props)
-
-    return query
-
-
-def mt(text):
-    global search_start_time, prev_time
-    alltime = time.time() - search_start_time
-    since_last = time.time() - prev_time
-    prev_time = time.time()
-    utils.p(text, alltime, since_last)
-
-
-def add_search_process(query, params):
-    global search_threads, thumb_workers_sml, thumb_workers_full, all_thumbs_loaded
-
-    while (len(search_threads) > 0):
-        old_thread = search_threads.pop(0)
-        old_thread[0].stop()
-        # TODO CARE HERE FOR ALSO KILLING THE Thumbnail THREADS.?
-        #  AT LEAST NOW SEARCH DONE FIRST WON'T REWRITE AN NEWER ONE
-    tempdir = paths.get_temp_dir('%s_search' % query['asset_type'])
-    headers = utils.get_headers(params['api_key'])
-
-    if params.get('get_next'):
-        urlquery = params['next']
-    else:
-        urlquery = query_to_url(query, params)
-
-    if thumb_workers_sml == []:
-        for a in range(0, 8):
-            thread = threading.Thread(target=thumb_download_worker,
-                                      args=(thumb_sml_download_threads, thumb_full_download_threads),
-                                      daemon=True)
-            thread.start()
-            thumb_workers_sml.append(thread)
-
-    all_thumbs_loaded = False
-
-    thread = Searcher(query, params, tempdir=tempdir, headers=headers, urlquery=urlquery)
-    thread.start()
-
-    search_threads.append([thread, tempdir, query['asset_type'], {}])  # 4th field is for results
-
-    mt('search thread started')
-
-
-def get_search_simple(parameters, filepath=None, page_size=100, max_results=100000000, api_key=''):
-    '''
-    Searches and returns the
-
-
-    Parameters
-    ----------
-    parameters - dict of blenderkit elastic parameters
-    filepath - a file to save the results. If None, results are returned
-    page_size - page size for retrieved results
-    max_results - max results of the search
-    api_key - BlenderKit api key
-
-    Returns
-    -------
-    Returns search results as a list, and optionally saves to filepath
-
-    '''
-    headers = utils.get_headers(api_key)
-    url = paths.get_api_url() + 'search/'
-    requeststring = url + '?query='
-    for p in parameters.keys():
-        requeststring += f'+{p}:{parameters[p]}'
-
-    requeststring += '&page_size=' + str(page_size)
-    requeststring += '&dict_parameters=1'
-
-    bk_logger.debug(requeststring)
-    response = rerequests.get(requeststring, headers=headers)  # , params = rparameters)
-    # print(response.json())
-    search_results = response.json()
-
-    results = []
-    results.extend(search_results['results'])
-    page_index = 2
-    page_count = math.ceil(search_results['count'] / page_size)
-    while search_results.get('next') and len(results) < max_results:
-        bk_logger.info(f'getting page {page_index} , total pages {page_count}')
-        response = rerequests.get(search_results['next'], headers=headers)  # , params = rparameters)
-        search_results = response.json()
-        # print(search_results)
-        results.extend(search_results['results'])
-        page_index += 1
-
-    if not filepath:
-        return results
-
-    with open(filepath, 'w', encoding='utf-8') as s:
-        json.dump(results, s, ensure_ascii=False, indent=4)
-    bk_logger.info(f'retrieved {len(results)} assets from elastic search')
-    return results
-
-
-def get_single_asset(asset_base_id):
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    params = {
-        'asset_base_id': asset_base_id
-    }
-    results = get_search_simple(params, api_key=preferences.api_key)
-    if len(results) > 0:
-        return results[0]
-    return None
-
-
-def search(category='', get_next=False, author_id=''):
-    ''' initialize searching'''
-    global search_start_time
-    # print(category,get_next,author_id)
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    search_start_time = time.time()
-    # mt('start')
-    scene = bpy.context.scene
-    wm = bpy.context.window_manager
-    ui_props = bpy.context.window_manager.blenderkitUI
-
-    props = utils.get_search_props()
-    if ui_props.asset_type == 'MODEL':
-        if not hasattr(wm, 'blenderkit_models'):
-            return;
-        query = build_query_model()
-
-    if ui_props.asset_type == 'SCENE':
-        if not hasattr(wm, 'blenderkit_scene'):
-            return;
-        query = build_query_scene()
-
-    if ui_props.asset_type == 'HDR':
-        if not hasattr(wm, 'blenderkit_HDR'):
-            return;
-        query = build_query_HDR()
-
-    if ui_props.asset_type == 'MATERIAL':
-        if not hasattr(wm, 'blenderkit_mat'):
-            return;
-
-        query = build_query_material()
-
-    if ui_props.asset_type == 'TEXTURE':
-        if not hasattr(wm, 'blenderkit_tex'):
-            return;
-        # props = scene.blenderkit_tex
-        # query = build_query_texture()
-
-    if ui_props.asset_type == 'BRUSH':
-        if not hasattr(wm, 'blenderkit_brush'):
-            return;
-        query = build_query_brush()
-
-    # crop long searches
-    if query.get('query'):
-        if len(query['query']) > 50:
-            query['query'] = strip_accents(query['query'])
-
-        if len(query['query']) > 150:
-            idx = query['query'].find(' ', 142)
-            query['query'] = query['query'][:idx]
-
-    # it's possible get_next was requested more than once.
-    # print(category,props.is_searching, get_next)
-    # print(query)
-    if props.is_searching and get_next == True:
-        # print('return because of get next and searching is happening')
-        return;
-
-    if category != '':
-        if utils.profile_is_validator() and user_preferences.categories_fix:
-            query['category'] = category
-        else:
-            query['category_subtree'] = category
-
-    if author_id != '':
-        query['author_id'] = author_id
-
-    elif props.own_only:
-        # if user searches for [another] author, 'only my assets' is invalid. that's why in elif.
-        profile = bpy.context.window_manager.get('bkit profile')
-        if profile is not None:
-            query['author_id'] = str(profile['user']['id'])
-
-    # utils.p('searching')
-    props.is_searching = True
-
-    page_size = min(30, ui_props.wcount * user_preferences.max_assetbar_rows)
-
-    params = {
-        'scene_uuid': bpy.context.scene.get('uuid', None),
-        'addon_version': version_checker.get_addon_version(),
-        'api_key': user_preferences.api_key,
-        'get_next': get_next,
-        'free_first': props.free_only,
-        'page_size': page_size,
-    }
-
-    orig_results = bpy.context.window_manager.get(f'bkit {ui_props.asset_type.lower()} search orig')
-    if orig_results is not None and get_next:
-        params['next'] = orig_results['next']
-    add_search_process(query, params)
-    tasks_queue.add_task((reports.add_report, ('BlenderKit searching....', 2)))
-
-    props.report = 'BlenderKit searching....'
-
-
-def update_filters():
-    sprops = utils.get_search_props()
-    ui_props = bpy.context.window_manager.blenderkitUI
-    fcommon = sprops.own_only or \
-              sprops.search_texture_resolution or \
-              sprops.search_file_size or \
-              sprops.search_procedural != 'BOTH' or \
-              sprops.free_only or \
-              sprops.quality_limit > 0
-
-    if ui_props.asset_type == 'MODEL':
-        sprops.use_filters = fcommon or \
-                             sprops.search_style != 'ANY' or \
-                             sprops.search_condition != 'UNSPECIFIED' or \
-                             sprops.search_design_year or \
-                             sprops.search_polycount
-    elif ui_props.asset_type == 'MATERIAL':
-        sprops.use_filters = fcommon
-    elif ui_props.asset_type == 'HDR':
-        sprops.use_filters = sprops.true_hdr
-
-
-def search_update(self, context):
-    utils.p('search updater')
-    # if self.search_keywords != '':
-    update_filters()
-    ui_props = bpy.context.window_manager.blenderkitUI
-    if ui_props.down_up != 'SEARCH':
-        ui_props.down_up = 'SEARCH'
-
-    # here we tweak the input if it comes form the clipboard. we need to get rid of asset type and set it in UI
-    sprops = utils.get_search_props()
-    instr = 'asset_base_id:'
-    atstr = 'asset_type:'
-    kwds = sprops.search_keywords
-    idi = kwds.find(instr)
-    ati = kwds.find(atstr)
-    # if the asset type already isn't there it means this update function
-    # was triggered by it's last iteration and needs to cancel
-    if ati > -1:
-        at = kwds[ati:].lower()
-        # uncertain length of the remaining string -  find as better method to check the presence of asset type
-        if at.find('model') > -1:
-            ui_props.asset_type = 'MODEL'
-        elif at.find('material') > -1:
-            ui_props.asset_type = 'MATERIAL'
-        elif at.find('brush') > -1:
-            ui_props.asset_type = 'BRUSH'
-        elif at.find('scene') > -1:
-            ui_props.asset_type = 'SCENE'
-        elif at.find('hdr') > -1:
-            ui_props.asset_type = 'HDR'
-        # now we trim the input copypaste by anything extra that is there,
-        # this is also a way for this function to recognize that it already has parsed the clipboard
-        # the search props can have changed and this needs to transfer the data to the other field
-        # this complex behaviour is here for the case where the user needs to paste manually into blender?
-        sprops = utils.get_search_props()
-        sprops.search_keywords = kwds[:ati].rstrip()
-        # return here since writing into search keywords triggers this update function once more.
-        return
-
-    # print('search update search')
-    search()
-
-
-# accented_string is of type 'unicode'
-def strip_accents(s):
-    return ''.join(c for c in unicodedata.normalize('NFD', s)
-                   if unicodedata.category(c) != 'Mn')
-
-
-class SearchOperator(Operator):
-    """Tooltip"""
-    bl_idname = "view3d.blenderkit_search"
-    bl_label = "BlenderKit asset search"
-    bl_description = "Search online for assets"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    esc: BoolProperty(name="Escape window",
-                      description="Escape window right after start",
-                      default=False,
-                      options={'SKIP_SAVE'}
-                      )
-
-    own: BoolProperty(name="own assets only",
-                      description="Find all own assets",
-                      default=False,
-                      options={'SKIP_SAVE'})
-
-    category: StringProperty(
-        name="category",
-        description="search only subtree of this category",
-        default="",
-        options={'SKIP_SAVE'}
-    )
-
-    author_id: StringProperty(
-        name="Author ID",
-        description="Author ID - search only assets by this author",
-        default="",
-        options={'SKIP_SAVE'}
-    )
-
-    get_next: BoolProperty(name="next page",
-                           description="get next page from previous search",
-                           default=False,
-                           options={'SKIP_SAVE'}
-                           )
-
-    keywords: StringProperty(
-        name="Keywords",
-        description="Keywords",
-        default="",
-        options={'SKIP_SAVE'}
-    )
-
-    # close_window: BoolProperty(name='Close window',
-    #                            description='Try to close the window below mouse before download',
-    #                            default=False)
-
-    tooltip: bpy.props.StringProperty(default='Runs search and displays the asset bar at the same time')
-
-    @classmethod
-    def description(cls, context, properties):
-        return properties.tooltip
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def execute(self, context):
-        # TODO ; this should all get transferred to properties of the search operator, so sprops don't have to be fetched here at all.
-        if self.esc:
-            bpy.ops.view3d.close_popup_button('INVOKE_DEFAULT')
-        sprops = utils.get_search_props()
-        if self.author_id != '':
-            sprops.search_keywords = ''
-        if self.keywords != '':
-            sprops.search_keywords = self.keywords
-
-        search(category=self.category, get_next=self.get_next, author_id=self.author_id)
-        # bpy.ops.view3d.blenderkit_asset_bar_widget()
-
-        return {'FINISHED'}
-
-    # def invoke(self, context, event):
-    #     if self.close_window:
-    #         context.window.cursor_warp(event.mouse_x, event.mouse_y - 100);
-    #         context.area.tag_redraw()
-    #
-    #         context.window.cursor_warp(event.mouse_x, event.mouse_y);
-    #     return self. execute(context)
-
-
-class UrlOperator(Operator):
-    """"""
-    bl_idname = "wm.blenderkit_url"
-    bl_label = ""
-    bl_description = "Search online for assets"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    tooltip: bpy.props.StringProperty(default='Open a web page')
-    url: bpy.props.StringProperty(default='Runs search and displays the asset bar at the same time')
-
-    @classmethod
-    def description(cls, context, properties):
-        return properties.tooltip
-
-    def execute(self, context):
-        bpy.ops.wm.url_open(url=self.url)
-        return {'FINISHED'}
-
-
-class TooltipLabelOperator(Operator):
-    """"""
-    bl_idname = "wm.blenderkit_tooltip"
-    bl_label = ""
-    bl_description = "Empty operator to be able to create tooltips on labels in UI"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    tooltip: bpy.props.StringProperty(default='Open a web page')
-
-    @classmethod
-    def description(cls, context, properties):
-        return properties.tooltip
-
-    def execute(self, context):
-        return {'FINISHED'}
-
-
-classes = [
-    SearchOperator,
-    UrlOperator,
-    TooltipLabelOperator
-]
-
-
-def register_search():
-    bpy.app.handlers.load_post.append(scene_load)
-
-    for c in classes:
-        bpy.utils.register_class(c)
-
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if user_preferences.use_timers and not bpy.app.background:
-        bpy.app.timers.register(search_timer)
-
-    categories.load_categories()
-
-
-def unregister_search():
-    bpy.app.handlers.load_post.remove(scene_load)
-
-    for c in classes:
-        bpy.utils.unregister_class(c)
-
-    if bpy.app.timers.is_registered(search_timer):
-        bpy.app.timers.unregister(search_timer)
diff --git a/blenderkit/tasks_queue.py b/blenderkit/tasks_queue.py
deleted file mode 100644
index 248e9be780ffae3d66a5b1bbd110741134909396..0000000000000000000000000000000000000000
--- a/blenderkit/tasks_queue.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import utils
-
-import bpy
-from bpy.app.handlers import persistent
-
-import queue
-import logging
-bk_logger = logging.getLogger('blenderkit')
-
-@persistent
-def scene_load(context):
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if user_preferences.use_timers and not bpy.app.background:
-        if not (bpy.app.timers.is_registered(queue_worker)):
-            bpy.app.timers.register(queue_worker)
-
-
-def get_queue():
-    # we pick just a random one of blender types, to try to get a persistent queue
-    t = bpy.types.Scene
-
-    if not hasattr(t, 'task_queue'):
-        t.task_queue = queue.Queue()
-    return t.task_queue
-
-class task_object:
-    def __init__(self, command = '', arguments = (), wait = 0, only_last = False, fake_context = False, fake_context_area = 'VIEW_3D'):
-        self.command = command
-        self.arguments = arguments
-        self.wait = wait
-        self.only_last = only_last
-        self.fake_context = fake_context
-        self.fake_context_area = fake_context_area
-
-def add_task(task, wait = 0, only_last = False, fake_context = False, fake_context_area = 'VIEW_3D'):
-    q = get_queue()
-    taskob = task_object(task[0],task[1], wait = wait, only_last = only_last, fake_context = fake_context, fake_context_area = fake_context_area)
-    q.put(taskob)
-
-
-def queue_worker():
-    # utils.p('start queue worker timer')
-
-    #bk_logger.debug('timer queue worker')
-    time_step = 2.0
-    q = get_queue()
-
-    back_to_queue = [] #delayed events
-    stashed = {}
-    # first round we get all tasks that are supposed to be stashed and run only once (only_last option)
-    # stashing finds tasks with the property only_last and same command and executes only the last one.
-    while not q.empty():
-        # print('queue while 1')
-
-        task = q.get()
-        if task.only_last:
-            #this now makes the keys not only by task, but also first argument.
-            # by now stashing is only used for ratings, where the first argument is url.
-            # This enables fast rating of multiple assets while allowing larger delay for uploading of ratings.
-            # this avoids a duplicate request error on the server
-            stashed[str(task.command)+str(task.arguments[0])] = task
-        else:
-            back_to_queue.append(task)
-    if len(stashed.keys())>1:
-        bk_logger.debug('task queue stashed task:' +str(stashed))
-    #return tasks to que except for stashed
-    for task in back_to_queue:
-        q.put(task)
-    #return stashed tasks to queue
-    for k in stashed.keys():
-        q.put(stashed[k])
-    #second round, execute or put back waiting tasks.
-    back_to_queue = []
-    while not q.empty():
-        # print('window manager', bpy.context.window_manager)
-        task = q.get()
-
-        if task.wait>0:
-            task.wait-=time_step
-            back_to_queue.append(task)
-        else:
-            bk_logger.debug('task queue task:'+ str( task.command) +str( task.arguments))
-            try:
-                if task.fake_context:
-                    fc = utils.get_fake_context(bpy.context, area_type = task.fake_context_area)
-                    task.command(fc,*task.arguments)
-                else:
-                    task.command(*task.arguments)
-            except Exception as e:
-                bk_logger.error('task queue failed task:'+ str(task.command)+str(task.arguments)+ str(e))
-                # bk_logger.exception('Got exception on main handler')
-                # raise
-        # print('queue while 2')
-    for task in back_to_queue:
-        q.put(task)
-    # utils.p('end queue worker timer')
-
-    return 2.0
-
-
-def register():
-    bpy.app.handlers.load_post.append(scene_load)
-
-
-def unregister():
-    bpy.app.handlers.load_post.remove(scene_load)
diff --git a/blenderkit/thumbnails/arrow_left.png b/blenderkit/thumbnails/arrow_left.png
deleted file mode 100644
index 97565169dd71d5a94cd4ce3afad5c493d442797f..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/arrow_left.png and /dev/null differ
diff --git a/blenderkit/thumbnails/arrow_right.png b/blenderkit/thumbnails/arrow_right.png
deleted file mode 100644
index fd16550ba4fc556cfadb6b953a1cd1756501bbce..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/arrow_right.png and /dev/null differ
diff --git a/blenderkit/thumbnails/bar_slider.png b/blenderkit/thumbnails/bar_slider.png
deleted file mode 100644
index ec627318f6e2aee402b278820dde7ae5e14c02bf..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/bar_slider.png and /dev/null differ
diff --git a/blenderkit/thumbnails/bell.png b/blenderkit/thumbnails/bell.png
deleted file mode 100644
index 2b724a26da329882bf9f6578c8e68b0e8a4b214f..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/bell.png and /dev/null differ
diff --git a/blenderkit/thumbnails/cc0.png b/blenderkit/thumbnails/cc0.png
deleted file mode 100644
index 3f5450f84503b5813c909c761e91a0b8ed880310..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/cc0.png and /dev/null differ
diff --git a/blenderkit/thumbnails/dumbbell.png b/blenderkit/thumbnails/dumbbell.png
deleted file mode 100644
index ffc709c6a11bb4a20843308857da114c438dba51..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/dumbbell.png and /dev/null differ
diff --git a/blenderkit/thumbnails/filter.png b/blenderkit/thumbnails/filter.png
deleted file mode 100644
index e128c35eed5f2413fb38122b829b5fe77abc4d3b..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/filter.png and /dev/null differ
diff --git a/blenderkit/thumbnails/filter_active.png b/blenderkit/thumbnails/filter_active.png
deleted file mode 100644
index de4fb3be163117bed02ed535def24a05234b4b6d..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/filter_active.png and /dev/null differ
diff --git a/blenderkit/thumbnails/flp.png b/blenderkit/thumbnails/flp.png
deleted file mode 100644
index 7ac3c3d75ad7181f0105f40a4cc9001ae12b8ce8..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/flp.png and /dev/null differ
diff --git a/blenderkit/thumbnails/fp.png b/blenderkit/thumbnails/fp.png
deleted file mode 100644
index 4e356ab19d22eac1b05edc2a7f97e3a50c3cf407..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/fp.png and /dev/null differ
diff --git a/blenderkit/thumbnails/intro.jpg b/blenderkit/thumbnails/intro.jpg
deleted file mode 100644
index 52ce56e390a75aa2590f7277877d53b2841f3f81..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/intro.jpg and /dev/null differ
diff --git a/blenderkit/thumbnails/locked.png b/blenderkit/thumbnails/locked.png
deleted file mode 100644
index f308392c6d0930d77e2c2ab979ee911d50839b32..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/locked.png and /dev/null differ
diff --git a/blenderkit/thumbnails/private.png b/blenderkit/thumbnails/private.png
deleted file mode 100644
index 7ac3c3d75ad7181f0105f40a4cc9001ae12b8ce8..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/private.png and /dev/null differ
diff --git a/blenderkit/thumbnails/royalty_free.png b/blenderkit/thumbnails/royalty_free.png
deleted file mode 100644
index b85fa91096c6cb970372f40e5b837709197d2c05..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/royalty_free.png and /dev/null differ
diff --git a/blenderkit/thumbnails/star_grey.png b/blenderkit/thumbnails/star_grey.png
deleted file mode 100644
index 53c5bd05a66ba6a2709a802240500100d89f5875..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/star_grey.png and /dev/null differ
diff --git a/blenderkit/thumbnails/star_white.png b/blenderkit/thumbnails/star_white.png
deleted file mode 100644
index 14e030cc39c354626bf5d20694111e9d0c64215e..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/star_white.png and /dev/null differ
diff --git a/blenderkit/thumbnails/thumbnail_not_available.jpg b/blenderkit/thumbnails/thumbnail_not_available.jpg
deleted file mode 100644
index c5b5172affb2a9b2bbe3c8bc314a554d7226f785..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/thumbnail_not_available.jpg and /dev/null differ
diff --git a/blenderkit/thumbnails/thumbnail_notready.jpg b/blenderkit/thumbnails/thumbnail_notready.jpg
deleted file mode 100644
index 5be976b9a808bac7350042e467072901a61fd078..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/thumbnail_notready.jpg and /dev/null differ
diff --git a/blenderkit/thumbnails/trophy.png b/blenderkit/thumbnails/trophy.png
deleted file mode 100644
index 01d77a226ee0cce9deb5f167a70349ad40147751..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/trophy.png and /dev/null differ
diff --git a/blenderkit/thumbnails/vs_deleted.png b/blenderkit/thumbnails/vs_deleted.png
deleted file mode 100644
index a7f4e134a30161187a3643a7dc08bd5485ba6a91..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/vs_deleted.png and /dev/null differ
diff --git a/blenderkit/thumbnails/vs_on_hold.png b/blenderkit/thumbnails/vs_on_hold.png
deleted file mode 100644
index eb7975172600f6ff9dcc87f4cc908cffb40e166f..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/vs_on_hold.png and /dev/null differ
diff --git a/blenderkit/thumbnails/vs_ready.png b/blenderkit/thumbnails/vs_ready.png
deleted file mode 100644
index ac52a3cd8c76de818fd259f870d6dcaedeef297b..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/vs_ready.png and /dev/null differ
diff --git a/blenderkit/thumbnails/vs_rejected.png b/blenderkit/thumbnails/vs_rejected.png
deleted file mode 100644
index 6ff663cf546c5c520bb21a659e4cc52251ac57dc..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/vs_rejected.png and /dev/null differ
diff --git a/blenderkit/thumbnails/vs_uploaded.png b/blenderkit/thumbnails/vs_uploaded.png
deleted file mode 100644
index 6ef39cb4f3568b7488b2ddc9fef864878015067c..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/vs_uploaded.png and /dev/null differ
diff --git a/blenderkit/thumbnails/vs_uploading.png b/blenderkit/thumbnails/vs_uploading.png
deleted file mode 100644
index e7276e4da2ef0598a30c78a6295cbd0f2ec613b6..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/vs_uploading.png and /dev/null differ
diff --git a/blenderkit/thumbnails/vs_validated.png b/blenderkit/thumbnails/vs_validated.png
deleted file mode 100644
index b2d8fdd297ab4d970ad7df8748dcfcd91e05c4d9..0000000000000000000000000000000000000000
Binary files a/blenderkit/thumbnails/vs_validated.png and /dev/null differ
diff --git a/blenderkit/ui.py b/blenderkit/ui.py
deleted file mode 100644
index f4ccf5914f669e0d9b3d8ea68a88db530b7c7485..0000000000000000000000000000000000000000
--- a/blenderkit/ui.py
+++ /dev/null
@@ -1,1937 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import paths, ratings, utils, search, upload, ui_bgl, download, bg_blender, colors, tasks_queue, \
-    ui_panels, icons, ratings_utils, reports
-
-import bpy
-
-import math, random
-
-from bpy.props import (
-    BoolProperty,
-    StringProperty,
-    IntProperty,
-    FloatVectorProperty
-)
-
-from bpy_extras import view3d_utils
-import mathutils
-from mathutils import Vector
-import time
-import datetime
-import os
-
-import logging
-
-draw_time = 0
-eval_time = 0
-
-bk_logger = logging.getLogger('blenderkit')
-
-handler_2d = None
-handler_3d = None
-active_area_pointer = None
-active_window_pointer = None
-active_region_pointer = None
-
-mappingdict = {
-    'MODEL': 'model',
-    'SCENE': 'scene',
-    'HDR': 'hdr',
-    'MATERIAL': 'material',
-    'TEXTURE': 'texture',
-    'BRUSH': 'brush'
-}
-
-verification_icons = {
-    'ready': 'vs_ready.png',
-    'deleted': 'vs_deleted.png',
-    'uploaded': 'vs_uploaded.png',
-    'uploading': 'vs_uploading.png',
-    'on_hold': 'vs_on_hold.png',
-    'validated': None,
-    'rejected': 'vs_rejected.png'
-
-}
-
-
-# class UI_region():
-#      def _init__(self, parent = None, x = 10,y = 10 , width = 10, height = 10, img = None, col = None):
-
-def get_approximate_text_width(st):
-    size = 10
-    for s in st:
-        if s in 'i|':
-            size += 2
-        elif s in ' ':
-            size += 4
-        elif s in 'sfrt':
-            size += 5
-        elif s in 'ceghkou':
-            size += 6
-        elif s in 'PadnBCST3E':
-            size += 7
-        elif s in 'GMODVXYZ':
-            size += 8
-        elif s in 'w':
-            size += 9
-        elif s in 'm':
-            size += 10
-        else:
-            size += 7
-    return size  # Convert to picas
-
-
-
-def get_asset_under_mouse(mousex, mousey):
-    s = bpy.context.scene
-    wm = bpy.context.window_manager
-    ui_props = bpy.context.window_manager.blenderkitUI
-    r = bpy.context.region
-
-    search_results = wm.get('search results')
-    if search_results is not None:
-
-        h_draw = min(ui_props.hcount, math.ceil(len(search_results) / ui_props.wcount))
-        for b in range(0, h_draw):
-            w_draw = min(ui_props.wcount, len(search_results) - b * ui_props.wcount - ui_props.scroll_offset)
-            for a in range(0, w_draw):
-                x = ui_props.bar_x + a * (ui_props.margin + ui_props.thumb_size) + ui_props.margin + ui_props.drawoffset
-                y = ui_props.bar_y - ui_props.margin - (ui_props.thumb_size + ui_props.margin) * (b + 1)
-                w = ui_props.thumb_size
-                h = ui_props.thumb_size
-
-                if x < mousex < x + w and y < mousey < y + h:
-                    return a + ui_props.wcount * b + ui_props.scroll_offset
-
-                #   return search_results[a]
-
-    return -3
-
-
-def draw_bbox(location, rotation, bbox_min, bbox_max, progress=None, color=(0, 1, 0, 1)):
-    ui_props = bpy.context.window_manager.blenderkitUI
-
-    rotation = mathutils.Euler(rotation)
-
-    smin = Vector(bbox_min)
-    smax = Vector(bbox_max)
-    v0 = Vector(smin)
-    v1 = Vector((smax.x, smin.y, smin.z))
-    v2 = Vector((smax.x, smax.y, smin.z))
-    v3 = Vector((smin.x, smax.y, smin.z))
-    v4 = Vector((smin.x, smin.y, smax.z))
-    v5 = Vector((smax.x, smin.y, smax.z))
-    v6 = Vector((smax.x, smax.y, smax.z))
-    v7 = Vector((smin.x, smax.y, smax.z))
-
-    arrowx = smin.x + (smax.x - smin.x) / 2
-    arrowy = smin.y - (smax.x - smin.x) / 2
-    v8 = Vector((arrowx, arrowy, smin.z))
-
-    vertices = [v0, v1, v2, v3, v4, v5, v6, v7, v8]
-    for v in vertices:
-        v.rotate(rotation)
-        v += Vector(location)
-
-    lines = [[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6, 7], [7, 4], [0, 4], [1, 5],
-             [2, 6], [3, 7], [0, 8], [1, 8]]
-    ui_bgl.draw_lines(vertices, lines, color)
-    if progress != None:
-        color = (color[0], color[1], color[2], .2)
-        progress = progress * .01
-        vz0 = (v4 - v0) * progress + v0
-        vz1 = (v5 - v1) * progress + v1
-        vz2 = (v6 - v2) * progress + v2
-        vz3 = (v7 - v3) * progress + v3
-        rects = (
-            (v0, v1, vz1, vz0),
-            (v1, v2, vz2, vz1),
-            (v2, v3, vz3, vz2),
-            (v3, v0, vz0, vz3))
-        for r in rects:
-            ui_bgl.draw_rect_3d(r, color)
-
-
-def get_rating_scalevalues(asset_type):
-    xs = []
-    if asset_type == 'model':
-        scalevalues = (0.5, 1, 2, 5, 10, 25, 50, 100, 250)
-        for v in scalevalues:
-            a = math.log2(v)
-            x = (a + 1) * (1. / 9.)
-            xs.append(x)
-    else:
-        scalevalues = (0.2, 1, 2, 3, 4, 5)
-        for v in scalevalues:
-            a = v
-            x = v / 5.
-            xs.append(x)
-    return scalevalues, xs
-
-
-def draw_ratings_bgl():
-    # return;
-    ui = bpy.context.window_manager.blenderkitUI
-
-    rating_possible, rated, asset, asset_data = is_rating_possible()
-    if rating_possible:  # (not rated or ui_props.rating_menu_on):
-        # print('rating is pssible', asset_data['name'])
-        bkit_ratings = asset.bkit_ratings
-
-        if ui.rating_button_on:
-            # print('should draw button')
-            img = utils.get_thumbnail('star_white.png')
-
-            ui_bgl.draw_image(ui.rating_x,
-                              ui.rating_y - ui.rating_button_width,
-                              ui.rating_button_width,
-                              ui.rating_button_width,
-                              img, 1)
-
-            # if ui_props.asset_type != 'BRUSH':
-            #     thumbnail_image = props.thumbnail
-            # else:
-            #     b = utils.get_active_brush()
-            #     thumbnail_image = b.icon_filepath
-
-            directory = paths.get_temp_dir('%s_search' % asset_data['assetType'])
-            tpath = os.path.join(directory, asset_data['thumbnail_small'])
-            img = utils.get_hidden_image(tpath, 'rating_preview')
-            ui_bgl.draw_image(ui.rating_x + ui.rating_button_width,
-                              ui.rating_y - ui.rating_button_width,
-                              ui.rating_button_width,
-                              ui.rating_button_width,
-                              img, 1)
-            return
-
-
-def draw_text_block(x=0, y=0, width=40, font_size=10, line_height=15, text='', color=colors.TEXT):
-    lines = text.split('\n')
-    nlines = []
-    for l in lines:
-        nlines.extend(search.split_subs(l, ))
-
-    column_lines = 0
-    for l in nlines:
-        ytext = y - column_lines * line_height
-        column_lines += 1
-        ui_bgl.draw_text(l, x, ytext, font_size, color)
-
-
-def draw_tooltip(x, y, name='', author='', quality='-', img=None, gravatar=None):
-    region = bpy.context.region
-    scale = bpy.context.preferences.view.ui_scale
-    t = time.time()
-
-    if not img or max(img.size[0], img.size[1]) == 0:
-        return;
-
-    x += 20
-    y -= 20
-    # first get image size scaled
-    isizex = int(512 * scale * img.size[0] / min(img.size[0], img.size[1]))
-    isizey = int(512 * scale * img.size[1] / min(img.size[0], img.size[1]))
-
-    ttipmargin = 5 * scale
-    # then do recurrent re-scaling, to know where to fit the tooltip
-    estimated_height = 2 * ttipmargin + isizey
-    if estimated_height > y:
-        scaledown = y / (estimated_height)
-        scale *= scaledown
-
-        isizex = int(512 * scale * img.size[0] / min(img.size[0], img.size[1]))
-        isizey = int(512 * scale * img.size[1] / min(img.size[0], img.size[1]))
-
-    ttipmargin = 5 * scale
-    textmargin = 12 * scale
-
-    if gravatar is not None:
-        overlay_height_base = 90
-    else:
-        overlay_height_base = 70
-
-    overlay_height = overlay_height_base * scale
-    name_height = int(20 * scale)
-
-    width = isizex + 2 * ttipmargin
-
-    properties_width = 0
-    for r in bpy.context.area.regions:
-        if r.type == 'UI':
-            properties_width = r.width
-
-    # limit to area borders
-    x = min(x + width, region.width - properties_width) - width
-
-    # define_colors
-    background_color = bpy.context.preferences.themes[0].user_interface.wcol_tooltip.inner
-    background_overlay = (background_color[0], background_color[1], background_color[2], .8)
-    textcol = bpy.context.preferences.themes[0].user_interface.wcol_tooltip.text
-    textcol = (textcol[0], textcol[1], textcol[2], 1)
-
-    # background
-    ui_bgl.draw_rect(x - ttipmargin,
-                     y - 2 * ttipmargin - isizey,
-                     isizex + ttipmargin * 2,
-                     2 * ttipmargin + isizey,
-                     background_color)
-
-    # main preview image
-    ui_bgl.draw_image(x, y - isizey - ttipmargin, isizex, isizey, img, 1)
-
-    # text overlay background
-    ui_bgl.draw_rect(x - ttipmargin,
-                     y - 2 * ttipmargin - isizey,
-                     isizex + ttipmargin * 2,
-                     ttipmargin + overlay_height,
-                     background_overlay)
-
-    # draw name
-    name_x = x + textmargin
-    name_y = y - isizey + overlay_height - textmargin - name_height
-    ui_bgl.draw_text(name, name_x, name_y, name_height, textcol)
-
-    # draw gravatar
-    author_x_text = x + isizex - textmargin
-    gravatar_size = overlay_height - 2 * textmargin
-    gravatar_y = y - isizey - ttipmargin + textmargin
-    if gravatar is not None:
-        author_x_text -= gravatar_size + textmargin
-        ui_bgl.draw_image(x + isizex - gravatar_size - textmargin,
-                          gravatar_y,  # + textmargin,
-                          gravatar_size, gravatar_size, gravatar, 1)
-
-    # draw author's name
-    author_text_size = int(name_height * .7)
-    ui_bgl.draw_text(author, author_x_text, gravatar_y, author_text_size, textcol, halign='RIGHT')
-
-    # draw quality
-    quality_text_size = int(name_height * 1)
-    img = utils.get_thumbnail('star_grey.png')
-    ui_bgl.draw_image(name_x, gravatar_y, quality_text_size, quality_text_size, img, .6)
-    ui_bgl.draw_text(str(quality), name_x + quality_text_size + 5, gravatar_y, quality_text_size, textcol)
-
-
-def draw_tooltip_with_author(asset_data, x, y):
-    # TODO move this lazy loading into a function and don't duplicate through the code
-
-    img = get_large_thumbnail_image(asset_data)
-    gimg = None
-    tooltip_data = asset_data.get('tooltip_data')
-    if tooltip_data is None:
-        author_text = ''
-
-        if bpy.context.window_manager.get('bkit authors') is not None:
-            a = bpy.context.window_manager['bkit authors'].get(asset_data['author']['id'])
-            if a is not None and a != '':
-                if a.get('gravatarImg') is not None:
-                    gimg = utils.get_hidden_image(a['gravatarImg'], a['gravatarHash']).name
-
-                if len(a['firstName']) > 0 or len(a['lastName']) > 0:
-                    author_text = f"by {a['firstName']} {a['lastName']}"
-
-        aname = asset_data['displayName']
-        aname = aname[0].upper() + aname[1:]
-        if len(aname) > 36:
-            aname = f"{aname[:33]}..."
-
-        rc = asset_data.get('ratingsCount')
-        show_rating_threshold = 0
-        rcount = 0
-        quality = '-'
-        if rc:
-            rcount = min(rc.get('quality', 0), rc.get('workingHours', 0))
-        if rcount > show_rating_threshold:
-            quality = round(asset_data['ratingsAverage'].get('quality'))
-        tooltip_data = {
-            'aname': aname,
-            'author_text': author_text,
-            'quality': quality,
-            'gimg': gimg
-        }
-        asset_data['tooltip_data'] = tooltip_data
-    gimg = tooltip_data['gimg']
-    if gimg is not None:
-        gimg = bpy.data.images[gimg]
-
-    draw_tooltip(x, y, name=tooltip_data['aname'],
-                 author=tooltip_data['author_text'],
-                 quality=tooltip_data['quality'],
-                 img=img,
-                 gravatar=gimg)
-
-
-def draw_callback_2d(self, context):
-    if not utils.guard_from_crash():
-        return
-
-    a = context.area
-    w = context.window
-    try:
-        # self.area might throw error just by itself.
-        a1 = self.area
-        w1 = self.window
-        go = True
-        if len(a.spaces[0].region_quadviews) > 0:
-            # print(dir(bpy.context.region_data))
-            # print('quad', a.spaces[0].region_3d, a.spaces[0].region_quadviews[0])
-            if a.spaces[0].region_3d != context.region_data:
-                go = False
-    except:
-        # bpy.types.SpaceView3D.draw_handler_remove(self._handle_2d, 'WINDOW')
-        # bpy.types.SpaceView3D.draw_handler_remove(self._handle_3d, 'WINDOW')
-        go = False
-    if go and a == a1 and w == w1:
-
-        props = context.window_manager.blenderkitUI
-        if props.down_up == 'SEARCH':
-            draw_ratings_bgl()
-            draw_asset_bar(self, context)
-        elif props.down_up == 'UPLOAD':
-            draw_callback_2d_upload_preview(self, context)
-
-
-def draw_downloader(x, y, percent=0, img=None, text=''):
-    if img is not None:
-        ui_bgl.draw_image(x, y, 50, 50, img, .5)
-
-    ui_bgl.draw_rect(x, y, 50, int(0.5 * percent), (.2, 1, .2, .3))
-    ui_bgl.draw_rect(x - 3, y - 3, 6, 6, (1, 0, 0, .3))
-    # if asset_data is not None:
-    #     ui_bgl.draw_text(asset_data['name'], x, y, colors.TEXT)
-    #     ui_bgl.draw_text(asset_data['filesSize'])
-    if text:
-        ui_bgl.draw_text(text, x, y - 15, 12, colors.TEXT)
-
-
-def draw_progress(x, y, text='', percent=None, color=colors.GREEN):
-    ui_bgl.draw_rect(x, y, percent, 5, color)
-    ui_bgl.draw_text(text, x, y + 8, 16, color)
-
-
-def draw_callback_3d_progress(self, context):
-    # 'star trek' mode is here
-
-    if not utils.guard_from_crash():
-        return
-    for threaddata in download.download_threads:
-        asset_data = threaddata[1]
-        tcom = threaddata[2]
-        if tcom.passargs.get('downloaders'):
-            for d in tcom.passargs['downloaders']:
-                if asset_data['assetType'] == 'model':
-                    draw_bbox(d['location'], d['rotation'], asset_data['bbox_min'], asset_data['bbox_max'],
-                              progress=tcom.progress)
-
-
-def draw_callback_2d_progress(self, context):
-    if not utils.guard_from_crash():
-        return
-
-    green = (.2, 1, .2, .3)
-    offset = 0
-    row_height = 35
-
-    ui = bpy.context.window_manager.blenderkitUI
-
-    x = ui.reports_x
-    y = ui.reports_y
-    index = 0
-    for threaddata in download.download_threads:
-        asset_data = threaddata[1]
-        tcom = threaddata[2]
-
-        directory = paths.get_temp_dir('%s_search' % asset_data['assetType'])
-        tpath = os.path.join(directory, asset_data['thumbnail_small'])
-        img = utils.get_hidden_image(tpath, asset_data['id'])
-
-        if tcom.passargs.get('downloaders'):
-            for d in tcom.passargs['downloaders']:
-
-                loc = view3d_utils.location_3d_to_region_2d(bpy.context.region, bpy.context.space_data.region_3d,
-                                                            d['location'])
-                # print('drawing downloader')
-                if loc is not None:
-                    if asset_data['assetType'] == 'model':
-                        # models now draw with star trek mode, no need to draw percent for the image.
-                        draw_downloader(loc[0], loc[1], percent=tcom.progress, img=img, text=tcom.report)
-                    else:
-                        draw_downloader(loc[0], loc[1], percent=tcom.progress, img=img, text=tcom.report)
-                # utils.p('end drawing downlaoders  downloader')
-        else:
-            draw_progress(x, y - index * 30, text='downloading %s' % asset_data['name'],
-                          percent=tcom.progress)
-            index += 1
-
-    for process in bg_blender.bg_processes:
-        tcom = process[1]
-        n = ''
-        if tcom.name is not None:
-            n = tcom.name + ': '
-        draw_progress(x, y - index * 30, '%s' % n + tcom.lasttext,
-                      tcom.progress)
-        index += 1
-    for report in reports.reports:
-        # print('drawing reports', x, y, report.text)
-        report.draw(x, y - index * 30)
-        index += 1
-        report.fade()
-
-
-def draw_callback_2d_upload_preview(self, context):
-    ui_props = context.window_manager.blenderkitUI
-
-    props = utils.get_upload_props()
-
-    # assets which don't need asset preview
-    if ui_props.asset_type == 'HDR':
-        return
-
-    if props != None and ui_props.draw_tooltip:
-
-        if ui_props.asset_type != 'BRUSH':
-            ui_props.thumbnail_image = props.thumbnail
-        else:
-            b = utils.get_active_brush()
-            ui_props.thumbnail_image = b.icon_filepath
-
-        img = utils.get_hidden_image(ui_props.thumbnail_image, 'upload_preview')
-
-        draw_tooltip(ui_props.bar_x, ui_props.bar_y, name=props.name, img=img)
-
-
-
-def get_large_thumbnail_image(asset_data):
-    '''Get thumbnail image from asset data'''
-    scene = bpy.context.scene
-    ui_props = bpy.context.window_manager.blenderkitUI
-    iname = utils.previmg_name(ui_props.active_index, fullsize=True)
-    directory = paths.get_temp_dir('%s_search' % mappingdict[ui_props.asset_type])
-    tpath = os.path.join(directory, asset_data['thumbnail'])
-    # if asset_data['assetType'] == 'hdr':
-    #     tpath = os.path.join(directory, asset_data['thumbnail'])
-    if not asset_data['thumbnail']:
-        tpath = paths.get_addon_thumbnail_path('thumbnail_not_available.jpg')
-
-    if asset_data['assetType'] == 'hdr':
-        colorspace = 'Non-Color'
-    else:
-        colorspace = 'sRGB'
-    img = utils.get_hidden_image(tpath, iname, colorspace=colorspace)
-    return img
-
-
-def draw_asset_bar(self, context):
-    s = bpy.context.scene
-    ui_props = context.window_manager.blenderkitUI
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    is_validator = utils.profile_is_validator()
-    r = self.region
-    # hc = bpy.context.preferences.themes[0].view_3d.space.header
-    # hc = bpy.context.preferences.themes[0].user_interface.wcol_menu_back.inner
-    # hc = (hc[0], hc[1], hc[2], .2)
-    hc = (1, 1, 1, .07)
-    # grey1 = (hc.r * .55, hc.g * .55, hc.b * .55, 1)
-    grey2 = (hc[0] * .8, hc[1] * .8, hc[2] * .8, .5)
-    # grey1 = (hc.r, hc.g, hc.b, 1)
-    white = (1, 1, 1, 0.2)
-    green = (.2, 1, .2, .7)
-    highlight = bpy.context.preferences.themes[0].user_interface.wcol_menu_item.inner_sel
-    highlight = (1, 1, 1, .2)
-    # highlight = (1, 1, 1, 0.8)
-    # background of asset bar
-    # if ui_props.hcount>0:
-    #     #this fixes a draw issue introduced in blender 2.91. draws a very small version of the image to avoid problems
-    #     # with alpha. Not sure why this works.
-    #     img = utils.get_thumbnail('arrow_left.png')
-    #     ui_bgl.draw_image(0, 0, 1,
-    #                       1,
-    #                       img,
-    #                       1)
-    if ui_props.hcount > 0 and ui_props.wcount > 0:
-        search_results = bpy.context.window_manager.get('search results')
-        search_results_orig = bpy.context.window_manager.get('search results orig')
-        if search_results == None:
-            return
-        h_draw = min(ui_props.hcount, math.ceil(len(search_results) / ui_props.wcount))
-
-        if ui_props.wcount > len(search_results):
-            bar_width = len(search_results) * (ui_props.thumb_size + ui_props.margin) + ui_props.margin
-        else:
-            bar_width = ui_props.bar_width
-        row_height = ui_props.thumb_size + ui_props.margin
-        ui_bgl.draw_rect(ui_props.bar_x, ui_props.bar_y - ui_props.bar_height, bar_width,
-                         ui_props.bar_height, hc)
-
-        if search_results is not None:
-            if ui_props.scroll_offset > 0 or ui_props.wcount * ui_props.hcount < len(search_results):
-                ui_props.drawoffset = 35
-            else:
-                ui_props.drawoffset = 0
-
-            if ui_props.wcount * ui_props.hcount < len(search_results):
-                # arrows
-                arrow_y = ui_props.bar_y - int((ui_props.bar_height + ui_props.thumb_size) / 2) + ui_props.margin
-                if ui_props.scroll_offset > 0:
-
-                    if ui_props.active_index == -2:
-                        ui_bgl.draw_rect(ui_props.bar_x, ui_props.bar_y - ui_props.bar_height, 25,
-                                         ui_props.bar_height, highlight)
-                    img = utils.get_thumbnail('arrow_left.png')
-                    ui_bgl.draw_image(ui_props.bar_x, arrow_y, 25,
-                                      ui_props.thumb_size,
-                                      img,
-                                      1)
-
-                if search_results_orig['count'] - ui_props.scroll_offset > (ui_props.wcount * ui_props.hcount) + 1:
-                    if ui_props.active_index == -1:
-                        ui_bgl.draw_rect(ui_props.bar_x + ui_props.bar_width - 25,
-                                         ui_props.bar_y - ui_props.bar_height, 25,
-                                         ui_props.bar_height,
-                                         highlight)
-                    img1 = utils.get_thumbnail('arrow_right.png')
-                    ui_bgl.draw_image(ui_props.bar_x + ui_props.bar_width - 25,
-                                      arrow_y, 25,
-                                      ui_props.thumb_size, img1, 1)
-            ar = context.window_manager.get('asset ratings')
-            for b in range(0, h_draw):
-                w_draw = min(ui_props.wcount, len(search_results) - b * ui_props.wcount - ui_props.scroll_offset)
-
-                y = ui_props.bar_y - (b + 1) * (row_height)
-                for a in range(0, w_draw):
-                    x = ui_props.bar_x + a * (
-                            ui_props.margin + ui_props.thumb_size) + ui_props.margin + ui_props.drawoffset
-
-                    #
-                    index = a + ui_props.scroll_offset + b * ui_props.wcount
-                    iname = utils.previmg_name(index)
-                    img = bpy.data.images.get(iname)
-                    if img is not None and img.size[0] > 0 and img.size[1] > 0:
-                        w = int(ui_props.thumb_size * img.size[0] / max(img.size[0], img.size[1]))
-                        h = int(ui_props.thumb_size * img.size[1] / max(img.size[0], img.size[1]))
-                        crop = (0, 0, 1, 1)
-                        if img.size[0] > img.size[1]:
-                            offset = (1 - img.size[1] / img.size[0]) / 2
-                            crop = (offset, 0, 1 - offset, 1)
-
-                        ui_bgl.draw_image(x, y, w, w, img, 1,
-                                          crop=crop)
-                        if index == ui_props.active_index:
-                            ui_bgl.draw_rect(x - ui_props.highlight_margin, y - ui_props.highlight_margin,
-                                             w + 2 * ui_props.highlight_margin, w + 2 * ui_props.highlight_margin,
-                                             highlight)
-                        # if index == ui_props.active_index:
-                        #     ui_bgl.draw_rect(x - highlight_margin, y - highlight_margin,
-                        #               w + 2*highlight_margin, h + 2*highlight_margin , highlight)
-
-                    else:
-                        ui_bgl.draw_rect(x, y, ui_props.thumb_size, ui_props.thumb_size, grey2)
-                        ui_bgl.draw_text('loading', x + ui_props.thumb_size // 2, y + ui_props.thumb_size // 2,
-                                         ui_props.thumb_size // 6, white, halign='CENTER', valign='CENTER')
-
-                    result = search_results[index]
-                    # code to inform validators that the validation is waiting too long and should be done asap
-                    if result['verificationStatus'] == 'uploaded':
-                        if is_validator:
-                            over_limit = utils.is_upload_old(result)
-                            if over_limit:
-                                redness = min(over_limit * .05, 0.5)
-                                red = (1, 0, 0, redness)
-                                ui_bgl.draw_rect(x, y, ui_props.thumb_size, ui_props.thumb_size, red)
-
-                    if result['downloaded'] > 0:
-                        ui_bgl.draw_rect(x, y, int(ui_props.thumb_size * result['downloaded'] / 100.0), 2, green)
-                    # object type icons - just a test..., adds clutter/ not so userfull:
-                    # icons = ('type_finished.png', 'type_template.png', 'type_particle_system.png')
-
-                    if (result.get('canDownload', True)) == 0:
-                        img = utils.get_thumbnail('locked.png')
-                        ui_bgl.draw_image(x + 2, y + 2, 24, 24, img, 1)
-
-                    # pcoll = icons.icon_collections["main"]
-                    # v_icon = pcoll['rejected']
-                    v_icon = verification_icons[result.get('verificationStatus', 'validated')]
-
-                    if v_icon is None and is_validator:
-                        # poke for validators to rate
-                        rating = ar.get(result['id'])
-                        if rating is not None:
-                            rating = rating.to_dict()
-                        if rating in (None, {}):
-                            v_icon = 'star_grey.png'
-
-                    if v_icon is not None:
-                        img = utils.get_thumbnail(v_icon)
-                        ui_bgl.draw_image(x + ui_props.thumb_size - 26, y + 2, 24, 24, img, 1)
-
-            # if user_preferences.api_key == '':
-            #     report = 'Register on BlenderKit website to upload your own assets.'
-            #     ui_bgl.draw_text(report, ui_props.bar_x + ui_props.margin,
-            #                      ui_props.bar_y - 25 - ui_props.margin - ui_props.bar_height, 15)
-            # elif len(search_results) == 0:
-            #     report = 'BlenderKit - No matching results found.'
-            #     ui_bgl.draw_text(report, ui_props.bar_x + ui_props.margin,
-            #                      ui_props.bar_y - 25 - ui_props.margin, 15)
-            if ui_props.draw_tooltip and len(search_results) > ui_props.active_index:
-                r = search_results[ui_props.active_index]
-                draw_tooltip_with_author(r, ui_props.mouse_x, ui_props.mouse_y)
-        s = bpy.context.scene
-        props = utils.get_search_props()
-        # if props.report != '' and props.is_searching or props.search_error:
-        #     ui_bgl.draw_text(props.report, ui_props.bar_x,
-        #                      ui_props.bar_y - 15 - ui_props.margin - ui_props.bar_height, 15)
-
-
-def object_in_particle_collection(o):
-    '''checks if an object is in a particle system as instance, to not snap to it and not to try to attach material.'''
-    for p in bpy.data.particles:
-        if p.render_type == 'COLLECTION':
-            if p.instance_collection:
-                for o1 in p.instance_collection.objects:
-                    if o1 == o:
-                        return True
-        if p.render_type == 'COLLECTION':
-            if p.instance_object == o:
-                return True
-    return False
-
-
-def deep_ray_cast(depsgraph, ray_origin, vec):
-    # this allows to ignore some objects, like objects with bounding box draw style or particle objects
-    object = None
-    # while object is None or object.draw
-    has_hit, snapped_location, snapped_normal, face_index, object, matrix = bpy.context.scene.ray_cast(
-        depsgraph, ray_origin, vec)
-    empty_set = False, Vector((0, 0, 0)), Vector((0, 0, 1)), None, None, None
-    if not object:
-        return empty_set
-    try_object = object
-    while try_object and (try_object.display_type == 'BOUNDS' or object_in_particle_collection(try_object)):
-        ray_origin = snapped_location + vec.normalized() * 0.0003
-        try_has_hit, try_snapped_location, try_snapped_normal, try_face_index, try_object, try_matrix = bpy.context.scene.ray_cast(
-            depsgraph, ray_origin, vec)
-        if try_has_hit:
-            # this way only good hits are returned, otherwise
-            has_hit, snapped_location, snapped_normal, face_index, object, matrix = try_has_hit, try_snapped_location, try_snapped_normal, try_face_index, try_object, try_matrix
-    if not (object.display_type == 'BOUNDS' or object_in_particle_collection(
-            try_object)):  # or not object.visible_get()):
-        return has_hit, snapped_location, snapped_normal, face_index, object, matrix
-    return empty_set
-
-
-def mouse_raycast(context, mx, my):
-    r = context.region
-    rv3d = context.region_data
-    coord = mx, my
-    # get the ray from the viewport and mouse
-    view_vector = view3d_utils.region_2d_to_vector_3d(r, rv3d, coord)
-    if rv3d.view_perspective == 'CAMERA' and rv3d.is_perspective == False:
-        #  ortographic cameras don'w work with region_2d_to_origin_3d
-        view_position = rv3d.view_matrix.inverted().translation
-        ray_origin = view3d_utils.region_2d_to_location_3d(r, rv3d, coord, depth_location=view_position)
-    else:
-        ray_origin = view3d_utils.region_2d_to_origin_3d(r, rv3d, coord, clamp=1.0)
-
-    ray_target = ray_origin + (view_vector * 1000000000)
-
-    vec = ray_target - ray_origin
-
-    has_hit, snapped_location, snapped_normal, face_index, object, matrix = deep_ray_cast(
-        bpy.context.view_layer.depsgraph, ray_origin, vec)
-
-    # backface snapping inversion
-    if view_vector.angle(snapped_normal) < math.pi / 2:
-        snapped_normal = -snapped_normal
-    # print(has_hit, snapped_location, snapped_normal, face_index, object, matrix)
-    # rote = mathutils.Euler((0, 0, math.pi))
-    randoffset = math.pi
-    if has_hit:
-        props = bpy.context.window_manager.blenderkit_models
-        up = Vector((0, 0, 1))
-
-        if props.perpendicular_snap:
-            if snapped_normal.z > 1 - props.perpendicular_snap_threshold:
-                snapped_normal = Vector((0, 0, 1))
-            elif snapped_normal.z < -1 + props.perpendicular_snap_threshold:
-                snapped_normal = Vector((0, 0, -1))
-            elif abs(snapped_normal.z) < props.perpendicular_snap_threshold:
-                snapped_normal.z = 0
-                snapped_normal.normalize()
-
-        snapped_rotation = snapped_normal.to_track_quat('Z', 'Y').to_euler()
-
-        if props.randomize_rotation and snapped_normal.angle(up) < math.radians(10.0):
-            randoffset = props.offset_rotation_amount + math.pi + (
-                    random.random() - 0.5) * props.randomize_rotation_amount
-        else:
-            randoffset = props.offset_rotation_amount  # we don't rotate this way on walls and ceilings. + math.pi
-        # snapped_rotation.z += math.pi + (random.random() - 0.5) * .2
-
-    else:
-        snapped_rotation = mathutils.Quaternion((0, 0, 0, 0)).to_euler()
-
-    snapped_rotation.rotate_axis('Z', randoffset)
-
-    return has_hit, snapped_location, snapped_normal, snapped_rotation, face_index, object, matrix
-
-
-def floor_raycast(context, mx, my):
-    r = context.region
-    rv3d = context.region_data
-    coord = mx, my
-
-    # get the ray from the viewport and mouse
-    view_vector = view3d_utils.region_2d_to_vector_3d(r, rv3d, coord)
-    ray_origin = view3d_utils.region_2d_to_origin_3d(r, rv3d, coord)
-    ray_target = ray_origin + (view_vector * 1000)
-
-    # various intersection plane normals are needed for corner cases that might actually happen quite often - in front and side view.
-    # default plane normal is scene floor.
-    plane_normal = (0, 0, 1)
-    if math.isclose(view_vector.x, 0, abs_tol=1e-4) and math.isclose(view_vector.z, 0, abs_tol=1e-4):
-        plane_normal = (0, 1, 0)
-    elif math.isclose(view_vector.z, 0, abs_tol=1e-4):
-        plane_normal = (1, 0, 0)
-
-    snapped_location = mathutils.geometry.intersect_line_plane(ray_origin, ray_target, (0, 0, 0), plane_normal,
-                                                               False)
-    if snapped_location != None:
-        has_hit = True
-        snapped_normal = Vector((0, 0, 1))
-        face_index = None
-        object = None
-        matrix = None
-        snapped_rotation = snapped_normal.to_track_quat('Z', 'Y').to_euler()
-        props = bpy.context.window_manager.blenderkit_models
-        if props.randomize_rotation:
-            randoffset = props.offset_rotation_amount + math.pi + (
-                    random.random() - 0.5) * props.randomize_rotation_amount
-        else:
-            randoffset = props.offset_rotation_amount + math.pi
-        snapped_rotation.rotate_axis('Z', randoffset)
-
-    return has_hit, snapped_location, snapped_normal, snapped_rotation, face_index, object, matrix
-
-
-def is_rating_possible():
-    ao = bpy.context.active_object
-    ui = bpy.context.window_manager.blenderkitUI
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    # first test if user is logged in.
-    if preferences.api_key == '':
-        return False, False, None, None
-    if bpy.context.scene.get('assets rated') is not None and ui.down_up == 'SEARCH':
-        if bpy.context.mode in ('SCULPT', 'PAINT_TEXTURE'):
-            b = utils.get_active_brush()
-            ad = b.get('asset_data')
-            if ad is not None:
-                rated = bpy.context.scene['assets rated'].get(ad['assetBaseId'])
-                return True, rated, b, ad
-        if ao is not None:
-            ad = None
-            # crawl parents to reach active asset. there could have been parenting so we need to find the first onw
-            ao_check = ao
-            while ad is None or (ad is None and ao_check.parent is not None):
-                s = bpy.context.scene
-                ad = ao_check.get('asset_data')
-                if ad is not None and ad.get('assetBaseId') is not None:
-
-                    s['assets rated'] = s.get('assets rated', {})
-                    rated = s['assets rated'].get(ad['assetBaseId'])
-                    # originally hidden for already rated assets
-                    return True, rated, ao_check, ad
-                elif ao_check.parent is not None:
-                    ao_check = ao_check.parent
-                else:
-                    break
-            # check also materials
-            m = ao.active_material
-            if m is not None:
-                ad = m.get('asset_data')
-
-                if ad is not None and ad.get('assetBaseId'):
-                    rated = bpy.context.scene['assets rated'].get(ad['assetBaseId'])
-                    return True, rated, m, ad
-
-        # if t>2 and t<2.5:
-        #     ui_props.rating_on = False
-
-    return False, False, None, None
-
-
-def interact_rating(r, mx, my, event):
-    ui = bpy.context.window_manager.blenderkitUI
-    rating_possible, rated, asset, asset_data = is_rating_possible()
-    if rating_possible:
-        bkit_ratings = asset.bkit_ratings
-
-        t = time.time() - ui.last_rating_time
-        if bpy.context.mode in ('SCULPT', 'PAINT_TEXTURE'):
-            accept_value = 'PRESS'
-        else:
-            accept_value = 'RELEASE'
-
-        if ui.rating_button_on and event.type == 'LEFTMOUSE' and event.value == accept_value:
-            if mouse_in_area(mx, my,
-                             ui.rating_x,
-                             ui.rating_y - ui.rating_button_width,
-                             ui.rating_button_width * 2,
-                             ui.rating_button_width):
-                # ui.rating_menu_on = True
-                ctx = utils.get_fake_context(bpy.context, area_type='VIEW_3D')
-                bpy.ops.wm.blenderkit_menu_rating_upload(ctx, 'INVOKE_DEFAULT', asset_name=asset_data['name'],
-                                                         asset_id=asset_data['id'],
-                                                         asset_type=asset_data['assetType'])
-                return True
-    return False
-
-
-def mouse_in_area(mx, my, x, y, w, h):
-    if x < mx < x + w and y < my < y + h:
-        return True
-    else:
-        return False
-
-
-def mouse_in_asset_bar(mx, my):
-    ui_props = bpy.context.window_manager.blenderkitUI
-    # search_results = bpy.context.window_manager.get('search results')
-    # if search_results == None:
-    #     return False
-    #
-    # w_draw1 = min(ui_props.wcount + 1, len(search_results) - b * ui_props.wcount - ui_props.scroll_offset)
-    # end = ui_props.bar_x + (w_draw1) * (
-    #         ui_props.margin + ui_props.thumb_size) + ui_props.margin + ui_props.drawoffset + 25
-
-    if ui_props.bar_y - ui_props.bar_height < my < ui_props.bar_y \
-            and mx > ui_props.bar_x and mx < ui_props.bar_x + ui_props.bar_width:
-        return True
-    else:
-        return False
-
-
-def mouse_in_region(r, mx, my):
-    if 0 < my < r.height and 0 < mx < r.width:
-        return True
-    else:
-        return False
-
-
-def update_ui_size(area, region):
-    if bpy.app.background or not area:
-        return
-    ui = bpy.context.window_manager.blenderkitUI
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    ui_scale = bpy.context.preferences.view.ui_scale
-
-    ui.margin = ui.bl_rna.properties['margin'].default * ui_scale
-    ui.thumb_size = user_preferences.thumb_size * ui_scale
-
-    reg_multiplier = 1
-    if not bpy.context.preferences.system.use_region_overlap:
-        reg_multiplier = 0
-
-    for r in area.regions:
-        if r.type == 'TOOLS':
-            ui.bar_x = r.width * reg_multiplier + ui.margin + ui.bar_x_offset * ui_scale
-        elif r.type == 'UI':
-            ui.bar_end = r.width * reg_multiplier + 100 * ui_scale
-
-    ui.bar_width = region.width - ui.bar_x - ui.bar_end
-    ui.wcount = math.floor(
-        (ui.bar_width - 2 * ui.drawoffset) / (ui.thumb_size + ui.margin))
-
-    search_results = bpy.context.window_manager.get('search results')
-    if search_results != None and ui.wcount > 0:
-        ui.hcount = min(user_preferences.max_assetbar_rows, math.ceil(len(search_results) / ui.wcount))
-    else:
-        ui.hcount = 1
-    ui.bar_height = (ui.thumb_size + ui.margin) * ui.hcount + ui.margin
-    ui.bar_y = region.height - ui.bar_y_offset * ui_scale
-    if ui.down_up == 'UPLOAD':
-        ui.reports_y = ui.bar_y - 600
-        ui.reports_x = ui.bar_x
-    else:
-        ui.reports_y = ui.bar_y - ui.bar_height - 100
-        ui.reports_x = ui.bar_x
-
-    ui.rating_x = ui.bar_x
-    ui.rating_y = ui.bar_y - ui.bar_height
-
-
-class ParticlesDropDialog(bpy.types.Operator):
-    """Tooltip"""
-    bl_idname = "object.blenderkit_particles_drop"
-    bl_label = "BlenderKit particle plants object drop"
-    bl_options = {'REGISTER', 'INTERNAL'}
-
-    asset_search_index: IntProperty(name="Asset index",
-                                    description="Index of the asset in asset bar",
-                                    default=0,
-                                    )
-
-    model_location: FloatVectorProperty(name="Location",
-                                        default=(0, 0, 0))
-
-    model_rotation: FloatVectorProperty(name="Rotation",
-                                        default=(0, 0, 0),
-                                        subtype='QUATERNION')
-
-    target_object: StringProperty(
-        name="Target object",
-        description="The object to which the particles will get applied",
-        default="", options={'SKIP_SAVE'})
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def draw(self, context):
-        layout = self.layout
-        message = 'This asset is a particle setup. BlenderKit can apply particles to the active/drag-drop object.' \
-                  'The number of particles is caluclated automatically, but if there are 2 many particles,' \
-                  ' BlenderKit can do the following steps to make sure Blender continues to run:' \
-                  '\n1.Switch to bounding box view of the particles.' \
-                  '\n2.Turn down number of particles that are shown in the view.' \
-                  '\n3.Hide the particle system completely from the 3D view.' \
-                  "as a result of this, it's possible you'll see the particle setup only in render view or " \
-                  "rendered images. You should still be careful and test particle systems on smaller objects first."
-        utils.label_multiline(layout, text=message, width=400)
-
-    def execute(self, context):
-        bpy.ops.scene.blenderkit_download(True,
-                                          # asset_type=ui_props.asset_type,
-                                          asset_index=self.asset_search_index,
-                                          model_location=self.model_rotation,
-                                          model_rotation=self.model_rotation,
-                                          target_object=self.target_object)
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-        return wm.invoke_props_dialog(self, width=400)
-
-
-# class MaterialDropDialog(bpy.types.Operator):
-#     """Tooltip"""
-#     bl_idname = "object.blenderkit_material_drop"
-#     bl_label = "BlenderKit material drop on linked objects"
-#     bl_options = {'REGISTER', 'INTERNAL'}
-#
-#     asset_search_index: IntProperty(name="Asset index",
-#                                     description="Index of the asset in asset bar",
-#                                     default=0,
-#                                     )
-#
-#     model_location: FloatVectorProperty(name="Location",
-#                                         default=(0, 0, 0))
-#
-#     model_rotation: FloatVectorProperty(name="Rotation",
-#                                         default=(0, 0, 0),
-#                                         subtype='QUATERNION')
-#
-#     target_object: StringProperty(
-#         name="Target object",
-#         description="The object to which the particles will get applied",
-#         default="", options={'SKIP_SAVE'})
-#
-#     target_material_slot: IntProperty(name="Target material slot",
-#                                     description="Index of the material on the object to be changed",
-#                                     default=0,
-#                                     )
-#
-#     @classmethod
-#     def poll(cls, context):
-#         return True
-#
-#     def draw(self, context):
-#         layout = self.layout
-#         message = "This asset is linked to the scene from an external file and cannot have material appended." \
-#                   " Do you want to bring it into Blender Scene?"
-#         utils.label_multiline(layout, text=message, width=400)
-#
-#     def execute(self, context):
-#         for c in bpy.data.collections:
-#             for o in c.objects:
-#                 if o.name != self.target_object:
-#                     continue;
-#                 for empty in bpy.context.visible_objects:
-#                     if not(empty.instance_type == 'COLLECTION' and empty.instance_collection == c):
-#                         continue;
-#                     utils.activate(empty)
-#                     break;
-#         bpy.ops.object.blenderkit_bring_to_scene()
-#         bpy.ops.scene.blenderkit_download(True,
-#                                           # asset_type=ui_props.asset_type,
-#                                           asset_index=self.asset_search_index,
-#                                           model_location=self.model_rotation,
-#                                           model_rotation=self.model_rotation,
-#                                           target_object=self.target_object,
-#                                           material_target_slot = self.target_slot)
-#         return {'FINISHED'}
-#
-#     def invoke(self, context, event):
-#         wm = context.window_manager
-#         return wm.invoke_props_dialog(self, width=400)
-
-class AssetBarOperator(bpy.types.Operator):
-    '''runs search and displays the asset bar at the same time'''
-    bl_idname = "view3d.blenderkit_asset_bar"
-    bl_label = "BlenderKit Asset Bar UI"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    do_search: BoolProperty(name="Run Search", description='', default=True, options={'SKIP_SAVE'})
-    keep_running: BoolProperty(name="Keep Running", description='', default=True, options={'SKIP_SAVE'})
-    free_only: BoolProperty(name="Free first", description='', default=False, options={'SKIP_SAVE'})
-
-    category: StringProperty(
-        name="Category",
-        description="search only subtree of this category",
-        default="", options={'SKIP_SAVE'})
-
-    tooltip: bpy.props.StringProperty(default='runs search and displays the asset bar at the same time')
-
-    @classmethod
-    def description(cls, context, properties):
-        return properties.tooltip
-
-    def search_more(self):
-        sro = bpy.context.window_manager.get('search results orig')
-        if sro is None:
-            return;
-        if sro.get('next') is None:
-            return
-        search_props = utils.get_search_props()
-        if search_props.is_searching:
-            return
-
-        search.search(get_next=True)
-
-    def exit_modal(self):
-        try:
-            bpy.types.SpaceView3D.draw_handler_remove(self._handle_2d, 'WINDOW')
-        except:
-            pass;
-        ui_props = bpy.context.window_manager.blenderkitUI
-
-        # ui_props.tooltip = ''
-        ui_props.active_index = -3
-        ui_props.draw_drag_image = False
-        ui_props.draw_snapped_bounds = False
-        ui_props.has_hit = False
-        ui_props.assetbar_on = False
-
-    def modal(self, context, event):
-
-        # This is for case of closing the area or changing type:
-        ui_props = context.window_manager.blenderkitUI
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-        areas = []
-
-        # timers testing - seems timers might be causing crashes. testing it this way now.
-        if not user_preferences.use_timers:
-            search.search_timer()
-            download.download_timer()
-            tasks_queue.queue_worker()
-            bg_blender.bg_update()
-
-        if bpy.context.scene != self.scene:
-            self.exit_modal()
-            return {'CANCELLED'}
-
-        for w in context.window_manager.windows:
-            areas.extend(w.screen.areas)
-
-        if self.area not in areas or self.area.type != 'VIEW_3D' or self.has_quad_views != (
-                len(self.area.spaces[0].region_quadviews) > 0):
-            # print('search areas')   bpy.context.area.spaces[0].region_quadviews
-            # stopping here model by now - because of:
-            #   switching layouts or maximizing area now fails to assign new area throwing the bug
-            #   internal error: modal gizmo-map handler has invalid area
-            self.exit_modal()
-            return {'CANCELLED'}
-
-            newarea = None
-            for a in context.window.screen.areas:
-                if a.type == 'VIEW_3D':
-                    self.area = a
-                    for r in a.regions:
-                        if r.type == 'WINDOW':
-                            self.region = r
-                    newarea = a
-                    break
-                    # context.area = a
-
-            # we check again and quit if things weren't fixed this way.
-            if newarea == None:
-                self.exit_modal()
-                return {'CANCELLED'}
-
-        update_ui_size(self.area, self.region)
-
-        # this was here to check if sculpt stroke is running, but obviously that didn't help,
-        #  since the RELEASE event is cought by operator and thus there is no way to detect a stroke has ended...
-        if bpy.context.mode in ('SCULPT', 'PAINT_TEXTURE'):
-            if event.type == 'MOUSEMOVE':  # ASSUME THAT SCULPT OPERATOR ACTUALLY STEALS THESE EVENTS,
-                # SO WHEN THERE ARE SOME WE CAN APPEND BRUSH...
-                bpy.context.window_manager['appendable'] = True
-            if event.type == 'LEFTMOUSE':
-                if event.value == 'PRESS':
-                    bpy.context.window_manager['appendable'] = False
-
-        self.area.tag_redraw()
-        s = context.scene
-
-        if ui_props.turn_off:
-            ui_props.turn_off = False
-            self.exit_modal()
-            ui_props.draw_tooltip = False
-            return {'CANCELLED'}
-
-        if context.region != self.region:
-            # print(time.time(), 'pass through because of region')
-            # print(context.region.type, self.region.type)
-            return {'PASS_THROUGH'}
-
-        if ui_props.down_up == 'UPLOAD':
-
-            ui_props.mouse_x = 0
-            ui_props.mouse_y = self.region.height
-
-            ui_props.draw_tooltip = True
-
-            # only generate tooltip once in a while
-            if (
-                    event.type == 'LEFTMOUSE' or event.type == 'RIGHTMOUSE') and event.value == 'RELEASE' or event.type == 'ENTER':
-                ao = bpy.context.active_object
-                if ui_props.asset_type == 'MODEL' and ao != None \
-                        or ui_props.asset_type == 'MATERIAL' and ao != None and ao.active_material != None \
-                        or ui_props.asset_type == 'BRUSH' and utils.get_active_brush() is not None \
-                        or ui_props.asset_type == 'SCENE' or ui_props.asset_type == 'HDR':
-                    export_data, upload_data = upload.get_upload_data(context=context, asset_type=ui_props.asset_type)
-                    # if upload_data:
-                    #     # print(upload_data)
-                    #     ui_props.tooltip = upload_data['displayName']  # search.generate_tooltip(upload_data)
-
-            return {'PASS_THROUGH'}
-
-        # TODO add one more condition here to take less performance.
-        r = self.region
-        s = bpy.context.scene
-        sr = bpy.context.window_manager.get('search results')
-        search_results_orig = bpy.context.window_manager.get('search results orig')
-        # If there aren't any results, we need no interaction(yet)
-        if sr is None:
-            return {'PASS_THROUGH'}
-        if len(sr) - ui_props.scroll_offset < (ui_props.wcount * user_preferences.max_assetbar_rows) + 15:
-            self.search_more()
-
-        if event.type == 'WHEELUPMOUSE' or event.type == 'WHEELDOWNMOUSE' or event.type == 'TRACKPADPAN':
-            # scrolling
-            mx = event.mouse_region_x
-            my = event.mouse_region_y
-
-            if not mouse_in_asset_bar(mx, my):
-                return {'PASS_THROUGH'}
-
-            # note - TRACKPADPAN is unsupported in blender by now.
-            # if event.type == 'TRACKPADPAN' :
-            #     print(dir(event))
-            #     print(event.value, event.oskey, event.)
-            if (event.type == 'WHEELDOWNMOUSE') and len(sr) - ui_props.scroll_offset > (
-                    ui_props.wcount * ui_props.hcount):
-                if ui_props.hcount > 1:
-                    ui_props.scroll_offset += ui_props.wcount
-                else:
-                    ui_props.scroll_offset += 1
-                if len(sr) - ui_props.scroll_offset < (ui_props.wcount * ui_props.hcount):
-                    ui_props.scroll_offset = len(sr) - (ui_props.wcount * ui_props.hcount)
-
-            if event.type == 'WHEELUPMOUSE' and ui_props.scroll_offset > 0:
-                if ui_props.hcount > 1:
-                    ui_props.scroll_offset -= ui_props.wcount
-                else:
-                    ui_props.scroll_offset -= 1
-                if ui_props.scroll_offset < 0:
-                    ui_props.scroll_offset = 0
-
-            return {'RUNNING_MODAL'}
-        if event.type == 'MOUSEMOVE':  # Apply
-
-            r = self.region
-            mx = event.mouse_region_x
-            my = event.mouse_region_y
-
-            ui_props.mouse_x = mx
-            ui_props.mouse_y = my
-
-            if not mouse_in_asset_bar(mx, my):  #
-
-                ui_props.active_index = -3
-                ui_props.draw_drag_image = False
-                ui_props.draw_snapped_bounds = False
-                ui_props.draw_tooltip = False
-                bpy.context.window.cursor_set("DEFAULT")
-                return {'PASS_THROUGH'}
-
-            sr = bpy.context.window_manager['search results']
-
-            bpy.context.window.cursor_set("HAND")
-
-            if sr != None and ui_props.wcount * ui_props.hcount > len(sr) and ui_props.scroll_offset > 0:
-                ui_props.scroll_offset = 0
-
-            asset_search_index = get_asset_under_mouse(mx, my)
-            ui_props.active_index = asset_search_index
-            if asset_search_index > -1:
-
-                asset_data = sr[asset_search_index]
-                ui_props.draw_tooltip = True
-
-                # ui_props.tooltip = asset_data['tooltip']
-                # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_asset_menu')
-
-            else:
-                ui_props.draw_tooltip = False
-
-            if mx > ui_props.bar_x + ui_props.bar_width - 50 and search_results_orig[
-                'count'] - ui_props.scroll_offset > (
-                    ui_props.wcount * ui_props.hcount) + 1:
-                ui_props.active_index = -1
-                return {'RUNNING_MODAL'}
-            if mx < ui_props.bar_x + 50 and ui_props.scroll_offset > 0:
-                ui_props.active_index = -2
-                return {'RUNNING_MODAL'}
-
-            return {'RUNNING_MODAL'}
-
-        if event.type == 'RIGHTMOUSE':
-            mx = event.mouse_x - r.x
-            my = event.mouse_y - r.y
-
-            if event.value == 'PRESS' and mouse_in_asset_bar(mx, my) and ui_props.active_index > -1:
-                # context.window.cursor_warp(event.mouse_x - 300, event.mouse_y - 10);
-
-                bpy.ops.wm.blenderkit_asset_popup('INVOKE_DEFAULT')
-                # context.window.cursor_warp(event.mouse_x, event.mouse_y);
-
-                # bpy.ops.wm.call_menu(name='OBJECT_MT_blenderkit_asset_menu')
-                return {'RUNNING_MODAL'}
-
-        if event.type == 'LEFTMOUSE':
-
-            r = self.region
-            mx = event.mouse_region_x
-            my = event.mouse_region_y
-
-            ui_props = context.window_manager.blenderkitUI
-            if event.value == 'PRESS' and ui_props.active_index > -1:
-                # start dragging models and materials
-                bpy.ops.view3d.asset_drag_drop('INVOKE_DEFAULT',
-                                               asset_search_index=ui_props.active_index)
-                # ui_props.draw_tooltip = False
-
-            if ui_props.rating_on:
-                res = interact_rating(r, mx, my, event)
-                if res:
-                    return {'RUNNING_MODAL'}
-
-            if not mouse_in_asset_bar(mx, my):
-                return {'PASS_THROUGH'}
-
-            # this can happen by switching result asset types - length of search result changes
-            if ui_props.scroll_offset > 0 and (ui_props.wcount * ui_props.hcount) > len(sr) - ui_props.scroll_offset:
-                ui_props.scroll_offset = len(sr) - (ui_props.wcount * ui_props.hcount)
-
-            if event.value == 'RELEASE':  # Confirm
-                # ui_props.drag_init = False
-
-                # scroll with buttons by a whole page
-                if mx > ui_props.bar_x + ui_props.bar_width - 50 and len(
-                        sr) - ui_props.scroll_offset > ui_props.wcount * ui_props.hcount:
-                    ui_props.scroll_offset = min(
-                        ui_props.scroll_offset + (ui_props.wcount * ui_props.hcount),
-                        len(sr) - ui_props.wcount * ui_props.hcount)
-                    return {'RUNNING_MODAL'}
-                if mx < ui_props.bar_x + 50 and ui_props.scroll_offset > 0:
-                    ui_props.scroll_offset = max(0, ui_props.scroll_offset - ui_props.wcount * ui_props.hcount)
-                    return {'RUNNING_MODAL'}
-
-                if ui_props.active_index == -3:
-                    return {'RUNNING_MODAL'}
-            else:
-                return {'RUNNING_MODAL'}
-
-        if event.type == 'W' and ui_props.active_index > -1:
-            sr = bpy.context.window_manager['search results']
-            asset_data = sr[ui_props.active_index]
-            a = bpy.context.window_manager['bkit authors'].get(asset_data['author']['id'])
-            if a is not None:
-                utils.p('author:', a)
-                if a.get('aboutMeUrl') is not None:
-                    bpy.ops.wm.url_open(url=a['aboutMeUrl'])
-            return {'RUNNING_MODAL'}
-        if event.type == 'A' and ui_props.active_index > -1:
-            sr = bpy.context.window_manager['search results']
-            asset_data = sr[ui_props.active_index]
-            a = asset_data['author']['id']
-            if a is not None:
-                sprops = utils.get_search_props()
-                sprops.search_keywords = ''
-                sprops.search_verification_status = 'ALL'
-                utils.p('author:', a)
-                search.search(author_id=a)
-            return {'RUNNING_MODAL'}
-
-        if event.type == 'X' and ui_props.active_index > -1:
-            # delete downloaded files for this asset
-            sr = bpy.context.window_manager['search results']
-            asset_data = sr[ui_props.active_index]
-            bk_logger.info('delete asset from local drive:' + asset_data['name'])
-            paths.delete_asset_debug(asset_data)
-            asset_data['downloaded'] = 0
-            return {'RUNNING_MODAL'}
-        return {'PASS_THROUGH'}
-
-    def invoke(self, context, event):
-        # FIRST START SEARCH
-        ui_props = context.window_manager.blenderkitUI
-        sr = bpy.context.window_manager.get('search results')
-
-        if self.do_search:
-            # we erase search keywords for cateogry search now, since these combinations usually return nothing now.
-            # when the db gets bigger, this can be deleted.
-            if self.category != '':
-                sprops = utils.get_search_props()
-                sprops.search_keywords = ''
-            search.search(category=self.category)
-
-        if ui_props.assetbar_on:
-            # we don't want to run the assetbar more than once, that's why it has a switch on/off behaviour,
-            # unless being called with 'keep_running' prop.
-            if not self.keep_running:
-                # this sends message to the originally running operator, so it quits, and then it ends this one too.
-                # If it initiated a search, the search will finish in a thread. The switch off procedure is run
-                # by the 'original' operator, since if we get here, it means
-                # same operator is already running.
-                ui_props.turn_off = True
-                # if there was an error, we need to turn off these props so we can restart after 2 clicks
-                ui_props.assetbar_on = False
-
-            else:
-                pass
-            return {'FINISHED'}
-
-        ui_props.dragging = False  # only for cases where assetbar ended with an error.
-        ui_props.assetbar_on = True
-        ui_props.turn_off = False
-
-        if sr is None:
-            bpy.context.window_manager['search results'] = []
-
-        if context.area.type != 'VIEW_3D':
-            self.report({'WARNING'}, "View3D not found, cannot run operator")
-            return {'CANCELLED'}
-
-        # the arguments we pass the the callback
-        args = (self, context)
-
-        self.window = context.window
-        self.area = context.area
-        self.scene = bpy.context.scene
-
-        self.has_quad_views = len(bpy.context.area.spaces[0].region_quadviews) > 0
-
-        for r in self.area.regions:
-            if r.type == 'WINDOW':
-                self.region = r
-
-        global active_window_pointer, active_area_pointer, active_region_pointer
-        active_window_pointer = self.window.as_pointer()
-        active_area_pointer = self.area.as_pointer()
-        active_region_pointer = self.region.as_pointer()
-
-        update_ui_size(self.area, self.region)
-
-        self._handle_2d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_2d, args, 'WINDOW', 'POST_PIXEL')
-
-        ui_props.assetbar_on = True
-
-        # in an exceptional case these were accessed before  drag start.
-        self.drag_start_x = 0
-        self.drag_start_y = 0
-
-        context.window_manager.modal_handler_add(self)
-        return {'RUNNING_MODAL'}
-
-    def execute(self, context):
-        return {'RUNNING_MODAL'}
-
-
-class TransferBlenderkitData(bpy.types.Operator):
-    """Regenerate cobweb"""
-    bl_idname = "object.blenderkit_data_trasnfer"
-    bl_label = "Transfer BlenderKit data"
-    bl_description = "Transfer blenderKit metadata from one object to another when fixing uploads with wrong parenting"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def execute(self, context):
-        source_ob = bpy.context.active_object
-        for target_ob in bpy.context.selected_objects:
-            if target_ob != source_ob:
-                target_ob.property_unset('blenderkit')
-                for k in source_ob.keys():
-                    target_ob[k] = source_ob[k]
-        source_ob.property_unset('blenderkit')
-        return {'FINISHED'}
-
-
-class UndoWithContext(bpy.types.Operator):
-    """Regenerate cobweb"""
-    bl_idname = "wm.undo_push_context"
-    bl_label = "BlnenderKit undo push"
-    bl_description = "BlenderKit undo push with fixed context"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    # def modal(self, context, event):
-    #     return {'RUNNING_MODAL'}
-
-    message: StringProperty('Undo Message', default='BlenderKit operation')
-
-    def execute(self, context):
-        # C_dict = utils.get_fake_context(context)
-        # w, a, r = get_largest_area(area_type=area_type)
-        # wm = bpy.context.window_manager#bpy.data.window_managers[0]
-        # w = wm.windows[0]
-        #
-        # C_dict = {'window': w, 'screen': w.screen}
-        # bpy.ops.ed.undo_push(C_dict, 'INVOKE_REGION_WIN', message=self.message)
-        # bpy.ops.ed.undo_push('INVOKE_REGION_WIN', message=self.message)
-
-        return {'FINISHED'}
-
-
-def draw_callback_dragging(self, context):
-    try:
-        img = bpy.data.images.get(self.iname)
-    except:
-        #  self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_dragging, args, 'WINDOW', 'POST_PIXEL')
-        #  self._handle_3d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_3d_dragging, args, 'WINDOW',
-        #   bpy.types.SpaceView3D.draw_handler_remove(self._handle,
-        # bpy.types.SpaceView3D.draw_handler_remove(self._handle_3d, 'WINDOW')
-
-        return
-    linelength = 35
-    scene = bpy.context.scene
-    ui_props = bpy.context.window_manager.blenderkitUI
-    ui_bgl.draw_image(self.mouse_x + linelength, self.mouse_y - linelength - ui_props.thumb_size,
-                      ui_props.thumb_size, ui_props.thumb_size, img, 1)
-    ui_bgl.draw_line2d(self.mouse_x, self.mouse_y, self.mouse_x + linelength,
-                       self.mouse_y - linelength, 2, colors.WHITE)
-
-
-def draw_callback_3d_dragging(self, context):
-    ''' Draw snapped bbox while dragging. '''
-    if not utils.guard_from_crash():
-        return
-    ui_props = context.window_manager.blenderkitUI
-    # print(ui_props.asset_type, self.has_hit, self.snapped_location)
-    if ui_props.asset_type == 'MODEL':
-        if self.has_hit:
-            draw_bbox(self.snapped_location, self.snapped_rotation, self.snapped_bbox_min, self.snapped_bbox_max)
-
-
-def find_and_activate_instancers(object):
-    for ob in bpy.context.visible_objects:
-        if ob.instance_type == 'COLLECTION' and ob.instance_collection and object.name in ob.instance_collection.objects:
-            utils.activate(ob)
-            return ob
-
-
-class AssetDragOperator(bpy.types.Operator):
-    """Drag & drop assets into scene"""
-    bl_idname = "view3d.asset_drag_drop"
-    bl_label = "BlenderKit asset drag drop"
-
-    asset_search_index: IntProperty(name="Active Index", default=0)
-    drag_length: IntProperty(name="Drag_length", default=0)
-
-    object_name = None
-
-    def handlers_remove(self):
-        bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
-        bpy.types.SpaceView3D.draw_handler_remove(self._handle_3d, 'WINDOW')
-
-    def mouse_release(self):
-        scene = bpy.context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-
-        if ui_props.asset_type == 'MODEL':
-            if not self.drag:
-                self.snapped_location = scene.cursor.location
-                self.snapped_rotation = (0, 0, 0)
-
-            target_object = ''
-            if self.object_name is not None:
-                target_object = self.object_name
-                target_slot = ''
-
-            if 'particle_plants' in self.asset_data['tags']:
-                bpy.ops.object.blenderkit_particles_drop("INVOKE_DEFAULT",
-                                                         asset_search_index=self.asset_search_index,
-                                                         model_location=self.snapped_location,
-                                                         model_rotation=self.snapped_rotation,
-                                                         target_object=target_object)
-            else:
-                bpy.ops.scene.blenderkit_download(True,
-                                                  # asset_type=ui_props.asset_type,
-                                                  asset_index=self.asset_search_index,
-                                                  model_location=self.snapped_location,
-                                                  model_rotation=self.snapped_rotation,
-                                                  target_object=target_object)
-        if ui_props.asset_type == 'MATERIAL':
-            object = None
-            target_object = ''
-            target_slot = ''
-            if not self.drag:
-                # click interaction
-                object = bpy.context.active_object
-                if object is None:
-                    ui_panels.ui_message(title='Nothing selected',
-                                         message=f"Select something to assign materials by clicking.")
-                    return
-                target_object = object.name
-                target_slot = object.active_material_index
-                self.snapped_location = object.location
-            elif self.object_name is not None and self.has_hit:
-
-                # first, test if object can have material applied.
-                object = bpy.data.objects[self.object_name]
-                # this enables to run Bring to scene automatically when dropping on a linked objects.
-                # it's however quite a slow operation, that's why not enabled (and finished) now.
-                # if object is not None and object.is_library_indirect:
-                #     find_and_activate_instancers(object)
-                #     bpy.ops.object.blenderkit_bring_to_scene()
-                if object is not None and \
-                        not object.is_library_indirect and \
-                        object.type in utils.supported_material_drag:
-
-                    target_object = object.name
-                    # create final mesh to extract correct material slot
-                    depsgraph = bpy.context.evaluated_depsgraph_get()
-                    object_eval = object.evaluated_get(depsgraph)
-
-                    if object.type == 'MESH':
-                        temp_mesh = object_eval.to_mesh()
-                        target_slot = temp_mesh.polygons[self.face_index].material_index
-                        object_eval.to_mesh_clear()
-                    else:
-                        ui_props.snapped_location = object.location
-                        target_slot = object.active_material_index
-
-            if not object:
-                return
-            if object.is_library_indirect:
-                ui_panels.ui_message(title='This object is linked from outer file',
-                                     message="Please select the model,"
-                                             "go to the 'Selected Model' panel "
-                                             "in BlenderKit and hit 'Bring to Scene' first.")
-                return
-            if object.type not in utils.supported_material_drag:
-                if object.type in utils.supported_material_click:
-                    ui_panels.ui_message(title='Unsupported object type',
-                                         message=f"Use click interaction for {object.type.lower()} object.")
-                    return
-                else:
-                    ui_panels.ui_message(title='Unsupported object type',
-                                         message=f"Can't assign materials to {object.type.lower()} object.")
-                    return
-
-            if target_object != '':
-                # position is for downloader:
-                loc = self.snapped_location
-                rotation = (0, 0, 0)
-
-                utils.automap(target_object, target_slot=target_slot,
-                              tex_size=self.asset_data.get('texture_size_meters', 1.0))
-                bpy.ops.scene.blenderkit_download(True,
-                                                  # asset_type=ui_props.asset_type,
-                                                  asset_index=self.asset_search_index,
-                                                  model_location=loc,
-                                                  model_rotation=rotation,
-                                                  target_object=target_object,
-                                                  material_target_slot=target_slot)
-
-        if ui_props.asset_type == 'HDR':
-            bpy.ops.scene.blenderkit_download('INVOKE_DEFAULT',
-                                              asset_index=self.asset_search_index,
-                                              # replace_resolution=True,
-                                              invoke_resolution=True,
-                                              max_resolution=self.asset_data.get('max_resolution', 0)
-                                              )
-
-        if ui_props.asset_type == 'SCENE':
-            bpy.ops.scene.blenderkit_download('INVOKE_DEFAULT',
-                                              asset_index=self.asset_search_index,
-                                              # replace_resolution=True,
-                                              invoke_resolution=False,
-                                              invoke_scene_settings=True
-                                              )
-
-        if ui_props.asset_type == 'BRUSH':
-            bpy.ops.scene.blenderkit_download(  # asset_type=ui_props.asset_type,
-                asset_index=self.asset_search_index,
-            )
-
-    def modal(self, context, event):
-        scene = bpy.context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        context.area.tag_redraw()
-
-        # if event.type == 'MOUSEMOVE':
-        if not hasattr(self, 'start_mouse_x'):
-            self.start_mouse_x = event.mouse_region_x
-            self.start_mouse_y = event.mouse_region_y
-
-        self.mouse_x = event.mouse_region_x
-        self.mouse_y = event.mouse_region_y
-
-        # are we dragging already?
-        drag_threshold = 10
-        if not self.drag and \
-                (abs(self.start_mouse_x - self.mouse_x) > drag_threshold or \
-                 abs(self.start_mouse_y - self.mouse_y) > drag_threshold):
-            self.drag = True
-
-        if self.drag and ui_props.assetbar_on:
-            # turn off asset bar here, shout start again after finishing drag drop.
-            ui_props.turn_off = True
-
-        if (event.type == 'ESC' or \
-            not mouse_in_region(context.region, self.mouse_x, self.mouse_y)) and \
-                (not self.drag or self.steps < 5):
-            # this case is for canceling from inside popup card when there's an escape attempt to close the window
-            return {'PASS_THROUGH'}
-
-        if event.type in {'RIGHTMOUSE', 'ESC'} or \
-                not mouse_in_region(context.region, self.mouse_x, self.mouse_y):
-            self.handlers_remove()
-            bpy.context.window.cursor_set("DEFAULT")
-            ui_props.dragging = False
-            bpy.ops.view3d.blenderkit_asset_bar_widget('INVOKE_REGION_WIN',
-                                                       do_search=False)
-
-            return {'CANCELLED'}
-
-        sprops = bpy.context.window_manager.blenderkit_models
-        if event.type == 'WHEELUPMOUSE':
-            sprops.offset_rotation_amount += sprops.offset_rotation_step
-            return {'RUNNING_MODAL'}
-        elif event.type == 'WHEELDOWNMOUSE':
-            sprops.offset_rotation_amount -= sprops.offset_rotation_step
-            return {'RUNNING_MODAL'}
-
-        if event.type == 'MOUSEMOVE':
-
-            #### TODO - this snapping code below is 3x in this file.... refactor it.
-            self.has_hit, self.snapped_location, self.snapped_normal, self.snapped_rotation, self.face_index, object, self.matrix = mouse_raycast(
-                context, event.mouse_region_x, event.mouse_region_y)
-            if object is not None:
-                self.object_name = object.name
-
-            # MODELS can be dragged on scene floor
-            if not self.has_hit and ui_props.asset_type == 'MODEL':
-                self.has_hit, self.snapped_location, self.snapped_normal, self.snapped_rotation, self.face_index, object, self.matrix = floor_raycast(
-                    context,
-                    event.mouse_region_x, event.mouse_region_y)
-                if object is not None:
-                    self.object_name = object.name
-
-            if ui_props.asset_type == 'MODEL':
-                self.snapped_bbox_min = Vector(self.asset_data['bbox_min'])
-                self.snapped_bbox_max = Vector(self.asset_data['bbox_max'])
-            #return {'RUNNING_MODAL'}
-
-        if event.type == 'LEFTMOUSE' and event.value == 'RELEASE':
-            self.mouse_release()  # does the main job with assets
-            self.handlers_remove()
-            bpy.context.window.cursor_set("DEFAULT")
-
-            bpy.ops.object.run_assetbar_fix_context(keep_running=True, do_search=False)
-            ui_props.dragging = False
-            return {'FINISHED'}
-
-        self.steps += 1
-
-        #pass event to assetbar so it can close itself
-        if ui_props.assetbar_on and ui_props.turn_off:
-                return {'PASS_THROUGH'}
-
-        return {'RUNNING_MODAL'}
-
-    def invoke(self, context, event):
-        if context.area.type == 'VIEW_3D':
-            # the arguments we pass the the callback
-            args = (self, context)
-            # Add the region OpenGL drawing callback
-            # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
-            self.iname = utils.previmg_name(self.asset_search_index)
-
-            self.mouse_x = 0
-            self.mouse_y = 0
-            self.steps = 0
-
-            self.has_hit = False
-            self.snapped_location = (0, 0, 0)
-            self.snapped_normal = (0, 0, 1)
-            self.snapped_rotation = (0, 0, 0)
-            self.face_index = 0
-            object = None
-            self.matrix = None
-
-            sr = bpy.context.window_manager['search results']
-            self.asset_data = sr[self.asset_search_index]
-
-            if not self.asset_data.get('canDownload'):
-                message = "Let's support asset creators and Open source."
-                link_text = 'Unlock the asset.'
-                url = paths.get_bkit_url() + '/get-blenderkit/' + self.asset_data['id'] + '/?from_addon=True'
-                bpy.ops.wm.blenderkit_url_dialog('INVOKE_REGION_WIN', url=url, message=message,
-                                                 link_text=link_text)
-
-                return {'CANCELLED'}
-
-            self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_dragging, args, 'WINDOW', 'POST_PIXEL')
-            self._handle_3d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_3d_dragging, args, 'WINDOW',
-                                                                     'POST_VIEW')
-
-            bpy.context.window.cursor_set("NONE")
-            ui_props = bpy.context.window_manager.blenderkitUI
-            ui_props.dragging = True
-            self.drag = False
-            context.window_manager.modal_handler_add(self)
-            return {'RUNNING_MODAL'}
-        else:
-            self.report({'WARNING'}, "View3D not found, cannot run operator")
-            return {'CANCELLED'}
-
-
-class RunAssetBarWithContext(bpy.types.Operator):
-    """Regenerate cobweb"""
-    bl_idname = "object.run_assetbar_fix_context"
-    bl_label = "BlnenderKit assetbar with fixed context"
-    bl_description = "Run assetbar with fixed context"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    keep_running: BoolProperty(name="Keep Running", description='', default=True, options={'SKIP_SAVE'})
-    do_search: BoolProperty(name="Run Search", description='', default=False, options={'SKIP_SAVE'})
-
-    # def modal(self, context, event):
-    #     return {'RUNNING_MODAL'}
-
-    def execute(self, context):
-        C_dict = utils.get_fake_context(context)
-        if C_dict.get('window'):  # no 3d view, no asset bar.
-            preferences = bpy.context.preferences.addons['blenderkit'].preferences
-            if 1:#preferences.experimental_features:
-                bpy.ops.view3d.blenderkit_asset_bar_widget(C_dict, 'INVOKE_REGION_WIN', keep_running=self.keep_running,
-                                                           do_search=self.do_search)
-
-            else:
-                bpy.ops.view3d.blenderkit_asset_bar(C_dict, 'INVOKE_REGION_WIN', keep_running=self.keep_running,
-                                                    do_search=self.do_search)
-        return {'FINISHED'}
-
-
-classes = (
-    AssetBarOperator,
-    # AssetBarExperiment,
-    AssetDragOperator,
-    RunAssetBarWithContext,
-    TransferBlenderkitData,
-    UndoWithContext,
-    ParticlesDropDialog
-)
-
-# store keymap items here to access after registration
-addon_keymapitems = []
-
-
-# @persistent
-def pre_load(context):
-    ui_props = bpy.context.window_manager.blenderkitUI
-    ui_props.assetbar_on = False
-    ui_props.turn_off = True
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    preferences.login_attempt = False
-
-
-def register_ui():
-    global handler_2d, handler_3d
-
-    for c in classes:
-        bpy.utils.register_class(c)
-
-    args = (None, bpy.context)
-
-    handler_2d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_2d_progress, args, 'WINDOW', 'POST_PIXEL')
-    handler_3d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_3d_progress, args, 'WINDOW', 'POST_VIEW')
-
-    wm = bpy.context.window_manager
-
-    # spaces solved by registering shortcut to Window. Couldn't register object mode before somehow.
-    if not wm.keyconfigs.addon:
-        return
-    km = wm.keyconfigs.addon.keymaps.new(name="Window", space_type='EMPTY')
-    # asset bar shortcut
-    kmi = km.keymap_items.new("object.run_assetbar_fix_context", 'SEMI_COLON', 'PRESS', ctrl=False, shift=False)
-    kmi.properties.keep_running = False
-    kmi.properties.do_search = False
-    addon_keymapitems.append(kmi)
-    # fast rating shortcut
-    wm = bpy.context.window_manager
-    km = wm.keyconfigs.addon.keymaps['Window']
-    # kmi = km.keymap_items.new(ratings.FastRateMenu.bl_idname, 'R', 'PRESS', ctrl=False, shift=False)
-    # addon_keymapitems.append(kmi)
-    # kmi = km.keymap_items.new(upload.FastMetadata.bl_idname, 'F', 'PRESS', ctrl=True, shift=False)
-    # addon_keymapitems.append(kmi)
-
-
-def unregister_ui():
-    global handler_2d, handler_3d
-    pre_load(bpy.context)
-
-    bpy.types.SpaceView3D.draw_handler_remove(handler_2d, 'WINDOW')
-    bpy.types.SpaceView3D.draw_handler_remove(handler_3d, 'WINDOW')
-
-    for c in classes:
-        bpy.utils.unregister_class(c)
-
-    wm = bpy.context.window_manager
-    if not wm.keyconfigs.addon:
-        return
-
-    km = wm.keyconfigs.addon.keymaps.get('Window')
-    if km:
-        for kmi in addon_keymapitems:
-            km.keymap_items.remove(kmi)
-    del addon_keymapitems[:]
diff --git a/blenderkit/ui_bgl.py b/blenderkit/ui_bgl.py
deleted file mode 100644
index 07362b550ce8c2627835ca4d4a4098afaeafc7be..0000000000000000000000000000000000000000
--- a/blenderkit/ui_bgl.py
+++ /dev/null
@@ -1,155 +0,0 @@
-# ##### 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 #####
-
-import bgl, blf
-
-import bpy, blf
-import gpu
-from gpu_extras.batch import batch_for_shader
-
-def draw_rect(x, y, width, height, color):
-    xmax = x + width
-    ymax = y + height
-    points = ((x, y),  # (x, y)
-              (x, ymax),  # (x, y)
-              (xmax, ymax),  # (x, y)
-              (xmax, y),  # (x, y)
-              )
-    indices = ((0, 1, 2), (2, 3, 0))
-
-    shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
-    batch = batch_for_shader(shader, 'TRIS', {"pos": points}, indices=indices)
-
-    shader.bind()
-    shader.uniform_float("color", color)
-    bgl.glEnable(bgl.GL_BLEND)
-    batch.draw(shader)
-
-
-def draw_line2d(x1, y1, x2, y2, width, color):
-    coords = (
-        (x1, y1), (x2, y2))
-
-    indices = (
-        (0, 1),)
-    bgl.glEnable(bgl.GL_BLEND)
-
-    shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
-    batch = batch_for_shader(shader, 'LINES', {"pos": coords}, indices=indices)
-    shader.bind()
-    shader.uniform_float("color", color)
-    batch.draw(shader)
-
-
-def draw_lines(vertices, indices, color):
-    bgl.glEnable(bgl.GL_BLEND)
-
-    shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
-    batch = batch_for_shader(shader, 'LINES', {"pos": vertices}, indices=indices)
-    shader.bind()
-    shader.uniform_float("color", color)
-    batch.draw(shader)
-
-
-def draw_rect_3d(coords, color):
-    indices = [(0, 1, 2), (2, 3, 0)]
-    shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
-    batch = batch_for_shader(shader, 'TRIS', {"pos": coords}, indices=indices)
-    shader.uniform_float("color", color)
-    batch.draw(shader)
-
-cached_images = {}
-def draw_image(x, y, width, height, image, transparency, crop=(0, 0, 1, 1), batch = None):
-    # draw_rect(x,y, width, height, (.5,0,0,.5))
-    if not image:
-        return;
-    ci = cached_images.get(image.filepath)
-    if ci is not None:
-        if ci['x'] == x and ci['y'] ==y:
-            batch = ci['batch']
-            image_shader = ci['image_shader']
-    if not batch:
-
-        coords = [
-            (x, y), (x + width, y),
-            (x, y + height), (x + width, y + height)]
-
-        uvs = [(crop[0], crop[1]),
-               (crop[2], crop[1]),
-               (crop[0], crop[3]),
-               (crop[2], crop[3]),
-               ]
-
-        indices = [(0, 1, 2), (2, 1, 3)]
-
-        image_shader = shader = gpu.shader.from_builtin('2D_IMAGE')
-        batch = batch_for_shader(image_shader, 'TRIS',
-                                 {"pos": coords,
-                                  "texCoord": uvs},
-                                 indices=indices)
-
-
-        # tell shader to use the image that is bound to image unit 0
-        image_shader.uniform_int("image", 0)
-        cached_images[image.filepath] = {
-            'x': x,
-            'y': y,
-            'batch': batch,
-            'image_shader': image_shader
-        }
-    # send image to gpu if it isn't there already
-    if image.gl_load():
-        raise Exception()
-
-    # texture identifier on gpu
-    texture_id = image.bindcode
-
-    # in case someone disabled it before
-    bgl.glEnable(bgl.GL_BLEND)
-
-    # bind texture to image unit 0
-    bgl.glActiveTexture(bgl.GL_TEXTURE0)
-    bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture_id)
-
-    image_shader.bind()
-
-    batch.draw(image_shader)
-
-    # bgl.glDisable(bgl.GL_TEXTURE_2D)
-    return batch
-
-
-def draw_text(text, x, y, size, color=(1, 1, 1, 0.5), halign = 'LEFT', valign = 'TOP'):
-    font_id = 1
-    # bgl.glColor4f(*color)
-    if type(text) != str:
-        text = str(text)
-    blf.color(font_id, color[0], color[1], color[2], color[3])
-    blf.size(font_id, size, 72)
-    if halign != 'LEFT':
-        width,height = blf.dimensions(font_id, text)
-        if halign == 'RIGHT':
-            x-=width
-        elif halign == 'CENTER':
-            x-=width//2
-        if valign=='CENTER':
-            y-=height//2
-        #bottom could be here but there's no reason for it
-    blf.position(font_id, x, y, 0)
-
-    blf.draw(font_id, text)
diff --git a/blenderkit/ui_panels.py b/blenderkit/ui_panels.py
deleted file mode 100644
index c3734554e62ddbd321e2598904251fa72bb95f78..0000000000000000000000000000000000000000
--- a/blenderkit/ui_panels.py
+++ /dev/null
@@ -1,2681 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import paths, comments_utils, ratings, ratings_utils, utils, download, categories, icons, search, \
-    resolutions, ui, \
-    tasks_queue, \
-    autothumb, upload
-
-from bpy.types import (
-    Panel
-)
-from bpy.props import (
-    IntProperty,
-    FloatProperty,
-    FloatVectorProperty,
-    StringProperty,
-    EnumProperty,
-    BoolProperty,
-    PointerProperty,
-)
-
-import bpy
-import os
-import random
-import logging
-import platform
-import ctypes
-
-bk_logger = logging.getLogger('blenderkit')
-
-
-#   this was moved to separate interface:
-
-def draw_ratings(layout, context, asset):
-    # layout.operator("wm.url_open", text="Read rating instructions", icon='QUESTION').url = 'https://support.google.com/?hl=en'
-    # the following shouldn't happen at all in an optimal case,
-    # this function should run only when asset was already checked to be existing
-    if asset == None:
-        return;
-
-    col = layout.column()
-    bkit_ratings = asset.bkit_ratings
-
-    # layout.template_icon_view(bkit_ratings, property, show_labels=False, scale=6.0, scale_popup=5.0)
-
-    row = col.row()
-    row.prop(bkit_ratings, 'rating_quality_ui', expand=True, icon_only=True, emboss=False)
-    if bkit_ratings.rating_quality > 0:
-        col.separator()
-        col.prop(bkit_ratings, 'rating_work_hours')
-    # w = context.region.width
-
-    # layout.label(text='problems')
-    # layout.prop(bkit_ratings, 'rating_problems', text='')
-    # layout.label(text='compliments')
-    # layout.prop(bkit_ratings, 'rating_compliments', text='')
-
-    # row = layout.row()
-    # op = row.operator("object.blenderkit_rating_upload", text="Send rating", icon='URL')
-    # return op
-    # re-enable layout if included in longer panel
-
-
-def draw_not_logged_in(source, message='Please Login/Signup to use this feature'):
-    title = "You aren't logged in"
-
-    def draw_message(source, context):
-        layout = source.layout
-        utils.label_multiline(layout, text=message)
-        draw_login_buttons(layout)
-
-    bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO')
-
-
-def draw_upload_common(layout, props, asset_type, context):
-    op = layout.operator("wm.url_open", text=f"Read {asset_type.lower()} upload instructions",
-                         icon='QUESTION')
-    if asset_type == 'MODEL':
-        op.url = paths.BLENDERKIT_MODEL_UPLOAD_INSTRUCTIONS_URL
-    if asset_type == 'MATERIAL':
-        op.url = paths.BLENDERKIT_MATERIAL_UPLOAD_INSTRUCTIONS_URL
-    if asset_type == 'BRUSH':
-        op.url = paths.BLENDERKIT_BRUSH_UPLOAD_INSTRUCTIONS_URL
-    if asset_type == 'SCENE':
-        op.url = paths.BLENDERKIT_SCENE_UPLOAD_INSTRUCTIONS_URL
-    if asset_type == 'HDR':
-        op.url = paths.BLENDERKIT_HDR_UPLOAD_INSTRUCTIONS_URL
-
-    row = layout.row(align=True)
-    if props.upload_state != '':
-        utils.label_multiline(layout, text=props.upload_state, width=context.region.width)
-    if props.uploading:
-        op = layout.operator('object.kill_bg_process', text="", icon='CANCEL')
-        op.process_source = asset_type
-        op.process_type = 'UPLOAD'
-        layout = layout.column()
-        layout.enabled = False
-    # if props.upload_state.find('Error') > -1:
-    #     layout.label(text = props.upload_state)
-
-    if props.asset_base_id == '':
-        optext = 'Upload %s' % asset_type.lower()
-        op = layout.operator("object.blenderkit_upload", text=optext, icon='EXPORT')
-        op.asset_type = asset_type
-        op.reupload = False
-        # make sure everything gets uploaded.
-        op.main_file = True
-        op.metadata = True
-        op.thumbnail = True
-
-    if props.asset_base_id != '':
-        op = layout.operator("object.blenderkit_upload", text='Reupload asset', icon='EXPORT')
-        op.asset_type = asset_type
-        op.reupload = True
-
-        op = layout.operator("object.blenderkit_upload", text='Upload as new asset', icon='EXPORT')
-        op.asset_type = asset_type
-        op.reupload = False
-
-        # layout.label(text = 'asset id, overwrite only for reuploading')
-        layout.label(text='asset has a version online.')
-        # row = layout.row()
-        # row.enabled = False
-        # row.prop(props, 'asset_base_id', icon='FILE_TICK')
-        # row = layout.row()
-        # row.enabled = False
-        # row.prop(props, 'id', icon='FILE_TICK')
-    layout.prop(props, 'category')
-    if props.category != 'NONE' and props.subcategory != 'NONE':
-        layout.prop(props, 'subcategory')
-    if props.subcategory != 'NONE' and props.subcategory1 != 'NONE':
-        layout.prop(props, 'subcategory1')
-
-    layout.prop(props, 'is_private', expand=True)
-    if props.is_private == 'PUBLIC':
-        layout.prop(props, 'license')
-        layout.prop(props, 'is_free', expand=True)
-
-    prop_needed(layout, props, 'name', props.name)
-    if props.is_private == 'PUBLIC':
-        prop_needed(layout, props, 'description', props.description)
-        prop_needed(layout, props, 'tags', props.tags)
-    else:
-        layout.prop(props, 'description')
-        layout.prop(props, 'tags')
-
-
-def poll_local_panels():
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    return user_preferences.panel_behaviour == 'BOTH' or user_preferences.panel_behaviour == 'LOCAL'
-
-
-def prop_needed(layout, props, name, value='', is_not_filled=''):
-    row = layout.row()
-    if value == is_not_filled:
-        # row.label(text='', icon = 'ERROR')
-        icon = 'ERROR'
-        row.alert = True
-        row.prop(props, name)  # , icon=icon)
-        row.alert = False
-    else:
-        # row.label(text='', icon = 'FILE_TICK')
-        icon = None
-        row.prop(props, name)
-
-
-def draw_panel_hdr_upload(self, context):
-    layout = self.layout
-    ui_props = bpy.context.window_manager.blenderkitUI
-
-    # layout.prop_search(ui_props, "hdr_upload_image", bpy.data, "images")
-    layout.prop(ui_props, "hdr_upload_image")
-
-    hdr = utils.get_active_HDR()
-
-    if hdr is not None:
-        props = hdr.blenderkit
-
-        layout = self.layout
-
-        draw_upload_common(layout, props, 'HDR', context)
-
-
-def draw_panel_hdr_search(self, context):
-    s = context.scene
-    wm = context.window_manager
-    props = wm.blenderkit_HDR
-
-    layout = self.layout
-    row = layout.row()
-    row.prop(props, "search_keywords", text="", icon='VIEWZOOM')
-    draw_assetbar_show_hide(row, props)
-    layout.prop(props, "own_only")
-
-    utils.label_multiline(layout, text=props.report)
-
-
-def draw_thumbnail_upload_panel(layout, props):
-    update = False
-    tex = autothumb.get_texture_ui(props.thumbnail, 'upload_preview')
-    if not tex or not tex.image:
-        return
-    box = layout.box()
-    box.template_icon(icon_value=tex.image.preview.icon_id, scale=6.0)
-
-
-def draw_panel_model_upload(self, context):
-    ob = bpy.context.active_object
-    while ob.parent is not None:
-        ob = ob.parent
-    props = ob.blenderkit
-
-    layout = self.layout
-
-    draw_upload_common(layout, props, 'MODEL', context)
-
-    col = layout.column()
-    if props.is_generating_thumbnail:
-        col.enabled = False
-
-    draw_thumbnail_upload_panel(col, props)
-
-    prop_needed(col, props, 'thumbnail', props.thumbnail)
-    if bpy.context.scene.render.engine in ('CYCLES', 'BLENDER_EEVEE'):
-        col.operator("object.blenderkit_generate_thumbnail", text='Generate thumbnail', icon='IMAGE')
-
-    # row = layout.row(align=True)
-    if props.is_generating_thumbnail:
-        row = layout.row(align=True)
-        row.label(text=props.thumbnail_generating_state)
-        op = row.operator('object.kill_bg_process', text="", icon='CANCEL')
-        op.process_source = 'MODEL'
-        op.process_type = 'THUMBNAILER'
-    elif props.thumbnail_generating_state != '':
-        utils.label_multiline(layout, text=props.thumbnail_generating_state)
-
-    # prop_needed(layout, props, 'style', props.style)
-    # prop_needed(layout, props, 'production_level', props.production_level)
-    layout.prop(props, 'style')
-    layout.prop(props, 'production_level')
-
-    layout.prop(props, 'condition')
-    layout.prop(props, 'pbr')
-    layout.label(text='design props:')
-    layout.prop(props, 'manufacturer')
-    layout.prop(props, 'designer')
-    layout.prop(props, 'design_collection')
-    layout.prop(props, 'design_variant')
-    layout.prop(props, 'use_design_year')
-    if props.use_design_year:
-        layout.prop(props, 'design_year')
-
-    row = layout.row()
-    row.prop(props, 'work_hours')
-
-    layout.prop(props, 'adult')
-
-
-def draw_panel_scene_upload(self, context):
-    s = bpy.context.scene
-    props = s.blenderkit
-
-    layout = self.layout
-    # if bpy.app.debug_value != -1:
-    #     layout.label(text='Scene upload not Implemented')
-    #     return
-    draw_upload_common(layout, props, 'SCENE', context)
-
-    #    layout = layout.column()
-
-    # row = layout.row()
-
-    # if props.dimensions[0] + props.dimensions[1] == 0 and props.face_count == 0:
-    #     icon = 'ERROR'
-    #     layout.operator("object.blenderkit_auto_tags", text='Auto fill tags', icon=icon)
-    # else:
-    #     layout.operator("object.blenderkit_auto_tags", text='Auto fill tags')
-
-    col = layout.column()
-    # if props.is_generating_thumbnail:
-    #     col.enabled = False
-    draw_thumbnail_upload_panel(col, props)
-
-    prop_needed(col, props, 'thumbnail', props.has_thumbnail, False)
-    # if bpy.context.scene.render.engine == 'CYCLES':
-    #     col.operator("object.blenderkit_generate_thumbnail", text='Generate thumbnail', icon='IMAGE_COL')
-
-    # row = layout.row(align=True)
-    # if props.is_generating_thumbnail:
-    #     row = layout.row(align=True)
-    #     row.label(text = props.thumbnail_generating_state)
-    #     op = row.operator('object.kill_bg_process', text="", icon='CANCEL')
-    #     op.process_source = 'MODEL'
-    #     op.process_type = 'THUMBNAILER'
-    # elif props.thumbnail_generating_state != '':
-    #    utils.label_multiline(layout, text = props.thumbnail_generating_state)
-
-    layout.prop(props, 'style')
-    layout.prop(props, 'production_level')
-    layout.prop(props, 'use_design_year')
-    if props.use_design_year:
-        layout.prop(props, 'design_year')
-    layout.prop(props, 'condition')
-    row = layout.row()
-    row.prop(props, 'work_hours')
-    layout.prop(props, 'adult')
-
-
-def draw_assetbar_show_hide(layout, props):
-    s = bpy.context.scene
-    ui_props = bpy.context.window_manager.blenderkitUI
-
-    if ui_props.assetbar_on:
-        icon = 'HIDE_OFF'
-        ttip = 'Click to Hide Asset Bar'
-    else:
-        icon = 'HIDE_ON'
-        ttip = 'Click to Show Asset Bar'
-
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if 1:#preferences.experimental_features:
-        op = layout.operator('view3d.blenderkit_asset_bar_widget', text='', icon=icon)
-    else:
-        op = layout.operator('view3d.blenderkit_asset_bar', text='', icon=icon)
-    op.keep_running = False
-    op.do_search = False
-    op.tooltip = ttip
-
-
-def draw_panel_model_search(self, context):
-    wm = bpy.context.window_manager
-    props = wm.blenderkit_models
-
-    layout = self.layout
-
-    row = layout.row()
-    row.prop(props, "search_keywords", text="", icon='VIEWZOOM')
-    draw_assetbar_show_hide(row, props)
-
-    icon = 'NONE'
-    if props.report == 'You need Full plan to get this item.':
-        icon = 'ERROR'
-    utils.label_multiline(layout, text=props.report, icon=icon)
-    if props.report == 'You need Full plan to get this item.':
-        layout.operator("wm.url_open", text="Get Full plan", icon='URL').url = paths.BLENDERKIT_PLANS
-
-    # layout.prop(props, "search_style")
-    # layout.prop(props, "own_only")
-    # layout.prop(props, "free_only")
-
-    # if props.search_style == 'OTHER':
-    #     layout.prop(props, "search_style_other")
-    # layout.prop(props, "search_engine")
-    # col = layout.column()
-    # layout.prop(props, 'append_link', expand=True, icon_only=False)
-    # layout.prop(props, 'import_as', expand=True, icon_only=False)
-
-    # draw_panel_categories(self, context)
-
-
-def draw_panel_scene_search(self, context):
-    wm = bpy.context.window_manager
-    props = wm.blenderkit_scene
-    layout = self.layout
-    # layout.label(text = "common search properties:")
-    row = layout.row()
-    row.prop(props, "search_keywords", text="", icon='VIEWZOOM')
-    draw_assetbar_show_hide(row, props)
-    layout.prop(props, "own_only")
-    utils.label_multiline(layout, text=props.report)
-
-    # layout.prop(props, "search_style")
-    # if props.search_style == 'OTHER':
-    #     layout.prop(props, "search_style_other")
-    # layout.prop(props, "search_engine")
-    layout.separator()
-    # draw_panel_categories(self, context)
-
-
-class VIEW3D_PT_blenderkit_model_properties(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_model_properties"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "Selected Model"
-    bl_context = "objectmode"
-
-    @classmethod
-    def poll(cls, context):
-        p = bpy.context.view_layer.objects.active is not None
-        return p
-
-    def draw(self, context):
-        # draw asset properties here
-        layout = self.layout
-
-        o = utils.get_active_model()
-        # o = bpy.context.active_object
-        if o.get('asset_data') is None:
-            utils.label_multiline(layout,
-                                  text='To upload this asset to BlenderKit, go to the Find and Upload Assets panel.')
-            layout.prop(o, 'name')
-
-        if o.get('asset_data') is not None:
-            ad = o['asset_data']
-            layout.label(text=str(ad['name']))
-            if o.instance_type == 'COLLECTION' and o.instance_collection is not None:
-                layout.operator('object.blenderkit_bring_to_scene', text='Bring to scene')
-
-            layout.label(text='Asset tools:')
-            draw_asset_context_menu(self.layout, context, ad, from_panel=True)
-            # if 'rig' in ad['tags']:
-            #     # layout.label(text = 'can make proxy')
-            #     layout.operator('object.blenderkit_make_proxy', text = 'Make Armature proxy')
-        # fast upload, blocked by now
-        # else:
-        #     op = layout.operator("object.blenderkit_upload", text='Store as private', icon='EXPORT')
-        #     op.asset_type = 'MODEL'
-        #     op.fast = True
-        # fun override project, not finished
-        # layout.operator('object.blenderkit_color_corrector')
-
-
-class NODE_PT_blenderkit_material_properties(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "NODE_PT_blenderkit_material_properties"
-    bl_space_type = 'NODE_EDITOR'
-    bl_region_type = 'UI'
-    bl_label = "Selected Material"
-    bl_context = "objectmode"
-
-    @classmethod
-    def poll(cls, context):
-        p = bpy.context.view_layer.objects.active is not None and bpy.context.active_object.active_material is not None
-        return p
-
-    def draw(self, context):
-        # draw asset properties here
-        layout = self.layout
-
-        m = bpy.context.active_object.active_material
-        # o = bpy.context.active_object
-        if m.get('asset_data') is None and m.blenderkit.id == '':
-            utils.label_multiline(layout,
-                                  text='To upload this asset to BlenderKit, go to the Find and Upload Assets panel.')
-            layout.prop(m, 'name')
-
-        if m.get('asset_data') is not None:
-            ad = m['asset_data']
-            layout.label(text=str(ad['name']))
-
-            layout.label(text='Asset tools:')
-            draw_asset_context_menu(self.layout, context, ad, from_panel=True)
-            # if 'rig' in ad['tags']:
-            #     # layout.label(text = 'can make proxy')
-            #     layout.operator('object.blenderkit_make_proxy', text = 'Make Armature proxy')
-        # fast upload, blocked by now
-        # else:
-        #     op = layout.operator("object.blenderkit_upload", text='Store as private', icon='EXPORT')
-        #     op.asset_type = 'MODEL'
-        #     op.fast = True
-        # fun override project, not finished
-        # layout.operator('object.blenderkit_color_corrector')
-
-
-def draw_rating_asset(self, context, asset):
-    layout = self.layout
-    col = layout.box()
-    # split = layout.split(factor=0.5)
-    # col1 = split.column()
-    # col2 = split.column()
-    # print('%s_search' % asset['asset_data']['assetType'])
-    directory = paths.get_temp_dir('%s_search' % asset['asset_data']['assetType'])
-    tpath = os.path.join(directory, asset['asset_data']['thumbnail_small'])
-    for image in bpy.data.images:
-        if image.filepath == tpath:
-            # split = row.split(factor=1.0, align=False)
-            col.template_icon(icon_value=image.preview.icon_id, scale=6.0)
-            break;
-        # layout.label(text = '', icon_value=image.preview.icon_id, scale = 10)
-    col.label(text=asset.name)
-    draw_ratings(col, context, asset=asset)
-
-
-class VIEW3D_PT_blenderkit_ratings(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_ratings"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "Please rate"
-    bl_context = "objectmode"
-
-    @classmethod
-    def poll(cls, context):
-        #
-        p = bpy.context.view_layer.objects.active is not None
-        return p
-
-    def draw(self, context):
-        # TODO make a list of assets inside asset appending code, to happen only when assets are added to the scene.
-        # draw asset properties here
-        layout = self.layout
-        assets = ratings.get_assets_for_rating()
-        if len(assets) > 0:
-            utils.label_multiline(layout, text='Please help BlenderKit community by rating these assets:')
-
-            for a in assets:
-                if a.bkit_ratings.rating_work_hours == 0:
-                    draw_rating_asset(self, context, asset=a)
-
-
-def draw_login_progress(layout):
-    layout.label(text='Login through browser')
-    layout.label(text='in progress.')
-    layout.operator("wm.blenderkit_login_cancel", text="Cancel", icon='CANCEL')
-
-
-class VIEW3D_PT_blenderkit_profile(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_profile"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "BlenderKit Profile"
-
-    @classmethod
-    def poll(cls, context):
-
-        return True
-
-    def draw(self, context):
-        # draw asset properties here
-        layout = self.layout
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-        if user_preferences.login_attempt:
-            draw_login_progress(layout)
-            return
-
-        if user_preferences.api_key != '':
-            me = bpy.context.window_manager.get('bkit profile')
-            if me is not None:
-                me = me['user']
-                # user name
-                if len(me['firstName']) > 0 or len(me['lastName']) > 0:
-                    layout.label(text=f"Me: {me['firstName']} {me['lastName']}")
-                else:
-                    layout.label(text=f"Me: {me['email']}")
-                # layout.label(text='Email: %s' % (me['email']))
-
-                # plan information
-
-                if me.get('currentPlanName') is not None:
-                    pn = me['currentPlanName']
-                    pcoll = icons.icon_collections["main"]
-                    if pn == 'Free':
-                        my_icon = pcoll['free']
-                    else:
-                        my_icon = pcoll['full']
-
-                    row = layout.row()
-                    row.label(text='My plan:')
-                    row.label(text='%s plan' % pn, icon_value=my_icon.icon_id)
-                    if pn == 'Free':
-                        layout.operator("wm.url_open", text="Change plan",
-                                        icon='URL').url = paths.get_bkit_url() + paths.BLENDERKIT_PLANS
-
-                # storage statistics
-                # if me.get('sumAssetFilesSize') is not None:  # TODO remove this when production server has these too.
-                #     layout.label(text='My public assets: %i MiB' % (me['sumAssetFilesSize']))
-                # if me.get('sumPrivateAssetFilesSize') is not None:
-                #     layout.label(text='My private assets: %i MiB' % (me['sumPrivateAssetFilesSize']))
-                if me.get('remainingPrivateQuota') is not None:
-                    layout.label(text='My free storage: %i MiB' % (me['remainingPrivateQuota']))
-
-            layout.operator("wm.url_open", text="See my uploads",
-                            icon='URL').url = paths.get_bkit_url() + paths.BLENDERKIT_USER_ASSETS
-
-
-class MarkNotificationRead(bpy.types.Operator):
-    """Mark notification as read here and also on BlenderKit server"""
-    bl_idname = "wm.blenderkit_mark_notification_read"
-    bl_label = "Mark notification as read"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    notification_id: bpy.props.IntProperty(
-        name="Id",
-        description="notification id",
-        default=-1)
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def execute(self, context):
-        notifications = bpy.context.window_manager['bkit notifications']
-        for n in notifications['results']:
-            if n['id'] == self.notification_id:
-                n['unread'] = 0
-        comments_utils.check_notifications_read()
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        api_key = user_preferences.api_key
-        comments_utils.mark_notification_read_thread(api_key, self.notification_id)
-
-        return {'FINISHED'}
-
-class MarkAllNotificationsRead(bpy.types.Operator):
-    """Mark notification as read here and also on BlenderKit server"""
-    bl_idname = "wm.blenderkit_mark_notifications_read_all"
-    bl_label = "Mark all notifications as read"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def execute(self, context):
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        api_key = user_preferences.api_key
-        notifications = bpy.context.window_manager['bkit notifications']
-        for n in notifications.get('results'):
-            if n['unread'] == 1:
-                n['unread'] = 0
-                comments_utils.mark_notification_read_thread(api_key, n['id'])
-
-        comments_utils.check_notifications_read()
-        return {'FINISHED'}
-
-class NotificationOpenTarget(bpy.types.Operator):
-    """"""
-    bl_idname = "wm.blenderkit_open_notification_target"
-    bl_label = ""
-    bl_description = "Open notification target and mark notification as read"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    tooltip: bpy.props.StringProperty(default='Open a web page')
-    url: bpy.props.StringProperty(default='Runs search and displays the asset bar at the same time')
-    notification_id: bpy.props.IntProperty(
-        name="Id",
-        description="notification id",
-        default=-1)
-
-    @classmethod
-    def description(cls, context, properties):
-        return properties.tooltip
-
-    def execute(self, context):
-        bpy.ops.wm.blenderkit_mark_notification_read(notification_id=self.notification_id)
-        bpy.ops.wm.url_open(url=self.url)
-        return {'FINISHED'}
-
-
-class LikeComment(bpy.types.Operator):
-    """Mark notification as read here and also on BlenderKit server"""
-    bl_idname = "wm.blenderkit_like_comment"
-    bl_label = "BlenderKit like/dislike comment"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    asset_id: StringProperty(
-        name="Asset Base Id",
-        description="Unique id of the asset (hidden)",
-        default="",
-        options={'SKIP_SAVE'})
-
-    comment_id: bpy.props.IntProperty(
-        name="Id",
-        description="comment id",
-        default=-1)
-
-    flag: bpy.props.StringProperty(
-        name="flag",
-        description="Like/dislike comment",
-        default="like")
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def execute(self, context):
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        api_key = user_preferences.api_key
-        comments_utils.send_comment_flag_to_thread(asset_id=self.asset_id, comment_id=self.comment_id, flag=self.flag,
-                                                   api_key=api_key)
-        return {'FINISHED'}
-
-
-def draw_notification(self, notification, width=600):
-    layout = self.layout
-    box = layout.box()
-    firstline = f"{notification['actor']['string']} {notification['verb']} {notification['target']['string']}"
-    box1 = box.box()
-    # row = box1.row()
-
-    split_last = 0.7
-    if notification['description']:
-        split_last = 0
-
-
-    rows = utils.label_multiline(box1, text=firstline, width=width, split_last = split_last)
-
-
-    if notification['description']:
-        rows = utils.label_multiline(box, text=notification['description'], width=width, split_last = 0.7)
-
-
-    if notification['target']:
-        # row = layout.row()
-        # split = row.split(factor=.8)
-        # split.label(text='')
-        # split = split.split()
-        # split = rows[-1].split(factor=0.8)
-        # split = split.split()
-        # split.alignment = 'RIGHT'
-        # row = split.row(align = True)
-        row = rows[-1]
-        row = row.row(align=False)
-
-        # row = row.split(factor = 0.7)
-
-        op = row.operator('wm.blenderkit_open_notification_target', text='Open page', icon='HIDE_OFF')
-        op.tooltip = 'Open the browser on the asset page to comment'
-        op.url = paths.get_bkit_url() + notification['target']['url']
-        op.notification_id = notification['id']
-        # split =
-        op = row.operator("wm.blenderkit_mark_notification_read", text="", icon='CANCEL')
-        op.notification_id = notification['id']
-
-
-def draw_notifications(self, context, width=600):
-    layout = self.layout
-    notifications = bpy.context.window_manager.get('bkit notifications')
-    if notifications is not None and notifications.get('count')>0:
-        row = layout.row()
-        # row.alert = True
-        split = row.split(factor = 0.7)
-        split.label(text='')
-        split = split.split()
-        split.operator('wm.blenderkit_mark_notifications_read_all', text = 'Mark All Read', icon = 'CANCEL')
-        for notification in notifications['results']:
-            if notification['unread'] == 1:
-                draw_notification(self, notification, width=width)
-
-
-class ShowNotifications(bpy.types.Operator):
-    """Show notifications"""
-    bl_idname = "wm.show_notifications"
-    bl_label = "Show BlenderKit notifications"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    notification_id: bpy.props.IntProperty(
-        name="Id",
-        description="notification id",
-        default=-1)
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def draw(self, context):
-        draw_notifications(self, context, width=600)
-
-    def execute(self, context):
-        wm = bpy.context.window_manager
-        return wm.invoke_popup(self, width=600)
-
-
-class VIEW3D_PT_blenderkit_notifications(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_notifications"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "BlenderKit Notifications"
-
-    @classmethod
-    def poll(cls, context):
-        notifications = bpy.context.window_manager.get('bkit notifications')
-        if notifications is not None and len(notifications['results']) > 0:
-            return True
-        return False
-
-    def draw(self, context):
-        draw_notifications(self, context)
-
-
-class VIEW3D_PT_blenderkit_login(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_login"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "BlenderKit Login"
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def draw(self, context):
-        layout = self.layout
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-        if user_preferences.login_attempt:
-            draw_login_progress(layout)
-            return
-
-        if user_preferences.enable_oauth:
-            draw_login_buttons(layout)
-
-
-def draw_panel_model_rating(self, context):
-    # o = bpy.context.active_object
-    o = utils.get_active_model()
-    # print('ratings active',o)
-    draw_ratings(self.layout, context, asset=o)  # , props)
-    # op.asset_type = 'MODEL'
-
-
-def draw_panel_material_upload(self, context):
-    o = bpy.context.active_object
-    mat = bpy.context.active_object.active_material
-
-    props = mat.blenderkit
-    layout = self.layout
-
-    draw_upload_common(layout, props, 'MATERIAL', context)
-
-    # THUMBNAIL
-    row = layout.column()
-    if props.is_generating_thumbnail:
-        row.enabled = False
-
-    draw_thumbnail_upload_panel(row, props)
-
-    prop_needed(row, props, 'thumbnail', props.has_thumbnail, False)
-
-    if bpy.context.scene.render.engine in ('CYCLES', 'BLENDER_EEVEE'):
-        layout.operator("object.blenderkit_generate_material_thumbnail", text='Render thumbnail with Cycles',
-                        icon='EXPORT')
-    if props.is_generating_thumbnail:
-        row = layout.row(align=True)
-        row.label(text=props.thumbnail_generating_state, icon='RENDER_STILL')
-        op = row.operator('object.kill_bg_process', text="", icon='CANCEL')
-        op.process_source = 'MATERIAL'
-        op.process_type = 'THUMBNAILER'
-    elif props.thumbnail_generating_state != '':
-        utils.label_multiline(layout, text=props.thumbnail_generating_state)
-
-    layout.prop(props, 'style')
-    # if props.style == 'OTHER':
-    #     layout.prop(props, 'style_other')
-    # layout.prop(props, 'engine')
-    # if props.engine == 'OTHER':
-    #     layout.prop(props, 'engine_other')
-    # layout.prop(props,'shaders')#TODO autofill on upload
-    # row = layout.row()
-
-    layout.prop(props, 'pbr')
-    layout.prop(props, 'uv')
-    layout.prop(props, 'animated')
-    layout.prop(props, 'texture_size_meters')
-
-    # tname = "." + bpy.context.active_object.active_material.name + "_thumbnail"
-    # if props.has_thumbnail and bpy.data.textures.get(tname) is not None:
-    #     row = layout.row()
-    #     # row.scale_y = 1.5
-    #     row.template_preview(bpy.data.textures[tname], preview_id='test')
-
-
-def draw_panel_material_search(self, context):
-    wm = context.window_manager
-    props = wm.blenderkit_mat
-
-    layout = self.layout
-    row = layout.row()
-    row.prop(props, "search_keywords", text="", icon='VIEWZOOM')
-    draw_assetbar_show_hide(row, props)
-    utils.label_multiline(layout, text=props.report)
-
-    # layout.prop(props, 'search_style')F
-    # if props.search_style == 'OTHER':
-    #     layout.prop(props, 'search_style_other')
-    # layout.prop(props, 'search_engine')
-    # if props.search_engine == 'OTHER':
-    #     layout.prop(props, 'search_engine_other')
-
-    # draw_panel_categories(self, context)
-
-
-def draw_panel_material_ratings(self, context):
-    asset = bpy.context.active_object.active_material
-    draw_ratings(self.layout, context, asset)  # , props)
-    # op.asset_type = 'MATERIAL'
-
-
-def draw_panel_brush_upload(self, context):
-    brush = utils.get_active_brush()
-    if brush is not None:
-        props = brush.blenderkit
-
-        layout = self.layout
-
-        draw_upload_common(layout, props, 'BRUSH', context)
-
-
-def draw_panel_brush_search(self, context):
-    wm = context.window_manager
-    props = wm.blenderkit_brush
-
-    layout = self.layout
-    row = layout.row()
-    row.prop(props, "search_keywords", text="", icon='VIEWZOOM')
-    draw_assetbar_show_hide(row, props)
-    layout.prop(props, "own_only")
-
-    utils.label_multiline(layout, text=props.report)
-    # draw_panel_categories(self, context)
-
-
-def draw_panel_brush_ratings(self, context):
-    # props = utils.get_brush_props(context)
-    brush = utils.get_active_brush()
-    draw_ratings(self.layout, context, asset=brush)  # , props)
-    #
-    # op.asset_type = 'BRUSH'
-
-
-def draw_login_buttons(layout, invoke=False):
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-    if user_preferences.login_attempt:
-        draw_login_progress(layout)
-    else:
-        if invoke:
-            layout.operator_context = 'INVOKE_DEFAULT'
-        else:
-            layout.operator_context = 'EXEC_DEFAULT'
-        if user_preferences.api_key == '':
-            layout.operator("wm.blenderkit_login", text="Login",
-                            icon='URL').signup = False
-            layout.operator("wm.blenderkit_login", text="Sign up",
-                            icon='URL').signup = True
-
-        else:
-            layout.operator("wm.blenderkit_login", text="Login as someone else",
-                            icon='URL').signup = False
-            layout.operator("wm.blenderkit_logout", text="Logout",
-                            icon='URL')
-
-
-class VIEW3D_PT_blenderkit_advanced_model_search(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_advanced_model_search"
-    bl_parent_id = "VIEW3D_PT_blenderkit_unified"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "Search filters"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        s = context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        return ui_props.down_up == 'SEARCH' and ui_props.asset_type == 'MODEL'
-
-    def draw(self, context):
-        wm = bpy.context.window_manager
-
-        props = wm.blenderkit_models
-        layout = self.layout
-        layout.separator()
-
-        # layout.label(text = "common searches keywords:")
-        # layout.prop(props, "search_global_keywords", text = "")
-        # layout.prop(props, "search_modifier_keywords")
-        # if props.search_engine == 'OTHER':
-        #     layout.prop(props, "search_engine_keyword")
-
-        layout.prop(props, "own_only")
-        layout.prop(props, "free_only")
-        layout.prop(props, "search_style")
-
-        # DESIGN YEAR
-        layout.prop(props, "search_design_year", text='Designed in Year')
-        if props.search_design_year:
-            row = layout.row(align=True)
-            row.prop(props, "search_design_year_min", text='Min')
-            row.prop(props, "search_design_year_max", text='Max')
-
-        # POLYCOUNT
-        layout.prop(props, "search_polycount", text='Poly Count ')
-        if props.search_polycount:
-            row = layout.row(align=True)
-            row.prop(props, "search_polycount_min", text='Min')
-            row.prop(props, "search_polycount_max", text='Max')
-
-        # TEXTURE RESOLUTION
-        layout.prop(props, "search_texture_resolution", text='Texture Resolutions')
-        if props.search_texture_resolution:
-            row = layout.row(align=True)
-            row.prop(props, "search_texture_resolution_min", text='Min')
-            row.prop(props, "search_texture_resolution_max", text='Max')
-
-        # FILE SIZE
-        layout.prop(props, "search_file_size", text='File Size (MB)')
-        if props.search_file_size:
-            row = layout.row(align=True)
-            row.prop(props, "search_file_size_min", text='Min')
-            row.prop(props, "search_file_size_max", text='Max')
-
-        # AGE
-        layout.prop(props, "search_condition", text='Condition')  # , text ='condition of object new/old e.t.c.')
-        layout.prop(props, "quality_limit", slider=True)  # , text ='condition of object new/old e.t.c.')
-
-        # layout.prop(props, "search_procedural", expand=True)
-        # ADULT
-        # layout.prop(props, "search_adult")  # , text ='condition of object new/old e.t.c.')
-
-
-class VIEW3D_PT_blenderkit_advanced_material_search(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_advanced_material_search"
-    bl_parent_id = "VIEW3D_PT_blenderkit_unified"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "Search filters"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        s = context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        return ui_props.down_up == 'SEARCH' and ui_props.asset_type == 'MATERIAL'
-
-    def draw(self, context):
-        wm = context.window_manager
-        props = wm.blenderkit_mat
-        layout = self.layout
-        layout.separator()
-
-        layout.prop(props, "own_only")
-
-        layout.label(text='Texture:')
-        col = layout.column()
-        col.prop(props, "search_procedural", expand=True)
-
-        if props.search_procedural == 'TEXTURE_BASED':
-            # TEXTURE RESOLUTION
-            layout.prop(props, "search_texture_resolution", text='Texture Resolution')
-            if props.search_texture_resolution:
-                row = layout.row(align=True)
-                row.prop(props, "search_texture_resolution_min", text='Min')
-                row.prop(props, "search_texture_resolution_max", text='Max')
-
-        # FILE SIZE
-        layout.prop(props, "search_file_size", text='File size (MB)')
-        if props.search_file_size:
-            row = layout.row(align=True)
-            row.prop(props, "search_file_size_min", text='Min')
-            row.prop(props, "search_file_size_max", text='Max')
-        layout.prop(props, "quality_limit", slider=True)
-
-
-class VIEW3D_PT_blenderkit_advanced_HDR_search(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_advanced_HDR_search"
-    bl_parent_id = "VIEW3D_PT_blenderkit_unified"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "Search filters"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        s = context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        return ui_props.down_up == 'SEARCH' and ui_props.asset_type == 'HDR'
-
-    def draw(self, context):
-        wm = context.window_manager
-        props = wm.blenderkit_HDR
-        layout = self.layout
-        layout.separator()
-
-        layout.prop(props, "own_only")
-        layout.prop(props, "true_hdr")
-
-
-class VIEW3D_PT_blenderkit_categories(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_categories"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "Categories"
-    bl_parent_id = "VIEW3D_PT_blenderkit_unified"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        s = context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        mode = True
-        if ui_props.asset_type == 'BRUSH' and not (context.sculpt_object or context.image_paint_object):
-            mode = False
-        return ui_props.down_up == 'SEARCH' and mode
-
-    def draw(self, context):
-        draw_panel_categories(self, context)
-
-
-def draw_scene_import_settings(self, context):
-    wm = bpy.context.window_manager
-    props = wm.blenderkit_scene
-    layout = self.layout
-    layout.prop(props, 'switch_after_append')
-    # layout.label(text='Import method:')
-    row = layout.row()
-    row.prop(props, 'append_link', expand=True, icon_only=False)
-
-
-class VIEW3D_PT_blenderkit_import_settings(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_import_settings"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "Import settings"
-    bl_parent_id = "VIEW3D_PT_blenderkit_unified"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        s = context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        return ui_props.down_up == 'SEARCH' and ui_props.asset_type in ['MATERIAL', 'MODEL', 'SCENE', 'HDR']
-
-    def draw(self, context):
-        layout = self.layout
-
-        s = context.scene
-        wm = bpy.context.window_manager
-        ui_props = bpy.context.window_manager.blenderkitUI
-
-        if ui_props.asset_type == 'MODEL':
-            # noinspection PyCallByClass
-            props = wm.blenderkit_models
-            layout.prop(props, 'randomize_rotation')
-            if props.randomize_rotation:
-                layout.prop(props, 'randomize_rotation_amount')
-            layout.prop(props, 'perpendicular_snap')
-            # if props.perpendicular_snap:
-            #     layout.prop(props,'perpendicular_snap_threshold')
-
-            layout.label(text='Import method:')
-            row = layout.row()
-            row.prop(props, 'append_method', expand=True, icon_only=False)
-
-        if ui_props.asset_type == 'MATERIAL':
-            props = wm.blenderkit_mat
-            layout.prop(props, 'automap')
-            layout.label(text='Import method:')
-            row = layout.row()
-
-            row.prop(props, 'append_method', expand=True, icon_only=False)
-        if ui_props.asset_type == 'SCENE':
-            draw_scene_import_settings(self, context)
-
-        if ui_props.asset_type == 'HDR':
-            props = wm.blenderkit_HDR
-
-        if ui_props.asset_type in ['MATERIAL', 'MODEL', 'HDR']:
-            layout.prop(props, 'resolution')
-        # layout.prop(props, 'unpack_files')
-
-
-class VIEW3D_PT_blenderkit_unified(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_unified"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "Find and Upload Assets"
-
-    @classmethod
-    def poll(cls, context):
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        return user_preferences.panel_behaviour == 'BOTH' or user_preferences.panel_behaviour == 'UNIFIED'
-
-    def draw(self, context):
-        s = context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        wm = bpy.context.window_manager
-        layout = self.layout
-        # layout.prop_tabs_enum(ui_props, "asset_type", icon_only = True)
-
-        row = layout.row()
-        # row.scale_x = 1.6
-        # row.scale_y = 1.6
-        #
-        row.prop(ui_props, 'down_up', expand=True, icon_only=False)
-        # row.label(text='')
-        # row = row.split().row()
-        # layout.alert = True
-        # layout.alignment = 'CENTER'
-        row = layout.row(align=True)
-        row.scale_x = 1.6
-        row.scale_y = 1.6
-        # split = row.split(factor=.
-
-        expand_icon = 'TRIA_DOWN'
-        if ui_props.asset_type_fold:
-            expand_icon = 'TRIA_RIGHT'
-        row = layout.row()
-        split = row.split(factor=0.15)
-        split.prop(ui_props, 'asset_type_fold', icon=expand_icon, icon_only=True, emboss=False)
-
-        if ui_props.asset_type_fold:
-            pass
-            # expanded interface with names in column
-            split = split.row()
-            split.scale_x = 8
-            split.scale_y = 1.6
-            # split = row
-            # split = layout.row()
-        else:
-            split = split.column()
-
-        split.prop(ui_props, 'asset_type', expand=True, icon_only=ui_props.asset_type_fold)
-        # row = layout.column(align = False)
-        # layout.prop(ui_props, 'asset_type', expand=False, text='')
-
-        w = context.region.width
-        if user_preferences.login_attempt:
-            draw_login_progress(layout)
-            return
-
-        if len(user_preferences.api_key) < 20 and user_preferences.asset_counter > 20:
-            if user_preferences.enable_oauth:
-                draw_login_buttons(layout)
-            else:
-                op = layout.operator("wm.url_open", text="Get your API Key",
-                                     icon='QUESTION')
-                op.url = paths.BLENDERKIT_SIGNUP_URL
-                layout.label(text='Paste your API Key:')
-                layout.prop(user_preferences, 'api_key', text='')
-            layout.separator()
-        # if bpy.data.filepath == '':
-        #     layout.alert = True
-        #    utils.label_multiline(layout, text="It's better to save your file first.", width=w)
-        #     layout.alert = False
-        #     layout.separator()
-
-        if ui_props.down_up == 'SEARCH':
-            if utils.profile_is_validator():
-                search_props = utils.get_search_props()
-                layout.prop(search_props, 'search_verification_status')
-                layout.prop(search_props, "unrated_only")
-
-            if ui_props.asset_type == 'MODEL':
-                # noinspection PyCallByClass
-                draw_panel_model_search(self, context)
-            if ui_props.asset_type == 'SCENE':
-                # noinspection PyCallByClass
-                draw_panel_scene_search(self, context)
-            if ui_props.asset_type == 'HDR':
-                # noinspection PyCallByClass
-                draw_panel_hdr_search(self, context)
-            elif ui_props.asset_type == 'MATERIAL':
-                draw_panel_material_search(self, context)
-            elif ui_props.asset_type == 'BRUSH':
-                if context.sculpt_object or context.image_paint_object:
-                    # noinspection PyCallByClass
-                    draw_panel_brush_search(self, context)
-                else:
-                    utils.label_multiline(layout, text='Switch to paint or sculpt mode.', width=context.region.width)
-                    return
-
-
-        elif ui_props.down_up == 'UPLOAD':
-            if not ui_props.assetbar_on:
-                text = 'Show asset preview - ;'
-            else:
-                text = 'Hide asset preview - ;'
-            op = layout.operator('view3d.blenderkit_asset_bar', text=text, icon='EXPORT')
-            op.keep_running = False
-            op.do_search = False
-            op.tooltip = 'Show/Hide asset preview'
-
-            e = s.render.engine
-            if e not in ('CYCLES', 'BLENDER_EEVEE'):
-                rtext = 'Only Cycles and EEVEE render engines are currently supported. ' \
-                        'Please use Cycles for all assets you upload to BlenderKit.'
-                utils.label_multiline(layout, rtext, icon='ERROR', width=w)
-                return;
-
-            if ui_props.asset_type == 'MODEL':
-                # utils.label_multiline(layout, "Uploaded models won't be available in b2.79", icon='ERROR')
-                if bpy.context.view_layer.objects.active is not None:
-                    draw_panel_model_upload(self, context)
-                else:
-                    layout.label(text='selet object to upload')
-            elif ui_props.asset_type == 'SCENE':
-                draw_panel_scene_upload(self, context)
-            elif ui_props.asset_type == 'HDR':
-                draw_panel_hdr_upload(self, context)
-
-            elif ui_props.asset_type == 'MATERIAL':
-                # utils.label_multiline(layout, "Uploaded materials won't be available in b2.79", icon='ERROR')
-
-                if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.active_material is not None:
-                    draw_panel_material_upload(self, context)
-                else:
-                    utils.label_multiline(layout, text='select object with material to upload materials', width=w)
-
-            elif ui_props.asset_type == 'BRUSH':
-                if context.sculpt_object or context.image_paint_object:
-                    draw_panel_brush_upload(self, context)
-                else:
-                    layout.label(text='Switch to paint or sculpt mode.')
-
-
-class BlenderKitWelcomeOperator(bpy.types.Operator):
-    """Login online on BlenderKit webpage"""
-
-    bl_idname = "wm.blenderkit_welcome"
-    bl_label = "Welcome to BlenderKit!"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    step: IntProperty(
-        name="step",
-        description="Tutorial Step",
-        default=0,
-        options={'SKIP_SAVE'}
-    )
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def draw(self, context):
-        layout = self.layout
-        if self.step == 0:
-            user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-            # message = "BlenderKit connects from Blender to an online, " \
-            #           "community built shared library of models, " \
-            #           "materials, and brushes. " \
-            #           "Use addon preferences to set up where files will be saved in the Global directory setting."
-            #
-            # utils.label_multiline(layout, text=message, width=300)
-
-            layout.template_icon(icon_value=self.img.preview.icon_id, scale=18)
-
-            # utils.label_multiline(layout, text="\n Let's start by searching for some cool materials?", width=300)
-            op = layout.operator("wm.url_open", text='Watch Video Tutorial', icon='QUESTION')
-            op.url = paths.BLENDERKIT_MANUAL
-
-        else:
-            message = "Operator Tutorial called with invalid step"
-
-    def execute(self, context):
-        if self.step == 0:
-            # move mouse:
-            # bpy.context.window_manager.windows[0].cursor_warp(1000, 1000)
-            # show n-key sidebar (spaces[index] has to be found for view3d too:
-            # bpy.context.window_manager.windows[0].screen.areas[5].spaces[0].show_region_ui = False
-            ui_props = bpy.context.window_manager.blenderkitUI
-            # random_searches = [
-            #     ('MATERIAL', 'ice'),
-            #     ('MODEL', 'car'),
-            #     ('MODEL', 'vase'),
-            #     ('MODEL', 'grass'),
-            #     ('MODEL', 'plant'),
-            #     ('MODEL', 'man'),
-            #     ('MATERIAL', 'metal'),
-            #     ('MATERIAL', 'wood'),
-            #     ('MATERIAL', 'floor'),
-            #     ('MATERIAL', 'bricks'),
-            # ]
-            # random_search = random.choice(random_searches)
-            # ui_props.asset_type = random_search[0]
-            ui_props.asset_type = 'MODEL'
-
-            score_limit = 450
-            if ui_props.asset_type == 'MATERIAL':
-                props = bpy.context.window_manager.blenderkit_mat
-
-            elif ui_props.asset_type == 'MODEL':
-                props = bpy.context.window_manager.blenderkit_models
-                score_limit = 1000
-
-            props.search_keywords = ''  # random_search[1]
-            props.search_keywords += f'+is_free:true+score_gte:{score_limit}+order:-created'  # random_search[1]
-            # search.search()
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = bpy.context.window_manager
-        img = utils.get_thumbnail('intro.jpg')
-        utils.img_to_preview(img, copy_original=True)
-        self.img = img
-        w, a, r = utils.get_largest_area(area_type='VIEW_3D')
-        if a is not None:
-            a.spaces.active.show_region_ui = True
-
-        return wm.invoke_props_dialog(self, width=500)
-
-
-def draw_asset_context_menu(layout, context, asset_data, from_panel=False):
-    ui_props = context.window_manager.blenderkitUI
-
-    author_id = str(asset_data['author'].get('id'))
-    wm = bpy.context.window_manager
-
-    layout.operator_context = 'INVOKE_DEFAULT'
-
-    if from_panel:
-        op = layout.operator('wm.blenderkit_menu_rating_upload', text='Add Rating')
-        op.asset_name = asset_data['name']
-        op.asset_id = asset_data['id']
-        op.asset_type = asset_data['assetType']
-
-    if from_panel and wm.get('bkit authors') is not None and author_id is not None:
-        a = bpy.context.window_manager['bkit authors'].get(author_id)
-        if a is not None:
-            # utils.p('author:', a)
-            op = layout.operator('wm.url_open', text="Open Author's Website")
-            if a.get('aboutMeUrl') is not None:
-                op.url = a['aboutMeUrl']
-            else:
-                op.url = paths.get_author_gallery_url(a['id'])
-            op = layout.operator('view3d.blenderkit_search', text="Show Assets By Author")
-            op.keywords = ''
-            op.author_id = author_id
-
-    op = layout.operator('view3d.blenderkit_search', text='Search Similar')
-    op.esc = True
-    op.tooltip = 'Search for similar assets in the library'
-    # build search string from description and tags:
-    op.keywords = asset_data['name']
-    if asset_data.get('description'):
-        op.keywords += ' ' + asset_data.get('description') + ' '
-    op.keywords += ' '.join(asset_data.get('tags'))
-
-    if asset_data.get('canDownload') != 0:
-        if len(bpy.context.selected_objects) > 0 and ui_props.asset_type == 'MODEL':
-            aob = bpy.context.active_object
-            if aob is None:
-                aob = bpy.context.selected_objects[0]
-            op = layout.operator('scene.blenderkit_download', text='Replace Active Models')
-            op.tooltip = "Replace all selected models with this one."
-
-            # this checks if the menu got called from right-click in assetbar(then index is 0 - x) or
-            # from a panel(then replacement happens from the active model)
-            if from_panel:
-                # called from addon panel
-                op.asset_base_id = asset_data['assetBaseId']
-            else:
-                op.asset_index = ui_props.active_index
-
-            # op.asset_type = ui_props.asset_type
-            op.model_location = aob.location
-            op.model_rotation = aob.rotation_euler
-            op.target_object = aob.name
-            op.material_target_slot = aob.active_material_index
-            op.replace = True
-            op.replace_resolution = False
-
-        # resolution replacement operator
-        # if asset_data['downloaded'] == 100: # only show for downloaded/used assets
-        # if ui_props.asset_type in ('MODEL', 'MATERIAL'):
-        #     layout.menu(OBJECT_MT_blenderkit_resolution_menu.bl_idname)
-
-        if ui_props.asset_type in ('MODEL', 'MATERIAL', 'HDR') and \
-                utils.get_param(asset_data, 'textureResolutionMax') is not None and \
-                utils.get_param(asset_data, 'textureResolutionMax') > 512:
-
-            s = bpy.context.scene
-
-            col = layout.column()
-            col.operator_context = 'INVOKE_DEFAULT'
-
-            if from_panel:
-                # Called from addon panel
-
-                if asset_data.get('resolution'):
-                    op = col.operator('scene.blenderkit_download', text='Replace asset resolution')
-                    op.asset_base_id = asset_data['assetBaseId']
-                    if asset_data['assetType'] == 'MODEL':
-                        o = utils.get_active_model()
-                        op.model_location = o.location
-                        op.model_rotation = o.rotation_euler
-                        op.target_object = o.name
-                        op.material_target_slot = o.active_material_index
-
-                    elif asset_data['assetType'] == 'MATERIAL':
-                        aob = bpy.context.active_object
-                        op.model_location = aob.location
-                        op.model_rotation = aob.rotation_euler
-                        op.target_object = aob.name
-                        op.material_target_slot = aob.active_material_index
-                    op.replace_resolution = True
-                    op.replace = False
-
-                    op.invoke_resolution = True
-                    op.max_resolution = asset_data.get('max_resolution',
-                                                       0)  # str(utils.get_param(asset_data, 'textureResolutionMax'))
-
-            elif asset_data['assetBaseId'] in s['assets used'].keys() and asset_data['assetType'] != 'hdr':
-                # HDRs are excluded from replacement, since they are always replaced.
-                # called from asset bar:
-                op = col.operator('scene.blenderkit_download', text='Replace asset resolution')
-
-                op.asset_index = ui_props.active_index
-                # op.asset_type = ui_props.asset_type
-                op.replace_resolution = True
-                op.replace = False
-                op.invoke_resolution = True
-                o = utils.get_active_model()
-                if o and o.get('asset_data'):
-                    if o['asset_data']['assetBaseId'] == bpy.context.window_manager['search results'][
-                        ui_props.active_index]:
-                        op.model_location = o.location
-                        op.model_rotation = o.rotation_euler
-                    else:
-                        op.model_location = (0, 0, 0)
-                        op.model_rotation = (0, 0, 0)
-                op.max_resolution = asset_data.get('max_resolution',
-                                                   0)  # str(utils.get_param(asset_data, 'textureResolutionMax'))
-            # print('operator res ', resolution)
-            # op.resolution = resolution
-
-    wm = bpy.context.window_manager
-    profile = wm.get('bkit profile')
-    if profile is not None:
-        # validation
-
-        if author_id == str(profile['user']['id']) or utils.profile_is_validator():
-            layout.label(text='Management tools:')
-
-            row = layout.row()
-            row.operator_context = 'INVOKE_DEFAULT'
-            op = layout.operator('wm.blenderkit_fast_metadata', text='Edit Metadata', icon='GREASEPENCIL')
-            op.asset_id = asset_data['id']
-            op.asset_type = asset_data['assetType']
-
-            if author_id == str(profile['user']['id']):
-                row.operator_context = 'EXEC_DEFAULT'
-                op = layout.operator('wm.blenderkit_url', text='Edit Metadata (browser)', icon='GREASEPENCIL')
-                op.url = paths.get_bkit_url() + paths.BLENDERKIT_USER_ASSETS + f"/{asset_data['assetBaseId']}/?edit#"
-
-            row.operator_context = 'INVOKE_DEFAULT'
-
-            if asset_data['assetType'] == 'model':
-                op = layout.operator('object.blenderkit_regenerate_thumbnail', text='Regenerate thumbnail')
-                op.asset_index = ui_props.active_index
-            elif asset_data['assetType'] == 'material':
-                op = layout.operator('object.blenderkit_regenerate_material_thumbnail', text='Regenerate thumbnail')
-                op.asset_index = ui_props.active_index
-                # op.asset_id = asset_data['id']
-                # op.asset_type = asset_data['assetType']
-
-        if author_id == str(profile['user']['id']):
-            row = layout.row()
-            row.operator_context = 'INVOKE_DEFAULT'
-            op = row.operator('object.blenderkit_change_status', text='Delete')
-            op.asset_id = asset_data['id']
-            op.state = 'deleted'
-
-        if utils.profile_is_validator():
-            layout.label(text='Dev Tools:')
-
-            op = layout.operator('object.blenderkit_print_asset_debug', text='Print asset debug')
-            op.asset_id = asset_data['id']
-
-
-# def draw_asset_resolution_replace(self, context, resolution):
-#     layout = self.layout
-#     ui_props = bpy.context.window_manager.blenderkitUI
-#
-#     op = layout.operator('scene.blenderkit_download', text=resolution)
-#     if ui_props.active_index == -3:
-#         # This happens if the command is called from addon panel
-#         o = utils.get_active_model()
-#         op.asset_base_id = o['asset_data']['assetBaseId']
-#
-#     else:
-#         op.asset_index = ui_props.active_index
-#
-#         op.asset_type = ui_props.asset_type
-#     if len(bpy.context.selected_objects) > 0:  # and ui_props.asset_type == 'MODEL':
-#         aob = bpy.context.active_object
-#         op.model_location = aob.location
-#         op.model_rotation = aob.rotation_euler
-#         op.target_object = aob.name
-#         op.material_target_slot = aob.active_material_index
-#     op.replace_resolution = True
-#     print('operator res ', resolution)
-#     op.resolution = resolution
-
-
-# class OBJECT_MT_blenderkit_resolution_menu(bpy.types.Menu):
-#     bl_label = "Replace Asset Resolution"
-#     bl_idname = "OBJECT_MT_blenderkit_resolution_menu"
-#
-#     def draw(self, context):
-#         ui_props = context.window_manager.blenderkitUI
-#
-#         # sr = bpy.context.window_manager['search results']
-#
-#         # sr = bpy.context.window_manager['search results']
-#         # asset_data = sr[ui_props.active_index]
-#
-#         for k in resolutions.resolution_props_to_server.keys():
-#             draw_asset_resolution_replace(self, context, k)
-
-
-class OBJECT_MT_blenderkit_asset_menu(bpy.types.Menu):
-    bl_label = "Asset options:"
-    bl_idname = "OBJECT_MT_blenderkit_asset_menu"
-
-    def draw(self, context):
-        ui_props = context.window_manager.blenderkitUI
-
-        sr = bpy.context.window_manager['search results']
-        asset_data = sr[ui_props.active_index]
-        draw_asset_context_menu(self.layout, context, asset_data, from_panel=False)
-
-
-def numeric_to_str(s):
-    if s:
-        if s < 1:
-            s = str(round(s, 1))
-        else:
-            s = str(round(s))
-    else:
-        s = '-'
-    return s
-
-
-def push_op_left(layout, strength=3):
-    for a in range(0, strength):
-        layout.label(text='')
-
-
-def label_or_url_or_operator(layout, text='', tooltip='', url='', operator=None, operator_kwargs={}, icon_value=None,
-                             icon=None):
-    '''automatically switch between different layout options for linking or tooltips'''
-    layout.emboss = 'NONE'
-
-    if operator is not None:
-        if icon:
-            op = layout.operator(operator, text=text, icon=icon)
-        elif icon_value:
-            op = layout.operator(operator, text=text, icon_value=icon_value)
-        else:
-            op = layout.operator(operator, text=text)
-        for kwarg in operator_kwargs.keys():
-            if type(operator_kwargs[kwarg]) == str:
-                quoatation = "'"
-            else:
-                quoatation = ""
-            exec(f"op.{kwarg} = {quoatation}{operator_kwargs[kwarg]}{quoatation}")
-        push_op_left(layout, strength=2)
-
-        return
-    if url != '':
-        if icon:
-            op = layout.operator('wm.blenderkit_url', text=text, icon=icon)
-        elif icon_value:
-            op = layout.operator('wm.blenderkit_url', text=text, icon_value=icon_value)
-        else:
-            op = layout.operator('wm.blenderkit_url', text=text)
-        op.url = url
-        op.tooltip = tooltip
-        push_op_left(layout, strength=5)
-
-        return
-    if tooltip != '':
-        if icon:
-            op = layout.operator('wm.blenderkit_tooltip', text=text, icon=icon)
-        elif icon_value:
-            op = layout.operator('wm.blenderkit_tooltip', text=text, icon_value=icon_value)
-        else:
-            op = layout.operator('wm.blenderkit_tooltip', text=text)
-        op.tooltip = tooltip
-
-        # these are here to move the text to left, since operators can only center text by default
-        push_op_left(layout, strength=3)
-        return
-    if icon:
-        layout.label(text=text, icon=icon)
-    elif icon_value:
-        layout.label(text=text, icon_value=icon_value)
-    else:
-        layout.label(text=text)
-
-
-class AssetPopupCard(bpy.types.Operator, ratings_utils.RatingsProperties):
-    """Generate Cycles thumbnail for model assets"""
-    bl_idname = "wm.blenderkit_asset_popup"
-    bl_label = "BlenderKit asset popup"
-
-    width = 800
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def draw_menu(self, context, layout):
-        # layout = layout.column()
-        draw_asset_context_menu(layout, context, self.asset_data, from_panel=False)
-
-    def draw_property(self, layout, left, right, icon=None, icon_value=None, url='', tooltip='', operator=None,
-                      operator_kwargs={}):
-        right = str(right)
-        row = layout.row()
-        split = row.split(factor=0.35)
-        split.alignment = 'RIGHT'
-        split.label(text=left)
-        split = split.split()
-        split.alignment = 'LEFT'
-        # split for questionmark:
-        if url != '':
-            split = split.split(factor=0.6)
-        label_or_url_or_operator(split, text=right, tooltip=tooltip, url=url, operator=operator,
-                                 operator_kwargs=operator_kwargs, icon_value=icon_value, icon=icon)
-        # additional questionmark icon where it's important?
-        if url != '':
-            split = split.split()
-            op = split.operator('wm.blenderkit_url', text='', icon='QUESTION')
-            op.url = url
-            op.tooltip = tooltip
-
-    def draw_asset_parameter(self, layout, key='', pretext='', do_search=False, decimal = True):
-        parameter = utils.get_param(self.asset_data, key)
-        if parameter == None:
-            return
-        if type(parameter) == int:
-            if decimal:
-                parameter = f"{parameter:,d}"
-            else:
-                parameter = f"{parameter}"
-        elif type(parameter) == float:
-            parameter = f"{parameter:,.1f}"
-        if do_search:
-            kwargs = {
-                'esc': True,
-                'keywords': f'+{key}:{parameter}',
-                'tooltip': f'search by {parameter}',
-            }
-            self.draw_property(layout, pretext, parameter, operator='view3d.blenderkit_search', operator_kwargs=kwargs)
-        else:
-            self.draw_property(layout, pretext, parameter)
-
-    def draw_description(self, layout, width=250):
-        if len(self.asset_data['description']) > 0:
-            box = layout.box()
-            box.scale_y = 0.4
-            box.label(text='Description')
-            box.separator()
-            link_more = utils.label_multiline(box, self.asset_data['description'], width=width, max_lines=10)
-            if link_more:
-                row = box.row()
-                row.scale_y = 2
-                op = row.operator('wm.blenderkit_url', text='See full description', icon='URL')
-                op.url = paths.get_asset_gallery_url(self.asset_data['assetBaseId'])
-                op.tooltip = 'Read full description on website'
-            box.separator()
-
-    def draw_properties(self, layout, width=250):
-
-        # if type(self.asset_data['parameters']) == list:
-        #     mparams = utils.params_to_dict(self.asset_data['parameters'])
-        # else:
-        #     mparams = self.asset_data['parameters']
-        mparams = self.asset_data['dictParameters']
-
-        pcoll = icons.icon_collections["main"]
-
-        box = layout.box()
-
-        box.scale_y = 0.4
-        box.label(text='Properties')
-        box.separator()
-
-        if self.asset_data.get('license') == 'cc_zero':
-            t = 'CC Zero          '
-            icon = pcoll['cc0']
-
-        else:
-            t = 'Royalty free'
-            icon = pcoll['royalty_free']
-
-        self.draw_property(box,
-                           'License', t,
-                           # icon_value=icon.icon_id,
-                           url="https://www.blenderkit.com/docs/licenses/",
-                           tooltip='All BlenderKit assets are available for commercial use. \n' \
-                                   'Click to read more about BlenderKit licenses on the website'
-                           )
-
-        if upload.can_edit_asset(asset_data=self.asset_data):
-            icon = pcoll[self.asset_data['verificationStatus']]
-            verification_status_tooltips = {
-                'uploading': "Your asset got stuck during upload. Probably, your file was too large "
-                             "or your connection too slow or interrupting. If you have repeated issues, "
-                             "please contact us and let us know, it might be a bug",
-                'uploaded': "Your asset uploaded successfully. Yay! If it's public, "
-                            "it's awaiting validation. If it's private, use it",
-                'on_hold': "Your asset needs some (usually smaller) fixes, "
-                           "so we can make it public for everybody."
-                           " Please check your email to see the feedback "
-                           "that we send to every creator personally",
-                'rejected': "The asset has serious quality issues, " \
-                            "and it's probable that it might be good to start " \
-                            "all over again or try with something simpler. " \
-                            "You also get personal feedback into your e-mail, " \
-                            "since we believe that together, we can all learn " \
-                            "to become awesome 3D artists",
-                'deleted': "You deleted this asset",
-                'validated': "Your asset passed our validation process, "
-                             "and is now available to BlenderKit users"
-
-            }
-            self.draw_property(box,
-                               'Verification',
-                               self.asset_data['verificationStatus'],
-                               icon_value=icon.icon_id,
-                               url="https://www.blenderkit.com/docs/validation-status/",
-                               tooltip=verification_status_tooltips[self.asset_data['verificationStatus']]
-
-                               )
-        # resolution/s
-        resolution = utils.get_param(self.asset_data, 'textureResolutionMax')
-
-        if resolution is not None:
-            fs = self.asset_data['files']
-
-            ress = f"{int(round(resolution / 1024, 0))}K"
-            self.draw_property(box, 'Resolution', ress,
-                               tooltip='Maximal resolution of textures in this asset.\n' \
-                                       'Most texture asset have also lower resolutions generated.\n' \
-                                       'Go to BlenderKit add-on import settings to set default resolution')
-
-            if fs and len(fs) > 2 and utils.profile_is_validator():
-                resolutions = ''
-                list.sort(fs, key=lambda f: f['fileType'])
-                for f in fs:
-                    if f['fileType'].find('resolution') > -1:
-                        resolutions += f['fileType'][11:] + ' '
-                resolutions = resolutions.replace('_', '.')
-                self.draw_property(box, 'Generated', resolutions)
-
-        self.draw_asset_parameter(box, key='designer', pretext='Designer', do_search=True)
-        self.draw_asset_parameter(box, key='manufacturer', pretext='Manufacturer',
-                                  do_search=True)
-        self.draw_asset_parameter(box, key='designCollection', pretext='Collection', do_search=True)
-        self.draw_asset_parameter(box, key='designVariant', pretext='Variant')
-        self.draw_asset_parameter(box, key='designYear', pretext='Design year', decimal = False)
-
-        self.draw_asset_parameter(box, key='faceCount', pretext='Face count')
-        # self.draw_asset_parameter(box, key='thumbnailScale', pretext='Preview scale')
-        # self.draw_asset_parameter(box, key='purePbr', pretext='Pure PBR')
-        # self.draw_asset_parameter(box, key='productionLevel', pretext='Readiness')
-        # self.draw_asset_parameter(box, key='condition', pretext='Condition')
-        if utils.profile_is_validator():
-            self.draw_asset_parameter(box, key='materialStyle', pretext='Style')
-            self.draw_asset_parameter(box, key='modelStyle', pretext='Style')
-
-        if utils.get_param(self.asset_data, 'dimensionX'):
-            t = utils.fmt_dimensions(mparams)
-            self.draw_property(box, 'Size', t)
-        if self.asset_data.get('filesSize'):
-            fs = self.asset_data['filesSize']
-            fsmb = fs // (1024 * 1024)
-            fskb = fs % 1024
-            if fsmb == 0:
-                self.draw_property(box, 'Original size', f'{fskb} KB')
-            else:
-                self.draw_property(box, 'Original size', f'{fsmb} MB')
-        # Tags section
-        # row = box.row()
-        # letters_on_row = 0
-        # max_on_row = width / 10
-        # for tag in self.asset_data['tags']:
-        #     if tag in ('manifold', 'uv', 'non-manifold'):
-        #         # these are sometimes accidentally stored in the lib
-        #         continue
-        #
-        #     # row.emboss='NONE'
-        #     # we need to split wisely
-        #     remaining_row = (max_on_row - letters_on_row) / max_on_row
-        #     split_factor = (len(tag) / max_on_row) / remaining_row
-        #     row = row.split(factor=split_factor)
-        #     letters_on_row += len(tag)
-        #     if letters_on_row > max_on_row:
-        #         letters_on_row = len(tag)
-        #         row = box.row()
-        #         remaining_row = (max_on_row - letters_on_row) / max_on_row
-        #         split_factor = (len(tag) / max_on_row) / remaining_row
-        #         row = row.split(factor=split_factor)
-        #
-        #     op = row.operator('wm')
-        #     op = row.operator('view3d.blenderkit_search', text=tag)
-        #     op.tooltip = f'Search items with tag {tag}'
-        #     # build search string from description and tags:
-        #     op.keywords = f'+tags:{tag}'
-
-        # self.draw_property(box, 'Tags', self.asset_data['tags']) #TODO make them clickable!
-
-        # Free/Full plan or private Access
-        plans_tooltip = 'BlenderKit has 2 plans:\n' \
-                        '  *  Free plan - more than 50% of all assets\n' \
-                        '  *  Full plan - unlimited access to everything\n' \
-                        'Click to go to subscriptions page'
-        plans_link = 'https://www.blenderkit.com/plans/pricing/'
-        if self.asset_data['isPrivate']:
-            t = 'Private'
-            self.draw_property(box, 'Access', t, icon='LOCKED')
-        elif self.asset_data['isFree']:
-            t = 'Free plan'
-            icon = pcoll['free']
-            self.draw_property(box, 'Access', t,
-                               icon_value=icon.icon_id,
-                               tooltip=plans_tooltip,
-                               url=plans_link)
-        else:
-            t = 'Full plan'
-            icon = pcoll['full']
-            self.draw_property(box, 'Access', t,
-                               icon_value=icon.icon_id,
-                               tooltip=plans_tooltip,
-                               url=plans_link)
-        if utils.profile_is_validator():
-            date = self.asset_data['created'][:10]
-            date = f"{date[8:10]}. {date[5:7]}. {date[:4]}"
-            self.draw_property(box, 'Created', date)
-        if utils.asset_from_newer_blender_version(self.asset_data):
-            # row = box.row()
-            box.alert = True
-            self.draw_property(box,
-                               'Blender version',
-                               self.asset_data['sourceAppVersion'],
-                               # icon='ERROR',
-                               tooltip='Asset is from a newer Blender version and might work incorrectly in your scene',
-                               )
-            box.alert = False
-        box.separator()
-
-    def draw_author_area(self, context, layout, width=330):
-        self.draw_author(context, layout, width=width)
-
-    def draw_author(self, context, layout, width=330):
-        image_split = 0.25
-        text_width = width
-        authors = bpy.context.window_manager['bkit authors']
-        a = authors.get(self.asset_data['author']['id'])
-        if a is not None:  # or a is '' or (a.get('gravatarHash') is not None and a.get('gravatarImg') is None):
-
-            row = layout.row()
-            author_box = row.box()
-            author_box.scale_y = 0.6  # get text lines closer to each other
-            author_box.label(text='Author')  # just one extra line to give spacing
-            if hasattr(self, 'gimg'):
-
-                author_left = author_box.split(factor=image_split)
-                author_left.template_icon(icon_value=self.gimg.preview.icon_id, scale=7)
-                text_area = author_left.split()
-                text_width = int(text_width * (1 - image_split))
-            else:
-                text_area = author_box
-
-            author_right = text_area.column()
-            row = author_right.row()
-            col = row.column()
-
-            utils.label_multiline(col, text=a['tooltip'], width=text_width)
-            # check if author didn't fill any data about himself and prompt him if that's the case
-            if utils.user_is_owner(asset_data=self.asset_data) and a.get('aboutMe') is not None and len(
-                    a.get('aboutMe', '')) == 0:
-                row = col.row()
-                row.enabled = False
-                row.label(text='Please introduce yourself to the community!')
-
-                op = col.operator('wm.blenderkit_url', text='Edit your profile')
-                op.url = 'https://www.blenderkit.com/profile'
-                op.tooltip = 'Edit your profile on BlenderKit webpage'
-
-            button_row = author_box.row()
-            button_row.scale_y = 2.0
-
-            if a.get('aboutMeUrl') is not None:
-                url = a['aboutMeUrl']
-                text = url
-                if len(url) > 45:
-                    text = url[:45] + '...'
-                op = button_row.operator('wm.url_open', text=text)
-                op.url = url
-                button_row = author_box.row()
-                button_row.scale_y = 2.0
-
-            url = paths.get_author_gallery_url(a['id'])
-            text = "Author's Profile"
-
-            op = button_row.operator('wm.url_open', text=text)
-            op.url = url
-
-            op = button_row.operator('view3d.blenderkit_search', text="Find Assets By Author")
-            op.esc = True
-            op.keywords = ''
-            op.author_id = self.asset_data['author']['id']
-
-    def draw_thumbnail_box(self, layout, width=250):
-        layout.emboss = 'NORMAL'
-
-        box_thumbnail = layout.box()
-
-        box_thumbnail.scale_y = .4
-        box_thumbnail.template_icon(icon_value=self.img.preview.icon_id, scale=width * .12)
-
-        # op = row.operator('view3d.asset_drag_drop', text='Drag & Drop from here', depress=True)
-        # From here on, only ratings are drawn, which won't be displayed for private assets from now on.
-
-        if not self.asset_data['isPrivate']:
-            row = box_thumbnail.row()
-            row.alignment = 'EXPAND'
-
-            # display_ratings = can_display_ratings(self.asset_data)
-            rc = self.asset_data.get('ratingsCount')
-            show_rating_threshold = 0
-            show_rating_prompt_threshold = 5
-
-            if rc:
-                rcount = min(rc['quality'], rc['workingHours'])
-            else:
-                rcount = 0
-            if rcount >= show_rating_threshold or upload.can_edit_asset(asset_data=self.asset_data):
-                s = numeric_to_str(self.asset_data['score'])
-                q = numeric_to_str(self.asset_data['ratingsAverage'].get('quality'))
-                c = numeric_to_str(self.asset_data['ratingsAverage'].get('workingHours'))
-            else:
-                s = '-'
-                q = '-'
-                c = '-'
-
-            pcoll = icons.icon_collections["main"]
-
-            row.emboss = 'NONE'
-            op = row.operator('wm.blenderkit_tooltip', text=str(s), icon_value=pcoll['trophy'].icon_id)
-            op.tooltip = 'Asset score calculated from user ratings. \n\n' \
-                         'Score = average quality × median complexity × 10*\n\n *Happiness multiplier'
-            row.label(text='   ')
-
-            tooltip_extension = f'.\n\nRatings results are shown for assets with more than {show_rating_threshold} ratings'
-            op = row.operator('wm.blenderkit_tooltip', text=str(q), icon='SOLO_ON')
-            op.tooltip = f"Quality, average from {rc['quality']} rating{'' if rc['quality'] == 1 else 's'}" \
-                         f"{tooltip_extension if rcount <= show_rating_threshold else ''}"
-            row.label(text='   ')
-
-            op = row.operator('wm.blenderkit_tooltip', text=str(c), icon_value=pcoll['dumbbell'].icon_id)
-            op.tooltip = f"Complexity, median from {rc['workingHours']} rating{'' if rc['workingHours'] == 1 else 's'}" \
-                         f"{tooltip_extension if rcount <= show_rating_threshold else ''}"
-
-            if rcount <= show_rating_prompt_threshold:
-                box_thumbnail.alert = True
-                box_thumbnail.label(text=f"")
-                box_thumbnail.label(
-                    text=f"This asset has only {rcount} rating{'' if rcount == 1 else 's'}, please rate.")
-                # box_thumbnail.label(text=f"Please rate this asset.")
-
-        row = box_thumbnail.row()
-        row.alert = False
-
-        row.scale_y = 3
-        ui_props = bpy.context.window_manager.blenderkitUI
-        if self.asset_data.get('canDownload', True):
-            row.prop(ui_props, 'drag_init_button', icon='MOUSE_LMB_DRAG', text='Click / Drag from here', emboss=True)
-        else:
-            op = layout.operator('wm.blenderkit_url', text='Unlock this asset', icon='UNLOCKED')
-            op.url = paths.get_bkit_url() + '/get-blenderkit/' + self.asset_data['id'] + '/?from_addon=True'
-
-    def draw_menu_desc_author(self, context, layout, width=330):
-        box = layout.column()
-
-        box.emboss = 'NORMAL'
-        # left - tooltip & params
-        row = box.row()
-        split_factor = 0.7
-        split_left = row.split(factor=split_factor)
-        col = split_left.column()
-        width_left = int(width * split_factor)
-        self.draw_description(col, width=width_left)
-
-        self.draw_properties(col, width=width_left)
-
-        # right - menu
-        split_right = split_left.split()
-        col = split_right.column()
-        self.draw_menu(context, col)
-
-        # author
-        self.draw_author_area(context, box, width=width)
-
-        # self.draw_author_area(context, box, width=width)
-        #
-        # col = box.column_flow(columns=2)
-        # self.draw_menu(context, col)
-        #
-        #
-        # # self.draw_description(box, width=int(width))
-        # self.draw_properties(box, width=int(width))
-
-        # define enum flags
-
-    def draw_titlebar(self, context, layout):
-        top_drag_bar = layout.box()
-        bcats = bpy.context.window_manager['bkit_categories']
-
-        cat_path = categories.get_category_path(bcats,
-                                                self.asset_data['category'])[1:]
-
-        cat_path_names = categories.get_category_name_path(bcats,
-                                                           self.asset_data['category'])[1:]
-
-        aname = self.asset_data['displayName']
-        aname = aname[0].upper() + aname[1:]
-
-        if 1:
-            name_row = top_drag_bar.row()
-            # name_row = name_row.split(factor=0.5)
-            # name_row = name_row.column()
-            # name_row = name_row.row()
-            for i, c in enumerate(cat_path):
-                cat_name = cat_path_names[i]
-                op = name_row.operator('view3d.blenderkit_asset_bar_widget', text=cat_name + '     >', emboss=True)
-                op.do_search = True
-                op.keep_running = True
-                op.tooltip = f"Browse {cat_name} category"
-                op.category = c
-                # name_row.label(text='>')
-
-            name_row.label(text=aname)
-            push_op_left(name_row, strength=3)
-            op = name_row.operator('view3d.close_popup_button', text='', icon='CANCEL')
-
-    def draw_comment(self, context, layout, comment, width=330):
-        row = layout.row()
-        # print(comment)
-        if comment['level'] > 0:
-            split = row.split(factor=0.05 * comment['level'])
-            split.label(text='')
-            row = split.split()
-        box = row.box()
-        box.emboss = 'NORMAL'
-        row = box.row()
-        split = row.split(factor=0.8)
-        is_moderator = comment['userModerator']
-        if is_moderator:
-            role_text = f" - moderator"
-        else:
-            role_text = ""
-        row = split.row()
-        row.enabled = False
-        row.label(text=f"{comment['submitDate']} - {comment['userName']}{role_text}")
-        removal = False
-        likes = 0
-        dislikes = 0
-        for l in comment['flags']:
-            if l['flag'] == 'like':
-                likes += 1
-            if l['flag'] == 'dislike':
-                dislikes += 1
-            if l['flag'] == 'removal':
-                removal = True
-        # row = box.row()
-        split1 = split.split()
-        # split1.emboss = 'NONE'
-        op = split1.operator('wm.blenderkit_like_comment', text=str(likes), icon='TRIA_UP')
-        op.asset_id = self.asset_data['assetBaseId']
-        op.comment_id = comment['id']
-        op.flag = 'like'
-        op = split1.operator('wm.blenderkit_like_comment', text=str(dislikes), icon='TRIA_DOWN')
-        op.asset_id = self.asset_data['assetBaseId']
-        op.comment_id = comment['id']
-        op.flag = 'dislike'
-        # op = split1.operator('wm.blenderkit_like_comment', text='report', icon='ERROR')
-        # op.asset_id = self.asset_data['assetBaseId']
-        # op.comment_id = comment['id']
-        # op.flag = 'removal'
-        if removal:
-            row.alert = True
-            row.label(text='', icon='ERROR')
-
-        rows = utils.label_multiline(box, text=comment['comment'], width=width * (1 - 0.05 * comment['level']))
-
-        row = rows[-1]
-        split = row.split(factor=.8)
-        split.label(text='')
-        split = split.split()
-        op = split.operator('wm.blenderkit_url', text='Reply', icon='GREASEPENCIL')
-        op.tooltip = 'Open the browser on the asset page to comment'
-        op.url = paths.get_bkit_url() + f"/asset-gallery-detail/{self.asset_data['id']}/"
-        # box.label(text=str(comment['flags']))
-
-    def draw(self, context):
-        layout = self.layout
-        # top draggable bar with name of the asset
-        top_row = layout.row()
-        self.draw_titlebar(context, top_row)
-        # left side
-        row = layout.row(align=True)
-        split_ratio = 0.45
-        split_left = row.split(factor=split_ratio)
-        left_column = split_left.column()
-        self.draw_thumbnail_box(left_column, width=int(self.width * split_ratio))
-        # self.draw_description(left_column, width = int(self.width*split_ratio))
-        # right split
-        split_right = split_left.split()
-        self.draw_menu_desc_author(context, split_right, width=int(self.width * (1 - split_ratio)))
-
-        if not utils.user_is_owner(asset_data=self.asset_data):
-            # Draw ratings, but not for owners of assets - doesn't make sense.
-            ratings_box = layout.box()
-            ratings.draw_ratings_menu(self, context, ratings_box)
-        # else:
-        #     ratings_box.label('Here you should find ratings, but you can not rate your own assets ;)')
-
-        tip_box = layout.box()
-        tip_box.label(text=self.tip)
-        # comments
-        if utils.profile_is_validator():
-            comments = bpy.context.window_manager.get('asset comments', {})
-            self.comments = comments.get(self.asset_data['assetBaseId'], [])
-            if self.comments is not None:
-                for comment in self.comments:
-                    self.draw_comment(context, layout, comment, width=self.width)
-
-    def prefill_ratings(self):
-        # pre-fill ratings
-        ratings = ratings_utils.get_rating_local(self.asset_id)
-        if ratings and ratings.get('quality'):
-            self.rating_quality = ratings['quality']
-        if ratings and ratings.get('working_hours'):
-            wh = int(ratings['working_hours'])
-            whs = str(wh)
-            if wh in self.possible_wh_values:
-                self.rating_work_hours_ui = whs
-            if wh < 6 and wh in self.possible_wh_values_1_5:
-                self.rating_work_hours_ui_1_5 = whs
-            if wh < 11 and wh in self.possible_wh_values_1_10:
-                self.rating_work_hours_ui_1_10 = whs
-
-    def execute(self, context):
-        wm = context.window_manager
-        ui_props = context.window_manager.blenderkitUI
-        ui_props.draw_tooltip = False
-        sr = bpy.context.window_manager['search results']
-        asset_data = sr[ui_props.active_index]
-        self.asset_data = asset_data
-
-        self.img = ui.get_large_thumbnail_image(asset_data)
-        utils.img_to_preview(self.img, copy_original=True)
-
-        self.asset_type = asset_data['assetType']
-        self.asset_id = asset_data['id']
-        # self.tex = utils.get_hidden_texture(self.img)
-        # self.tex.update_tag()
-
-        authors = bpy.context.window_manager['bkit authors']
-        a = authors.get(asset_data['author']['id'])
-
-        if a is not None and a.get('gravatarImg') is not None:
-            self.gimg = utils.get_hidden_image(a['gravatarImg'], a['gravatarHash'])
-
-        bl_label = asset_data['name']
-        self.tip = search.get_random_tip()
-        self.tip = self.tip.replace('\n', '')
-
-        # pre-fill ratings
-        self.prefill_ratings()
-
-        # get comments
-        if utils.profile_is_validator():
-            user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-            api_key = user_preferences.api_key
-            comments = comments_utils.get_comments_local(asset_data['assetBaseId'])
-            # if comments is None:
-            comments_utils.get_comments_thread(asset_data['assetBaseId'], api_key)
-            comments = bpy.context.window_manager.get('asset comments', {})
-            self.comments = comments.get(asset_data['assetBaseId'], [])
-
-        return wm.invoke_popup(self, width=self.width)
-
-
-class OBJECT_MT_blenderkit_login_menu(bpy.types.Menu):
-    bl_label = "BlenderKit login/signup:"
-    bl_idname = "OBJECT_MT_blenderkit_login_menu"
-
-    def draw(self, context):
-        layout = self.layout
-
-        # utils.label_multiline(layout, text=message)
-        draw_login_buttons(layout)
-
-
-class SetCategoryOperator(bpy.types.Operator):
-    """Visit subcategory"""
-    bl_idname = "view3d.blenderkit_set_category"
-    bl_label = "BlenderKit Set Active Category"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    category: bpy.props.StringProperty(
-        name="Category",
-        description="set this category active",
-        default="")
-
-    asset_type: bpy.props.StringProperty(
-        name="Asset Type",
-        description="asset type",
-        default="")
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def execute(self, context):
-        acat = bpy.context.window_manager['active_category'][self.asset_type]
-        if self.category == '':
-            acat.remove(acat[-1])
-        else:
-            acat.append(self.category)
-        # we have to write back to wm. Thought this should happen with original list.
-        bpy.context.window_manager['active_category'][self.asset_type] = acat
-        return {'FINISHED'}
-
-
-class ClosePopupButton(bpy.types.Operator):
-    """Close popup window"""
-    bl_idname = "view3d.close_popup_button"
-    bl_label = "Close popup"
-    bl_options = {'REGISTER', 'INTERNAL'}
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def win_close(self):
-        VK_ESCAPE = 0x1B
-        ctypes.windll.user32.keybd_event(VK_ESCAPE)
-        return True
-
-    def mouse_trick(self, context, x, y):
-        # import time
-        context.area.tag_redraw()
-        w = context.window
-        w.cursor_warp(w.x + 15, w.y + w.height - 15);
-        # time.sleep(.12)
-        w.cursor_warp(x, y);
-        context.area.tag_redraw()
-
-    def invoke(self, context, event):
-        if platform.system() == 'Windows':
-            self.win_close()
-        else:
-            self.mouse_trick(context, event.mouse_x, event.mouse_y)
-        return {'FINISHED'}
-
-
-class UrlPopupDialog(bpy.types.Operator):
-    """Generate Cycles thumbnail for model assets"""
-    bl_idname = "wm.blenderkit_url_dialog"
-    bl_label = "BlenderKit message:"
-    bl_options = {'REGISTER', 'INTERNAL'}
-
-    url: bpy.props.StringProperty(
-        name="Url",
-        description="url",
-        default="")
-
-    link_text: bpy.props.StringProperty(
-        name="Url",
-        description="url",
-        default="Go to website")
-
-    message: bpy.props.StringProperty(
-        name="Text",
-        description="text",
-        default="")
-
-    # @classmethod
-    # def poll(cls, context):
-    #     return bpy.context.view_layer.objects.active is not None
-
-    def draw(self, context):
-        layout = self.layout
-        utils.label_multiline(layout, text=self.message, width=300)
-
-        layout.active_default = True
-        op = layout.operator("wm.url_open", text=self.link_text, icon='QUESTION')
-        if not utils.user_logged_in():
-            utils.label_multiline(layout,
-                                  text='Already subscribed? You need to login to access your Full Plan.',
-                                  width=300)
-
-            layout.operator_context = 'EXEC_DEFAULT'
-            layout.operator("wm.blenderkit_login", text="Login",
-                            icon='URL').signup = False
-        op.url = self.url
-
-    def execute(self, context):
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-        return wm.invoke_props_dialog(self, width=300)
-
-
-class LoginPopupDialog(bpy.types.Operator):
-    """Popup a dialog which enables the user to log in after being logged out automatically."""
-    bl_idname = "wm.blenderkit_login_dialog"
-    bl_label = "BlenderKit login"
-    bl_options = {'REGISTER', 'INTERNAL'}
-
-    message: bpy.props.StringProperty(
-        name="Message",
-        description="",
-        default="Your were logged out from BlenderKit. Please login again. ")
-
-    # @classmethod
-    # def poll(cls, context):
-    #     return bpy.context.view_layer.objects.active is not None
-
-    def draw(self, context):
-        layout = self.layout
-        utils.label_multiline(layout, text=self.message)
-
-        layout.active_default = True
-        op = layout.operator
-        op = layout.operator("wm.url_open", text=self.link_text, icon='QUESTION')
-        op.url = self.url
-
-    def execute(self, context):
-        # start_thumbnailer(self, context)
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-
-        return wm.invoke_props_dialog(self)
-
-
-def draw_panel_categories(self, context):
-    s = context.scene
-    ui_props = bpy.context.window_manager.blenderkitUI
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    layout = self.layout
-    # row = layout.row()
-    # row.prop(ui_props, 'asset_type', expand=True, icon_only=True)
-    wm = bpy.context.window_manager
-    if wm.get('bkit_categories') == None:
-        return
-    col = layout.column(align=True)
-    if wm.get('active_category') is not None:
-        acat = wm['active_category'][ui_props.asset_type]
-        if len(acat) > 1:
-            # we are in subcategory, so draw the parent button
-            op = col.operator('view3d.blenderkit_set_category', text='...', icon='FILE_PARENT')
-            op.asset_type = ui_props.asset_type
-            op.category = ''
-    cats = categories.get_category(wm['bkit_categories'], cat_path=acat)
-    # draw freebies only in models parent category
-    # if ui_props.asset_type == 'MODEL' and len(acat) == 1:
-    #     op = col.operator('view3d.blenderkit_asset_bar_widget', text='freebies')
-    #     op.free_only = True
-
-    for c in cats['children']:
-        if c['assetCount'] > 0 or (utils.profile_is_validator() and user_preferences.categories_fix):
-            row = col.row(align=True)
-            if len(c['children']) > 0 and c['assetCount'] > 15 or (
-                    utils.profile_is_validator() and user_preferences.categories_fix):
-                row = row.split(factor=.8, align=True)
-            # row = split.split()
-            ctext = '%s (%i)' % (c['name'], c['assetCount'])
-
-            preferences = bpy.context.preferences.addons['blenderkit'].preferences
-            if 1:#preferences.experimental_features:
-                op = row.operator('view3d.blenderkit_asset_bar_widget', text=ctext)
-            else:
-                op = row.operator('view3d.blenderkit_asset_bar', text=ctext)
-            op.do_search = True
-            op.keep_running = True
-            op.tooltip = f"Browse {c['name']} category"
-            op.category = c['slug']
-            if len(c['children']) > 0 and c['assetCount'] > 15 or (
-                    utils.profile_is_validator() and user_preferences.categories_fix):
-                # row = row.split()
-                op = row.operator('view3d.blenderkit_set_category', text='>>')
-                op.asset_type = ui_props.asset_type
-                op.category = c['slug']
-                # for c1 in c['children']:
-                #     if c1['assetCount']>0:
-                #         row = col.row()
-                #         split = row.split(percentage=.2)
-                #         row = split.split()
-                #         row = split.split()
-                #         ctext = '%s (%i)' % (c1['name'], c1['assetCount'])
-                #         op = row.operator('view3d.blenderkit_search', text=ctext)
-                #         op.category = c1['slug']
-
-
-class VIEW3D_PT_blenderkit_downloads(Panel):
-    bl_category = "BlenderKit"
-    bl_idname = "VIEW3D_PT_blenderkit_downloads"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'UI'
-    bl_label = "Downloads"
-
-    @classmethod
-    def poll(cls, context):
-        return len(download.download_threads) > 0
-
-    def draw(self, context):
-        layout = self.layout
-        for i, threaddata in enumerate(download.download_threads):
-            tcom = threaddata[2]
-            asset_data = threaddata[1]
-            row = layout.row()
-            row.label(text=asset_data['name'])
-            row.label(text=str(int(tcom.progress)) + ' %')
-            op = row.operator('scene.blenderkit_download_kill', text='', icon='CANCEL')
-            op.thread_index = i
-            if tcom.passargs.get('retry_counter', 0) > 0:
-                row = layout.row()
-                row.label(text='failed. retrying ... ', icon='ERROR')
-                row.label(text=str(tcom.passargs["retry_counter"]))
-
-                layout.separator()
-
-
-def header_search_draw(self, context):
-    '''Top bar menu in 3D view'''
-
-    if not utils.guard_from_crash():
-        return;
-
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    if not preferences.search_in_header:
-        return
-    if context.mode not in ('PAINT_TEXTURE', 'OBJECT', 'SCULPT'):
-        return
-
-    layout = self.layout
-    s = bpy.context.scene
-    wm = bpy.context.window_manager
-    ui_props = bpy.context.window_manager.blenderkitUI
-    if ui_props.asset_type == 'MODEL':
-        props = wm.blenderkit_models
-    if ui_props.asset_type == 'MATERIAL':
-        props = wm.blenderkit_mat
-    if ui_props.asset_type == 'BRUSH':
-        props = wm.blenderkit_brush
-    if ui_props.asset_type == 'HDR':
-        props = wm.blenderkit_HDR
-    if ui_props.asset_type == 'SCENE':
-        props = wm.blenderkit_scene
-
-    # the center snap menu is in edit and object mode if tool settings are off.
-    # if context.space_data.show_region_tool_header == True or context.mode[:4] not in ('EDIT', 'OBJE'):
-    #     layout.separator_spacer()
-    layout.prop(ui_props, "asset_type", expand=True, icon_only=True, text='', icon='URL')
-    layout.prop(props, "search_keywords", text="", icon='VIEWZOOM')
-    draw_assetbar_show_hide(layout, props)
-    layout.popover(panel="VIEW3D_PT_blenderkit_categories", text="", icon='OUTLINER')
-
-    pcoll = icons.icon_collections["main"]
-
-    if props.use_filters:
-        icon_id = pcoll['filter_active'].icon_id
-    else:
-        icon_id = pcoll['filter'].icon_id
-
-    if ui_props.asset_type == 'MODEL':
-        layout.popover(panel="VIEW3D_PT_blenderkit_advanced_model_search", text="", icon_value=icon_id)
-
-    elif ui_props.asset_type == 'MATERIAL':
-        layout.popover(panel="VIEW3D_PT_blenderkit_advanced_material_search", text="", icon_value=icon_id)
-    elif ui_props.asset_type == 'HDR':
-        layout.popover(panel="VIEW3D_PT_blenderkit_advanced_HDR_search", text="", icon_value=icon_id)
-
-    notifications = bpy.context.window_manager.get('bkit notifications')
-    if notifications is not None and notifications['count'] > 0:
-        layout.operator('wm.show_notifications', text="", icon_value=pcoll['bell'].icon_id)
-        # layout.popover(panel="VIEW3D_PT_blenderkit_notifications", text="", icon_value=pcoll['bell'].icon_id)
-
-    if utils.profile_is_validator():
-        search_props = utils.get_search_props()
-        layout.prop(search_props, 'search_verification_status', text='')
-
-
-def ui_message(title, message):
-    def draw_message(self, context):
-        layout = self.layout
-        utils.label_multiline(layout, text=message, width=400)
-
-    bpy.context.window_manager.popup_menu(draw_message, title=title, icon='INFO')
-
-
-# We can store multiple preview collections here,
-# however in this example we only store "main"
-preview_collections = {}
-
-classes = (
-    SetCategoryOperator,
-    VIEW3D_PT_blenderkit_profile,
-    VIEW3D_PT_blenderkit_login,
-    VIEW3D_PT_blenderkit_notifications,
-    VIEW3D_PT_blenderkit_unified,
-    VIEW3D_PT_blenderkit_advanced_model_search,
-    VIEW3D_PT_blenderkit_advanced_material_search,
-    VIEW3D_PT_blenderkit_advanced_HDR_search,
-    VIEW3D_PT_blenderkit_categories,
-    VIEW3D_PT_blenderkit_import_settings,
-    VIEW3D_PT_blenderkit_model_properties,
-    NODE_PT_blenderkit_material_properties,
-    # VIEW3D_PT_blenderkit_ratings,
-    VIEW3D_PT_blenderkit_downloads,
-    # OBJECT_MT_blenderkit_resolution_menu,
-    OBJECT_MT_blenderkit_asset_menu,
-    OBJECT_MT_blenderkit_login_menu,
-    AssetPopupCard,
-    UrlPopupDialog,
-    ClosePopupButton,
-    BlenderKitWelcomeOperator,
-    MarkNotificationRead,
-    LikeComment,
-    ShowNotifications,
-    NotificationOpenTarget,
-    MarkAllNotificationsRead,
-)
-
-
-def header_draw(self, context):
-    layout = self.layout
-
-    self.draw_tool_settings(context)
-
-    layout.separator_spacer()
-    header_search_draw(self,context)
-    layout.separator_spacer()
-
-    self.draw_mode_settings(context)
-
-
-def register_ui_panels():
-    for c in classes:
-        bpy.utils.register_class(c)
-
-    bpy.types.VIEW3D_HT_tool_header.draw = header_draw
-    # bpy.types.VIEW3D_HT_tool_header.append(header_search_draw)
-    # bpy.types.VIEW3D_MT_editor_menus.append(header_search_draw)
-
-
-def unregister_ui_panels():
-    bpy.types.VIEW3D_HT_tool_header.remove(header_search_draw)
-    # bpy.types.VIEW3D_MT_editor_menus.remove(header_search_draw)
-    for c in classes:
-        # print('unregister', c)
-        bpy.utils.unregister_class(c)
diff --git a/blenderkit/upload.py b/blenderkit/upload.py
deleted file mode 100644
index 3d8b705ba05e8ee8639b87d926aa114ed1b8c24c..0000000000000000000000000000000000000000
--- a/blenderkit/upload.py
+++ /dev/null
@@ -1,1387 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import asset_inspector, paths, utils, bg_blender, autothumb, version_checker, search, ui_panels, ui, \
-    overrides, colors, rerequests, categories, upload_bg, tasks_queue, image_utils, asset_bar_op, reports
-
-import tempfile, os, subprocess, json, re
-
-import bpy
-import requests
-import threading
-import sys
-
-BLENDERKIT_EXPORT_DATA_FILE = "data.json"
-
-from bpy.props import (  # TODO only keep the ones actually used when cleaning
-    EnumProperty,
-    BoolProperty,
-    StringProperty,
-)
-from bpy.types import (
-    Operator,
-    Panel,
-    AddonPreferences,
-    PropertyGroup,
-    UIList
-)
-
-licenses = (
-    ('royalty_free', 'Royalty Free', 'royalty free commercial license'),
-    ('cc_zero', 'Creative Commons Zero', 'Creative Commons Zero'),
-)
-
-
-def comma2array(text):
-    commasep = text.split(',')
-    ar = []
-    for i, s in enumerate(commasep):
-        s = s.strip()
-        if s != '':
-            ar.append(s)
-    return ar
-
-
-def get_app_version():
-    ver = bpy.app.version
-    return '%i.%i.%i' % (ver[0], ver[1], ver[2])
-
-
-def add_version(data):
-    app_version = get_app_version()
-    addon_version = version_checker.get_addon_version()
-    data["sourceAppName"] = "blender"
-    data["sourceAppVersion"] = app_version
-    data["addonVersion"] = addon_version
-
-
-def write_to_report(props, text):
-    props.report = props.report + ' - ' + text + '\n\n'
-
-
-def check_missing_data_model(props):
-    autothumb.update_upload_model_preview(None, None)
-    if not props.has_thumbnail:
-        write_to_report(props, 'Add thumbnail:')
-        props.report += props.thumbnail_generating_state + '\n'
-    if props.engine == 'NONE':
-        write_to_report(props, 'Set at least one rendering/output engine')
-
-    # if not any(props.dimensions):
-    #     write_to_report(props, 'Run autotags operator or fill in dimensions manually')
-
-
-def check_missing_data_scene(props):
-    autothumb.update_upload_model_preview(None, None)
-    if not props.has_thumbnail:
-        write_to_report(props, 'Add thumbnail:')
-        props.report += props.thumbnail_generating_state + '\n'
-    if props.engine == 'NONE':
-        write_to_report(props, 'Set at least one rendering/output engine')
-
-
-def check_missing_data_material(props):
-    autothumb.update_upload_material_preview(None, None)
-    if not props.has_thumbnail:
-        write_to_report(props, 'Add thumbnail:')
-        props.report += props.thumbnail_generating_state
-    if props.engine == 'NONE':
-        write_to_report(props, 'Set rendering/output engine')
-
-
-def check_missing_data_brush(props):
-    autothumb.update_upload_brush_preview(None, None)
-    if not props.has_thumbnail:
-        write_to_report(props, 'Add thumbnail:')
-        props.report += props.thumbnail_generating_state
-
-
-def check_missing_data(asset_type, props):
-    '''
-    checks if user did everything allright for particular assets and notifies him back if not.
-    Parameters
-    ----------
-    asset_type
-    props
-
-    Returns
-    -------
-
-    '''
-    props.report = ''
-
-    if props.name == '':
-        write_to_report(props, f'Set {asset_type.lower()} name.\n'
-                               f'It has to be in English and \n'
-                               f'can not be  longer than 40 letters.\n')
-    if len(props.name) > 40:
-        write_to_report(props, f'The name is too long. maximum is 40 letters')
-
-    if props.is_private == 'PUBLIC':
-
-        if len(props.description) < 20:
-            write_to_report(props, "The description is too short or empty. \n"
-                                   "Please write a description that describes \n "
-                                   "your asset as good as possible.\n"
-                                   "Description helps to bring your asset up\n in relevant search results. ")
-        if props.tags == '':
-            write_to_report(props, 'Write at least 3 tags.\n'
-                                   'Tags help to bring your asset up in relevant search results.')
-
-    if asset_type == 'MODEL':
-        check_missing_data_model(props)
-    if asset_type == 'SCENE':
-        check_missing_data_scene(props)
-    elif asset_type == 'MATERIAL':
-        check_missing_data_material(props)
-    elif asset_type == 'BRUSH':
-        check_missing_data_brush(props)
-
-    if props.report != '':
-        props.report = f'Please fix these issues before {props.is_private.lower()} upload:\n\n' + props.report
-
-
-def sub_to_camel(content):
-    replaced = re.sub(r"_.",
-                      lambda m: m.group(0)[1].upper(), content)
-    return (replaced)
-
-
-def camel_to_sub(content):
-    replaced = re.sub(r"[A-Z]", lambda m: '_' + m.group(0).lower(), content)
-    return replaced
-
-
-def get_upload_data(caller=None, context=None, asset_type=None):
-    '''
-    works though metadata from addom props and prepares it for upload to dicts.
-    Parameters
-    ----------
-    caller - upload operator or none
-    context - context
-    asset_type - asset type in capitals (blender enum)
-
-    Returns
-    -------
-    export_ddta- all extra data that the process needs to upload and communicate with UI from a thread.
-        - eval_path_computing - string path to UI prop that denots if upload is still running
-        - eval_path_state - string path to UI prop that delivers messages about upload to ui
-        - eval_path - path to object holding upload data to be able to access it with various further commands
-        - models - in case of model upload, list of objects
-        - thumbnail_path - path to thumbnail file
-
-    upload_data - asset_data generated from the ui properties
-
-    '''
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    api_key = user_preferences.api_key
-
-    export_data = {
-        # "type": asset_type,
-    }
-    upload_params = {}
-    if asset_type == 'MODEL':
-        # Prepare to save the file
-        mainmodel = utils.get_active_model()
-
-        props = mainmodel.blenderkit
-
-        obs = utils.get_hierarchy(mainmodel)
-        obnames = []
-        for ob in obs:
-            obnames.append(ob.name)
-        export_data["models"] = obnames
-        export_data["thumbnail_path"] = bpy.path.abspath(props.thumbnail)
-
-        eval_path_computing = "bpy.data.objects['%s'].blenderkit.uploading" % mainmodel.name
-        eval_path_state = "bpy.data.objects['%s'].blenderkit.upload_state" % mainmodel.name
-        eval_path = "bpy.data.objects['%s']" % mainmodel.name
-
-        engines = [props.engine.lower()]
-        if props.engine1 != 'NONE':
-            engines.append(props.engine1.lower())
-        if props.engine2 != 'NONE':
-            engines.append(props.engine2.lower())
-        if props.engine3 != 'NONE':
-            engines.append(props.engine3.lower())
-        if props.engine == 'OTHER':
-            engines.append(props.engine_other.lower())
-
-        style = props.style.lower()
-        # if style == 'OTHER':
-        #     style = props.style_other.lower()
-
-        pl_dict = {'FINISHED': 'finished', 'TEMPLATE': 'template'}
-
-        upload_data = {
-            "assetType": 'model',
-
-        }
-        upload_params = {
-            "productionLevel": props.production_level.lower(),
-            "model_style": style,
-            "engines": engines,
-            "modifiers": comma2array(props.modifiers),
-            "materials": comma2array(props.materials),
-            "shaders": comma2array(props.shaders),
-            "uv": props.uv,
-            "dimensionX": round(props.dimensions[0], 4),
-            "dimensionY": round(props.dimensions[1], 4),
-            "dimensionZ": round(props.dimensions[2], 4),
-
-            "boundBoxMinX": round(props.bbox_min[0], 4),
-            "boundBoxMinY": round(props.bbox_min[1], 4),
-            "boundBoxMinZ": round(props.bbox_min[2], 4),
-
-            "boundBoxMaxX": round(props.bbox_max[0], 4),
-            "boundBoxMaxY": round(props.bbox_max[1], 4),
-            "boundBoxMaxZ": round(props.bbox_max[2], 4),
-
-            "animated": props.animated,
-            "rig": props.rig,
-            "simulation": props.simulation,
-            "purePbr": props.pbr,
-            "faceCount": props.face_count,
-            "faceCountRender": props.face_count_render,
-            "manifold": props.manifold,
-            "objectCount": props.object_count,
-
-            "procedural": props.is_procedural,
-            "nodeCount": props.node_count,
-            "textureCount": props.texture_count,
-            "megapixels": round(props.total_megapixels / 1000000),
-            # "scene": props.is_scene,
-        }
-        if props.use_design_year:
-            upload_params["designYear"] = props.design_year
-        if props.condition != 'UNSPECIFIED':
-            upload_params["condition"] = props.condition.lower()
-        if props.pbr:
-            pt = props.pbr_type
-            pt = pt.lower()
-            upload_params["pbrType"] = pt
-
-        if props.texture_resolution_max > 0:
-            upload_params["textureResolutionMax"] = props.texture_resolution_max
-            upload_params["textureResolutionMin"] = props.texture_resolution_min
-        if props.mesh_poly_type != 'OTHER':
-            upload_params["meshPolyType"] = props.mesh_poly_type.lower()  # .replace('_',' ')
-
-        optional_params = ['manufacturer', 'designer', 'design_collection', 'design_variant']
-        for p in optional_params:
-            if eval('props.%s' % p) != '':
-                upload_params[sub_to_camel(p)] = eval('props.%s' % p)
-
-    if asset_type == 'SCENE':
-        # Prepare to save the file
-        s = bpy.context.scene
-
-        props = s.blenderkit
-
-        export_data["scene"] = s.name
-        export_data["thumbnail_path"] = bpy.path.abspath(props.thumbnail)
-
-        eval_path_computing = "bpy.data.scenes['%s'].blenderkit.uploading" % s.name
-        eval_path_state = "bpy.data.scenes['%s'].blenderkit.upload_state" % s.name
-        eval_path = "bpy.data.scenes['%s']" % s.name
-
-        engines = [props.engine.lower()]
-        if props.engine1 != 'NONE':
-            engines.append(props.engine1.lower())
-        if props.engine2 != 'NONE':
-            engines.append(props.engine2.lower())
-        if props.engine3 != 'NONE':
-            engines.append(props.engine3.lower())
-        if props.engine == 'OTHER':
-            engines.append(props.engine_other.lower())
-
-        style = props.style.lower()
-        # if style == 'OTHER':
-        #     style = props.style_other.lower()
-
-        pl_dict = {'FINISHED': 'finished', 'TEMPLATE': 'template'}
-
-        upload_data = {
-            "assetType": 'scene',
-
-        }
-        upload_params = {
-            "productionLevel": props.production_level.lower(),
-            "model_style": style,
-            "engines": engines,
-            "modifiers": comma2array(props.modifiers),
-            "materials": comma2array(props.materials),
-            "shaders": comma2array(props.shaders),
-            "uv": props.uv,
-
-            "animated": props.animated,
-            # "simulation": props.simulation,
-            "purePbr": props.pbr,
-            "faceCount": 1,  # props.face_count,
-            "faceCountRender": 1,  # props.face_count_render,
-            "objectCount": 1,  # props.object_count,
-
-            # "scene": props.is_scene,
-        }
-        if props.use_design_year:
-            upload_params["designYear"] = props.design_year
-        if props.condition != 'UNSPECIFIED':
-            upload_params["condition"] = props.condition.lower()
-        if props.pbr:
-            pt = props.pbr_type
-            pt = pt.lower()
-            upload_params["pbrType"] = pt
-
-        if props.texture_resolution_max > 0:
-            upload_params["textureResolutionMax"] = props.texture_resolution_max
-            upload_params["textureResolutionMin"] = props.texture_resolution_min
-        if props.mesh_poly_type != 'OTHER':
-            upload_params["meshPolyType"] = props.mesh_poly_type.lower()  # .replace('_',' ')
-
-    elif asset_type == 'MATERIAL':
-        mat = bpy.context.active_object.active_material
-        props = mat.blenderkit
-
-        # props.name = mat.name
-
-        export_data["material"] = str(mat.name)
-        export_data["thumbnail_path"] = bpy.path.abspath(props.thumbnail)
-        # mat analytics happen here, since they don't take up any time...
-        asset_inspector.check_material(props, mat)
-
-        eval_path_computing = "bpy.data.materials['%s'].blenderkit.uploading" % mat.name
-        eval_path_state = "bpy.data.materials['%s'].blenderkit.upload_state" % mat.name
-        eval_path = "bpy.data.materials['%s']" % mat.name
-
-        engine = props.engine
-        if engine == 'OTHER':
-            engine = props.engine_other
-        engine = engine.lower()
-        style = props.style.lower()
-        # if style == 'OTHER':
-        #     style = props.style_other.lower()
-
-        upload_data = {
-            "assetType": 'material',
-
-        }
-
-        upload_params = {
-            "material_style": style,
-            "engine": engine,
-            "shaders": comma2array(props.shaders),
-            "uv": props.uv,
-            "animated": props.animated,
-            "purePbr": props.pbr,
-            "textureSizeMeters": props.texture_size_meters,
-            "procedural": props.is_procedural,
-            "nodeCount": props.node_count,
-            "textureCount": props.texture_count,
-            "megapixels": round(props.total_megapixels / 1000000),
-
-        }
-
-        if props.pbr:
-            upload_params["pbrType"] = props.pbr_type.lower()
-
-        if props.texture_resolution_max > 0:
-            upload_params["textureResolutionMax"] = props.texture_resolution_max
-            upload_params["textureResolutionMin"] = props.texture_resolution_min
-
-    elif asset_type == 'BRUSH':
-        brush = utils.get_active_brush()
-
-        props = brush.blenderkit
-        # props.name = brush.name
-
-        export_data["brush"] = str(brush.name)
-        export_data["thumbnail_path"] = bpy.path.abspath(brush.icon_filepath)
-
-        eval_path_computing = "bpy.data.brushes['%s'].blenderkit.uploading" % brush.name
-        eval_path_state = "bpy.data.brushes['%s'].blenderkit.upload_state" % brush.name
-        eval_path = "bpy.data.brushes['%s']" % brush.name
-
-        # mat analytics happen here, since they don't take up any time...
-
-        brush_type = ''
-        if bpy.context.sculpt_object is not None:
-            brush_type = 'sculpt'
-
-        elif bpy.context.image_paint_object:  # could be just else, but for future p
-            brush_type = 'texture_paint'
-
-        upload_params = {
-            "mode": brush_type,
-        }
-
-        upload_data = {
-            "assetType": 'brush',
-        }
-
-    elif asset_type == 'HDR':
-        ui_props = bpy.context.window_manager.blenderkitUI
-
-        # imagename = ui_props.hdr_upload_image
-        image = ui_props.hdr_upload_image  # bpy.data.images.get(imagename)
-        if not image:
-            return None, None
-
-        props = image.blenderkit
-
-        image_utils.analyze_image_is_true_hdr(image)
-
-        # props.name = brush.name
-        base, ext = os.path.splitext(image.filepath)
-        thumb_path = base + '.jpg'
-        export_data["thumbnail_path"] = bpy.path.abspath(thumb_path)
-
-        export_data["hdr"] = str(image.name)
-        export_data["hdr_filepath"] = str(bpy.path.abspath(image.filepath))
-        # export_data["thumbnail_path"] = bpy.path.abspath(brush.icon_filepath)
-
-        eval_path_computing = "bpy.data.images['%s'].blenderkit.uploading" % image.name
-        eval_path_state = "bpy.data.images['%s'].blenderkit.upload_state" % image.name
-        eval_path = "bpy.data.images['%s']" % image.name
-
-        # mat analytics happen here, since they don't take up any time...
-
-        upload_params = {
-            "textureResolutionMax": props.texture_resolution_max,
-            "trueHDR": props.true_hdr
-        }
-
-        upload_data = {
-            "assetType": 'hdr',
-        }
-
-    elif asset_type == 'TEXTURE':
-        style = props.style
-        # if style == 'OTHER':
-        #     style = props.style_other
-
-        upload_data = {
-            "assetType": 'texture',
-
-        }
-        upload_params = {
-            "style": style,
-            "animated": props.animated,
-            "purePbr": props.pbr,
-            "resolution": props.resolution,
-        }
-        if props.pbr:
-            pt = props.pbr_type
-            pt = pt.lower()
-            upload_data["pbrType"] = pt
-
-    add_version(upload_data)
-
-    # caller can be upload operator, but also asset bar called from tooltip generator
-    if caller and caller.properties.main_file == True:
-        upload_data["name"] = props.name
-        upload_data["displayName"] = props.name
-    else:
-        upload_data["displayName"] = props.name
-
-    upload_data["description"] = props.description
-    upload_data["tags"] = comma2array(props.tags)
-    # category is always only one value by a slug, that's why we go down to the lowest level and overwrite.
-    if props.category == '':
-        upload_data["category"] = asset_type.lower()
-    else:
-        upload_data["category"] = props.category
-    if props.subcategory != 'NONE':
-        upload_data["category"] = props.subcategory
-    if props.subcategory1 != 'NONE':
-        upload_data["category"] = props.subcategory1
-
-    upload_data["license"] = props.license
-    upload_data["isFree"] = props.is_free == 'FREE'
-    upload_data["isPrivate"] = props.is_private == 'PRIVATE'
-    upload_data["token"] = user_preferences.api_key
-
-    upload_data['parameters'] = upload_params
-
-    # if props.asset_base_id != '':
-    export_data['assetBaseId'] = props.asset_base_id
-    export_data['id'] = props.id
-    export_data['eval_path_computing'] = eval_path_computing
-    export_data['eval_path_state'] = eval_path_state
-    export_data['eval_path'] = eval_path
-
-    return export_data, upload_data
-
-
-def patch_individual_metadata(asset_id, metadata_dict, api_key):
-    upload_data = metadata_dict
-    url = paths.get_api_url() + 'assets/' + str(asset_id) + '/'
-    headers = utils.get_headers(api_key)
-    try:
-        r = rerequests.patch(url, json=upload_data, headers=headers, verify=True)  # files = files,
-    except requests.exceptions.RequestException as e:
-        print(e)
-        return {'CANCELLED'}
-    return {'FINISHED'}
-
-
-# class OBJECT_MT_blenderkit_fast_metadata_menu(bpy.types.Menu):
-#     bl_label = "Fast category change"
-#     bl_idname = "OBJECT_MT_blenderkit_fast_metadata_menu"
-#
-#     def draw(self, context):
-#         layout = self.layout
-#         ui_props = context.window_manager.blenderkitUI
-#
-#         # sr = bpy.context.window_manager['search results']
-#         sr = bpy.context.window_manager['search results']
-#         asset_data = sr[ui_props.active_index]
-#         categories = bpy.context.window_manager['bkit_categories']
-#         wm = bpy.context.win
-#         for c in categories:
-#             if c['name'].lower() == asset_data['assetType']:
-#                 for ch in c['children']:
-#                     op = layout.operator('wm.blenderkit_fast_metadata', text = ch['name'])
-#                     op = layout.operator('wm.blenderkit_fast_metadata', text = ch['name'])
-
-
-def update_free_full(self, context):
-    if self.asset_type == 'material':
-        if self.free_full == 'FULL':
-            self.free_full = 'FREE'
-            ui_panels.ui_message(title="All BlenderKit materials are free",
-                                 message="Any material uploaded to BlenderKit is free." \
-                                         " However, it can still earn money for the author," \
-                                         " based on our fair share system. " \
-                                         "Part of subscription is sent to artists based on usage by paying users.")
-
-
-def can_edit_asset(active_index=-1, asset_data=None):
-    if active_index < 0 and not asset_data:
-        return False
-    profile = bpy.context.window_manager.get('bkit profile')
-    if profile is None:
-        return False
-    if utils.profile_is_validator():
-        return True
-    if not asset_data:
-        sr = bpy.context.window_manager['search results']
-        asset_data = dict(sr[active_index])
-    if int(asset_data['author']['id']) == int(profile['user']['id']):
-        return True
-    return False
-
-
-class FastMetadata(bpy.types.Operator):
-    """Edit metadata of the asset"""
-    bl_idname = "wm.blenderkit_fast_metadata"
-    bl_label = "Update metadata"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    asset_id: StringProperty(
-        name="Asset Base Id",
-        description="Unique name of the asset (hidden)",
-        default=""
-    )
-    asset_type: StringProperty(
-        name="Asset Type",
-        description="Asset Type",
-        default=""
-    )
-    name: StringProperty(
-        name="Name",
-        description="Main name of the asset",
-        default="",
-    )
-    description: StringProperty(
-        name="Description",
-        description="Description of the asset",
-        default="")
-    tags: StringProperty(
-        name="Tags",
-        description="List of tags, separated by commas (optional)",
-        default="",
-    )
-    category: EnumProperty(
-        name="Category",
-        description="main category to put into",
-        items=categories.get_category_enums,
-        update=categories.update_category_enums
-    )
-    subcategory: EnumProperty(
-        name="Subcategory",
-        description="main category to put into",
-        items=categories.get_subcategory_enums,
-        update=categories.update_subcategory_enums
-    )
-    subcategory1: EnumProperty(
-        name="Subcategory",
-        description="main category to put into",
-        items=categories.get_subcategory1_enums
-    )
-    license: EnumProperty(
-        items=licenses,
-        default='royalty_free',
-        description='License. Please read our help for choosing the right licenses',
-    )
-    is_private: EnumProperty(
-        name="Thumbnail Style",
-        items=(
-            ('PRIVATE', 'Private', "You asset will be hidden to public. The private assets are limited by a quota."),
-            ('PUBLIC', 'Public', '"Your asset will go into the validation process automatically')
-        ),
-        description="If not marked private, your asset will go into the validation process automatically\n"
-                    "Private assets are limited by quota",
-        default="PUBLIC",
-    )
-
-    free_full: EnumProperty(
-        name="Free or Full Plan",
-        items=(
-            ('FREE', 'Free', "You consent you want to release this asset as free for everyone"),
-            ('FULL', 'Full', 'Your asset will be in the full plan')
-        ),
-        description="Choose whether the asset should be free or in the Full Plan",
-        default="FULL",
-        update=update_free_full
-    )
-
-    ####################
-
-    @classmethod
-    def poll(cls, context):
-        scene = bpy.context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        return True
-
-    def draw(self, context):
-        layout = self.layout
-        # col = layout.column()
-        layout.label(text=self.message)
-        row = layout.row()
-
-        layout.prop(self, 'category')
-        if self.category != 'NONE' and self.subcategory != 'NONE':
-            layout.prop(self, 'subcategory')
-        if self.subcategory != 'NONE' and self.subcategory1 != 'NONE':
-            enums = categories.get_subcategory1_enums(self, context)
-            if enums[0][0] != 'NONE':
-                layout.prop(self, 'subcategory1')
-        layout.prop(self, 'name')
-        layout.prop(self, 'description')
-        layout.prop(self, 'tags')
-        layout.prop(self, 'is_private', expand=True)
-        layout.prop(self, 'free_full', expand=True)
-        if self.is_private == 'PUBLIC':
-            layout.prop(self, 'license')
-
-    def execute(self, context):
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        props = bpy.context.window_manager.blenderkitUI
-        if self.subcategory1 != 'NONE':
-            category = self.subcategory1
-        elif self.subcategory != 'NONE':
-            category = self.subcategory
-        else:
-            category = self.category
-        utils.update_tags(self, context)
-
-        mdict = {
-            'category': category,
-            'displayName': self.name,
-            'description': self.description,
-            'tags': comma2array(self.tags),
-            'isPrivate': self.is_private == 'PRIVATE',
-            'isFree': self.free_full == 'FREE',
-            'license': self.license,
-        }
-
-        thread = threading.Thread(target=patch_individual_metadata,
-                                  args=(self.asset_id, mdict, user_preferences.api_key))
-        thread.start()
-        tasks_queue.add_task((reports.add_report, (f'Uploading metadata for {self.name}. '
-                                              f'Refresh search results to see that changes applied correctly.', 8,)))
-
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        scene = bpy.context.scene
-        ui_props = bpy.context.window_manager.blenderkitUI
-        if ui_props.active_index > -1:
-            sr = bpy.context.window_manager['search results']
-            asset_data = dict(sr[ui_props.active_index])
-        else:
-
-            active_asset = utils.get_active_asset_by_type(asset_type=self.asset_type)
-            asset_data = active_asset.get('asset_data')
-
-        if not can_edit_asset(asset_data=asset_data):
-            return {'CANCELLED'}
-        self.asset_id = asset_data['id']
-        self.asset_type = asset_data['assetType']
-        cat_path = categories.get_category_path(bpy.context.window_manager['bkit_categories'],
-                                                asset_data['category'])
-        try:
-            if len(cat_path) > 1:
-                self.category = cat_path[1]
-            if len(cat_path) > 2:
-                self.subcategory = cat_path[2]
-        except Exception as e:
-            print(e)
-
-        self.message = f"Fast edit metadata of {asset_data['name']}"
-        self.name = asset_data['displayName']
-        self.description = asset_data['description']
-        self.tags = ','.join(asset_data['tags'])
-        if asset_data['isPrivate']:
-            self.is_private = 'PRIVATE'
-        else:
-            self.is_private = 'PUBLIC'
-
-        if asset_data['isFree']:
-            self.free_full = 'FREE'
-        else:
-            self.free_full = 'FULL'
-        self.license = asset_data['license']
-
-        wm = context.window_manager
-
-        return wm.invoke_props_dialog(self, width=600)
-
-
-def verification_status_change_thread(asset_id, state, api_key):
-    upload_data = {
-        "verificationStatus": state
-    }
-    url = paths.get_api_url() + 'assets/' + str(asset_id) + '/'
-    headers = utils.get_headers(api_key)
-    try:
-        r = rerequests.patch(url, json=upload_data, headers=headers, verify=True)  # files = files,
-    except requests.exceptions.RequestException as e:
-        print(e)
-        return {'CANCELLED'}
-    return {'FINISHED'}
-
-
-def get_upload_location(props):
-    '''
-    not used by now, gets location of uploaded asset - potentially usefull if we draw a nice upload gizmo in viewport.
-    Parameters
-    ----------
-    props
-
-    Returns
-    -------
-
-    '''
-    scene = bpy.context.scene
-    ui_props = bpy.context.window_manager.blenderkitUI
-    if ui_props.asset_type == 'MODEL':
-        if bpy.context.view_layer.objects.active is not None:
-            ob = utils.get_active_model()
-            return ob.location
-    if ui_props.asset_type == 'SCENE':
-        return None
-    elif ui_props.asset_type == 'MATERIAL':
-        if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.active_material is not None:
-            return bpy.context.active_object.location
-    elif ui_props.asset_type == 'TEXTURE':
-        return None
-    elif ui_props.asset_type == 'BRUSH':
-        return None
-    return None
-
-
-def check_storage_quota(props):
-    if props.is_private == 'PUBLIC':
-        return True
-
-    profile = bpy.context.window_manager.get('bkit profile')
-    if profile is None or profile.get('remainingPrivateQuota') is None:
-        preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        adata = search.request_profile(preferences.api_key)
-        if adata is None:
-            props.report = 'Please log-in first.'
-            return False
-        search.write_profile(adata)
-        profile = adata
-    quota = profile['user'].get('remainingPrivateQuota')
-    if quota is None or quota > 0:
-        return True
-    props.report = 'Private storage quota exceeded.'
-    return False
-
-
-def auto_fix(asset_type=''):
-    # this applies various procedures to ensure coherency in the database.
-    asset = utils.get_active_asset()
-    props = utils.get_upload_props()
-    if asset_type == 'MATERIAL':
-        overrides.ensure_eevee_transparency(asset)
-        asset.name = props.name
-
-
-upload_threads = []
-
-
-class Uploader(threading.Thread):
-    '''
-       Upload thread -
-        - first uploads metadata
-        - blender gets started to process the file if .blend is uploaded
-        - if files need to be uploaded, uploads them
-        - thumbnail goes first
-        - files get uploaded
-
-       Returns
-       -------
-
-   '''
-
-    def __init__(self, upload_data=None, export_data=None, upload_set=None):
-        super(Uploader, self).__init__()
-        self.upload_data = upload_data
-        self.export_data = export_data
-        self.upload_set = upload_set
-        self._stop_event = threading.Event()
-
-    def stop(self):
-        self._stop_event.set()
-
-    def stopped(self):
-        return self._stop_event.is_set()
-
-    def send_message(self, message):
-        message = str(message).replace("'", "")
-
-        # this adds a UI report but also writes above the upload panel fields.
-        tasks_queue.add_task((reports.add_report, (message,)))
-        estring = f"{self.export_data['eval_path_state']} = '{message}'"
-        tasks_queue.add_task((exec, (estring,)))
-
-    def end_upload(self, message):
-        estring = self.export_data['eval_path_computing'] + ' = False'
-        tasks_queue.add_task((exec, (estring,)))
-        self.send_message(message)
-
-    def run(self):
-        # utils.pprint(upload_data)
-        self.upload_data['parameters'] = utils.dict_to_params(
-            self.upload_data['parameters'])  # weird array conversion only for upload, not for tooltips.
-
-        script_path = os.path.dirname(os.path.realpath(__file__))
-
-        # first upload metadata to server, so it can be saved inside the current file
-        url = paths.get_api_url() + 'assets/'
-
-        headers = utils.get_headers(self.upload_data['token'])
-
-        # self.upload_data['license'] = 'ovejajojo'
-        json_metadata = self.upload_data  # json.dumps(self.upload_data, ensure_ascii=False).encode('utf8')
-
-        # tasks_queue.add_task((reports.add_report, ('Posting metadata',)))
-        self.send_message('Posting metadata')
-        if self.export_data['assetBaseId'] == '':
-            try:
-                r = rerequests.post(url, json=json_metadata, headers=headers, verify=True,
-                                    immediate=True)  # files = files,
-
-                # tasks_queue.add_task((reports.add_report, ('uploaded metadata',)))
-                utils.p(r.text)
-                self.send_message('uploaded metadata')
-
-            except requests.exceptions.RequestException as e:
-                print(e)
-                self.end_upload(e)
-                return {'CANCELLED'}
-
-        else:
-            url += self.export_data['id'] + '/'
-            try:
-                if 'MAINFILE' in self.upload_set:
-                    json_metadata["verificationStatus"] = "uploading"
-                r = rerequests.patch(url, json=json_metadata, headers=headers, verify=True,
-                                     immediate=True)  # files = files,
-                self.send_message('uploaded metadata')
-
-                # tasks_queue.add_task((reports.add_report, ('uploaded metadata',)))
-                # parse the request
-                # print('uploaded metadata')
-                print(r.text)
-            except requests.exceptions.RequestException as e:
-                print(e)
-                self.end_upload(e)
-                return {'CANCELLED'}
-
-        if self.stopped():
-            self.end_upload('Upload cancelled by user')
-            return
-        # props.upload_state = 'step 1'
-        if self.upload_set == ['METADATA']:
-            self.end_upload('Metadata posted successfully')
-            return {'FINISHED'}
-        try:
-            rj = r.json()
-            # utils.pprint(rj)
-            # if r.status_code not in (200, 201):
-            #     if r.status_code == 401:
-            #         ###reports.add_report(r.detail, 5, colors.RED)
-            #     return {'CANCELLED'}
-            # if props.asset_base_id == '':
-            #     props.asset_base_id = rj['assetBaseId']
-            #     props.id = rj['id']
-            if self.export_data['assetBaseId'] == '':
-                self.export_data['assetBaseId'] = rj['assetBaseId']
-                self.export_data['id'] = rj['id']
-                # here we need to send asset ID's back into UI to be written in asset data.
-                estring = f"{self.export_data['eval_path']}.blenderkit.asset_base_id = '{rj['assetBaseId']}'"
-                tasks_queue.add_task((exec, (estring,)))
-                estring = f"{self.export_data['eval_path']}.blenderkit.id = '{rj['id']}'"
-                tasks_queue.add_task((exec, (estring,)))
-                # after that, the user's file needs to be saved to save the
-                # estring = f"bpy.ops.wm.save_as_mainfile(filepath={self.export_data['source_filepath']}, compress=False, copy=True)"
-                # tasks_queue.add_task((exec, (estring,)))
-
-            self.upload_data['assetBaseId'] = self.export_data['assetBaseId']
-            self.upload_data['id'] = self.export_data['id']
-
-            # props.uploading = True
-
-            if 'MAINFILE' in self.upload_set:
-                if self.upload_data['assetType'] == 'hdr':
-                    fpath = self.export_data['hdr_filepath']
-                else:
-                    fpath = os.path.join(self.export_data['temp_dir'], self.upload_data['assetBaseId'] + '.blend')
-
-                    clean_file_path = paths.get_clean_filepath()
-
-                    data = {
-                        'export_data': self.export_data,
-                        'upload_data': self.upload_data,
-                        'debug_value': self.export_data['debug_value'],
-                        'upload_set': self.upload_set,
-                    }
-                    datafile = os.path.join(self.export_data['temp_dir'], BLENDERKIT_EXPORT_DATA_FILE)
-
-                    with open(datafile, 'w', encoding='utf-8') as s:
-                        json.dump(data, s, ensure_ascii=False, indent=4)
-
-                    self.send_message('preparing scene - running blender instance')
-
-                    proc = subprocess.run([
-                        self.export_data['binary_path'],
-                        "--background",
-                        "-noaudio",
-                        clean_file_path,
-                        "--python", os.path.join(script_path, "upload_bg.py"),
-                        "--", datafile
-                    ], bufsize=1, stdout=sys.stdout, stdin=subprocess.PIPE, creationflags=utils.get_process_flags())
-
-            if self.stopped():
-                self.end_upload('Upload stopped by user')
-                return
-
-            files = []
-            if 'THUMBNAIL' in self.upload_set:
-                files.append({
-                    "type": "thumbnail",
-                    "index": 0,
-                    "file_path": self.export_data["thumbnail_path"]
-                })
-            if 'MAINFILE' in self.upload_set:
-                files.append({
-                    "type": "blend",
-                    "index": 0,
-                    "file_path": fpath
-                })
-
-                if not os.path.exists(fpath):
-                    self.send_message("File packing failed, please try manual packing first")
-                    return {'CANCELLED'}
-
-            self.send_message('Uploading files')
-
-            uploaded = upload_bg.upload_files(self.upload_data, files)
-
-            if uploaded:
-                # mark on server as uploaded
-                if 'MAINFILE' in self.upload_set:
-                    confirm_data = {
-                        "verificationStatus": "uploaded"
-                    }
-
-                    url = paths.get_api_url() + 'assets/'
-
-                    headers = utils.get_headers(self.upload_data['token'])
-
-                    url += self.upload_data["id"] + '/'
-
-                    r = rerequests.patch(url, json=confirm_data, headers=headers, verify=True)  # files = files,
-
-                self.end_upload('Upload finished successfully')
-            else:
-                self.end_upload('Upload failed')
-        except Exception as e:
-            self.end_upload(e)
-            print(e)
-            return {'CANCELLED'}
-
-
-def start_upload(self, context, asset_type, reupload, upload_set):
-    '''start upload process, by processing data, then start a thread that cares about the rest of the upload.'''
-
-    # fix the name first
-    props = utils.get_upload_props()
-
-    utils.name_update(props)
-
-    storage_quota_ok = check_storage_quota(props)
-    if not storage_quota_ok:
-        self.report({'ERROR_INVALID_INPUT'}, props.report)
-        return {'CANCELLED'}
-
-    location = get_upload_location(props)
-    props.upload_state = 'preparing upload'
-
-    auto_fix(asset_type=asset_type)
-
-    # do this for fixing long tags in some upload cases
-    props.tags = props.tags[:]
-
-    # check for missing metadata
-    check_missing_data(asset_type, props)
-    # if previous check did find any problems then
-    if props.report != '':
-        return {'CANCELLED'}
-
-    if not reupload:
-        props.asset_base_id = ''
-        props.id = ''
-
-    export_data, upload_data = get_upload_data(caller=self, context=context, asset_type=asset_type)
-
-    # check if thumbnail exists, generate for HDR:
-    if 'THUMBNAIL' in upload_set:
-        if asset_type == 'HDR':
-            image_utils.generate_hdr_thumbnail()
-            # get upload data because the image utils function sets true_hdr
-            export_data, upload_data = get_upload_data(caller=self, context=context, asset_type=asset_type)
-
-        elif not os.path.exists(export_data["thumbnail_path"]):
-            props.upload_state = 'Thumbnail not found'
-            props.uploading = False
-            return {'CANCELLED'}
-
-    if upload_set == {'METADATA'}:
-        props.upload_state = "Updating metadata. Please don't close Blender until upload finishes"
-    else:
-        props.upload_state = "Starting upload. Please don't close Blender until upload finishes"
-    props.uploading = True
-
-    # save a copy of the file for processing. Only for blend files
-    basename, ext = os.path.splitext(bpy.data.filepath)
-    if not ext:
-        ext = ".blend"
-    export_data['temp_dir'] = tempfile.mkdtemp()
-    export_data['source_filepath'] = os.path.join(export_data['temp_dir'], "export_blenderkit" + ext)
-    if asset_type != 'HDR':
-        # if this isn't here, blender crashes.
-        bpy.context.preferences.filepaths.file_preview_type = 'NONE'
-
-        bpy.ops.wm.save_as_mainfile(filepath=export_data['source_filepath'], compress=False, copy=True)
-
-    export_data['binary_path'] = bpy.app.binary_path
-    export_data['debug_value'] = bpy.app.debug_value
-
-    upload_thread = Uploader(upload_data=upload_data, export_data=export_data, upload_set=upload_set)
-
-    upload_thread.start()
-
-    upload_threads.append(upload_thread)
-    return {'FINISHED'}
-
-
-asset_types = (
-    ('MODEL', 'Model', 'Set of objects'),
-    ('SCENE', 'Scene', 'Scene'),
-    ('HDR', 'HDR', 'HDR image'),
-    ('MATERIAL', 'Material', 'Any .blend Material'),
-    ('TEXTURE', 'Texture', 'A texture, or texture set'),
-    ('BRUSH', 'Brush', 'Brush, can be any type of blender brush'),
-    ('ADDON', 'Addon', 'Addnon'),
-)
-
-
-class UploadOperator(Operator):
-    """Tooltip"""
-    bl_idname = "object.blenderkit_upload"
-    bl_description = "Upload or re-upload asset + thumbnail + metadata"
-
-    bl_label = "BlenderKit asset upload"
-    bl_options = {'REGISTER', 'INTERNAL'}
-
-    # type of upload - model, material, textures, e.t.c.
-    asset_type: EnumProperty(
-        name="Type",
-        items=asset_types,
-        description="Type of upload",
-        default="MODEL",
-    )
-
-    reupload: BoolProperty(
-        name="reupload",
-        description="reupload but also draw so that it asks what to reupload",
-        default=False,
-        options={'SKIP_SAVE'}
-    )
-
-    metadata: BoolProperty(
-        name="metadata",
-        default=True,
-        options={'SKIP_SAVE'}
-    )
-
-    thumbnail: BoolProperty(
-        name="thumbnail",
-        default=False,
-        options={'SKIP_SAVE'}
-    )
-
-    main_file: BoolProperty(
-        name="main file",
-        default=False,
-        options={'SKIP_SAVE'}
-    )
-
-    @classmethod
-    def poll(cls, context):
-        return utils.uploadable_asset_poll()
-
-    def execute(self, context):
-        bpy.ops.object.blenderkit_auto_tags()
-        props = utils.get_upload_props()
-
-        # in case of name change, we have to reupload everything, since the name is stored in blender file,
-        # and is used for linking to scene
-        # if props.name_changed:
-        #     # TODO: this needs to be replaced with new double naming scheme (metadata vs blend data)
-        #     # print('has to reupload whole data, name has changed.')
-        #     self.main_file = True
-        #     props.name_changed = False
-
-        upload_set = []
-        if not self.reupload:
-            upload_set = ['METADATA', 'THUMBNAIL', 'MAINFILE']
-        else:
-            if self.metadata:
-                upload_set.append('METADATA')
-            if self.thumbnail:
-                upload_set.append('THUMBNAIL')
-            if self.main_file:
-                upload_set.append('MAINFILE')
-
-        # this is accessed later in get_upload_data and needs to be written.
-        # should pass upload_set all the way to it probably
-        if 'MAINFILE' in upload_set:
-            self.main_file = True
-
-        result = start_upload(self, context, self.asset_type, self.reupload, upload_set=upload_set, )
-
-        if props.report != '':
-            # self.report({'ERROR_INVALID_INPUT'}, props.report)
-            self.report({'ERROR_INVALID_CONTEXT'}, props.report)
-
-        return result
-
-    def draw(self, context):
-        props = utils.get_upload_props()
-        layout = self.layout
-
-        if self.reupload:
-            # layout.prop(self, 'metadata')
-            layout.prop(self, 'main_file')
-            layout.prop(self, 'thumbnail')
-
-        if props.asset_base_id != '' and not self.reupload:
-            utils.label_multiline(layout, text="Really upload as new?\n"
-                                               "Do this only when you create\n"
-                                               "a new asset from an old one.\n"
-                                               "For updates of thumbnail or model use reupload.\n",
-                                  width=400, icon='ERROR')
-
-
-        if props.is_private == 'PUBLIC':
-            if self.asset_type == 'MODEL':
-                utils.label_multiline(layout, text='You marked the asset as public.\n'
-                                                   'This means it will be validated by our team.\n\n'
-                                                   'Please test your upload after it finishes:\n'
-                                                   '-   Open a new file\n'
-                                                   '-   Find the asset and download it\n'
-                                                   '-   Check if it snaps correctly to surfaces\n'
-                                                   '-   Check if it has all textures and renders as expected\n'
-                                                   '-   Check if it has correct size in world units (for models)'
-                                      , width=400)
-            elif self.asset_type == 'HDR':
-                if not props.true_hdr:
-                    utils.label_multiline(layout, text="This image isn't HDR,\n"
-                                                       "It has a low dynamic range.\n"
-                                                       "BlenderKit library accepts 360 degree images\n"
-                                                       "however the default filter setting for search\n"
-                                                       "is to show only true HDR images\n"
-                                          , icon='ERROR', width=400)
-
-                utils.label_multiline(layout, text='You marked the asset as public.\n'
-                                                   'This means it will be validated by our team.\n\n'
-                                                   'Please test your upload after it finishes:\n'
-                                                   '-   Open a new file\n'
-                                                   '-   Find the asset and download it\n'
-                                                   '-   Check if it works as expected\n'
-                                      , width=400)
-            else:
-                utils.label_multiline(layout, text='You marked the asset as public.\n'
-                                                   'This means it will be validated by our team.\n\n'
-                                                   'Please test your upload after it finishes:\n'
-                                                   '-   Open a new file\n'
-                                                   '-   Find the asset and download it\n'
-                                                   '-   Check if it works as expected\n'
-                                      , width=400)
-
-    def invoke(self, context, event):
-
-        if not utils.user_logged_in():
-            ui_panels.draw_not_logged_in(self, message='To upload assets you need to login/signup.')
-            return {'CANCELLED'}
-
-        if self.asset_type == 'HDR':
-            props = utils.get_upload_props()
-            # getting upload data for images ensures true_hdr check so users can be informed about their handling
-            # simple 360 photos or renders with LDR are hidden by default..
-            export_data, upload_data = get_upload_data(asset_type='HDR')
-
-        # if props.is_private == 'PUBLIC':
-        return context.window_manager.invoke_props_dialog(self)
-        # else:
-        #     return self.execute(context)
-
-
-class AssetDebugPrint(Operator):
-    """Change verification status"""
-    bl_idname = "object.blenderkit_print_asset_debug"
-    bl_description = "BlenderKit print asset data for debug purposes"
-    bl_label = "BlenderKit print asset data"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    # type of upload - model, material, textures, e.t.c.
-    asset_id: StringProperty(
-        name="asset id",
-    )
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def execute(self, context):
-        preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-        if not bpy.context.window_manager['search results']:
-            print('no search results found')
-            return {'CANCELLED'};
-        # update status in search results for validator's clarity
-        sr = bpy.context.window_manager['search results']
-
-        result = None
-        for r in sr:
-            if r['id'] == self.asset_id:
-                result = r.to_dict()
-        if not result:
-            ad = bpy.context.active_object.get('asset_data')
-            if ad:
-                result = ad.to_dict()
-        if result:
-            t = bpy.data.texts.new(result['name'])
-            t.write(json.dumps(result, indent=4, sort_keys=True))
-            print(json.dumps(result, indent=4, sort_keys=True))
-        return {'FINISHED'}
-
-
-class AssetVerificationStatusChange(Operator):
-    """Change verification status"""
-    bl_idname = "object.blenderkit_change_status"
-    bl_description = "Change asset status"
-    bl_label = "Change verification status"
-    bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
-
-    # type of upload - model, material, textures, e.t.c.
-    asset_id: StringProperty(
-        name="asset id",
-    )
-
-    state: StringProperty(
-        name="verification_status",
-        default='uploaded'
-    )
-
-    @classmethod
-    def poll(cls, context):
-        return True
-
-    def draw(self, context):
-        layout = self.layout
-        # if self.state == 'deleted':
-        layout.label(text='Really delete asset from BlenderKit online storage?')
-        # layout.prop(self, 'state')
-
-    def execute(self, context):
-        preferences = bpy.context.preferences.addons['blenderkit'].preferences
-
-        if not bpy.context.window_manager['search results']:
-            return {'CANCELLED'};
-        # update status in search results for validator's clarity
-        sr = bpy.context.window_manager['search results']
-
-        for r in sr:
-            if r['id'] == self.asset_id:
-                r['verificationStatus'] = self.state
-
-        thread = threading.Thread(target=verification_status_change_thread,
-                                  args=(self.asset_id, self.state, preferences.api_key))
-        thread.start()
-        if asset_bar_op.asset_bar_operator is not None:
-            asset_bar_op.asset_bar_operator.update_layout(context, None)
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        # print(self.state)
-        if self.state == 'deleted':
-            wm = context.window_manager
-            return wm.invoke_props_dialog(self)
-        return {'RUNNING_MODAL'}
-
-
-def register_upload():
-    bpy.utils.register_class(UploadOperator)
-    bpy.utils.register_class(FastMetadata)
-    bpy.utils.register_class(AssetDebugPrint)
-    bpy.utils.register_class(AssetVerificationStatusChange)
-
-
-def unregister_upload():
-    bpy.utils.unregister_class(UploadOperator)
-    bpy.utils.unregister_class(FastMetadata)
-    bpy.utils.unregister_class(AssetDebugPrint)
-    bpy.utils.unregister_class(AssetVerificationStatusChange)
diff --git a/blenderkit/upload_bg.py b/blenderkit/upload_bg.py
deleted file mode 100644
index cfcb8224bf6438a08adaacb0ce96d278fed2e12c..0000000000000000000000000000000000000000
--- a/blenderkit/upload_bg.py
+++ /dev/null
@@ -1,187 +0,0 @@
-# ##### 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 #####
-
-
-
-from blenderkit import paths, append_link, bg_blender, utils, rerequests, tasks_queue, ui, reports
-
-import sys, json, os, time
-import requests
-import logging
-
-import bpy
-
-BLENDERKIT_EXPORT_DATA = sys.argv[-1]
-
-
-def print_gap():
-    print('\n\n\n\n')
-
-
-class upload_in_chunks(object):
-    def __init__(self, filename, chunksize=1 << 13, report_name='file'):
-        self.filename = filename
-        self.chunksize = chunksize
-        self.totalsize = os.path.getsize(filename)
-        self.readsofar = 0
-        self.report_name = report_name
-
-    def __iter__(self):
-        with open(self.filename, 'rb') as file:
-            while True:
-                data = file.read(self.chunksize)
-                if not data:
-                    sys.stderr.write("\n")
-                    break
-                self.readsofar += len(data)
-                percent = self.readsofar * 1e2 / self.totalsize
-                tasks_queue.add_task((reports.add_report, (f"Uploading {self.report_name} {percent}%",)))
-
-                # bg_blender.progress('uploading %s' % self.report_name, percent)
-                # sys.stderr.write("\r{percent:3.0f}%".format(percent=percent))
-                yield data
-
-    def __len__(self):
-        return self.totalsize
-
-
-def upload_file(upload_data, f):
-    headers = utils.get_headers(upload_data['token'])
-    version_id = upload_data['id']
-
-    message = f"uploading {f['type']} {os.path.basename(f['file_path'])}"
-    tasks_queue.add_task((reports.add_report, (message,)))
-
-    upload_info = {
-        'assetId': version_id,
-        'fileType': f['type'],
-        'fileIndex': f['index'],
-        'originalFilename': os.path.basename(f['file_path'])
-    }
-    upload_create_url = paths.get_api_url() + 'uploads/'
-    upload = rerequests.post(upload_create_url, json=upload_info, headers=headers, verify=True)
-    upload = upload.json()
-    #
-    chunk_size = 1024 * 1024 * 2
-    # utils.pprint(upload)
-    # file gets uploaded here:
-    uploaded = False
-    # s3 upload is now the only option
-    for a in range(0, 5):
-        if not uploaded:
-            try:
-                upload_response = requests.put(upload['s3UploadUrl'],
-                                               data=upload_in_chunks(f['file_path'], chunk_size, f['type']),
-                                               stream=True, verify=True)
-
-                if 250 > upload_response.status_code > 199:
-                    uploaded = True
-                    upload_done_url = paths.get_api_url() + 'uploads_s3/' + upload['id'] + '/upload-file/'
-                    upload_response = rerequests.post(upload_done_url, headers=headers, verify=True)
-                    # print(upload_response)
-                    # print(upload_response.text)
-                    tasks_queue.add_task((reports.add_report, (f"Finished file upload: {os.path.basename(f['file_path'])}",)))
-                    return True
-                else:
-                    print(upload_response.text)
-                    message = f"Upload failed, retry. File : {f['type']} {os.path.basename(f['file_path'])}"
-                    tasks_queue.add_task((reports.add_report, (message,)))
-
-            except Exception as e:
-                print(e)
-                message = f"Upload failed, retry. File : {f['type']} {os.path.basename(f['file_path'])}"
-                tasks_queue.add_task((reports.add_report, (message,)))
-                time.sleep(1)
-
-            # confirm single file upload to bkit server
-
-
-
-
-    return False
-
-
-def upload_files(upload_data, files):
-    '''uploads several files in one run'''
-    uploaded_all = True
-    for f in files:
-        uploaded = upload_file(upload_data, f)
-        if not uploaded:
-            uploaded_all = False
-        tasks_queue.add_task((reports.add_report, (f"Uploaded all files for asset {upload_data['name']}",)))
-    return uploaded_all
-
-
-if __name__ == "__main__":
-    try:
-        # bg_blender.progress('preparing scene - append data')
-        with open(BLENDERKIT_EXPORT_DATA, 'r',encoding='utf-8') as s:
-            data = json.load(s)
-
-        bpy.app.debug_value = data.get('debug_value', 0)
-        export_data = data['export_data']
-        upload_data = data['upload_data']
-
-        bpy.data.scenes.new('upload')
-        for s in bpy.data.scenes:
-            if s.name != 'upload':
-                bpy.data.scenes.remove(s)
-
-        if upload_data['assetType'] == 'model':
-            obnames = export_data['models']
-            main_source, allobs = append_link.append_objects(file_name=export_data['source_filepath'],
-                                                             obnames=obnames,
-                                                             rotation=(0, 0, 0))
-            g = bpy.data.collections.new(upload_data['name'])
-            for o in allobs:
-                g.objects.link(o)
-            bpy.context.scene.collection.children.link(g)
-        elif upload_data['assetType'] == 'scene':
-            sname = export_data['scene']
-            main_source = append_link.append_scene(file_name=export_data['source_filepath'],
-                                                   scenename=sname)
-            bpy.data.scenes.remove(bpy.data.scenes['upload'])
-            main_source.name = sname
-        elif upload_data['assetType'] == 'material':
-            matname = export_data['material']
-            main_source = append_link.append_material(file_name=export_data['source_filepath'], matname=matname)
-
-        elif upload_data['assetType'] == 'brush':
-            brushname = export_data['brush']
-            main_source = append_link.append_brush(file_name=export_data['source_filepath'], brushname=brushname)
-
-        bpy.ops.file.pack_all()
-
-        main_source.blenderkit.uploading = False
-        #write ID here.
-        main_source.blenderkit.asset_base_id = export_data['assetBaseId']
-        main_source.blenderkit.id = export_data['id']
-
-        fpath = os.path.join(export_data['temp_dir'], upload_data['assetBaseId'] + '.blend')
-
-        #if this isn't here, blender crashes.
-        bpy.context.preferences.filepaths.file_preview_type = 'NONE'
-
-        bpy.ops.wm.save_as_mainfile(filepath=fpath, compress=True, copy=False)
-        os.remove(export_data['source_filepath'])
-
-
-    except Exception as e:
-        print(e)
-        # bg_blender.progress(e)
-        sys.exit(1)
diff --git a/blenderkit/utils.py b/blenderkit/utils.py
deleted file mode 100644
index 952219ad7b1a60ac2a82baf6623f67b4658391e7..0000000000000000000000000000000000000000
--- a/blenderkit/utils.py
+++ /dev/null
@@ -1,1001 +0,0 @@
-# ##### 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 #####
-
-
-from blenderkit import paths, rerequests, image_utils
-
-import bpy
-from mathutils import Vector
-import json
-import os
-import sys
-import shutil
-import logging
-import traceback
-import inspect
-import datetime
-
-bk_logger = logging.getLogger('blenderkit')
-
-ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000
-BELOW_NORMAL_PRIORITY_CLASS = 0x00004000
-HIGH_PRIORITY_CLASS = 0x00000080
-IDLE_PRIORITY_CLASS = 0x00000040
-NORMAL_PRIORITY_CLASS = 0x00000020
-REALTIME_PRIORITY_CLASS = 0x00000100
-
-supported_material_click = ('MESH', 'CURVE', 'META', 'FONT', 'SURFACE', 'VOLUME', 'GPENCIL')
-supported_material_drag = ('MESH', 'CURVE', 'META', 'FONT', 'SURFACE', 'VOLUME', 'GPENCIL')
-
-
-# supported_material_drag = ('MESH')
-
-
-def experimental_enabled():
-    preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    return preferences.experimental_features
-
-
-def get_process_flags():
-    flags = BELOW_NORMAL_PRIORITY_CLASS
-    if sys.platform != 'win32':  # TODO test this on windows
-        flags = 0
-    return flags
-
-
-def activate(ob):
-    bpy.ops.object.select_all(action='DESELECT')
-    ob.select_set(True)
-    bpy.context.view_layer.objects.active = ob
-
-def selection_get():
-    aob = bpy.context.view_layer.objects.active
-    selobs = bpy.context.view_layer.objects.selected[:]
-    return (aob, selobs)
-
-
-def selection_set(sel):
-    bpy.ops.object.select_all(action='DESELECT')
-    bpy.context.view_layer.objects.active = sel[0]
-    for ob in sel[1]:
-        ob.select_set(True)
-
-
-def get_active_model():
-    if bpy.context.view_layer.objects.active is not None:
-        ob = bpy.context.view_layer.objects.active
-        while ob.parent is not None:
-            ob = ob.parent
-        return ob
-    return None
-
-
-def get_active_HDR():
-    scene = bpy.context.scene
-    ui_props = bpy.context.window_manager.blenderkitUI
-    image = ui_props.hdr_upload_image
-    return image
-
-
-def get_selected_models():
-    '''
-    Detect all hierarchies that contain asset data from selection. Only parents that have actual ['asset data'] get returned
-    Returns
-    list of objects containing asset data.
-
-    '''
-    obs = bpy.context.selected_objects[:]
-    done = {}
-    parents = []
-    for ob in obs:
-        if ob not in done:
-            while ob.parent is not None and ob not in done and ob.blenderkit.asset_base_id == '' and ob.instance_collection is None:
-                done[ob] = True
-                ob = ob.parent
-
-            if ob not in parents and ob not in done:
-                if ob.blenderkit.name != '' or ob.instance_collection is not None:
-                    parents.append(ob)
-            done[ob] = True
-
-    # if no blenderkit - like objects were found, use the original selection.
-    if len(parents) == 0:
-        parents = obs
-    return parents
-
-
-def get_selected_replace_adepts():
-    '''
-    Detect all hierarchies that contain either asset data from selection, or selected objects themselves.
-    Returns
-    list of objects for replacement.
-
-    '''
-    obs = bpy.context.selected_objects[:]
-    done = {}
-    parents = []
-    for selected_ob in obs:
-        ob = selected_ob
-        if ob not in done:
-            while ob.parent is not None and ob not in done and ob.blenderkit.asset_base_id == '' and ob.instance_collection is None:
-                done[ob] = True
-                # print('step,',ob.name)
-                ob = ob.parent
-
-            # print('fin', ob.name)
-            if ob not in parents and ob not in done:
-                if ob.blenderkit.name != '' or ob.instance_collection is not None:
-                    parents.append(ob)
-
-            done[ob] = True
-    # print(parents)
-    # if no blenderkit - like objects were found, use the original selection.
-    if len(parents) == 0:
-        parents = obs
-    pprint('replace adepts')
-    pprint(str(parents))
-    return parents
-
-
-def exclude_collection(name, state=True):
-    '''
-    Set the exclude state of collection
-    Parameters
-    ----------
-    name - name of collection
-    state - default True.
-
-    Returns
-    -------
-    None
-    '''
-    vl = bpy.context.view_layer.layer_collection
-    cc = [vl]
-    found = False
-    while len(cc) > 0 and not found:
-        c = cc.pop()
-        if c.name == name:
-            c.exclude = state
-            found = True
-        cc.extend(c.children)
-
-def get_search_props():
-    scene = bpy.context.scene
-    wm = bpy.context.window_manager
-    if scene is None:
-        return;
-    uiprops = bpy.context.window_manager.blenderkitUI
-    props = None
-    if uiprops.asset_type == 'MODEL':
-        if not hasattr(wm, 'blenderkit_models'):
-            return;
-        props = wm.blenderkit_models
-    if uiprops.asset_type == 'SCENE':
-        if not hasattr(wm, 'blenderkit_scene'):
-            return;
-        props = wm.blenderkit_scene
-    if uiprops.asset_type == 'HDR':
-        if not hasattr(wm, 'blenderkit_HDR'):
-            return;
-        props = wm.blenderkit_HDR
-    if uiprops.asset_type == 'MATERIAL':
-        if not hasattr(wm, 'blenderkit_mat'):
-            return;
-        props = wm.blenderkit_mat
-
-    if uiprops.asset_type == 'TEXTURE':
-        if not hasattr(wm, 'blenderkit_tex'):
-            return;
-        # props = scene.blenderkit_tex
-
-    if uiprops.asset_type == 'BRUSH':
-        if not hasattr(wm, 'blenderkit_brush'):
-            return;
-        props = wm.blenderkit_brush
-    return props
-
-
-def get_active_asset_by_type(asset_type='model'):
-    asset_type = asset_type.lower()
-    if asset_type == 'model':
-        if bpy.context.view_layer.objects.active is not None:
-            ob = get_active_model()
-            return ob
-    if asset_type == 'scene':
-        return bpy.context.scene
-    if asset_type == 'hdr':
-        return get_active_HDR()
-    if asset_type == 'material':
-        if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.active_material is not None:
-            return bpy.context.active_object.active_material
-    if asset_type == 'texture':
-        return None
-    if asset_type == 'brush':
-        b = get_active_brush()
-        if b is not None:
-            return b
-    return None
-
-
-def get_active_asset():
-    scene = bpy.context.scene
-    ui_props = bpy.context.window_manager.blenderkitUI
-    if ui_props.asset_type == 'MODEL':
-        if bpy.context.view_layer.objects.active is not None:
-            ob = get_active_model()
-            return ob
-    if ui_props.asset_type == 'SCENE':
-        return bpy.context.scene
-    if ui_props.asset_type == 'HDR':
-        return get_active_HDR()
-    elif ui_props.asset_type == 'MATERIAL':
-        if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.active_material is not None:
-            return bpy.context.active_object.active_material
-    elif ui_props.asset_type == 'TEXTURE':
-        return None
-    elif ui_props.asset_type == 'BRUSH':
-        b = get_active_brush()
-        if b is not None:
-            return b
-    return None
-
-
-def get_upload_props():
-    scene = bpy.context.scene
-    ui_props = bpy.context.window_manager.blenderkitUI
-    if ui_props.asset_type == 'MODEL':
-        if bpy.context.view_layer.objects.active is not None:
-            ob = get_active_model()
-            return ob.blenderkit
-    if ui_props.asset_type == 'SCENE':
-        s = bpy.context.scene
-        return s.blenderkit
-    if ui_props.asset_type == 'HDR':
-
-        hdr = ui_props.hdr_upload_image  # bpy.data.images.get(ui_props.hdr_upload_image)
-        if not hdr:
-            return None
-        return hdr.blenderkit
-    elif ui_props.asset_type == 'MATERIAL':
-        if bpy.context.view_layer.objects.active is not None and bpy.context.active_object.active_material is not None:
-            return bpy.context.active_object.active_material.blenderkit
-    elif ui_props.asset_type == 'TEXTURE':
-        return None
-    elif ui_props.asset_type == 'BRUSH':
-        b = get_active_brush()
-        if b is not None:
-            return b.blenderkit
-    return None
-
-
-def previmg_name(index, fullsize=False):
-    if not fullsize:
-        return '.bkit_preview_' + str(index).zfill(3)
-    else:
-        return '.bkit_preview_full_' + str(index).zfill(3)
-
-
-def get_active_brush():
-    context = bpy.context
-    brush = None
-    if context.sculpt_object:
-        brush = context.tool_settings.sculpt.brush
-    elif context.image_paint_object:  # could be just else, but for future possible more types...
-        brush = context.tool_settings.image_paint.brush
-    return brush
-
-
-def load_prefs():
-    user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-    # if user_preferences.api_key == '':
-    fpath = paths.BLENDERKIT_SETTINGS_FILENAME
-    if os.path.exists(fpath):
-        try:
-            with open(fpath, 'r', encoding='utf-8') as s:
-                prefs = json.load(s)
-                user_preferences.api_key = prefs.get('API_key', '')
-                user_preferences.global_dir = prefs.get('global_dir', paths.default_global_dict())
-                user_preferences.api_key_refresh = prefs.get('API_key_refresh', '')
-        except Exception as e:
-            print('failed to read addon preferences.')
-            print(e)
-            os.remove(fpath)
-
-
-def save_prefs(self, context):
-    # first check context, so we don't do this on registration or blender startup
-    if not bpy.app.background:  # (hasattr kills blender)
-        user_preferences = bpy.context.preferences.addons['blenderkit'].preferences
-        # we test the api key for length, so not a random accidentally typed sequence gets saved.
-        lk = len(user_preferences.api_key)
-        if 0 < lk < 25:
-            # reset the api key in case the user writes some nonsense, e.g. a search string instead of the Key
-            user_preferences.api_key = ''
-            props = get_search_props()
-            props.report = 'Login failed. Please paste a correct API Key.'
-
-        prefs = {
-            'API_key': user_preferences.api_key,
-            'API_key_refresh': user_preferences.api_key_refresh,
-            'global_dir': user_preferences.global_dir,
-        }
-        try:
-            fpath = paths.BLENDERKIT_SETTINGS_FILENAME
-            if not os.path.exists(paths._presets):
-                os.makedirs(paths._presets)
-            with open(fpath, 'w', encoding='utf-8') as s:
-                json.dump(prefs, s, ensure_ascii=False, indent=4)
-        except Exception as e:
-            print(e)
-
-
-def uploadable_asset_poll():
-    '''returns true if active asset type can be uploaded'''
-    ui_props = bpy.context.window_manager.blenderkitUI
-    if ui_props.asset_type == 'MODEL':
-        return bpy.context.view_layer.objects.active is not None
-    if ui_props.asset_type == 'MATERIAL':
-        return bpy.context.view_layer.objects.active is not None and bpy.context.active_object.active_material is not None
-    if ui_props.asset_type == 'HDR':
-        return ui_props.hdr_upload_image is not None
-    return True
-
-
-def get_hidden_texture(name, force_reload=False):
-    t = bpy.data.textures.get(name)
-    if t is None:
-        t = bpy.data.textures.new(name, 'IMAGE')
-    if not t.image or t.image.name != name:
-        img = bpy.data.images.get(name)
-        if img:
-            t.image = img
-    return t
-
-
-def img_to_preview(img, copy_original=False):
-    if bpy.app.version[0] >= 3:
-        img.preview_ensure()
-    if not copy_original:
-        return;
-    if img.preview.image_size != img.size:
-        img.preview.image_size = (img.size[0], img.size[1])
-        img.preview.image_pixels_float = img.pixels[:]
-    # img.preview.icon_size = (img.size[0], img.size[1])
-    # img.preview.icon_pixels_float = img.pixels[:]
-
-
-def get_hidden_image(tpath, bdata_name, force_reload=False, colorspace='sRGB'):
-    if bdata_name[0] == '.':
-        hidden_name = bdata_name
-    else:
-        hidden_name = '.%s' % bdata_name
-    img = bpy.data.images.get(hidden_name)
-
-    if tpath.startswith('//'):
-        tpath = bpy.path.abspath(tpath)
-
-    if img == None or (img.filepath != tpath):
-        if tpath.startswith('//'):
-            tpath = bpy.path.abspath(tpath)
-        if not os.path.exists(tpath) or os.path.isdir(tpath):
-            tpath = paths.get_addon_thumbnail_path('thumbnail_notready.jpg')
-
-        if img is None:
-            img = bpy.data.images.load(tpath)
-            img_to_preview(img)
-            img.name = hidden_name
-        else:
-            if img.filepath != tpath:
-                if img.packed_file is not None:
-                    img.unpack(method='USE_ORIGINAL')
-
-                img.filepath = tpath
-                img.reload()
-                img_to_preview(img)
-        image_utils.set_colorspace(img, colorspace)
-
-    elif force_reload:
-        if img.packed_file is not None:
-            img.unpack(method='USE_ORIGINAL')
-        img.reload()
-        img_to_preview(img)
-        image_utils.set_colorspace(img, colorspace)
-
-    return img
-
-
-def get_thumbnail(name):
-    p = paths.get_addon_thumbnail_path(name)
-    name = '.%s' % name
-    img = bpy.data.images.get(name)
-    if img == None:
-        img = bpy.data.images.load(p)
-        image_utils.set_colorspace(img, 'sRGB')
-        img.name = name
-        img.name = name
-
-    return img
-
-
-def files_size_to_text(size):
-    fsmb = size / (1024 * 1024)
-    fskb = size % 1024
-    if fsmb == 0:
-        return f'{round(fskb)}KB'
-    else:
-        return f'{round(fsmb, 1)}MB'
-
-
-def get_brush_props(context):
-    brush = get_active_brush()
-    if brush is not None:
-        return brush.blenderkit
-    return None
-
-
-def p(text, text1='', text2='', text3='', text4='', text5='', level='DEBUG'):
-    '''debug printing depending on blender's debug value'''
-
-    if 1:  # bpy.app.debug_value != 0:
-        # print('-----BKit debug-----\n')
-        # traceback.print_stack()
-        texts = [text1, text2, text3, text4, text5]
-        text = str(text)
-        for t in texts:
-            if t != '':
-                text += ' ' + str(t)
-
-        bk_logger.debug(text)
-        # print('---------------------\n')
-
-
-def copy_asset(fp1, fp2):
-    '''synchronizes the asset between folders, including it's texture subdirectories'''
-    if 1:
-        bk_logger.debug('copy asset')
-        bk_logger.debug(fp1 + ' ' + fp2)
-        if not os.path.exists(fp2):
-            shutil.copyfile(fp1, fp2)
-            bk_logger.debug('copied')
-        source_dir = os.path.dirname(fp1)
-        target_dir = os.path.dirname(fp2)
-        for subdir in os.scandir(source_dir):
-            if not subdir.is_dir():
-                continue
-            target_subdir = os.path.join(target_dir, subdir.name)
-            if os.path.exists(target_subdir):
-                continue
-            bk_logger.debug(str(subdir) + ' ' + str(target_subdir))
-            shutil.copytree(subdir, target_subdir)
-            bk_logger.debug('copied')
-
-    # except Exception as e:
-    #     print('BlenderKit failed to copy asset')
-    #     print(fp1, fp2)
-    #     print(e)
-
-
-def pprint(data, data1=None, data2=None, data3=None, data4=None):
-    '''pretty print jsons'''
-    p(json.dumps(data, indent=4, sort_keys=True))
-
-
-def get_hierarchy(ob):
-    '''get all objects in a tree'''
-    obs = []
-    doobs = [ob]
-    # pprint('get hierarchy')
-    pprint(ob.name)
-    while len(doobs) > 0:
-        o = doobs.pop()
-        doobs.extend(o.children)
-        obs.append(o)
-    return obs
-
-
-def select_hierarchy(ob, state=True):
-    obs = get_hierarchy(ob)
-    for ob in obs:
-        ob.select_set(state)
-    return obs
-
-
-def delete_hierarchy(ob):
-    obs = get_hierarchy(ob)
-    bpy.ops.object.delete({"selected_objects": obs})
-
-
-def get_bounds_snappable(obs, use_modifiers=False):
-    # progress('getting bounds of object(s)')
-    parent = obs[0]
-    while parent.parent is not None:
-        parent = parent.parent
-    maxx = maxy = maxz = -10000000
-    minx = miny = minz = 10000000
-
-    s = bpy.context.scene
-
-    obcount = 0  # calculates the mesh obs. Good for non-mesh objects
-    matrix_parent = parent.matrix_world
-    for ob in obs:
-        # bb=ob.bound_box
-        mw = ob.matrix_world
-        subp = ob.parent
-        # while parent.parent is not None:
-        #     mw =
-
-        if ob.type == 'MESH' or ob.type == 'CURVE':
-            # If to_mesh() works we can use it on curves and any other ob type almost.
-            # disabled to_mesh for 2.8 by now, not wanting to use dependency graph yet.
-            depsgraph = bpy.context.evaluated_depsgraph_get()
-
-            object_eval = ob.evaluated_get(depsgraph)
-            if ob.type == 'CURVE':
-                mesh = object_eval.to_mesh()
-            else:
-                mesh = object_eval.data
-
-            # to_mesh(context.depsgraph, apply_modifiers=self.applyModifiers, calc_undeformed=False)
-            obcount += 1
-            if mesh is not None:
-                for c in mesh.vertices:
-                    coord = c.co
-                    parent_coord = matrix_parent.inverted() @ mw @ Vector(
-                        (coord[0], coord[1], coord[2]))  # copy this when it works below.
-                    minx = min(minx, parent_coord.x)
-                    miny = min(miny, parent_coord.y)
-                    minz = min(minz, parent_coord.z)
-                    maxx = max(maxx, parent_coord.x)
-                    maxy = max(maxy, parent_coord.y)
-                    maxz = max(maxz, parent_coord.z)
-                # bpy.data.meshes.remove(mesh)
-            if ob.type == 'CURVE':
-                object_eval.to_mesh_clear()
-
-    if obcount == 0:
-        minx, miny, minz, maxx, maxy, maxz = 0, 0, 0, 0, 0, 0
-
-    minx *= parent.scale.x
-    maxx *= parent.scale.x
-    miny *= parent.scale.y
-    maxy *= parent.scale.y
-    minz *= parent.scale.z
-    maxz *= parent.scale.z
-
-    return minx, miny, minz, maxx, maxy, maxz
-
-
-def get_bounds_worldspace(obs, use_modifiers=False):
-    # progress('getting bounds of object(s)')
-    s = bpy.context.scene
-    maxx = maxy = maxz = -10000000
-    minx = miny = minz = 10000000
-    obcount = 0  # calculates the mesh obs. Good for non-mesh objects
-    for ob in obs:
-        # bb=ob.bound_box
-        mw = ob.matrix_world
-        if ob.type == 'MESH' or ob.type == 'CURVE':
-            depsgraph = bpy.context.evaluated_depsgraph_get()
-            ob_eval = ob.evaluated_get(depsgraph)
-            mesh = ob_eval.to_mesh()
-            obcount += 1
-            if mesh is not None:
-                for c in mesh.vertices:
-                    coord = c.co
-                    world_coord = mw @ Vector((coord[0], coord[1], coord[2]))
-                    minx = min(minx, world_coord.x)
-                    miny = min(miny, world_coord.y)
-                    minz = min(minz, world_coord.z)
-                    maxx = max(maxx, world_coord.x)
-                    maxy = max(maxy, world_coord.y)
-                    maxz = max(maxz, world_coord.z)
-            ob_eval.to_mesh_clear()
-
-    if obcount == 0:
-        minx, miny, minz, maxx, maxy, maxz = 0, 0, 0, 0, 0, 0
-    return minx, miny, minz, maxx, maxy, maxz
-
-
-def is_linked_asset(ob):
-    return ob.get('asset_data') and ob.instance_collection != None
-
-
-def get_dimensions(obs):
-    minx, miny, minz, maxx, maxy, maxz = get_bounds_snappable(obs)
-    bbmin = Vector((minx, miny, minz))
-    bbmax = Vector((maxx, maxy, maxz))
-    dim = Vector((maxx - minx, maxy - miny, maxz - minz))
-    return dim, bbmin, bbmax
-
-
-def requests_post_thread(url, json, headers):
-    r = rerequests.post(url, json=json, verify=True, headers=headers)
-
-
-def get_headers(api_key):
-    headers = {
-        "accept": "application/json",
-    }
-    if api_key != '':
-        headers["Authorization"] = "Bearer %s" % api_key
-    return headers
-
-
-def scale_2d(v, s, p):
-    '''scale a 2d vector with a pivot'''
-    return (p[0] + s[0] * (v[0] - p[0]), p[1] + s[1] * (v[1] - p[1]))
-
-
-def scale_uvs(ob, scale=1.0, pivot=Vector((.5, .5))):
-    mesh = ob.data
-    if len(mesh.uv_layers) > 0:
-        uv = mesh.uv_layers[mesh.uv_layers.active_index]
-
-        # Scale a UV map iterating over its coordinates to a given scale and with a pivot point
-        for uvindex in range(len(uv.data)):
-            uv.data[uvindex].uv = scale_2d(uv.data[uvindex].uv, scale, pivot)
-
-
-# map uv cubic and switch of auto tex space and set it to 1,1,1
-def automap(target_object=None, target_slot=None, tex_size=1, bg_exception=False, just_scale=False):
-    wm = bpy.context.window_manager
-    mat_props = wm.blenderkit_mat
-    if mat_props.automap:
-        tob = bpy.data.objects[target_object]
-        # only automap mesh models
-        if tob.type == 'MESH' and len(tob.data.polygons) > 0:
-            # check polycount for a rare case where no polys are in editmesh
-            actob = bpy.context.active_object
-            bpy.context.view_layer.objects.active = tob
-
-            # auto tex space
-            if tob.data.use_auto_texspace:
-                tob.data.use_auto_texspace = False
-
-            if not just_scale:
-                tob.data.texspace_size = (1, 1, 1)
-
-            if 'automap' not in tob.data.uv_layers:
-                bpy.ops.mesh.uv_texture_add()
-                uvl = tob.data.uv_layers[-1]
-                uvl.name = 'automap'
-
-            # TODO limit this to active material
-            # tob.data.uv_textures['automap'].active = True
-
-            scale = tob.scale.copy()
-
-            if target_slot is not None:
-                tob.active_material_index = target_slot
-            bpy.ops.object.mode_set(mode='EDIT')
-            bpy.ops.mesh.select_all(action='DESELECT')
-
-            # this exception is just for a 2.8 background thunmbnailer crash, can be removed when material slot select works...
-            if bg_exception:
-                bpy.ops.mesh.select_all(action='SELECT')
-            else:
-                bpy.ops.object.material_slot_select()
-
-            scale = (scale.x + scale.y + scale.z) / 3.0
-
-            if tex_size == 0:# prevent division by zero, it's possible to have 0 in tex size by unskilled uploaders
-                tex_size = 1
-
-            if not just_scale:
-
-                bpy.ops.uv.cube_project(
-                    cube_size=scale * 2.0 / (tex_size),
-                    correct_aspect=False)  # it's * 2.0 because blender can't tell size of a unit cube :)
-
-            bpy.ops.object.editmode_toggle()
-            tob.data.uv_layers.active = tob.data.uv_layers['automap']
-            tob.data.uv_layers["automap"].active_render = True
-            # this by now works only for thumbnail preview, but should be extended to work on arbitrary objects.
-            # by now, it takes the basic uv map = 1 meter. also, it now doeasn't respect more materials on one object,
-            # it just scales whole UV.
-            if just_scale:
-                scale_uvs(tob, scale=Vector((1 / tex_size, 1 / tex_size)))
-            bpy.context.view_layer.objects.active = actob
-
-
-def name_update(props):
-    '''
-    Update asset name function, gets run also before upload. Makes sure name doesn't change in case of reuploads,
-    and only displayName gets written to server.
-    '''
-    scene = bpy.context.scene
-    ui_props = bpy.context.window_manager.blenderkitUI
-
-    # props = get_upload_props()
-    if props.name_old != props.name:
-        props.name_changed = True
-        props.name_old = props.name
-        nname = props.name.strip()
-        nname = nname.replace('_', ' ')
-
-        if nname.isupper():
-            nname = nname.lower()
-        nname = nname[0].upper() + nname[1:]
-        props.name = nname
-        # here we need to fix the name for blender data = ' or " give problems in path evaluation down the road.
-    fname = props.name
-    fname = fname.replace('\'', '')
-    fname = fname.replace('\"', '')
-    asset = get_active_asset()
-    if ui_props.asset_type != 'HDR':
-        # Here we actually rename assets datablocks, but don't do that with HDR's and possibly with others
-        asset.name = fname
-
-def fmt_dimensions(p):
-    '''formats dimensions to correct string'''
-    dims = [p['dimensionX'],p['dimensionY'],p['dimensionZ']]
-    maxl = max(dims)
-    if maxl>1:
-        unit = 'm'
-        unitscale = 1
-    elif maxl>.01:
-        unit = 'cm'
-        unitscale = 100
-    else:
-        unit = 'mm'
-        unitscale = 1000
-    s = f'{fmt_length(dims[0]*unitscale)}×{fmt_length(dims[1]*unitscale)}×{fmt_length(dims[2]*unitscale)} {unit}'
-    return s
-
-def fmt_length(prop):
-    prop = str(round(prop, 2))
-    return prop
-
-
-def get_param(asset_data, parameter_name, default=None):
-    if not asset_data.get('dictParameters'):
-        # this can appear in older version files.
-        return default
-
-    return asset_data['dictParameters'].get(parameter_name, default)
-
-    # for p in asset_data['parameters']:
-    #     if p.get('parameterType') == parameter_name:
-    #         return p['value']
-    # return default
-
-
-def params_to_dict(params):
-    params_dict = {}
-    for p in params:
-        params_dict[p['parameterType']] = p['value']
-    return params_dict
-
-
-def dict_to_params(inputs, parameters=None):
-    if parameters == None:
-        parameters = []
-    for k in inputs.keys():
-        if type(inputs[k]) == list:
-            strlist = ""
-            for idx, s in enumerate(inputs[k]):
-                strlist += s
-                if idx < len(inputs[k]) - 1:
-                    strlist += ','
-
-            value = "%s" % strlist
-        elif type(inputs[k]) != bool:
-            value = inputs[k]
-        else:
-            value = str(inputs[k])
-        parameters.append(
-            {
-                "parameterType": k,
-                "value": value
-            })
-    return parameters
-
-
-def update_tags(self, context):
-    props = self
-
-    commasep = props.tags.split(',')
-    ntags = []
-    for tag in commasep:
-        if len(tag) > 19:
-            short_tags = tag.split(' ')
-            for short_tag in short_tags:
-                if len(short_tag) > 19:
-                    short_tag = short_tag[:18]
-                ntags.append(short_tag)
-        else:
-            ntags.append(tag)
-    if len(ntags) == 1:
-        ntags = ntags[0].split(' ')
-    ns = ''
-    for t in ntags:
-        if t != '':
-            ns += t + ','
-    ns = ns[:-1]
-    if props.tags != ns:
-        props.tags = ns
-
-
-def user_logged_in():
-    a = bpy.context.window_manager.get('bkit profile')
-    if a is not None:
-        return True
-    return False
-
-
-def profile_is_validator():
-    a = bpy.context.window_manager.get('bkit profile')
-    if a is not None and a['user'].get('exmenu'):
-        return True
-    return False
-
-
-def user_is_owner(asset_data=None):
-    '''Checks if the current logged in user is owner of the asset'''
-    profile = bpy.context.window_manager.get('bkit profile')
-    if profile is None:
-        return False
-    if int(asset_data['author']['id']) == int(profile['user']['id']):
-        return True
-    return False
-
-
-def asset_from_newer_blender_version(asset_data):
-    '''checks if asset is from a newer blender version, to avoid incompatibility'''
-    bver = bpy.app.version
-    aver = asset_data['sourceAppVersion'].split('.')
-    bver_f = bver[0] + bver[1] * .01 + bver[2] * .0001
-    if len(aver)>=3:
-        aver_f = int(aver[0]) + int(aver[1]) * .01 + int(aver[2]) * .0001
-        return aver_f>bver_f
-    return False
-
-def guard_from_crash():
-    '''
-    Blender tends to crash when trying to run some functions
-     with the addon going through unregistration process.
-     This function is used in these functions (like draw callbacks)
-     so these don't run during unregistration.
-    '''
-    if bpy.context.preferences.addons.get('blenderkit') is None:
-        return False;
-    if bpy.context.preferences.addons['blenderkit'].preferences is None:
-        return False;
-    return True
-
-
-def get_largest_area(area_type='VIEW_3D'):
-    maxsurf = 0
-    maxa = None
-    maxw = None
-    region = None
-    for w in bpy.data.window_managers[0].windows:
-        for a in w.screen.areas:
-            if a.type == area_type:
-                asurf = a.width * a.height
-                if asurf > maxsurf:
-                    maxa = a
-                    maxw = w
-                    maxsurf = asurf
-
-                    for r in a.regions:
-                        if r.type == 'WINDOW':
-                            region = r
-    global active_area_pointer, active_window_pointer, active_region_pointer
-    active_window_pointer = maxw.as_pointer()
-    active_area_pointer = maxa.as_pointer()
-    active_region_pointer = region.as_pointer()
-    return maxw, maxa, region
-
-
-def get_fake_context(context, area_type='VIEW_3D'):
-    C_dict = {}  # context.copy() #context.copy was a source of problems - incompatibility with addons that also define context
-    C_dict.update(region='WINDOW')
-
-    # try:
-    #     context = context.copy()
-    #     # print('bk context copied successfully')
-    # except Exception as e:
-    #     print(e)
-    #     print('BlenderKit: context.copy() failed. Can be a colliding addon.')
-    context = {}
-
-    if context.get('area') is None or context.get('area').type != area_type:
-        w, a, r = get_largest_area(area_type=area_type)
-        if w:
-            # sometimes there is no area of the requested type. Let's face it, some people use Blender without 3d view.
-            override = {'window': w, 'screen': w.screen, 'area': a, 'region': r}
-            C_dict.update(override)
-        # print(w,a,r)
-    return C_dict
-
-
-# def is_url(text):
-
-
-def label_multiline(layout, text='', icon='NONE', width=-1, max_lines=10, split_last = 0):
-    '''
-     draw a ui label, but try to split it in multiple lines.
-
-    Parameters
-    ----------
-    layout
-    text
-    icon
-    width width to split by in character count
-    max_lines maximum lines to draw
-
-    Returns
-    -------
-    rows of the text(to add extra elements)
-    '''
-    rows = []
-    if text.strip() == '':
-        return [layout.row()]
-    text = text.replace('\r\n', '\n')
-    lines = text.split('\n')
-    if width > 0:
-        threshold = int(width / 5.5)
-    else:
-        threshold = 35
-    li = 0
-    for l in lines:
-        # if is_url(l):
-        li += 1
-        while len(l) > threshold:
-            i = l.rfind(' ', 0, threshold)
-            if i < 1:
-                i = threshold
-            l1 = l[:i]
-            row = layout.row()
-            row.label(text=l1, icon=icon)
-            rows.append(row)
-            icon = 'NONE'
-            l = l[i:].lstrip()
-            li += 1
-            if li > max_lines:
-                break;
-        if li > max_lines:
-            break;
-        row = layout.row()
-        if split_last > 0:
-            row = row.split(factor=split_last)
-        row.label(text=l, icon=icon)
-        rows.append(row)
-        icon = 'NONE'
-    # if li > max_lines:
-    return rows
-
-
-def is_upload_old(asset_data):
-    '''
-    estimates if the asset is far too long in the 'uploaded' state
-    This returns the number of days the validation is over the limit.
-    '''
-    date_time_str = asset_data["created"][:10]
-    # date_time_str = 'Jun 28 2018 7:40AM'
-    date_time_obj = datetime.datetime.strptime(date_time_str, '%Y-%m-%d')
-    today = date_time_obj.today()
-    age = today - date_time_obj
-    old = datetime.timedelta(days=5)
-    if age > old:
-        return (age.days - old.days)
-    return 0
-
-def trace():
-    traceback.print_stack()
diff --git a/blenderkit/version_checker.py b/blenderkit/version_checker.py
deleted file mode 100644
index 37aeadc46fa9e2303cd431f28f3c7f754d9fcb2f..0000000000000000000000000000000000000000
--- a/blenderkit/version_checker.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# ##### 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 #####
-
-import bpy
-from blenderkit import paths
-
-import requests, os, json, threading
-
-
-def get_addon_version():
-    # should return addon version, but since Blender 3.0 this is synced with Blender version
-    ver = bpy.app.version
-    return '%i.%i.%i' % (ver[0], ver[1], ver[2])
-
-
-    # import blenderkit
-    # ver = blenderkit.bl_info['version']
-    # return '%i.%i.%i' % (ver[0], ver[1], ver[2])
-
-
-def check_version(url, api_key, module):
-    headers = {
-        "accept": "application/json",
-        "Authorization": "Bearer %s" % api_key}
-
-    print('checking online version of module %s' % str(module.bl_info['name']))
-    try:
-        r = requests.get(url, headers=headers)
-        data = r.json()
-        ver_online = {
-            'addonVersion2.8': data['addonVersion']
-        }
-        tempdir = paths.get_temp_dir()
-
-        ver_filepath = os.path.join(tempdir, 'addon_version.json')
-        with open(ver_filepath, 'w', encoding = 'utf-8') as s:
-            json.dump(ver_online, s,  ensure_ascii=False, indent=4)
-    except:
-        print("couldn't check online for version updates")
-
-
-def compare_versions(module):
-    try:
-        ver_local = module.bl_info['version']
-        ver_local_float = ver_local[0] + .01 * ver_local[1] + .0001 * ver_local[2]
-
-        tempdir = paths.get_temp_dir()
-        ver_filepath = os.path.join(tempdir, 'addon_version.json')
-        with open(ver_filepath, 'r',encoding='utf-8') as s:
-            data = json.load(s)
-
-        ver_online = data['addonVersion2.8'].split('.')
-        ver_online_float = int(ver_online[0]) + .01 * int(ver_online[1]) + .0001 * int(ver_online[2])
-
-        # print('versions: installed-%s, online-%s' % (str(ver_local_float), str(ver_online_float)))
-        if ver_online_float > ver_local_float:
-            return True
-    except:
-        print("couldn't compare addon versions")
-    return False
-
-
-def check_version_thread(url, API_key, module):
-    thread = threading.Thread(target=check_version, args=([url, API_key, module]), daemon=True)
-    thread.start()