# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from rna_prop_ui import PropertyPanel
from .properties_grease_pencil_common import (
    AnnotationDataPanel,
    GreasePencilToolsPanel,
)
from bpy.app.translations import pgettext_iface as iface_

def act_strip(context):
    try:
        return context.scene.sequence_editor.active_strip
    except AttributeError:
        return None

def draw_color_balance(layout, color_balance):

    flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
    col = flow.column()

    box = col.box()
    split = box.split(factor=0.35)
    col = split.column(align=True)
    col.label(text="Lift:")
    col.separator()
    col.separator()
    col.prop(color_balance, "lift", text="")
    col.prop(color_balance, "invert_lift", text="Invert", icon='ARROW_LEFTRIGHT')
    split.template_color_picker(color_balance, "lift", value_slider=True, cubic=True)

    col = flow.column()

    box = col.box()
    split = box.split(factor=0.35)
    col = split.column(align=True)
    col.label(text="Gamma:")
    col.separator()
    col.separator()
    col.prop(color_balance, "gamma", text="")
    col.prop(color_balance, "invert_gamma", text="Invert", icon='ARROW_LEFTRIGHT')
    split.template_color_picker(color_balance, "gamma", value_slider=True, lock_luminosity=True, cubic=True)

    col = flow.column()

    box = col.box()
    split = box.split(factor=0.35)
    col = split.column(align=True)
    col.label(text="Gain:")
    col.separator()
    col.separator()
    col.prop(color_balance, "gain", text="")
    col.prop(color_balance, "invert_gain", text="Invert", icon='ARROW_LEFTRIGHT')
    split.template_color_picker(color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True)

class SEQUENCER_HT_header(Header):
    bl_space_type = 'SEQUENCE_EDITOR'

    def draw(self, context):
        layout = self.layout

        st = context.space_data
        scene = context.scene

        row = layout.row(align=True)
        row.template_header()

        layout.prop(st, "view_type", text="")

        SEQUENCER_MT_editor_menus.draw_collapsible(context, layout)

        '''if st.view_type == 'SEQUENCER':
            layout.prop(st, "show_backdrop", text="Backdrop")'''

        layout.separator_spacer()

        layout.template_running_jobs()

        if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
            layout.separator()

            if(bpy.context.scene.use_audio):
                icon = "MUTE_IPO_OFF"
            else:
                icon = "MUTE_IPO_ON"

            layout.operator( "screen.audio_mute_toggle", text = "", icon = icon )

            layout.operator("sequencer.refresh_all", icon="FILE_REFRESH", text="")

        if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
            layout.prop(st, "display_mode", text="", icon_only=True)

        if st.view_type != 'SEQUENCER':
            layout.prop(st, "preview_channels", text="", icon_only=True)
            layout.prop(st, "display_channel", text="Channel")

            ed = scene.sequence_editor
            if ed:
                row = layout.row(align=True)
                row.prop(ed, "show_overlay", text="", icon='GHOST_ENABLED')
                if ed.show_overlay:
                    row.prop(ed, "overlay_frame", text="")
                    row.prop(ed, "use_overlay_lock", text="", icon='LOCKED')

                    row = layout.row()
                    row.prop(st, "overlay_type", text="")

        if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
            gpd = context.gpencil_data
            toolsettings = context.tool_settings

            # Proportional editing
            if gpd and gpd.use_stroke_edit_mode:
                row = layout.row(align=True)
                row.prop(toolsettings, "proportional_edit", icon_only=True)
                if toolsettings.proportional_edit != 'DISABLED':
                    row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)

class SEQUENCER_MT_editor_menus(Menu):
    bl_idname = "SEQUENCER_MT_editor_menus"
    bl_label = ""

    def draw(self, context):
        self.draw_menus(self.layout, context)

    @staticmethod
    def draw_menus(layout, context):
        st = context.space_data

        layout.menu("SEQUENCER_MT_view")

        if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:

            layout.menu("SEQUENCER_MT_select")
            layout.menu("SEQUENCER_MT_add")
            layout.menu("SEQUENCER_MT_edit")
            layout.menu("SEQUENCER_MT_split")
            layout.menu("SEQUENCER_MT_transform")
            layout.menu("SEQUENCER_MT_strip")
            layout.menu("SEQUENCER_MT_navigation")
            layout.menu("SEQUENCER_MT_marker")

class SEQUENCER_MT_view_render(Menu):
    bl_label = "Render"

    def draw(self, context):
        layout = self.layout

        layout.operator("render.opengl", text="Viewport Render Image", icon='RENDER_STILL').sequencer = True
        props = layout.operator("render.opengl", text="Viewport Render Animation", icon='RENDER_ANIMATION')
        props.animation = True
        props.sequencer = True
        layout.separator()
        layout.operator("sound.mixdown", text="Audio", icon='FILE_SOUND')

class SEQUENCER_MT_view_toggle(Menu):
    bl_label = "View Type"

    def draw(self, context):
        layout = self.layout

        layout.operator("sequencer.view_toggle").type = 'SEQUENCER'
        layout.operator("sequencer.view_toggle").type = 'PREVIEW'
        layout.operator("sequencer.view_toggle").type = 'SEQUENCER_PREVIEW'

class SEQUENCER_MT_preview_zoom(Menu):
    bl_label = "Zoom"

    def draw(self, context):
        layout = self.layout
        layout.operator_context = 'INVOKE_REGION_PREVIEW'

        layout.operator("view2d.zoom_in", text = "In")
        layout.operator("view2d.zoom_out", text = "Out")
        layout.operator("view2d.zoom_border", text = "Box...")

        layout.separator()

        ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))

        for a, b in ratios:
            layout.operator(
                "sequencer.view_zoom_ratio",
                text=iface_("Zoom %d:%d") % (a, b),
                translate=False,
            ).ratio = a / b
        layout.operator_context = 'INVOKE_DEFAULT'

class SEQUENCER_MT_view_zoom(Menu):
    bl_label = "Frame"

    def draw(self, context):
        layout = self.layout

        layout.operator("view2d.zoom_border", text = "Box...")
        layout.operator("sequencer.view_selected", text="Selected")
        layout.operator("sequencer.view_all", text="All")
        layout.operator("sequencer.view_frame", text="Playhead")
        layout.separator()

        prop = layout.operator("view2d.zoom_in", text="Horizontal In")
        layout.operator("view2d.zoom_out", text="Horizontal Out")
        layout.operator_context = "EXEC_REGION_WIN"
        layout.operator("sequencer.zoom_vertical", text="Vertical In").direction = "IN"
        layout.operator("sequencer.zoom_vertical", text="Vertical Out").direction = "OUT"

class SEQUENCER_MT_view_frame(Menu):
    bl_label = "Frame"

    def draw(self, context):
        layout = self.layout

'''        layout.operator("view2d.zoom_border", text = "Box...")
        layout.operator("sequencer.view_selected", text="Selected")
        layout.operator("sequencer.view_all", text="All")
        layout.operator("sequencer.view_frame", text="Playhead") '''

class SEQUENCER_MT_view_preview(Menu):
    bl_label = "Preview Range"

    def draw(self, context):
        layout = self.layout

        layout.operator("anim.previewrange_set", text = "Set Box...")
        layout.operator("anim.previewrange_clear", text = "Clear Box")

        layout.separator()

        layout.operator("sequencer.preview_selected", text = "Selected")
        layout.operator("sequencer.set_preview_range", text = "Set In").type = "IN"
        layout.operator("sequencer.set_preview_range", text = "Set Out").type = "OUT"

class SEQUENCER_MT_view_channel(Menu):
    bl_label = "Channel"

    def draw(self, context):
        layout = self.layout

        layout.operator("sequencer.view_channel", text = "Solo").type = "SOLO"
        layout.operator("sequencer.view_channel", text = "All").type = "ALL"

class SEQUENCER_MT_view(Menu):
    bl_label = "View"

    def draw(self, context):
        layout = self.layout

        st = context.space_data
        is_preview = st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}
        is_sequencer_view = st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}

        if st.view_type == 'PREVIEW':
            # Specifying the REGION_PREVIEW context is needed in preview-only
            # mode, else the lookup for the shortcut will fail in
            # wm_keymap_item_find_props() (see #32595).
            layout.operator_context = 'INVOKE_REGION_PREVIEW'
        layout.operator("sequencer.properties", icon='MENU_PANEL', text = "Toggle Sidebar")
        layout.operator_context = 'INVOKE_DEFAULT'

        layout.separator()

        if is_sequencer_view:
            layout.operator_context = 'INVOKE_REGION_WIN'

            layout.menu("SEQUENCER_MT_view_zoom")

            layout.menu("SEQUENCER_MT_view_preview")

            layout.menu("SEQUENCER_MT_view_channel")

            layout.operator_context = 'INVOKE_DEFAULT'

            layout.separator()

        if is_preview:
            layout.operator_context = 'INVOKE_REGION_PREVIEW'
            layout.operator("sequencer.view_all_preview", text="Fit Preview in window")

            layout.separator()

            layout.menu("SEQUENCER_MT_preview_zoom")

            layout.operator_context = 'INVOKE_DEFAULT'

            # # XXX, invokes in the header view
            #layout.operator("sequencer.view_ghost_border", text="Overlay Border")

        if is_sequencer_view:

            layout.prop(st, "show_backdrop",text="Backdrop")
            layout.prop(st, "show_strip_offset", text="Offsets")

            layout.prop(st, "show_frame_indicator", text="Frame Number")

            #layout.separator()

            layout.prop(st, "show_seconds", text="Seconds")
            if context.space_data.show_seconds:
                layout.prop(context.preferences.view, "timecode_style", text="")

            layout.prop_menu_enum(st, "waveform_display_type", text="Waveform")

        if is_preview:

            if st.display_mode == 'IMAGE':

                layout.separator()

                layout.prop(st, "show_safe_areas")
                layout.prop(st, "show_metadata")

            elif st.display_mode == 'WAVEFORM':

                layout.separator()

                layout.prop(st, "show_separate_color")

        layout.separator()

        layout.menu("SEQUENCER_MT_view_render")

        layout.separator()

        layout.menu("INFO_MT_area")

class SEQUENCER_MT_transform_gaps(Menu):
    bl_label = "Gaps"

    def draw(self, context):
        layout = self.layout

        layout.operator("sequencer.gap_remove", text = "Extract at Playhead").all=False
        layout.operator("sequencer.gap_remove", text = "Extract All").all=True
        layout.operator("sequencer.concatenate", text = "Extract after Selection")

        layout.separator()

        layout.operator("sequencer.gap_insert", text = "Insert Gap")

class SEQUENCER_MT_transform_move(Menu):
    bl_label = "Move in Steps"

    def draw(self, context):
        layout = self.layout

        layout.operator("sequencer.move", text = "Up").direction = "UP"
        layout.operator("sequencer.move", text = "Down").direction = "DOWN"
        layout.operator("sequencer.move", text = "Left").direction = "LEFT"
        layout.operator("sequencer.move", text = "Right").direction = "RIGHT"

class SEQUENCER_MT_transform(Menu):
    bl_label = "Transform"

    def draw(self, context):
        layout = self.layout

        layout.operator("transform.transform", text="Move").mode = 'TRANSLATION'
        layout.operator("transform.transform", text="Move/Extend from Frame").mode = 'TIME_EXTEND'
        layout.operator("sequencer.slip", text="Slip Strip Contents")

        layout.separator()

        layout.menu("SEQUENCER_MT_transform_move")

        layout.separator()

        layout.operator_menu_enum("sequencer.swap", "side")

        layout.separator()

        layout.menu("SEQUENCER_MT_transform_gaps")

        layout.separator()

        layout.operator("sequencer.snap", text = "Snap to Playhead")

