PSCommander.psm1

function New-CommanderToolbarIcon {
    <#
    .SYNOPSIS
    Creates a notification tray toolbar icon.
     
    .DESCRIPTION
    Creates a notification tray toolbar icon.
     
    .PARAMETER Text
    Text to display when the icon is hovered.
     
    .PARAMETER MenuItem
    Menu items to display when the icon is right clicked.
     
    .PARAMETER LoadMenuItems
    A script block to call to dynamically load menu items.
     
    .PARAMETER HideExit
    Hides the exit menu item.
     
    .PARAMETER HideConfig
    Hides the config menu item.
 
    .PARAMETER Icon
    Path to an icon file to display in the toolbar.
     
    .EXAMPLE
    New-CommanderToolbarIcon -MenuItem @(
        New-CommanderMenuItem -Text 'Notepad' -Action {
            Start-Process notepad
        } -MenuItem @(
            New-CommanderMenuItem -Text 'Subnotepad' -Action {
                Start-Process notepad
            }
        ) -LoadMenuItems {
            New-CommanderMenuItem -Text 'Dynamic SubNotepad' -Action {
                Start-Process notepad
            }
        }
    ) -LoadMenuItems {
        New-CommanderMenuItem -Text 'Dynamic Notepad' -Action {
            Start-Process notepad
        }
    }
 
    Creates a tool bar icon with several menu items.
 
 
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [string]$Text, 
        [Parameter()]
        [pscommander.MenuItem[]]$MenuItem,
        [Parameter()]
        [ScriptBlock]$LoadMenuItems,
        [Parameter()]
        [Switch]$HideExit,
        [Parameter()]
        [Switch]$HideConfig,
        [Parameter()]
        [string]$Icon
    )

    Process {
        $ToolbarIcon = [pscommander.ToolbarIcon]::new()
        $ToolbarIcon.Text = $Text 
        $ToolbarIcon.MenuItems = $MenuItem
        $ToolbarIcon.LoadItems = $LoadMenuItems
        $ToolbarIcon.HideExit = $HideExit
        $ToolbarIcon.HideConfig = $HideConfig
        $ToolbarIcon.Icon = $Icon
        $ToolbarIcon
    }
}

function New-CommanderMenuItem {
    <#
    .SYNOPSIS
    Creates a new menu item to use within a toolbar notification icon.
     
    .DESCRIPTION
    Creates a new menu item to use within a toolbar notification icon.
     
    .PARAMETER Text
    The text to display for this menu item.
     
    .PARAMETER Action
    A script block to invoke when the menu item is clicked.
     
    .PARAMETER MenuItem
    Child menu items to display.
     
    .PARAMETER LoadMenuItems
    Child menu items to load dynamically.
 
    .PARAMETER ArgumentList
    Arguments passed to the action.
 
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [string]$Text,
        [Parameter()]
        [ScriptBlock]$Action, 
        [Parameter()]
        [pscommander.MenuItem[]]$MenuItem,
        [Parameter()]
        [ScriptBlock]$LoadMenuItems,
        [Parameter()]
        [object[]]$ArgumentList = @()
    )

    Process {
        $mi = [pscommander.MenuItem]::new()
        $mi.Text = $Text 
        $mi.Action = $Action
        $mi.Children = $MenuItem
        $mi.LoadChildren = $LoadMenuItems
        $mi.ArgumentList = $ArgumentList
        $mi
    }
}

function New-CommanderHotKey {
    <#
    .SYNOPSIS
    Creates a new global hot key binding.
     
    .DESCRIPTION
    Creates a new global hot key binding.
     
    .PARAMETER ModifierKey
    One or modifier keys to use for this hot key.
     
    .PARAMETER Key
    The main key to use for this hot key.
     
    .PARAMETER Action
    The action to invoke for this hot key.
     
    .EXAMPLE
    New-CommanderHotKey -Key 'T' -ModifierKey 'Ctrl' -Action {
        Start-Process notepad
    }
 
    Starts notepad when Ctrl+T is pressed.
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [pscommander.ModifierKeys]$ModifierKey,
        [Parameter(Mandatory)]
        [pscommander.Keys]$Key,
        [Parameter(Mandatory)]
        [ScriptBlock]$Action
    )

    $HotKey = [pscommander.HotKey]::new()
    $HotKey.Id = Get-Random
    $HotKey.ModifierKeys = $ModifierKey
    $HotKey.Keys = $Key
    $HotKey.Action = $Action

    $HotKey
}