class SEQUENCER_MT_edit_input(Menu):
    bl_label = "Inputs"

    def draw(self, context):
        layout = self.layout
        edit = act_edit(context)

        layout.operator("sequencer.reload", text="Reload Strips")
        layout.operator("sequencer.reload", text="Reload Strips and Adjust Length").adjust_length = True
        prop = layout.operator("sequencer.change_path", text="Change Path/Files")
        layout.operator("sequencer.swap_data", text="Swap Data")

        if edit:
            stype = edit.type

            if stype == 'IMAGE':
                prop.filter_image = True
            elif stype == 'MOVIE':
                prop.filter_movie = True
            elif stype == 'SOUND':
                prop.filter_sound = True

class SEQUENCER_MT_select_cursor(Menu):
    bl_label = "Select Playhead"

    def draw(self, context):
        layout = self.layout
        layout.operator("sequencer.select_time_cursor", text="Current Frame").extent = "FALSE"
        props = layout.operator("sequencer.select", text="Left")
        props.left_right = 'LEFT'
        props.linked_time = True
        props = layout.operator("sequencer.select", text="Right")
        props.left_right = 'RIGHT'
        props.linked_time = True

class SEQUENCER_MT_select_handle(Menu):
    bl_label = "Select Handle"

    def draw(self, context):
        layout = self.layout

        layout.operator("sequencer.select_handles", text="Both").side = 'BOTH'
        layout.operator("sequencer.select_handles", text="Left").side = 'LEFT'
        layout.operator("sequencer.select_handles", text="Right").side = 'RIGHT'

class SEQUENCER_MT_select_channel(Menu):
    bl_label = "Select Channel"

    def draw(self, context):
        layout = self.layout

        layout.operator("sequencer.select_channel", text="All")
        layout.operator("sequencer.select_active_side", text="Left").side = 'LEFT'
        layout.operator("sequencer.select_active_side", text="Right").side = 'RIGHT'

class SEQUENCER_MT_select_Mouse(Menu):
    bl_label = "Select Mouse"

    def draw(self, context):
        layout = self.layout

        props = layout.operator("sequencer.select", text = "Handles")
        props.extend = False
        props.linked_time = False
        props.left_right = 'NONE'
        props.linked_handle = True

        props = layout.operator("sequencer.select", text = "Time Linked")
        props.extend = False
        props.linked_time = True
        props.left_right = 'MOUSE'
        props.linked_handle = False

        props = layout.operator("sequencer.select", text = "Extended")
        props.extend = True
        props.linked_time = False
        props.left_right = 'NONE'
        props.linked_handle = False

class SEQUENCER_MT_select_linked(Menu):
    bl_label = "Select Linked"

    def draw(self, context):
        layout = self.layout

        layout.operator("sequencer.select_linked", text = "All")
        layout.operator("sequencer.select_less", text = "Less")
        layout.operator("sequencer.select_more", text = "More")

class SEQUENCER_MT_select(Menu):
    bl_label = "Select"

    def draw(self, context):
        layout = self.layout

        prop = layout.operator("sequencer.select_box", text = "Box...")

        layout.separator()
        layout.operator("sequencer.select_all", text="All").action = 'SELECT'
        layout.operator("sequencer.select_all", text="None").action = 'DESELECT'
        layout.operator("sequencer.select_all", text="Invert").action = 'INVERT'

        layout.separator()

        layout.menu("SEQUENCER_MT_select_cursor", text ="Playhead")
        layout.menu("SEQUENCER_MT_select_handle", text ="Handle")
        layout.menu("SEQUENCER_MT_select_channel", text ="Channel")
        layout.menu("SEQUENCER_MT_select_linked", text ="Linked")
        layout.menu("SEQUENCER_MT_select_Mouse", text ="Mouse Cursor")

        layout.separator()

        layout.operator("sequencer.select_all_locked_strips", text = "Locked")
        layout.operator("sequencer.select_all_mute_strips", text ="Muted/Hidden")

        layout.separator()

        layout.operator_menu_enum("sequencer.select_grouped", "type", text="Grouped")

class SEQUENCER_MT_marker(Menu):
    bl_label = "Marker"

    def draw(self, context):
        layout = self.layout

        st = context.space_data
        is_sequencer_view = st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}

        from .space_time import marker_menu_generic
        marker_menu_generic(layout)

        if is_sequencer_view:
            layout.prop(st, "use_marker_sync")

class SEQUENCER_MT_navigation_play(Menu):
    bl_label = "Toggle Play"

    def draw(self, context):
        layout = self.layout

        layout.operator("screen.animation_play", text="Forward", icon = "PLAY")
        props = layout.operator("screen.animation_play", text="Reverse", icon = "PLAY_REVERSE")
        props.reverse = True

class SEQUENCER_MT_navigation_frame(Menu):
    bl_label = "Frame"

    def draw(self, context):
        layout = self.layout

        props = layout.operator("screen.frame_offset", text="Previous")
        props.delta = -1
        props = layout.operator("screen.frame_offset", text="Next")
        props.delta = 1

class SEQUENCER_MT_navigation_cut(Menu):
    bl_label = "Cut"

    def draw(self, context):
        layout = self.layout

        props = layout.operator("sequencer.strip_jump", text="Previous")
        props.next = False
        props.center = False
        props = layout.operator("sequencer.strip_jump", text="Next")
        props.next = True
        props.center = False

class SEQUENCER_MT_navigation_strip(Menu):
    bl_label = "Strip"

    def draw(self, context):
        layout = self.layout

        props = layout.operator("sequencer.strip_jump", text="Previous")
        props.next = False
        props.center = True
        props = layout.operator("sequencer.strip_jump", text="Next")
        props.next = True
        props.center = True

class SEQUENCER_MT_navigation_keyframe(Menu):
    bl_label = "Keyframe"

    def draw(self, context):
        layout = self.layout

        props = layout.operator("screen.keyframe_jump", text="Previous", icon = "PREV_KEYFRAME")
        props.next = False
        props = layout.operator("screen.keyframe_jump", text="Next", icon = "NEXT_KEYFRAME")
        props.next = True

class SEQUENCER_MT_navigation(Menu):
    bl_label = "Navigation"

    def draw(self, context):
        layout = self.layout

        layout.menu("SEQUENCER_MT_navigation_play")

        layout.separator()

        layout.menu("SEQUENCER_MT_navigation_frame")

        layout.menu("SEQUENCER_MT_navigation_cut")

        layout.menu("SEQUENCER_MT_navigation_strip")

        layout.menu("SEQUENCER_MT_navigation_keyframe")

        layout.separator()

        props = layout.operator("screen.frame_jump", text="Start", icon = "REW")
        props.end = False
        props = layout.operator("screen.frame_jump", text="End", icon = "FF")
        props.end = True

class SEQUENCER_MT_add(Menu):
    bl_label = "Add"

    def draw(self, context):

        layout = self.layout
        layout.operator_context = 'INVOKE_REGION_WIN'

        bpy_data_scenes_len = len(bpy.data.scenes)
        if bpy_data_scenes_len > 10:
            layout.operator_context = 'INVOKE_DEFAULT'
            layout.operator("sequencer.scene_strip_add", text="Scene...", icon='SCENE_DATA')
        elif bpy_data_scenes_len > 1:
            layout.operator_menu_enum("sequencer.scene_strip_add", "scene", text="Scene", icon='SCENE_DATA')
        else:
            layout.menu("SEQUENCER_MT_add_empty", text="Scene", icon='SCENE_DATA')
        del bpy_data_scenes_len

        bpy_data_movieclips_len = len(bpy.data.movieclips)
        if bpy_data_movieclips_len > 10:
            layout.operator_context = 'INVOKE_DEFAULT'
            layout.operator("sequencer.movieclip_strip_add", text="Clip...", icon='TRACKER')
        elif bpy_data_movieclips_len > 0:
            layout.operator_menu_enum("sequencer.movieclip_strip_add", "clip", text="Clip", icon='TRACKER')
        else:
            layout.menu("SEQUENCER_MT_add_empty", text="Clip", icon='TRACKER')
        del bpy_data_movieclips_len

        bpy_data_masks_len = len(bpy.data.masks)
        if bpy_data_masks_len > 10:
            layout.operator_context = 'INVOKE_DEFAULT'
            layout.operator("sequencer.mask_strip_add", text="Mask...", icon='MOD_MASK')
        elif bpy_data_masks_len > 0:
            layout.operator_menu_enum("sequencer.mask_strip_add", "mask", text="Mask", icon='MOD_MASK')
        else:
            layout.menu("SEQUENCER_MT_add_empty", text="Mask", icon='MOD_MASK')
        del bpy_data_masks_len

        layout.separator()

        layout.operator("sequencer.movie_strip_add", text="Movie", icon='FILE_MOVIE')
        layout.operator("sequencer.sound_strip_add", text="Sound", icon='FILE_SOUND')
        layout.operator("sequencer.image_strip_add", text="Image/Sequence", icon='FILE_IMAGE')

        layout.separator()

        layout.operator_context = 'INVOKE_REGION_WIN'
        layout.operator("sequencer.effect_strip_add", text="Color", icon='COLOR').type = 'COLOR'
        layout.operator("sequencer.effect_strip_add", text="Text", icon='FONT_DATA').type = 'TEXT'

        layout.separator()

        layout.operator("sequencer.effect_strip_add", text="Adjustment Layer", icon='COLOR').type = 'ADJUSTMENT'

        layout.operator_context = 'INVOKE_DEFAULT'
        layout.menu("SEQUENCER_MT_add_effect")

        col = layout.column()
        col.menu("SEQUENCER_MT_add_transitions")

class SEQUENCER_MT_add_empty(Menu):
    bl_label = "Empty"

    def draw(self, context):
        layout = self.layout

        layout.label(text="No Items Available")

class SEQUENCER_MT_add_transitions(Menu):
    bl_label = "Transitions"

    def draw(self, context):
        if context.selected_sequences:
            selected_seq = len(context.selected_sequences)
        else:
            selected_seq = 0

        layout = self.layout

        col = layout.column()
        col.operator("sequencer.crossfade_sounds", text="Sound Crossfade")

        col.separator()

        col.operator("sequencer.effect_strip_add", text="Crossfade").type = 'CROSS'
        col.operator("sequencer.effect_strip_add", text="Gamma Crossfade").type = 'GAMMA_CROSS'

        col.separator()

        col.operator("sequencer.effect_strip_add", text="Wipe").type = 'WIPE'
        col.enabled = selected_seq >= 2

class SEQUENCER_MT_add_effect(Menu):
    bl_label = "Effect Strip"

    def draw(self, context):
        if context.selected_sequences:
            selected_seq = len(context.selected_sequences)
        else:
            selected_seq = 0

        layout = self.layout
        layout.operator_context = 'INVOKE_REGION_WIN'

        col = layout.column()
        col.operator("sequencer.effect_strip_add", text="Add").type = 'ADD'
        col.operator("sequencer.effect_strip_add", text="Subtract").type = 'SUBTRACT'
        col.operator("sequencer.effect_strip_add", text="Multiply").type = 'MULTIPLY'
        col.operator("sequencer.effect_strip_add", text="Over Drop").type = 'OVER_DROP'
        col.operator("sequencer.effect_strip_add", text="Alpha Over").type = 'ALPHA_OVER'
        col.operator("sequencer.effect_strip_add", text="Alpha Under").type = 'ALPHA_UNDER'
        col.operator("sequencer.effect_strip_add", text="Color Mix").type = 'COLORMIX'
        col.enabled = selected_seq >=2

        layout.separator()

        layout.operator("sequencer.effect_strip_add", text="Multicam Selector").type = 'MULTICAM'

        layout.separator()

        col = layout.column()
        col.operator("sequencer.effect_strip_add", text="Transform").type = 'TRANSFORM'
        col.operator("sequencer.effect_strip_add", text="Speed Control").type = 'SPEED'

        col.separator()

        col.operator("sequencer.effect_strip_add", text="Glow").type = 'GLOW'
        col.operator("sequencer.effect_strip_add", text="Gaussian Blur").type = 'GAUSSIAN_BLUR'
        col.enabled = selected_seq != 0

class SEQUENCER_MT_split(Menu):
    bl_label = "Split"

    def draw(self, context):
        layout = self.layout

        layout.operator("sequencer.split", text = "Soft").type = "SOFT"
        layout.operator("sequencer.split", text = "Hard").type = "HARD"

        layout.separator()

        layout.operator("sequencer.split_mode", text = "Mode...")

        layout.separator()

        layout.operator("sequencer.split_extract", text = "Extract Left").direction = "LEFT"
        layout.operator("sequencer.split_extract", text = "Extract Right").direction = "RIGHT"

        layout.separator()

        layout.operator("sequencer.split_lift", text = "Lift Left").direction = "LEFT"
        layout.operator("sequencer.split_lift", text = "Lift Right").direction = "RIGHT"

class SEQUENCER_MT_edit_remove(Menu):
    bl_label = "Cut"

    def draw(self, context):
        layout = self.layout

        layout.operator("sequencer.delete_lift", text = "Lift")
        layout.operator("sequencer.ripple_delete", text="Extract")

class SEQUENCER_MT_edit(Menu):
    bl_label = "Edit"

    def draw(self, context):
        layout = self.layout

        layout.operator_context = 'INVOKE_REGION_WIN'

        layout.menu("SEQUENCER_MT_edit_remove")
        layout.operator("sequencer.copy", text="Copy", icon = "COPYDOWN")
        layout.operator("sequencer.paste", text="Paste", icon = "PASTEDOWN")

        layout.separator()

        layout.operator("sequencer.duplicate_move")
        layout.operator("sequencer.extend_to_fill")

        layout.separator()

        layout.operator("sequencer.meta_toggle", text="Toggle Meta")

class SEQUENCER_MT_strip_input(Menu):
    bl_label = "Inputs"

    def draw(self, context):
        layout = self.layout
        strip = act_strip(context)

        layout.operator("sequencer.reload", text="Reload Strips")
        layout.operator("sequencer.reload", text="Reload Strips and Adjust Length").adjust_length = True
        prop = layout.operator("sequencer.change_path", text="Change Path/Files")
        layout.operator("sequencer.swap_data", text="Swap Data")

        if strip:
            stype = strip.type

            if stype == 'IMAGE':
                prop.filter_image = True
            elif stype == 'MOVIE':
                prop.filter_movie = True
            elif stype == 'SOUND':
                prop.filter_sound = True

class SEQUENCER_MT_strip_movie(Menu):
    bl_label = "Movie"

    def draw(self, context):
        layout = self.layout

        layout.operator("sequencer.deinterlace_selected_movies", text = "Deinterlace")
        layout.operator("sequencer.reverse_selected_movies", text = "Reverse")
        layout.operator("sequencer.flip_x_selected_movies", text = "Flip X")
        layout.operator("sequencer.flip_y_selected_movies", text = "Flip Y")

        layout.separator()

        layout.operator("sequencer.rendersize")

class SEQUENCER_MT_strip_mute(Menu):
    bl_label = "Mute/Hide"

    def draw(self, context):
        layout = self.layout

        layout.operator("sequencer.mute", text="Mute/Hide").unselected = False
        layout.operator("sequencer.unmute", text="Un-Mute/Un-Hide").unselected = False

        layout.separator()

        layout.operator("sequencer.mute", text="Mute/Hide Deselected").unselected = True
        layout.operator("sequencer.unmute", text="Un-Mute/Un-Hide Deselected").unselected = True

class SEQUENCER_MT_strip_effect(Menu):
    bl_label = "Effect"

    def draw(self, context):
        layout = self.layout

        layout.operator_menu_enum("sequencer.change_effect_input", "swap")
        layout.operator_menu_enum("sequencer.change_effect_type", "type")
        layout.operator("sequencer.reassign_inputs")
        layout.operator("sequencer.swap_inputs")

class SEQUENCER_MT_strip(Menu):
    bl_label = "Strip"

    def draw(self, context):
        layout = self.layout

        layout.operator_context = 'INVOKE_REGION_WIN'

        layout.menu("SEQUENCER_MT_strip_mute")

        layout.separator()

        layout.operator("sequencer.lock", text = "Lock", icon='LOCKED')
        layout.operator("sequencer.unlock", text = "Unlock", icon='UNLOCKED')

        layout.separator()

        layout.operator("sequencer.meta_make")

        #layout.separator()

        strip = act_strip(context)

        if strip:
            stype = strip.type

            if stype in {
                    'CROSS', 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
                    'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'WIPE', 'GLOW',
                    'TRANSFORM', 'COLOR', 'SPEED', 'MULTICAM', 'ADJUSTMENT',
                    'GAUSSIAN_BLUR', 'TEXT',
            }:

                layout.separator()

                layout.menu("SEQUENCER_MT_strip_effect")

            elif stype in {'MOVIE'}:

                layout.separator()

                layout.menu("SEQUENCER_MT_strip_movie")

            elif stype in {'IMAGE'}:

                layout.separator()

                layout.operator("sequencer.rendersize")
                layout.operator("sequencer.images_separate")

            elif stype == 'META':

                #layout.separator()

                layout.operator("sequencer.meta_separate", text = "Un-Meta")

            elif stype == 'SOUND':
                st = context.space_data
                strip = act_strip(context)
                sound = strip.sound
                if st.waveform_display_type == 'DEFAULT_WAVEFORMS':

                    layout.separator()

                    #layout.prop(strip, "show_waveform") # only for active strip, but with checkbox.
                    layout.operator("sequencer.show_waveform_selected_sounds", text = "Toggle Draw Waveform")

            if stype != 'SOUND':

                layout.separator()

                layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
                layout.operator("sequencer.strip_modifier_copy", text = "Apply Modifiers to Selection")
                layout.operator("sequencer.toggle_all_modifiers", text ="Toggle All Modifiers")

        layout.separator()

        #layout.operator("sequencer.offset_clear") #Replaced by match frame
        layout.operator("sequencer.match_frame")

        layout.operator("sequencer.rebuild_proxy")

        layout.separator()

        layout.menu("SEQUENCER_MT_strip_input")

class SequencerButtonsPanel:
    bl_space_type = 'SEQUENCE_EDITOR'
    bl_region_type = 'UI'

    @staticmethod
    def has_sequencer(context):
        return (context.space_data.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'})

    @classmethod
    def poll(cls, context):
        return cls.has_sequencer(context) and (act_strip(context) is not None)

class SequencerButtonsPanel_Output:
    bl_space_type = 'SEQUENCE_EDITOR'
    bl_region_type = 'UI'

    @staticmethod
    def has_preview(context):
        st = context.space_data
        return (st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}) or st.show_backdrop

    @classmethod
    def poll(cls, context):
        return cls.has_preview(context)

class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel):
    bl_label = "Edit Strip"
    bl_category = "Strip"

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False  # No animation.

        scene = context.scene
        frame_current = scene.frame_current
        strip = act_strip(context)

        row = layout.row(align=True)
        #row.prop(strip, "type", text="")
        row.prop(strip, "name", text=""+strip.type.title()+"")
        row.prop(strip, "lock", toggle=True, icon_only=True)

        if strip.type != 'SOUND':

            layout.prop(strip, "blend_type", text="Blend")

            row = layout.row(align=True)
            sub = row.row(align=True)
            sub.active = (not strip.mute)

            sub.prop(strip, "blend_alpha", text="Opacity", slider=True)
            sub.prop(strip, "mute", toggle=True, icon_only=True)

            if strip.type == 'SCENE':
                scene = strip.scene
                if scene:

                    row = layout.row(align=True)
                    sub = row.row(align=True)
                    sub.active = (not strip.mute)

                    sub.prop(scene, "audio_volume", text="Volume")

                    if strip.mute:
                        icon = "MUTE_IPO_OFF"
                    else:
                        icon = "MUTE_IPO_ON"

                    sub.prop(strip, "mute", toggle=True, icon_only=True, icon=icon) #icon not working!

            layout.prop(strip, "use_translation", text="Image Offset")
            if strip.use_translation:
                #row = layout.row(align=True)
                layout.prop(strip.transform, "offset_x", text="X")
                layout.prop(strip.transform, "offset_y", text="Y")

            layout.prop(strip, "use_crop", text="Image Crop")
            if strip.use_crop:
                col = layout.column(align=True)
                col.prop(strip.crop, "max_y")
                row = col.row(align=True)
                row.prop(strip.crop, "min_x", text = "Left/Right")
                row.prop(strip.crop, "max_x", text = "")
                col.prop(strip.crop, "min_y")

        if strip.type == 'SOUND':

            st = context.space_data
            #strip = act_strip(context)
            sound = strip.sound

            col = layout.column()
            #col.prop(strip, "volume")
            row = col.row(align=True)
            sub = row.row(align=True)
            sub.active = (not strip.mute)

            sub.prop(scene, "audio_volume", text="Volume")

            if strip.mute:
                icon = "MUTE_IPO_OFF"
            else:
                icon = "MUTE_IPO_ON"

            sub.prop(strip, "mute", toggle=True, icon_only=True, icon=icon) #Icon not working!

            col.prop(strip, "pitch")
            col.prop(strip, "pan")

            if sound is not None:

                row = layout.row()
                if st.waveform_display_type == 'DEFAULT_WAVEFORMS':
                    row = row.split(factor=0.60)
                    row.prop(strip, "show_waveform")
                row.prop(sound, "use_mono")