function New-CommanderSchedule {
    <#
    .SYNOPSIS
    Creates a scheduled action based on a CRON expression.
     
    .DESCRIPTION
    Creates a scheduled action based on a CRON expression.
     
    .PARAMETER Action
    The action to execute on the schedule.
     
    .PARAMETER CronExpression
    The CRON expression that defines when to run the action.
     
    .EXAMPLE
    New-CommanderSchedule -CronExpression "* * * * *" -Action {
        Start-Process Notepad
    }
 
    Starts notepad every minute.
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [ScriptBlock]$Action,
        [Parameter()]
        [string]$CronExpression
    )

    $Schedule = [pscommander.Schedule]::new()
    $Schedule.Action = $Action 
    $Schedule.Cron = $CronExpression
    
    $Schedule
}

function New-CommanderContextMenu {
    <#
    .SYNOPSIS
    Creates a context menu item that executes PowerShell.
     
    .DESCRIPTION
    Creates a context menu item that executes PowerShell.
     
    .PARAMETER Action
    The script block action to execute. $Args[0] will include the path the was right clicked.
     
    .PARAMETER Text
    The text to display.
     
    .PARAMETER Location
    The location to display this context menu item. File will display this action when right clicking on the associated file extension. FolderLeftPane will display when right clicking on a folder in the left pane of the explorer window. FolderRightPane will display when right clicking on the folder in the right pane of the explorer window or the desktop.
     
    .PARAMETER Extension
    The extension to associate this context menu item to. This requires that Location is set to File.
     
    .PARAMETER DisplayOnShiftClick
    Displays this option only when shift is help down during the right click.
     
    .PARAMETER Position
    The location to position this context menu item. You can select Top, Bottom and None. None is the default.
     
    .PARAMETER Icon
    An icon to display for this context menu item.
     
    .PARAMETER IconIndex
    The index within the icon file to use.
     
    .EXAMPLE
    New-CommanderContextMenu -Text 'Click me' -Action {
        Start-Process code -ArgumentList $args[0]
    }
 
    Starts VS Code and opens the file that was right clicked.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ScriptBlock]$Action, 
        [Parameter(Mandatory)]
        [string]$Text, 
        [Parameter()]
        [ValidateSet("FolderLeftPanel", "FolderRightPanel", "File")]
        [string]$Location = "File", 
        [Parameter()]
        [string]$Extension = "*",
        [Parameter()]
        [Switch]$DisplayOnShiftClick,
        [Parameter()]
        [ValidateSet("Top", "Bottom", "None")]
        [string]$Position = 'None',
        [Parameter()]
        [string]$Icon,
        [Parameter()]
        [int]$IconIndex
    )

    $ContextMenu = [pscommander.ExplorerContextMenu]::new()
    $ContextMenu.Id = Get-Random
    $ContextMenu.Action = $Action 
    $ContextMenu.Text = $Text 
    $ContextMenu.Location = $Location 
    $ContextMenu.Extension = $Extension 
    $ContextMenu.Extended = $DisplayOnShiftClick
    $ContextMenu.Position = $Position
    $ContextMenu.Icon = $Icon 
    $ContextMenu.IconIndex = $IconIndex
    $ContextMenu 
}

function New-CommanderFileAssociation {
    <#
    .SYNOPSIS
    Creates a file association that will invoke the action when it's opened.
     
    .DESCRIPTION
    Creates a file association that will invoke the action when it's opened.
     
    .PARAMETER Extension
    The extension to associate with the action.
     
    .PARAMETER Action
    The action to execute when the file type is opened. $Args[0] will be the full file name of the file opened.
     
    .EXAMPLE
    New-CommanderFileAssociation -Extension ".ps2" -Action {
        Start-Process code -ArgumentList $Args[0]
    }
 
    Starts VS Code and opens the opened PS2 file.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Extension,
        [Parameter(Mandatory)]
        [scriptblock]$Action
    )

    if (-not $Extension.StartsWith('.'))
    {
        throw "Extension needs to start with '.'"
    }

    $FileAssociation = [pscommander.FileAssociation]::new()
    $FileAssociation.Id = Get-Random
    $FileAssociation.Extension = $Extension
    $FileAssociation.Action = $Action
    $FileAssociation
}