class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
    bl_label = "Effect Strip"
    bl_category = "Strip"

    @classmethod
    def poll(cls, context):
        if not cls.has_sequencer(context):
            return False

        strip = act_strip(context)
        if not strip:
            return False

        return strip.type in {
            'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
            'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
            'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED',
            'MULTICAM', 'GAUSSIAN_BLUR', 'TEXT', 'COLORMIX'
        }

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False  # No animation.

        strip = act_strip(context)

        if strip.input_count > 0:
            col = layout.column()
            col.enabled = False
            col.prop(strip, "input_1")
            if strip.input_count > 1:
                col.prop(strip, "input_2")

        if strip.type == 'COLOR':
            layout.prop(strip, "color")

        elif strip.type == 'WIPE':
            col = layout.column()
            col.prop(strip, "transition_type")
            col.alignment = "RIGHT"
            col.row().prop(strip, "direction", expand=True)

            col = layout.column()
            col.prop(strip, "blur_width", slider=True)
            if strip.transition_type in {'SINGLE', 'DOUBLE'}:
                col.prop(strip, "angle")

        elif strip.type == 'GLOW':
            flow = layout.column_flow()
            flow.prop(strip, "threshold", slider=True)
            flow.prop(strip, "clamp", slider=True)
            flow.prop(strip, "boost_factor")
            flow.prop(strip, "blur_radius")

            row = layout.row()
            row.prop(strip, "quality", slider=True)
            row.prop(strip, "use_only_boost")

        elif strip.type == 'SPEED':
            layout.prop(strip, "use_default_fade", text="Stretch to input strip length")
            if not strip.use_default_fade:
                layout.prop(strip, "use_as_speed")
                if strip.use_as_speed:
                    layout.prop(strip, "speed_factor")
                else:
                    layout.prop(strip, "speed_factor", text="Frame Number")
                    layout.prop(strip, "scale_to_length")

        elif strip.type == 'TRANSFORM':
            layout = self.layout
            col = layout.column()

            col.prop(strip, "interpolation")
            col.prop(strip, "translation_unit")
            layout=layout.column(align=True)
            layout.prop(strip, "translate_start_x", text="Position X")
            layout.prop(strip, "translate_start_y", text="Y")

            layout.separator()

            col = layout.column(align=True)
            col.prop(strip, "use_uniform_scale")
            if strip.use_uniform_scale:
                col = layout.column(align=True)
                col.prop(strip, "scale_start_x", text="Scale")
            else:
                layout.prop(strip, "scale_start_x", text="Scale X")
                layout.prop(strip, "scale_start_y", text="Y")

            layout.separator()

            layout.prop(strip, "rotation_start", text="Rotation")

        elif strip.type == 'MULTICAM':
            col = layout.column(align=True)
            strip_channel = strip.channel

            col.prop(strip, "multicam_source", text="Source Channel")

            # The multicam strip needs at least 2 strips to be useful
            if strip_channel > 2:
                BT_ROW = 4
                #col.alignment = "RIGHT"
                col.label(text="    Cut to")
                row = col.row()

                for i in range(1, strip_channel):
                    if (i % BT_ROW) == 1:
                        row = col.row(align=True)

                    # Workaround - .enabled has to have a separate UI block to work
                    if i == strip.multicam_source:
                        sub = row.row(align=True)
                        sub.enabled = False
                        sub.operator("sequencer.cut_multicam", text=f"{i:d}").camera = i
                    else:
                        sub_1 = row.row(align=True)
                        sub_1.enabled = True
                        sub_1.operator("sequencer.cut_multicam", text=f"{i:d}").camera = i

                if strip.channel > BT_ROW and (strip_channel - 1) % BT_ROW:
                    for i in range(strip.channel, strip_channel + ((BT_ROW + 1 - strip_channel) % BT_ROW)):
                        row.label(text="")
            else:
                col.separator()
                col.label(text="Two or more channels are needed below this strip", icon='INFO')

        elif strip.type == 'TEXT':
            col = layout.column()
            col.prop(strip, "text")
            col.prop(strip, "font_size")

            row = col.row()
            row.prop(strip, "color")
            row = col.row()
            row.prop(strip, "use_shadow")
            rowsub = row.row()
            rowsub.active = strip.use_shadow
            rowsub.prop(strip, "shadow_color", text="")

            col.prop(strip, "align_x")
            col.prop(strip, "align_y", text = "Y")
            row = col.row(align=True)
            row.prop(strip, "location", text="Location")
            col.prop(strip, "wrap_width")
            sub = layout.column(align=True)
            split = sub.split(factor=0.495, align=True)
            split.alignment = 'RIGHT'
            split.label(text="Export Subtitles")
            split.operator("sequencer.export_subtitles", text="", icon='EXPORT')

        col = layout.column(align=True)
        if strip.type == 'SPEED':
            col.prop(strip, "multiply_speed")
        elif strip.type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'OVER_DROP'}:
            col.prop(strip, "use_default_fade", text="Default fade")
            if not strip.use_default_fade:
                col.prop(strip, "effect_fader", text="Effect Fader")
        elif strip.type == 'GAUSSIAN_BLUR':
            layout = layout.column(align=True)
            layout.prop(strip, "size_x", text = "Size X")
            layout.prop(strip, "size_y", text = "Y")
        elif strip.type == 'COLORMIX':
            layout.prop(strip, "blend_effect", text="Blend Mode")
            row = layout.row(align=True)
            row.prop(strip, "factor", slider=True)

class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
    bl_label = "Strip Input"
    bl_category = "Strip"

    @classmethod
    def poll(cls, context):
        if not cls.has_sequencer(context):
            return False

        strip = act_strip(context)
        if not strip:
            return False

        return strip.type in {'MOVIE', 'IMAGE'}

        ''', 'SCENE', 'MOVIECLIP', 'META',
        'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
        'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
        'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
        'MULTICAM', 'SPEED', 'ADJUSTMENT', 'COLORMIX' }'''

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False  # No animation.

        scene = context.scene

        strip = act_strip(context)

        seq_type = strip.type

        # draw a filename if we have one
        if seq_type == 'IMAGE':
            layout.prop(strip, "directory", text="")

            # Current element for the filename

            elem = strip.strip_elem_from_frame(scene.frame_current)
            if elem:
                layout.prop(elem, "filename", text="")  # strip.elements[0] could be a fallback

            layout.prop(strip.colorspace_settings, "name", text="Color Space")

            layout.prop(strip, "alpha_mode", text="Alpha")
            sub = layout.column(align=True)
            split = sub.split(factor=0.495, align=True)
            split.alignment = 'RIGHT'
            split.label(text="Change Data/Files")
            split.operator("sequencer.change_path", text="", icon='FILEBROWSER').filter_image = True

        elif seq_type == 'MOVIE':
            layout.prop(strip, "filepath", text="")

            layout.prop(strip.colorspace_settings, "name", text="Color Space")

            layout.prop(strip, "mpeg_preseek")
            layout.prop(strip, "stream_index")

        if scene.render.use_multiview and seq_type in {'IMAGE', 'MOVIE'}:
            layout.prop(strip, "use_multiview")

            col = layout.column()
            col.active = strip.use_multiview

            col.row().prop(strip, "views_format", expand=True)

            box = col.box()
            box.active = strip.views_format == 'STEREO_3D'
            box.template_image_stereo_3d(strip.stereo_3d_format)

class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
    bl_label = "Sound"
    bl_category = "Strip"

    @classmethod
    def poll(cls, context):
        if not cls.has_sequencer(context):
            return False

        strip = act_strip(context)
        if not strip:
            return False

        return (strip.type == 'SOUND')

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False  # No animation.

        st = context.space_data
        strip = act_strip(context)
        sound = strip.sound

        layout.template_ID(strip, "sound", open="sound.open")
        if sound is not None:
            layout.prop(sound, "filepath", text="")

            layout.use_property_split = True
            layout.use_property_decorate = False  # No animation.

            layout.alignment = 'RIGHT'
            sub = layout.column(align=True)
            split = sub.split(factor=0.5, align=True)
            split.alignment = 'RIGHT'
            if sound.packed_file:
                split.label(text="Unpack")
                split.operator("sound.unpack", icon='PACKAGE', text="")
            else:
                split.label(text="Pack")
                split.operator("sound.pack", icon='UGLYPACKAGE', text="")

            layout.prop(sound, "use_memory_cache")

class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
    bl_label = "Scene"
    bl_category = "Strip"

    @classmethod
    def poll(cls, context):
        if not cls.has_sequencer(context):
            return False

        strip = act_strip(context)
        if not strip:
            return False

        return (strip.type == 'SCENE')

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False  # No animation.

        strip = act_strip(context)

        layout.template_ID(strip, "scene")

        scene = strip.scene
        layout.prop(strip, "use_sequence")

        if not strip.use_sequence:
            layout.alignment = 'RIGHT'
            sub = layout.column(align=True)
            split = sub.split(factor=0.5, align=True)
            split.alignment = 'RIGHT'
            split.label(text="Camera Override")
            split.template_ID(strip, "scene_camera")

            layout.prop(strip, "use_grease_pencil", text="Show Grease Pencil")

        if not strip.use_sequence:
            if scene:
                # Warning, this is not a good convention to follow.
                # Expose here because setting the alpha from the 'Render' menu is very inconvenient.
                #layout.label(text="Preview")
                layout.prop(scene.render, "alpha_mode")

class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
    bl_label = "Mask"
    bl_category = "Strip"

    @classmethod
    def poll(cls, context):
        if not cls.has_sequencer(context):
            return False

        strip = act_strip(context)
        if not strip:
            return False

        return (strip.type == 'MASK')

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False  # No animation.

        strip = act_strip(context)

        layout.template_ID(strip, "mask")

        mask = strip.mask

        if mask:
            sta = mask.frame_start
            end = mask.frame_end
            layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)

class SEQUENCER_PT_data(SequencerButtonsPanel, Panel):
    bl_label = "Strip Data"
    bl_category = "Strip"
    #bl_parent_id = "SEQUENCER_PT_edit"
    bl_options = {'DEFAULT_CLOSED'}

    @classmethod
    def poll(cls, context):
        if not cls.has_sequencer(context):
            return False

        strip = act_strip(context)
        if not strip:
            return False

        return strip.type

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = False
        layout.use_property_decorate = False  # No animation.

        scene = context.scene
        frame_current = scene.frame_current
        strip = act_strip(context)

        length_list = [str(strip.frame_start), str(strip.frame_final_end), str(strip.frame_final_duration), str(strip.frame_offset_start), str(strip.frame_offset_end), str(strip.animation_offset_start), str(strip.animation_offset_end)]
        max_length = max(len(x) for x in length_list)
        max_factor = (1.9-max_length)/30

        sub = layout.row(align=True)
        sub.enabled = not strip.lock
        split = sub.split(factor=0.5+max_factor)
        split.alignment = 'RIGHT'
        split.label(text='Channel')
        split.prop(strip, "channel", text="")

        sub = layout.column(align=True)
        sub.enabled = not strip.lock
        split = sub.split(factor=0.5+max_factor)
        split.alignment = 'RIGHT'
        split.label(text="Start")
        split.prop(strip, "frame_start", text=str(bpy.utils.smpte_from_frame(strip.frame_start)).replace(':', ' '))
        split = sub.split(factor=0.5+max_factor)
        split.alignment = 'RIGHT'
        split.label(text="End")
        split.prop(strip, "frame_final_end", text=str(bpy.utils.smpte_from_frame(strip.frame_final_end)).replace(':', ' '))
        split = sub.split(factor=0.5+max_factor)
        split.alignment = 'RIGHT'
        split.label(text="Duration")
        split.prop(strip, "frame_final_duration", text=str(bpy.utils.smpte_from_frame(strip.frame_final_duration)).replace(':', ' '))

        if not isinstance(strip, bpy.types.EffectSequence):
            layout.alignment = 'RIGHT'
            sub = layout.column(align=True)
            split = sub.split(factor=0.5+max_factor, align=True)
            split.alignment = 'RIGHT'
            split.label(text="Soft Trim Start")
            split.prop(strip, "frame_offset_start", text=str(bpy.utils.smpte_from_frame(strip.frame_offset_start)).replace(':', ' '))
            split = sub.split(factor=0.5+max_factor, align=True)
            split.alignment = 'RIGHT'
            split.label(text='End')
            split.prop(strip, "frame_offset_end", text=str(bpy.utils.smpte_from_frame(strip.frame_offset_end)).replace(':', ' '))

            layout.alignment = 'RIGHT'
            sub = layout.column(align=True)
            split = sub.split(factor=0.5+max_factor)
            split.alignment = 'RIGHT'
            split.label(text="Hard Trim Start")
            split.prop(strip, "animation_offset_start", text=str(bpy.utils.smpte_from_frame(strip.animation_offset_start)).replace(':', ' '))
            split = sub.split(factor=0.5+max_factor, align=True)
            split.alignment = 'RIGHT'
            split.label(text='End')
            split.prop(strip, "animation_offset_end", text=str(bpy.utils.smpte_from_frame(strip.animation_offset_end)).replace(':', ' '))

        playhead = frame_current - strip.frame_start
        col = layout.column(align=True)
        col = col.box()
        col.active = (frame_current >= strip.frame_start and frame_current <= strip.frame_start + strip.frame_final_duration)
        split = col.split(factor=0.5+max_factor)
        split.alignment = 'RIGHT'
        split.label(text="Playhead")
        #split.alignment = 'LEFT'
        split.label(text="%s:   %s" % ((bpy.utils.smpte_from_frame(playhead).replace(':', ' ')), (str(playhead))))

        ''' Old data - anyone missing this data?
        col.label(text=iface_("Frame Offset %d:%d") % (strip.frame_offset_start, strip.frame_offset_end),
                  translate=False)
        col.label(text=iface_("Frame Still %d:%d") % (strip.frame_still_start, strip.frame_still_end), translate=False)'''

        elem = False

        if strip.type == 'IMAGE':
            elem = strip.strip_elem_from_frame(frame_current)
        elif strip.type == 'MOVIE':
            elem = strip.elements[0]

        if strip.type != "SOUND":
            split = col.split(factor=0.5+max_factor)
            split.alignment = 'RIGHT'
            split.label(text="Resolution")
            #split.alignment = 'CENTER'
            if elem and elem.orig_width > 0 and elem.orig_height > 0:
                split.label(text="%dx%d" % (elem.orig_width, elem.orig_height), translate=False)
            else:
                split.label(text="None")

        if strip.type == "SCENE":
            scene = strip.scene

            if scene:
                sta = scene.frame_start
                end = scene.frame_end
                split = col.split(factor=0.5+max_factor)
                split.alignment = 'RIGHT'
                split.label(text="Original Frame Range")
                split.alignment = 'LEFT'
                split.label(text="%d-%d (%d)" % (sta, end, end - sta + 1), translate=False)

class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
    bl_label = "Filter"
    bl_category = "Strip"

    @classmethod
    def poll(cls, context):
        if not cls.has_sequencer(context):
            return False

        strip = act_strip(context)
        if not strip:
            return False

        return strip.type in {
            'MOVIE', 'IMAGE', 'SCENE', 'MOVIECLIP', 'MASK',
            'META', 'ADD', 'SUBTRACT', 'ALPHA_OVER',
            'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY',
            'OVER_DROP', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
            'MULTICAM', 'SPEED', 'ADJUSTMENT', 'COLORMIX'
        }

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False  # No animation.

        strip = act_strip(context)

        col = layout.column()
        col.prop(strip, "strobe")

        if strip.type == 'MOVIECLIP':
            col = layout.column()
            col.label(text="Tracker")
            col.prop(strip, "stabilize2d")

            col = layout.column()
            col.label(text="Distortion")
            col.prop(strip, "undistort")

        split = layout.split(factor=0.6)
        col = split.column()
        col.prop(strip, "use_reverse_frames", text="Reverse")
        col.prop(strip, "use_deinterlace")

        col = split.column()
        col.prop(strip, "use_flip_x", text="X Flip")
        col.prop(strip, "use_flip_y", text="Y Flip")

        #layout.label(text="Color")
        col = layout.column(align=True)
        col.prop(strip, "color_saturation", text="Saturation")
        col.prop(strip, "color_multiply", text="Multiply")
        layout.prop(strip, "use_float", text="Convert to Float")

class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
    bl_label = "Proxy/Timecode"
    bl_category = "Strip"

    @classmethod
    def poll(cls, context):
        if not cls.has_sequencer(context):
            return False

        strip = act_strip(context)
        if not strip:
            return False

        return strip.type in {'MOVIE', 'IMAGE', 'SCENE', 'META', 'MULTICAM'}

    def draw_header(self, context):
        strip = act_strip(context)

        self.layout.prop(strip, "use_proxy", text="")

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False  # No animation.

        ed = context.scene.sequence_editor

        strip = act_strip(context)

        if strip.proxy:
            proxy = strip.proxy

            flow = layout.column_flow()
            flow.prop(ed, "proxy_storage", text="Storage")
            if ed.proxy_storage == 'PROJECT':
                flow.prop(ed, "proxy_dir", text="Directory")
            else:
                flow.prop(proxy, "use_proxy_custom_directory")
                flow.prop(proxy, "use_proxy_custom_file")

                if proxy.use_proxy_custom_directory and not proxy.use_proxy_custom_file:
                    flow.prop(proxy, "directory")
                if proxy.use_proxy_custom_file:
                    flow.prop(proxy, "filepath")

            layout = layout.box()
            row = layout.row(align=True)
            row.prop(strip.proxy, "build_25")
            row.prop(strip.proxy, "build_75")
            row = layout.row(align=True)
            row.prop(strip.proxy, "build_50")
            row.prop(strip.proxy, "build_100")

            layout = self.layout
            layout.use_property_split = True
            layout.use_property_decorate = False  # No animation.

            layout.prop(proxy, "use_overwrite")

            col = layout.column()
            col.prop(proxy, "quality", text="Build JPEG Quality")

            if strip.type == 'MOVIE':
                col = layout.column()

                col.prop(proxy, "timecode", text = "Timecode Index")

        col = layout.column()
        col.operator("sequencer.enable_proxies")
        col.operator("sequencer.rebuild_proxy")

class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel):
    bl_label = "Scene Preview/Render"
    bl_space_type = 'SEQUENCE_EDITOR'
    bl_region_type = 'UI'

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False  # No animation.
        render = context.scene.render

        col = layout.column()
        col.prop(render, "sequencer_gl_preview", text="")

        row = col.row()
        row.active = render.sequencer_gl_preview == 'SOLID'
        row.prop(render, "use_sequencer_gl_textured_solid")

        col.prop(render, "use_sequencer_gl_dof")

class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel):
    bl_label = "View Settings"

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False  # No animation.

        st = context.space_data

        col = layout.column()
        if st.display_mode == 'IMAGE':
            col.prop(st, "show_overexposed")
            col.separator()

        elif st.display_mode == 'WAVEFORM':
            col.prop(st, "show_separate_color")

        col = layout.column()
        col.separator()
        col.prop(st, "proxy_render_size")

class SEQUENCER_PT_view_safe_areas(SequencerButtonsPanel_Output, Panel):
    bl_label = "Safe Areas"
    bl_options = {'DEFAULT_CLOSED'}

    @classmethod
    def poll(cls, context):
        st = context.space_data
        is_preview = st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}
        return is_preview and (st.display_mode == 'IMAGE')

    def draw_header(self, context):
        st = context.space_data

        self.layout.prop(st, "show_safe_areas", text="")

    def draw(self, context):
        from .properties_data_camera import draw_display_safe_settings

        layout = self.layout
        #layout.use_property_split = True
        #layout.use_property_decorate = False  # No animation.

        st = context.space_data
        safe_data = context.scene.safe_areas

        draw_display_safe_settings(layout, safe_data, st)

class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
    bl_label = "Modifiers"
    bl_category = "Modifiers"

    def draw(self, context):
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False  # No animation.

        strip = act_strip(context)
        ed = context.scene.sequence_editor

        layout.prop(strip, "use_linear_modifiers")

        layout.operator_menu_enum("sequencer.strip_modifier_add", "type")
        layout.operator("sequencer.strip_modifier_copy")

        for mod in strip.modifiers:
            box = layout.box()

            row = box.row()
            row.prop(mod, "show_expanded", text="", emboss=False)
            row.prop(mod, "name", text="")

            row.prop(mod, "mute", text="")

            sub = row.row(align=True)
            props = sub.operator("sequencer.strip_modifier_move", text="", icon='TRIA_UP')
            props.name = mod.name
            props.direction = 'UP'
            props = sub.operator("sequencer.strip_modifier_move", text="", icon='TRIA_DOWN')
            props.name = mod.name
            props.direction = 'DOWN'

            row.operator("sequencer.strip_modifier_remove", text="", icon='X', emboss=False).name = mod.name

            if mod.show_expanded:
                row = box.row()
                row.prop(mod, "input_mask_type", expand=True)

                if mod.input_mask_type == 'STRIP':
                    sequences_object = ed
                    if ed.meta_stack:
                        sequences_object = ed.meta_stack[-1]
                    box.prop_search(mod, "input_mask_strip", sequences_object, "sequences", text="Mask")
                else:
                    box.prop(mod, "input_mask_id")
                    row = box.row()
                    row.prop(mod, "mask_time", expand=True)

                if mod.type == 'COLOR_BALANCE':
                    box.prop(mod, "color_multiply")
                    draw_color_balance(box, mod.color_balance)
                elif mod.type == 'CURVES':
                    box.template_curve_mapping(mod, "curve_mapping", type='COLOR', show_tone=True)
                elif mod.type == 'HUE_CORRECT':
                    box.template_curve_mapping(mod, "curve_mapping", type='HUE')
                elif mod.type == 'BRIGHT_CONTRAST':
                    col = box.column()
                    col.prop(mod, "bright")
                    col.prop(mod, "contrast")
                elif mod.type == 'WHITE_BALANCE':
                    col = box.column()
                    col.prop(mod, "white_value")
                elif mod.type == 'TONEMAP':
                    col = box.column()
                    col.prop(mod, "tonemap_type")
                    if mod.tonemap_type == 'RD_PHOTORECEPTOR':
                        col.prop(mod, "intensity")
                        col.prop(mod, "contrast")
                        col.prop(mod, "adaptation")
                        col.prop(mod, "correction")
                    elif mod.tonemap_type == 'RH_SIMPLE':
                        col.prop(mod, "key")
                        col.prop(mod, "offset")
                        col.prop(mod, "gamma")

class SEQUENCER_PT_grease_pencil(AnnotationDataPanel, SequencerButtonsPanel_Output, Panel):
    bl_space_type = 'SEQUENCE_EDITOR'
    bl_region_type = 'UI'

    # NOTE: this is just a wrapper around the generic GP Panel
    # But, it should only show up when there are images in the preview region

class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsPanel_Output, Panel):
    bl_space_type = 'SEQUENCE_EDITOR'
    bl_region_type = 'UI'

    # NOTE: this is just a wrapper around the generic GP tools panel
    # It contains access to some essential tools usually found only in
    # toolbar, which doesn't exist here...

class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
    _context_path = "scene.sequence_editor.active_strip"
    _property_type = (bpy.types.Sequence,)
    bl_category = "Strip"