function New-CommanderShortcut {
    <#
    .SYNOPSIS
    Creates a new desktop shortcut that will run the action.
     
    .DESCRIPTION
    Creates a new desktop shortcut that will run the action.
     
    .PARAMETER Text
    The text to display on the desktop.
     
    .PARAMETER Description
    The description shown when hovering the shortcut.
     
    .PARAMETER Icon
    The icon to display.
     
    .PARAMETER Action
    The action to execute when the shortcut is clicked.
     
    .EXAMPLE
    New-CommanderShortcut -Text 'Click Me' -Description 'Nice' -Action {
        Start-Process notepad
    }
 
    Creates a shortcut that will start notepad when clicked.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Text,
        [Parameter()]
        [string]$Description,
        [Parameter()]
        [string]$Icon,
        [Parameter(Mandatory)]
        [ScriptBlock]$Action
    )

    $Shortcut = [pscommander.Shortcut]::new()
    $Shortcut.Id = Get-Random
    $Shortcut.Text = $Text
    $Shortcut.Description = $Description
    $Shortcut.Icon = $Icon
    $Shortcut.Action = $Action
    $Shortcut
}

function Start-Commander {
    <#
    .SYNOPSIS
    Starts PSCommander.
     
    .DESCRIPTION
    Starts PSCommander
     
    .EXAMPLE
    Start-Commander
 
    Starts PSCommander
    #>


    param($ConfigPath)

    if (-not $ConfigPath)
    {
        $Documents = [System.Environment]::GetFolderPath('MyDocuments')
        $ConfigPath = [IO.Path]::Combine($Documents, 'PSCommander', 'config.ps1')
    }

    if (-not (Test-Path $ConfigPath))
    {
        Write-Warning "Configuration file for PSCommander not found. Creating config file..."
        New-Item -Path (Join-Path $Documents 'PSCommander') -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
        "New-CommanderToolbarIcon -MenuItem @(
    New-CommanderMenuItem -Text 'Documentation' -Action {
        Start-Process 'https://docs.poshtools.com/powershell-pro-tools-documentation/pscommander'
    }
)"
 | Out-File $ConfigPath 
        Start-Process -FilePath "$PSScriptRoot\psscriptpad.exe" -ArgumentList @("-c `"$ConfigPath`"")
    }

    Start-Process (Join-Path $PSScriptRoot "PSCommander.exe") -ArgumentList "--configFilePath '$ConfigPath'"
}

function Install-Commander {
    <#
    .SYNOPSIS
    Sets commander to run on logon.
 
    .DESCRIPTION
    Sets commander to run on logon.
 
    .EXAMPLE
    Install-Commander
 
    Sets commander to run on logon.
    #>

    New-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" -Name 'PSCommander' -Value (Join-Path $PSScriptRoot "pscommander.exe") -Force | Out-Null 
}

function Uninstall-Commander {
    <#
    .SYNOPSIS
    Stops commander from running on logon.
     
    .DESCRIPTION
    Stops commander from running on logon.
     
    .EXAMPLE
    Uninstall-Commander
 
    Stops commander from running on logon.
    #>

    Remove-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" -Name 'PSCommander'
}

function Install-CommanderLicense {
    <#
    .SYNOPSIS
    Installs a PowerShell Pro Tools license to use with PSCommander.
     
    .DESCRIPTION
    Installs a PowerShell Pro Tools license to use with PSCommander. You will need to restart PSCommander after installing the license.
     
    .PARAMETER Path
    The path to the PowerShell Pro Tools license.
     
    .EXAMPLE
    Install-CommanderLicense -Path .\license.txt
     
    Installs the PSCommander license.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Path
    )

    if (-not (Test-Path $Path))
    {
        throw "File not found"
    }

    $Content = Get-Content $Path -Raw
    $Folder = Join-Path $env:appdata "PowerShell Pro Tools"
    if (-not (Test-Path $Folder))
    {
        New-Item -Path $Folder -ItemType 'Directory'
    }

    $Content | Out-File (Join-Path $Folder "license.lic")
}

function Register-CommanderEvent {
    <#
    .SYNOPSIS
    Registers a handler to invoke when an event takes place.
     
    .DESCRIPTION
    Registers a handler to invoke when an event takes place.
     
    .PARAMETER OnCommander
    Specifies event handlers for events within commander.
 
    .PARAMETER OnWindows
    Specifies event handlers for events within Windows.
 
    .PARAMETER WmiEventType
    Specifies the WMI event type to query when using -OnWindows WmiEvent
 
    .PARAMETER WmiEventFilter
    Specifies the WMI event filter to query when using -OnWindows WmiEvent
     
    .PARAMETER Action
    The action to invoke when an event takes place.
     
    .EXAMPLE
    Register-CommanderEvent -OnCommander Start -Action {
        Start-Process notepad
    }
 
    Starts notepad when commander starts.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ParameterSetName = "Commander")]
        [ValidateSet('start', 'stop', 'error')]
        [string]$OnCommander,
        [Parameter(Mandatory, ParameterSetName = "Windows")]
        [ValidateSet('ProcessStarted', 'WmiEvent')]
        [string]$OnWindows,
        [Parameter(ParameterSetName = "Windows")]
        [string]$WmiEventType,
        [Parameter(ParameterSetName = "Windows")]
        [string]$WmiEventFilter,
        [Parameter(Mandatory)]
        [ScriptBlock]$Action
    )

    $CommanderEvent = [pscommander.CommanderEvent]::new()
    $CommanderEvent.Id = Get-Random
    $CommanderEvent.Category = $PSCmdlet.ParameterSetName

    if ($OnCommander)
    {
        $CommanderEvent.Event = $OnCommander
    }
    
    if ($OnWindows)
    {
        $CommanderEvent.Event = $OnWindows
        if ($OnWindows -eq 'ProcessStarted')
        {
            $CommanderEvent.Properties['WmiEventType'] = "__InstanceCreationEvent"
            $CommanderEvent.Properties['WmiEventFilter'] = 'TargetInstance isa "Win32_Process"'
        }

        if ($OnWindows -eq 'WmiEvent')
        {
            $CommanderEvent.Properties['WmiEventType'] = $WmiEventType
            $CommanderEvent.Properties['WmiEventFilter'] = $WmiEventFilter
        }
    }

    $CommanderEvent.Action = $Action
    $CommanderEvent
}
# SIG # Begin signature block
# MIIZgQYJKoZIhvcNAQcCoIIZcjCCGW4CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUWph3FcRIB7Hn4uaxg/CB+zHg
# z7CgghSPMIIE/jCCA+agAwIBAgIQDUJK4L46iP9gQCHOFADw3TANBgkqhkiG9w0B
# AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz
# c3VyZWQgSUQgVGltZXN0YW1waW5nIENBMB4XDTIxMDEwMTAwMDAwMFoXDTMxMDEw
# NjAwMDAwMFowSDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu
# MSAwHgYDVQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMTCCASIwDQYJKoZIhvcN
# AQEBBQADggEPADCCAQoCggEBAMLmYYRnxYr1DQikRcpja1HXOhFCvQp1dU2UtAxQ
# tSYQ/h3Ib5FrDJbnGlxI70Tlv5thzRWRYlq4/2cLnGP9NmqB+in43Stwhd4CGPN4
# bbx9+cdtCT2+anaH6Yq9+IRdHnbJ5MZ2djpT0dHTWjaPxqPhLxs6t2HWc+xObTOK
# fF1FLUuxUOZBOjdWhtyTI433UCXoZObd048vV7WHIOsOjizVI9r0TXhG4wODMSlK
# XAwxikqMiMX3MFr5FK8VX2xDSQn9JiNT9o1j6BqrW7EdMMKbaYK02/xWVLwfoYer
# vnpbCiAvSwnJlaeNsvrWY4tOpXIc7p96AXP4Gdb+DUmEvQECAwEAAaOCAbgwggG0
# MA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsG
# AQUFBwMIMEEGA1UdIAQ6MDgwNgYJYIZIAYb9bAcBMCkwJwYIKwYBBQUHAgEWG2h0
# dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAfBgNVHSMEGDAWgBT0tuEgHf4prtLk
# YaWyoiWyyBc1bjAdBgNVHQ4EFgQUNkSGjqS6sGa+vCgtHUQ23eNqerwwcQYDVR0f
# BGowaDAyoDCgLoYsaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJl
# ZC10cy5jcmwwMqAwoC6GLGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFz
# c3VyZWQtdHMuY3JsMIGFBggrBgEFBQcBAQR5MHcwJAYIKwYBBQUHMAGGGGh0dHA6
# Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBPBggrBgEFBQcwAoZDaHR0cDovL2NhY2VydHMu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJRFRpbWVzdGFtcGluZ0NB
# LmNydDANBgkqhkiG9w0BAQsFAAOCAQEASBzctemaI7znGucgDo5nRv1CclF0CiNH
# o6uS0iXEcFm+FKDlJ4GlTRQVGQd58NEEw4bZO73+RAJmTe1ppA/2uHDPYuj1UUp4
# eTZ6J7fz51Kfk6ftQ55757TdQSKJ+4eiRgNO/PT+t2R3Y18jUmmDgvoaU+2QzI2h
# F3MN9PNlOXBL85zWenvaDLw9MtAby/Vh/HUIAHa8gQ74wOFcz8QRcucbZEnYIpp1
# FUL1LTI4gdr0YKK6tFL7XOBhJCVPst/JKahzQ1HavWPWH1ub9y4bTxMd90oNcX6X
# t/Q/hOvB46NJofrOp79Wz7pZdmGJX36ntI5nePk2mOHLKNpbh6aKLzCCBSAwggQI
# oAMCAQICEAt+xO9Gr4vTuh34OEyIkdwwDQYJKoZIhvcNAQELBQAwcjELMAkGA1UE
# BhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2lj
# ZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUg
# U2lnbmluZyBDQTAeFw0yMTA0MDUwMDAwMDBaFw0yMjA0MTIyMzU5NTlaMF4xCzAJ
# BgNVBAYTAlVTMQ4wDAYDVQQIEwVJZGFobzEPMA0GA1UEBxMGSGFpbGV5MRYwFAYD
# VQQKEw1BZGFtIERyaXNjb2xsMRYwFAYDVQQDEw1BZGFtIERyaXNjb2xsMIIBIjAN
# BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwIuNYs3TqwWb2B366lXeTnod7DUH
# PG8X65leprfUJkvAN82lexIMGxhFm7NW33PL/PQqfaAf7VoTF/b+sNiHUaSxoNkO
# uOaB9kxqz/JELaDbC7aLZ5fMtQ6XYZzF8w3O5ND1EchkXgRYfvArgGQ/FHRsWP38
# yRJUKgkUiamXc3Vndf5fR+0cAv//T2xkT8Qtea6PZVYT/FMvCOCU6JNKvrQizI8X
# of5BfnVjJmsqYyKzJ9H+XskKLUG4Z5R4E/Iyl5tqE71beCymgf2hfbj0jQyoGN98
# UEnHXSLs/s1QgF8xj4EdMWm7LbU7PEbCFST8YBCsEXE2Ws956D3HQ5cRnQIDAQAB
# o4IBxDCCAcAwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0O
# BBYEFFlwWJYbrJY+eGzrteeyGguWHT3aMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUE
# DDAKBggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdp
# Y2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2Ny
# bDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwSwYDVR0gBEQw
# QjA2BglghkgBhv1sAwEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2Vy
# dC5jb20vQ1BTMAgGBmeBDAEEATCBhAYIKwYBBQUHAQEEeDB2MCQGCCsGAQUFBzAB
# hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTgYIKwYBBQUHMAKGQmh0dHA6Ly9j
# YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1cmVkSURDb2RlU2ln
# bmluZ0NBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQBHZcWj
# Ajcj20p1mdag+bH1DX2Sx/9ctNT3jlTONCEeXNUNy7IR4KC1hcBksJwWphbTEgmv
# XDswoeV+d4W2i1+llV0d6CUL5xmMuv7iW3f5Ia+9Dj9RZFOt00W0v6nigtbS5d85
# k6zZXegWVmlRP5z/gwfLzCLbEo87JpX7LuQP9vWcCjRP2uCp6L7TtP4Ol+u18sti
# tw+PXBazxZXg0I0J8UpBQkjyLofo7be+5fcZnrt8rKcqhCJAGkkgQCfbkfRMWd84
# bH3tsNGTYIR6jzaL830OunyO2+uPRreYR6yHCa4IhrvKfI5xj1sFO077hm/EGsxv
# lgpPiI/H8Otl7KM5MIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1U0O1b5VQCDANBgkq
# hkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBB
# c3N1cmVkIElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcNMjgxMDIyMTIwMDAw
# WjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
# ExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3Vy
# ZWQgSUQgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
# CgKCAQEA+NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid2zLXcep2nQUut4/6
# kkPApfmJ1DcZ17aq8JyGpdglrA55KDp+6dFn08b7KSfH03sjlOSRI5aQd4L5oYQj
# ZhJUM1B0sSgmuyRpwsJS8hRniolF1C2ho+mILCCVrhxKhwjfDPXiTWAYvqrEsq5w
# MWYzcT6scKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzLfnQ5Ng2Q7+S1TqSp
# 6moKq4TzrGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR93O8vYWxYoNzQYIH
# 5DiLanMg0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckwEgYDVR0TAQH/BAgw
# BgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwMweQYI
# KwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j
# b20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp
# Q2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6
# Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmww
# OqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ
# RFJvb3RDQS5jcmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUH
# AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZIAYb9bAMwHQYD
# VR0OBBYEFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQYMBaAFEXroq/0ksuC
# MS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1aJLPzItEVyCx8JSl2
# qB1dHC06GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew4fbRknUPUbRupY5a4l4kgU4Q
# pO4/cY5jDhNLrddfRHnzNhQGivecRk5c/5CxGwcOkRX7uq+1UcKNJK4kxscnKqEp
# KBo6cSgCPC6Ro8AlEeKcFEehemhor5unXCBc2XGxDI+7qPjFEmifz0DLQESlE/Dm
# ZAwlCEIysjaKJAL+L3J+HNdJRZboWR3p+nRka7LrZkPas7CM1ekN3fYBIM6ZMWM9
# CBoYs4GbT8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhsRDKyZqHnGKSaZFHv
# MIIFMTCCBBmgAwIBAgIQCqEl1tYyG35B5AXaNpfCFTANBgkqhkiG9w0BAQsFADBl
# MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
# d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
# b3QgQ0EwHhcNMTYwMTA3MTIwMDAwWhcNMzEwMTA3MTIwMDAwWjByMQswCQYDVQQG
# EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
# cnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0
# YW1waW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvdAy7kvN
# j3/dqbqCmcU5VChXtiNKxA4HRTNREH3Q+X1NaH7ntqD0jbOI5Je/YyGQmL8TvFfT
# w+F+CNZqFAA49y4eO+7MpvYyWf5fZT/gm+vjRkcGGlV+Cyd+wKL1oODeIj8O/36V
# +/OjuiI+GKwR5PCZA207hXwJ0+5dyJoLVOOoCXFr4M8iEA91z3FyTgqt30A6XLdR
# 4aF5FMZNJCMwXbzsPGBqrC8HzP3w6kfZiFBe/WZuVmEnKYmEUeaC50ZQ/ZQqLKfk
# dT66mA+Ef58xFNat1fJky3seBdCEGXIX8RcG7z3N1k3vBkL9olMqT4UdxB08r8/a
# rBD13ays6Vb/kwIDAQABo4IBzjCCAcowHQYDVR0OBBYEFPS24SAd/imu0uRhpbKi
# JbLIFzVuMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMBIGA1UdEwEB
# /wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMI
# MHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl
# cnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v
# RGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRo
# dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0Eu
# Y3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1
# cmVkSURSb290Q0EuY3JsMFAGA1UdIARJMEcwOAYKYIZIAYb9bAACBDAqMCgGCCsG
# AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAsGCWCGSAGG/WwH
# ATANBgkqhkiG9w0BAQsFAAOCAQEAcZUS6VGHVmnN793afKpjerN4zwY3QITvS4S/
# ys8DAv3Fp8MOIEIsr3fzKx8MIVoqtwU0HWqumfgnoma/Capg33akOpMP+LLR2HwZ
# YuhegiUexLoceywh4tZbLBQ1QwRostt1AuByx5jWPGTlH0gQGF+JOGFNYkYkh2OM
# kVIsrymJ5Xgf1gsUpYDXEkdws3XVk4WTfraSZ/tTYYmo9WuWwPRYaQ18yAGxuSh1
# t5ljhSKMYcp5lH5Z/IwP42+1ASa2bKXuh1Eh5Fhgm7oMLSttosR+u8QlK0cCCHxJ
# rhO24XxCQijGGFbPQTS2Zl22dHv1VjMiLyI2skuiSpXY9aaOUjGCBFwwggRYAgEB
# MIGGMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNV
# BAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNz
# dXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0ECEAt+xO9Gr4vTuh34OEyIkdwwCQYFKw4D
# AhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwG
# CisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZI
# hvcNAQkEMRYEFBnAa1PV+5ktlcTrnRm/QWdmF5m2MA0GCSqGSIb3DQEBAQUABIIB
# AFG5fyaPeD3lMeB5Klexz2ZaRlfuzu+q4KgoFBZQCMNok8VGjDZ33zHJ0jm4NvFj
# Ab3scRs94eLhGC4QLmiunMuBhi++4OBr5D7WEE46kA/JObxP43NGkCcvnDI/kcgD
# j77kcedvJZ06gJZ9eRbKlOv3ZX85TjeXNtfjL5c2XHNbe5maRxOIMXu3O3H5s7z8
# nhkp/etAni3fOXbu8y428GkgyIL592qOj3pzlnOtZxkrxLvpktEtKyz81GfKjx/p
# Lsr7RifqqqGkYKkNlvnp6G2hhW0xazZ26UDglQAOHzIwTX1pMambUm9PepTGoUPG
# RJrf++a9Sk84nP4pIC3gpbKhggIwMIICLAYJKoZIhvcNAQkGMYICHTCCAhkCAQEw
# gYYwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UE
# CxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1
# cmVkIElEIFRpbWVzdGFtcGluZyBDQQIQDUJK4L46iP9gQCHOFADw3TANBglghkgB
# ZQMEAgEFAKBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkF
# MQ8XDTIxMDQwNjExMjQyNFowLwYJKoZIhvcNAQkEMSIEIGknYj0sPlPo+pjkadwE
# yCqNeWZoXiiD7vLNYBgVqddEMA0GCSqGSIb3DQEBAQUABIIBAJp2NK5ZwQ15ybv8
# Zn2U9+MKRWwwZBckHzVLmepebMKDJDGvGEwg5e+JVfHztBURpnYHv5EkF5bzJvn9
# z2oqqOv0b8+7LQrg/ASG2B6ZHgCyPOck68ZxFDxYyXqrYUzq22YM+mr0o5wcloB5
# WADbv0IXZCuB+IasBGiE4CftSeFCfIZz3OB1gEQ9YTW0v1e826K9DTHDZcY/evTg
# DlaDmKRpEgGFimC8NHp6w0U+TND6rFpLjkv1H/Ua46ZF5h5cWLxK7H0MmPz4TkI+
# +RBN7S7/iQpIeTd/VcC5a5BfuoCCMEbDm+B0b64lxZzB43UtA20Kdx/092a8bLTe
# Fhlo8CM=
# SIG # End signature block