classes = (
    SEQUENCER_HT_header,
    SEQUENCER_MT_editor_menus,
    SEQUENCER_MT_view,
    SEQUENCER_MT_view_render,
    SEQUENCER_MT_view_toggle,
    SEQUENCER_MT_view_frame,
    SEQUENCER_MT_view_channel,
    SEQUENCER_MT_preview_zoom,
    SEQUENCER_MT_view_zoom,
    SEQUENCER_MT_view_preview,
    SEQUENCER_MT_select_cursor,
    SEQUENCER_MT_select_handle,
    SEQUENCER_MT_select_channel,
    SEQUENCER_MT_select_Mouse,
    SEQUENCER_MT_select_linked,
    SEQUENCER_MT_select,
    SEQUENCER_MT_add,
    SEQUENCER_MT_add_effect,
    SEQUENCER_MT_add_transitions,
    SEQUENCER_MT_add_empty,
    SEQUENCER_MT_edit,
    SEQUENCER_MT_edit_input,
    SEQUENCER_MT_split,
    SEQUENCER_MT_edit_remove,
    SEQUENCER_MT_transform,
    SEQUENCER_MT_transform_gaps,
    SEQUENCER_MT_transform_move,
    SEQUENCER_MT_strip,
    SEQUENCER_MT_strip_movie,
    SEQUENCER_MT_strip_input,
    SEQUENCER_MT_strip_mute,
    SEQUENCER_MT_strip_effect,
    SEQUENCER_MT_navigation,
    SEQUENCER_MT_navigation_play,
    SEQUENCER_MT_navigation_frame,
    SEQUENCER_MT_navigation_cut,
    SEQUENCER_MT_navigation_strip,
    SEQUENCER_MT_navigation_keyframe,
    SEQUENCER_MT_marker,
    SEQUENCER_PT_edit,
    SEQUENCER_PT_effect,
    SEQUENCER_PT_input,
    SEQUENCER_PT_sound,
    SEQUENCER_PT_scene,
    SEQUENCER_PT_mask,
    SEQUENCER_PT_filter,
    SEQUENCER_PT_data,
    SEQUENCER_PT_proxy,
    SEQUENCER_PT_preview,
    SEQUENCER_PT_view,
    SEQUENCER_PT_view_safe_areas,
    SEQUENCER_PT_modifiers,
    SEQUENCER_PT_grease_pencil,
    SEQUENCER_PT_grease_pencil_tools,
    SEQUENCER_PT_custom_props,

)

if __name__ == "__main__":  # only for live edit.
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)


import re
from tabulate import tabulate

def main(args):
    path = vars(args)['path']
    windows_audit(path)

def windows_audit(path: str):
    parameter = ['Без аудита', 'Успех и сбой', 'Успех', 'Сбой']
    master_map = {}

    with open(path, 'r') as filez:

        current_table = ''
        for s in filez:
            if "Категория или подкатегория" in s:
                break

        for s in filez:
            if s[0] != ' ':
                current_table = s.replace('\n', '')
                master_map[current_table] = {}
            else:
                for p in parameter:
                    if re.search(p + '$', s):
                        value = p
                        key = s.split(p)[0].strip()
                        master_map[current_table][key] = value

    for k in master_map:
        print(k)
        print(tabulate(master_map[k].items(), headers=['Параметр', 'Значение'], tablefmt="grid"))
        print()


import itertools
import operator
import string

from pathlib import Path
from collections import deque, namedtuple

from . import data
from . import diff

def init ():
    data.init ()
    # init() should happen once
    if (data.GIT_DIR /'refs/heads/master').is_file():
        return
    data.update_ref ('HEAD', data.RefValue (symbolic=True, value='refs/heads/master'))

def write_tree ():
    # Get Index as a tree of dicts
    index_as_tree = {}
    with data.get_index () as index:
        for path, oid in index.items ():
            path = path.split ('/')
            dirpath, filename = path[:-1], path[-1]

            current = index_as_tree
            # Find the dict for the directory of this file
            for dirname in dirpath:
                current = current.setdefault (dirname, {})
            current[filename] = oid

    def write_tree_recursive (tree_dict):
        entries = []
        for name, value in tree_dict.items ():
            if type (value) is dict:
                type_ = 'tree'
                oid = write_tree_recursive (value)
            else:
                type_ = 'blob'
                oid = value
            entries.append ((name, oid, type_))

        tree = ''.join (f'{type_} {oid} {name}\n'
                        for name, oid, type_
                        in sorted (entries))
        return data.hash_object (tree.encode (), 'tree')

    return write_tree_recursive (index_as_tree)

# def _iter_tree_entries (oid):
#     if not oid:
#         return
#     tree = data.get_object (oid, 'tree')
#     for entry in tree.decode ().splitlines ():
#         type_, oid, name = entry.split (' ', 2)
#         yield type_, oid, name

def _iter_tree_entries (oid):
    if not oid:
        return ''
    return (entry.split (' ', 2)
            for entry in data.get_object (oid, 'tree').decode ().splitlines ())

def get_tree (oid, base_path=''):
    result = {}
    for type_, oid, name in _iter_tree_entries (oid):
        assert '/' not in name
        # assert name not in ('..', '.')
        path = base_path + name
        if type_ == 'blob':
            result[path] = oid
        elif type_ == 'tree':
            result.update (get_tree (oid, f'{path}/'))
        else:
            assert False, f'Unknown tree entry {type_}'
    return result

# def get_working_tree ():
#     result = {}
#     for root, _, filenames in os.walk ('.'):
#         for filename in filenames:
#             path = os.path.relpath (f'{root}/{filename}')
#             if is_ignored (path) or not os.path.isfile (path):
#                 continue
#             with open (path, 'rb') as f:
#                 result[path] = data.hash_object (f.read ())
#     return result

def get_working_tree ():
    file_path = Path('.')
    result = {}
    for fp in (fp for fp in file_path.rglob('*')
               if not is_ignored(fp) and fp.is_file()):
        result [str(fp)] = data.hash_object(fp.read_bytes())
    return result

def get_index_tree ():
    with data.get_index () as index:
        return index

# def _empty_current_directory ():
#     for root, dirnames, filenames in os.walk ('.', topdown=False):
#         for filename in filenames:
#             path = os.path.relpath (f'{root}/{filename}')
#             if is_ignored (path) or not os.path.isfile (path):
#                 continue
#             os.remove (path)
#         for dirname in dirnames:
#             path = os.path.relpath (f'{root}/{dirname}')
#             if is_ignored (path):
#                 continue
#             try:
#                 os.rmdir (path)
#             except (FileNotFoundError, OSError):
#                 # Deletion might fail if the directory contains ignored files,
#                 # so it's OK
#                 pass

def _empty_current_directory ():
    """ Remove all files/directories of the current tree (unless is_ignored)"""
    paths = []

    # First removing all files...
    for path in (fp for fp in Path('.').rglob ('*')
               if not is_ignored (fp)):
        if path.is_file ():
            path.unlink ()
        else:
            paths.append(path)

    # then removing all directories...
    paths.sort (reverse=True)
    for path in paths:
        path.rmdir()

def read_tree (tree_oid, update_working=False):
    with data.get_index () as index:
        index.clear ()
        index.update (get_tree (tree_oid))

        if update_working:
            _checkout_index (index)

def read_tree_merged (t_base, t_HEAD, t_other, update_working=False):
    with data.get_index () as index:
        index.clear ()
        index.update (diff.merge_trees (
            get_tree (t_base),
            get_tree (t_HEAD),
            get_tree (t_other)
        ))

        if update_working:
            _checkout_index (index)

def _checkout_index (index):
    """For every entry in the index, the respected object is copied to the given
    file path. Any missing directory structure is created during the process.
    """
    _empty_current_directory ()
    for path, oid in index.items ():
        fp = Path(path)
        if not fp.parent.is_dir():
            fp.parent.mkdir(parents=True, exist_ok=True)
        fp.write_bytes(data.get_object (oid, 'blob'))

def commit (message):
    commit = f'tree {write_tree ()}\n'

    HEAD = data.get_ref ('HEAD').value
    if HEAD:
        commit += f'parent {HEAD}\n'
    MERGE_HEAD = data.get_ref ('MERGE_HEAD').value
    if MERGE_HEAD:
        commit += f'parent {MERGE_HEAD}\n'
        data.delete_ref ('MERGE_HEAD', deref=False)

    commit += '\n'
    commit += f'{message}\n'

    oid = data.hash_object (commit.encode (), 'commit')

    data.update_ref ('HEAD', data.RefValue (symbolic=False, value=oid))

    return oid

def checkout (name):
    oid = get_oid (name)
    commit = get_commit (oid)
    read_tree (commit.tree, update_working=True)

    if is_branch (name):
        HEAD = data.RefValue (symbolic=True, value=f'refs/heads/{name}')
    else:
        HEAD = data.RefValue (symbolic=False, value=oid)

    data.update_ref ('HEAD', HEAD, deref=False)

def reset (oid):
    data.update_ref ('HEAD', data.RefValue (symbolic=False, value=oid))

def merge (other):
    HEAD = data.get_ref ('HEAD').value
    assert HEAD
    merge_base = get_merge_base (other, HEAD)
    c_other = get_commit (other)

    # Handle fast-forward merge
    if merge_base == HEAD:
        read_tree (c_other.tree, update_working=True)
        data.update_ref ('HEAD',
                         data.RefValue (symbolic=False, value=other))
        print ('Fast-forward merge, no need to commit')
        return

    data.update_ref ('MERGE_HEAD', data.RefValue (symbolic=False, value=other))

    c_base = get_commit (merge_base)
    c_HEAD = get_commit (HEAD)
    read_tree_merged (c_base.tree, c_HEAD.tree, c_other.tree, update_working=True)
    print ('Merged in working tree\nPlease commit')

def get_merge_base (oid1, oid2):
    parents1 = set (iter_commits_and_parents ({oid1}))

    for oid in iter_commits_and_parents ({oid2}):
        if oid in parents1:
            return oid

def is_ancestor_of (commit, maybe_ancestor):
    return maybe_ancestor in iter_commits_and_parents ({commit})

def create_tag (name, oid):
    data.update_ref (f'refs/tags/{name}', data.RefValue (symbolic=False, value=oid))

def create_branch (name, oid):
    data.update_ref (f'refs/heads/{name}', data.RefValue (symbolic=False, value=oid))

def iter_branch_names ():
    """ Return a generator yielding all branch names """
    return (ref[0].split('/')[-1] for ref in data.iter_refs ('refs/heads/'))

def is_branch (branch):
    return data.get_ref (f'refs/heads/{branch}').value is not None

def get_branch_name ():
    HEAD = data.get_ref ('HEAD', deref=False)
    if not HEAD.symbolic:
        return None
    HEAD = HEAD.value
    assert HEAD.startswith ('refs/heads/')
    return HEAD.split('/')[-1]

Commit = namedtuple ('Commit', ['tree', 'parents', 'message'])

def get_commit (oid):
    parents = []

    commit = data.get_object (oid, 'commit').decode ()
    lines = iter (commit.splitlines ())
    for line in itertools.takewhile (operator.truth, lines):
        key, value = line.split (' ', 1)
        if key == 'tree':
            tree = value
        elif key == 'parent':
            parents.append (value)
        else:
            assert False, f'Unknown field {key}'

    message = '\n'.join (lines)
    return Commit (tree=tree, parents=parents, message=message)

def iter_commits_and_parents (oids):
    # N.B. Must yield the oid before acccessing it (to allow caller to fetch it
    # if needed)
    oids = deque (oids)
    visited = set ()

    while oids:
        oid = oids.popleft ()
        if not oid or oid in visited:
            continue
        visited.add (oid)
        yield oid

        commit = get_commit (oid)
        # Return first parent next
        oids.extendleft (commit.parents[:1])
        # Return other parents later
        oids.extend (commit.parents[1:])

def iter_objects_in_commits (oids):
    # N.B. Must yield the oid before acccessing it (to allow caller to fetch it
    # if needed)

    visited = set ()
    def iter_objects_in_tree (oid):
        visited.add (oid)
        yield oid
        for type_, oid, _ in _iter_tree_entries (oid):
            if oid not in visited:
                if type_ == 'tree':
                    yield from iter_objects_in_tree (oid)
                else:
                    visited.add (oid)
                    yield oid

    for oid in iter_commits_and_parents (oids):
        yield oid
        commit = get_commit (oid)
        if commit.tree not in visited:
            yield from iter_objects_in_tree (commit.tree)

def get_oid (name):
    if name == '@': name = 'HEAD'

    # Name is ref
    refs_to_try = [
        f'{name}',
        f'refs/{name}',
        f'refs/tags/{name}',
        f'refs/heads/{name}',
    ]
    for ref in refs_to_try:
        if data.get_ref (ref, deref=False).value:
            return data.get_ref (ref).value

    # Name is SHA1
    is_hex = all (c in string.hexdigits for c in name)
    if len (name) == 40 and is_hex:
        return name

    assert False, f'Unknown name {name}'

# def add (filenames):

#     def add_file (filename):
#         # Normalize path
#         filename = os.path.relpath (filename)
#         with open (filename, 'rb') as f:
#             oid = data.hash_object (f.read ())
#         index[filename] = oid

#     def add_directory (dirname):
#         for root, _, filenames in os.walk (dirname):
#             for filename in filenames:
#                 # Normalize path
#                 path = os.path.relpath (f'{root}/{filename}')
#                 if is_ignored (path) or not os.path.isfile (path):
#                     continue
#                 add_file (path)

#     with data.get_index () as index:
#         for name in filenames:
#             if os.path.isfile (name):
#                 add_file (name)
#             elif os.path.isdir (name):
#                 add_directory (name)

def add (filenames):
    """
    Add one or more files/directories to the Index file
    Expects a list of file paths
    """
    with data.get_index () as index:
        for file_path in filenames:
            if is_ignored(file_path):
                continue
            elif file_path.is_file():
                # add file/hash for specified file
                index[str(file_path)] = data.hash_object(file_path.read_bytes())
            elif file_path.is_dir():
                # Add dictionary of files/hashes within specified path
                result = {}
                for fp in (fp for fp in file_path.rglob('*')
                        if not is_ignored(fp) and fp.is_file()):
                    result [str(fp)] = data.hash_object(fp.read_bytes())
                index.update(**result)

# def is_ignored (path):
#     return '.gitcl' in path.split ('/')

def is_ignored (path):
    """ Filter criteria of files/dirs to be ignored """
    # exlude Python cache files
    if '__pycache__' in path.parts:
        return False

    # dirs to exclude
    for s in [ '.gitignore', '.gitcl', 'gitcl.egg-info']:
        if s in path.parts:
            return True

    return False


def solution(survey, choices):
    answer = ""
    # 각 성격 유형의 점수를 계산하기 위해서 딕셔너리에 담아준다.
    scores = {"R": 0, "T": 0, "C": 0, "F": 0, "J": 0, "M": 0, "A": 0, "N": 0}

    # len(survey) == len(choices) 둘 중 하나 선택해서 해당 길이만큼 돌아준다.
    for i in range(len(choices)):
        # survey의 두개의 유형이 붙어있으니까 strip을 사용해서 떨어뜨린다.
        a, b = survey[i].strip()
        # 만약 해당 선택점수가 4점 미만이라면
        if choices[i] < 4:
            # 앞의 유형에 4 - 선택점수
            scores[a] += 4 - choices[i]
        # 만약 해당 선택점수가 4점이 넘는다면
        elif choices[i] > 4:
            # 뒤의 유형에 선택점수 - 4
            scores[b] += choices[i] - 4

    # 만약 T가 R보다 크다면 T유형을 answer에 더해주고
    if scores["R"] < scores["T"]:
        answer += "T"
    # 작거나 같으면 사전적으로 R이 먼저이므로 R을 더해준다.
    else:
        answer += "R"

    if scores["C"] < scores["F"]:
        answer += "F"
    else:
        answer += "C"

    if scores["J"] < scores["M"]:
        answer += "M"
    else:
        answer += "J"

    if scores["A"] < scores["N"]:
        answer += "N"
    else:
        answer += "A"

    return answer


import numpy as np
import math

def karatsuba(x,y):
    if (x<10 or y <10):
        return x * y

    n = max(len(str(x)),len(str(y)))//2
    p = 10**n

    a,b = divmod(x,p) #a = x//p, b = x%p
    c,d = divmod(y,p)

    ac = karatsuba(a,c)
    bd = karatsuba(b,d)
    abcd = karatsuba(a+b,c+d) - ac - bd
    return (ac*p + abcd)*p + bd


'''
By: ind3x
This script is something of a sustitude cypher but for this part i had to change the index to start at 1
'''

import fidx
from sympy import mod_inverse
#create custom type `list1b` from `list`
fidx.add(list, name='list1')

#add a map int indexes (i -> i-1)
fidx.list1.set_index_map(int, lambda _,i: i-1, override=True)

#create your lists

#numbers that form strings
numbers= fidx.list1([268,413,110,190,426,419,108,229,310,379,323,373,385,236,92,96,169,321,284,185,154,137,186])

#Array of charrecters sustituted by numbers
letters_and_numbers= fidx.list1(['A','B','C','D','E','F','J','H','I','J','K','L','M','N','O','P','Q','R','S',
'T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9','_'])

print("\nLetters and numbers are:",len(letters_and_numbers))
print("Flag is:", len(numbers), " long\n")

i=1
while i <= len(numbers):
    mod = numbers[i] % 41
    print(letters_and_numbers[mod_inverse(mod,41)], end='')
    i +=1
print("\n")


import sys
import os
import requests
import json
from argparse import ArgumentParser

def main(argv):
    parser = ArgumentParser()
    parser.add_argument("--token", dest="token", help="GitHub API personal access token ")
    parser.add_argument("--action", dest="action", default="build", help="The trigger action")
    parser.add_argument("--branch", dest="branch", help="The branch to build")
    parser.add_argument("--skip-engine", dest="skip_engine", action='store_true', default=False, help="Skip building the engine")
    parser.add_argument("--skip-sdk", dest="skip_sdk", action='store_true', default=False, help="Skip building the Defold SDK")
    parser.add_argument("--skip-bob", dest="skip_bob", action='store_true', default=False, help="Skip building bob")
    parser.add_argument("--skip-editor", dest="skip_editor", action='store_true', default=False, help="Skip building the editor")
    parser.add_argument("--skip-sign", dest="skip_sign", action='store_true', default=False, help="Skip signing the artefacts")

    args = parser.parse_args()

    if not args.token:
        args.token = os.environ.get("GITHUB_TOKEN")
    if not args.token:
        print("You must provide a GitHub token")
        exit(1)

    post_data = {
        "event_type": args.action,
        "client_payload": {
            "skip_engine": args.skip_engine,
            "skip_sdk": args.skip_sdk,
            "skip_bob": args.skip_bob,
            "skip_editor": args.skip_editor,
            "skip_sign": args.skip_sign,
            "branch": args.branch
        }
    }

    headers = {
        "Accept": "application/vnd.github.everest-preview+json",
        "Authorization": "token %s" % args.token
    }

    r = requests.post('https://api.github.com/repos/defold/defold/dispatches', json=post_data, headers=headers)
    print(r)

if __name__ == "__main__":
    main(sys.argv[1:])


import numpy as np
import matplotlib.pyplot as plt

class Transformer():
    def __init___(self):
        pass

    def body_to_earth(self, rocAtt):

        psi = rocAtt[0] * np.pi/180
        theta = rocAtt[1] * np.pi/180
        phi = rocAtt[2] * np.pi/180

        y = np.array([[np.cos(phi), -np.sin(phi), 0],
                      [np.sin(phi),  np.cos(phi), 0],
                      [          0,            0, 1]])

        p = np.array([[ np.cos(theta), 0, np.sin(theta)],
                      [             0, 1,             0],
                      [-np.sin(theta), 0, np.cos(theta)]])

        r = np.array([[1,           0,            0],
                      [0, np.cos(psi), -np.sin(psi)],
                      [0, np.sin(psi),  np.cos(psi)]])

        PP = np.array([[0, 0, -1],
                       [0, 1,  0],
                       [1, 0,  0]])

        transformation_mtx = y@p@r

        return transformation_mtx

    def TVC_convential_vector(self, theta1, theta2):
        convential_vector = np.array([np.cos(theta1)*np.cos(theta2),
                                      np.sin(theta2),
                                      -np.cos(theta2)*np.sin(theta1)])
        return convential_vector


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat May 13 18:50:37 2023

@author: jonas
"""

'''

IMPORTS

'''

# Standard library imports
import os
import sys
import glob
import ast
from pathlib import Path

# Related third party imports
import numpy as np
import pandas as pd
import h5py
import matplotlib.pyplot as plt
from matplotlib import pyplot
from scipy.signal import butter, lfilter, freqz, find_peaks, correlate, gaussian, filtfilt
from scipy import stats
from scipy import signal
from IPython.core.interactiveshell import InteractiveShell
from sklearn.mixture import GaussianMixture
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import quantities as pq
from quantities import ms, s, Hz
import pickle

# Local application/library specific imports
import neo
from neo.io import NeuroExplorerIO
import McsPy
import McsPy.McsData
import McsPy.McsCMOS
from McsPy import ureg, Q_
import elephant
from elephant.spike_train_generation import homogeneous_poisson_process, homogeneous_gamma_process
from elephant import neo_tools as nt
from elephant.spade import spade
from elephant.spade import pvalue_spectrum
from elephant.spade import concepts_mining
from elephant.spade import concept_output_to_patterns

InteractiveShell.ast_node_interactivity = 'all'

'''

FUNCTIONS

'''

def spikedic_to_neospiketrains(spikedic, recordinglength):

    spiketrains = []
    keylist_spiketrains = []
    for key in spikedic:
        key_array_sec=np.asarray(spikedic[key])

        # adjust the minimal amount of spikes per spiketrain
        if len(key_array_sec)>0:
            st = neo.SpikeTrain(list(key_array_sec), units='sec', t_stop=recordinglength)
            spiketrains.append(st)
            keylist_spiketrains.append(key)

    return spiketrains, keylist_spiketrains

def cut_reloaded_spikedic(spikedic, scale_factor_for_second, start=0, stop=60):

    cutted_dic = {}
    temp_list = []

    for key in spikedic:
        templist = []
        spikes = spikedic[key]
        for i in spikes:
            j = i*scale_factor_for_second # the ticks have already been applied in the burststarts
            if (j>=start) and (j<stop):
                templist.append(i)
        cutted_dic[key] = templist

    return cutted_dic

def remove_artefact_spikes(spikes, recording_length, tick, scale_factor_for_second, window=0.01):

    removing_times = []
    i = 0
    removed_spikes = {}
    kicked_out = {}
    while i < recording_length:
        activechannels = 0
        for key in spikes:
            for s in spikes[key]:
                if i <= s*tick*scale_factor_for_second < (i + window):
                    activechannels += 1
        if activechannels >= 100:
            removing_times.append(i)
        i += window

    print(removing_times)
    for key in spikes:
        new_spikes = []
        kicked_out_list = []

        s_list_save = list(spikes[key])
        s_list = list(spikes[key])
        for s in s_list_save:
            for time in removing_times:
                if time <= s*tick*scale_factor_for_second < (time + window*2):
                    kicked_out_list.append(s)
                    try:
                        s_list.remove(s)
                    except ValueError:
                        pass
                #else:
                 #   new_spikes.append(s)
        removed_spikes[key] = s_list
        kicked_out[key] = kicked_out_list

    return removed_spikes, kicked_out

def gaussian_smoothing(y, window_size=10, sigma=500):

    filt = signal.gaussian(window_size, sigma)

    return signal.convolve(y, filt, mode='same')

def convert_spiketimes_to_seconds(spike_dict, scale_factor, tick):
    """
    Convert spike times to seconds.

    Parameters:
    spike_dict (dict): Dictionary with channel labels as keys and lists of integer spike times as values.
    scale_factor (int): Scale factor to convert spike times to seconds.
    tick (int): Tick of the recordings.

    Returns:
    dict: A dictionary with channel labels as keys and lists of spike times in seconds as values.
    """

    # Convert spike_dict values to seconds
    spike_dict_seconds = {k: [tick_val * scale_factor * tick for tick_val in v] for k, v in spike_dict.items()}

    return spike_dict_seconds

def extract_spikes_in_lfp_periods(spike_dict_seconds, lfp_start_times, window=1.0):
    """
    Extract spikes that occur within a window period after each LFP start time, and adjust the spike times so
    that they appear as if the LFP periods occurred consecutively.

    Parameters:
    spike_dict_seconds (dict): Dictionary with channel labels as keys and lists of spike times in seconds as values.
    lfp_start_times (list): List of LFP start times.
    window (float, optional): Window period after each LFP start time. Default is 1.0.

    Returns:
    dict: A dictionary with channel labels as keys and lists of adjusted spike times within the LFP periods as values.
    """

    # Initialize an empty dictionary to store the spikes within the LFP periods
    spikes_in_lfp_periods = {k: [] for k in spike_dict_seconds.keys()}

    # Initialize a variable to keep track of the total time of the previous LFP periods
    total_previous_time = 0.0

    # Loop over the LFP start times
    for start_time in lfp_start_times:
        end_time = start_time + window

        # Loop over the channels
        for channel, spike_times in spike_dict_seconds.items():
            # Add spikes that fall within the window period after the LFP start time,
            # and adjust the spike times as if the LFP periods occurred consecutively
            spikes_in_lfp_periods[channel].extend([(t - start_time + total_previous_time) for t in spike_times if start_time <= t < end_time])

        # Add the current window period to the total time of the previous LFP periods
        total_previous_time += window

    return spikes_in_lfp_periods

'''

SCRIPT

'''

# for testing:
#/Users/jonas/Documents/DATA/SPADE_LFP_202305/SPADE_Trial/output/2022-04-06_cortex_div13_biometra_ID2203039CE_nodrug_spont_2

def main():

    #inputdirectory = input('Please enter the file directory: ')
    os.chdir(inputdirectory)
    filelist = glob.glob('*.pkl')

    print(filelist)
    df_list = []
    for i in filelist:
        filename = i
        filename = i.split('Dictionary_')[1].split('.pkl')[0]

        print('Working on ' + filename)
        print('this is element ' + str(filelist.index(i)) + ' of ' + str(len(filelist)))

        #create the outputdirectory
        mainoutputdirectory = os.path.join(inputdirectory, 'output_spade')
        outputdirectory = os.path.join(mainoutputdirectory, filename)
        try:
            Path(outputdirectory).mkdir(parents=True, exist_ok=False)
        except FileExistsError:
            pass

        '''
        all basic parameters are imported
        '''
        MAIN_RECORDING_DICTIONARY = pickle.load(open('MAIN_RECORDING_Dictionary_'+filename+'.pkl', "rb"))
        spikedic_MAD = MAIN_RECORDING_DICTIONARY['spikedic_MAD']
        tick = MAIN_RECORDING_DICTIONARY['Infos_Recording']['tick']
        timelengthrecording_s = MAIN_RECORDING_DICTIONARY['Infos_Recording']['timelengthrecording_s']
        info_dics_subrecordings = MAIN_RECORDING_DICTIONARY['Infos_Recording']['info_dics_subrecordings']
        Infos_Recording = MAIN_RECORDING_DICTIONARY['Infos_Recording']
        key_timepoint = list(info_dics_subrecordings.keys())[0]
        first_recording_timepoint = info_dics_subrecordings[key_timepoint]['first_recording_timepoint']
        subrec_infos = info_dics_subrecordings[key_timepoint]
        scale_factor_for_second = MAIN_RECORDING_DICTIONARY['Infos_Recording']['scale_factor_for_second']
        relevant_factor = timelengthrecording_s*0.05
        fr_dic = MAIN_RECORDING_DICTIONARY['fr_dic']

        '''
        removal of artefacts
        '''

        spikedic_MAD, kicked_out = remove_artefact_spikes(spikes=spikedic_MAD,
                                                          recording_length=timelengthrecording_s,
                                                          tick=tick,
                                                          scale_factor_for_second=scale_factor_for_second)

        '''
        remove

        '''
        active_channels = 0
        spikedic_seconds = {}
        for key in spikedic_MAD:
            sec_array = np.asarray(spikedic_MAD[key])*tick*scale_factor_for_second
            spikedic_seconds[key]=sec_array
            active_channels += 1

        spikearray_seconds = np.asarray(list(spikedic_seconds.values()))

        '''
        get one-dimensional array of every detected spike
        '''
        scale_factor_for_milisecond = 1e-03
        full_spike_list = []
        full_spike_list_seconds = []
        for key in spikedic_MAD:
            # without the relevant factor --every channel will be plotted
            x = list(np.asarray(spikedic_MAD[key])*scale_factor_for_milisecond*tick)
            full_spike_list = full_spike_list + x

            xs = list(np.asarray(spikedic_MAD[key])*scale_factor_for_second*tick)
            full_spike_list_seconds = full_spike_list_seconds + xs
        full_spikes = sorted(full_spike_list)
        full_spikes_seconds = sorted(full_spike_list_seconds)

        mean_fr_whole_recording = np.around((len(full_spikes_seconds) / timelengthrecording_s), 3)

        #define bins
        binsize = 0.005 #seconds
        #bins= np.arange(0, timelengthrecording_s+binsize, binsize)

        #trial of population burst plot as inspired by Andrea Corna
        bins = int(timelengthrecording_s / binsize)+1

        firing_rate_histogram = np.histogram(full_spikes_seconds, bins=bins)
        firing_rate = firing_rate_histogram[0]*200 #conversion to hertz
        #firing_rate = firing_rate_histogram[0]

        # using firing rate histogram already conversed to hertz
        N = int(1/binsize) # für eine Sekunde, das Sliding window, also letztlich number of bins
        plot_N = int(0.01/binsize)
        # gaussian smmothing fo the firing rate and moving average
        fr_gau = gaussian_smoothing(firing_rate)
        plot_fr_gau = gaussian_smoothing(firing_rate)
        ma_fr_gau = np.convolve(fr_gau, np.ones(N)/N, mode='full')
        plotting_ma_fr_gau = np.convolve(fr_gau, np.ones(plot_N)/plot_N, mode='full')

        # we look for the mean of the MA as threshold
        # we arrange this mean in an array for plotting
        mean_ma_fr_gau = np.mean(ma_fr_gau)
        std_ma_fr_gau = np.std(ma_fr_gau)
        network_burst_threshold = mean_ma_fr_gau
        shape_for_threshold = np.shape(ma_fr_gau)
        network_burst_threshold_array = np.full(shape_for_threshold, network_burst_threshold)

        '''
        PLOTTING OF THE corrected Rasterplot
        '''

        fig = plt.figure(figsize = (10,6))
        gs = fig.add_gridspec(2, hspace = 0, height_ratios=[2,5])
        axs = gs.subplots(sharex=False, sharey=False)
        axs[0].plot(ma_fr_gau, color= 'black', lw= 0.5)
        axs[0].set_ylabel('Firing Rate [Hz]')
        axs[0].set_ylim(0, 5000)
        axs[1].eventplot(spikearray_seconds, color = 'black', linewidths = 0.5,
                         linelengths = 1, colors = 'black')
        axs[1].set_ylabel('Relevant Channels')
        fig.suptitle(filename)

        '''
        remove until here

        '''
        lfp_list = [4.56, 73.9, 99.36, 147.26, 167.29, 179.9, 194.14, 217.1, 238.38, 254.1]

        spikedic_in_seconds = convert_spiketimes_to_seconds(spike_dict=spikedic_MAD,
                                                            scale_factor=scale_factor_for_second,
                                                            tick=tick)

        spikes_in_lfp_periods = extract_spikes_in_lfp_periods(spike_dict_seconds=spikedic_in_seconds,
                                                              lfp_start_times = lfp_list,
                                                              window=1.0)

        # add the parameters for SPADE
        bin_size = 5 * pq.ms # time resolution to discretize the spiketrains
        winlen = 10 # maximal pattern length in bins (i.e., sliding window)
        dither = 20 * pq.ms
        spectrum = '#'
        alpha = 0.05
        stat='fdr_bh'

        # get the recordinglenght needed to create the neo spikearray

        spikes = []
        for key in spikes_in_lfp_periods:
            spikes.append(spikes_in_lfp_periods[key])
            spikearray = np.sort(np.concatenate(spikes, axis = 0))
            spikelist = list(spikearray)

        recordinglength = round(spikearray[-1]) + 1

        # create the neo spiketrain
        spiketrains, keylist_spiketrains = spikedic_to_neospiketrains(spikedic=spikes_in_lfp_periods,
                                                                      recordinglength=recordinglength)

        result_spade = spade(spiketrains, bin_size=bin_size, winlen=winlen, n_surr=500, min_occ=4, min_spikes=2, min_neu=2, stat_corr=stat,
                       spectrum=spectrum, alpha=alpha)


from p5 import *

class Particle:
    def __init__(self, start_x, start_y):
        self.pos = Vector(start_x, start_y)
        self.vel = Vector(0, 0)
        self.acc = Vector(0, 0)
        self.radius = 48 * random_uniform(0.1, 1)

    def display(self):
        fill(255, 150)
        circle(self.pos, self.radius)

    def update(self):
        self.vel += self.acc
        self.pos += self.vel
        self.acc = Vector(0, 0)
        # print(self.pos, self.vel)

    def apply_force(self, force):
        self.acc += force

    def check_edges(self):
        if self.pos.y > height:
            self.vel.y *= -1
            self.pos.y = height

        if self.pos.x > width:
            self.vel.x *= -1
            self.pos.x = width

def setup():
    global particles
    particles = []
    size(640, 360)
    no_stroke()

def mouse_pressed():
    particles.append(Particle(mouse_x, mouse_y))

def key_pressed(event):
    if event.key == " " and len(particles) > 0:
        particles.pop(0)

def draw():
    background(51)

    gravity = Vector(0, .1)
    wind = Vector(.1, 0)
    for particle in particles:
        particle.apply_force(gravity)
        if mouse_is_pressed:
            particle.apply_force(wind)

        particle.update()
        particle.check_edges()
        particle.display()

if __name__ == '__main__':
    run()


def _parse_doc_ref(self):
        """Parse the document handle.

        Sets the ``_series``, ``_serial``, and ``_handle`` attributes.
        """
        command = LatexCommand(
            'setDocRef',
            {'name': 'handle', 'required': True, 'bracket': '{'})
        try:
            parsed = next(command.parse(self._tex))
        except StopIteration:
            self._logger.warning('lsstdoc has no setDocRef')
            self._handle = None
            self._series = None
            self._serial = None
            return

        self._handle = parsed['handle']
        try:
            self._series, self._serial = self._handle.split('-', 1)
        except ValueError:
            self._logger.warning('lsstdoc handle cannot be parsed into '
                                 'series and serial: %r', self._handle)
            self._series = None
            self._serial = None