powershell-cli-menu-helpers.psm1
function Select-ItemFromList { <# .Synopsis Offers the possibility to select multible values in a cli based menu list. .DESCRIPTION Offers the possibility to select multible values in a cli based menu list. A filter, cancel, multiselect and empty return option is available. The function will return the selected items. .PARAMETER ListTitle The title of the list. .PARAMETER Items The items to show in the list. .PARAMETER PropertyName The name of the property to render in the list. .PARAMETER MultiselectOption Enables the multiselect option. .PARAMETER CancelOption Enables the cancel option. .PARAMETER FilterOption Enables the filter option. .PARAMETER AllowEmptyReturn Enables the empty return option. .INPUTS None. You cannot pipe objects to Select-ItemFromList. .OUTPUTS System.Management.Automation.PSObject[] Select-ItemFromList returns the selected items as an object in the following format. [PSCustomObject]@{ Items = $null # Array of the items State = $null # %OK% / %CANCEL% } .EXAMPLE # Select an applicaiton to start [System.Array]$Applications = @( [PSCustomObject]@{Name = 'Notepad'; Path = "$($env:windir)\System32\notepad.exe" }, [PSCustomObject]@{Name = 'Calc'; Path = "$($env:windir)\System32\calc.exe" }, [PSCustomObject]@{Name = 'Explorer'; Path = "$($env:windir)\System32\Explorer.exe" } ) [PSCustomObject]$Application = Select-ItemFromList -ListTitle 'Please select an applicaiton to start' -Items $Applications -PropertyName 'Name' Start-Process -FilePath $Application.Items.Path .EXAMPLE # Select multiple processes to get furhter detailes later $Processes = Select-ItemFromList -ListTitle "Select process, press 'd' if done" -Items (Get-Process | Select-Object -First 10) -PropertyName 'ProcessName' -MultiselectOption -CancelOption -FilterOption if ($Processes.State -eq '%OK%') { foreach ($Process in $Processes.Items) { $Process | Select-Object -Property Id, ProcessName } } .LINK https://github.com/netcloud/powershell-cli-menu-helpers #> [OutputType([System.Management.Automation.PSObject[]])] Param( [System.String]$ListTitle, [System.Management.Automation.PSObject[]]$Items, [Parameter(Mandatory = $true)] [System.String]$PropertyName, [System.Management.Automation.SwitchParameter]$MultiselectOption, [System.Management.Automation.SwitchParameter]$CancelOption, [System.Management.Automation.SwitchParameter]$FilterOption, [System.Management.Automation.SwitchParameter]$AllowEmptyReturn = $false ) Begin { # Prepare the output object [PSCustomObject]$ReturnObj = [PSCustomObject]@{ Items = $null State = $null # %OK% / %CANCEL% } # Define the possible options [System.Array]$Options = @( [PSCustomObject]@{display = $MultiselectOption; letter = 'a'; description = 'Select all' }, [PSCustomObject]@{display = $MultiselectOption; letter = 'u'; description = 'Unselect all' }, [PSCustomObject]@{display = $FilterOption; letter = 'f'; description = 'Apply filter' }, [PSCustomObject]@{display = $FilterOption; letter = 'r'; description = 'Reset filter' }, [PSCustomObject]@{display = ($MultiselectOption -or $AllowEmptyReturn); letter = 'd'; description = 'Done selecting' }, [PSCustomObject]@{display = $CancelOption; letter = 'c'; description = 'Cancel' } ) # Add internal needed properties to the items for ($i = 1; $i -le $Items.Count; $i ++) { Add-Member -InputObject $Items[$i - 1] -MemberType NoteProperty -Name '_id' -Value $i -Force Add-Member -InputObject $Items[$i - 1] -MemberType NoteProperty -Name '_selected' -Value $false -Force } # Set filters filter Get-SelectedItem { if ($_._selected) { $_ } } filter Get-FilteredItem { if ($_.$PropertyName -like "*$Filter*") { $_ } } } Process { # Display the list in a loop [System.Boolean]$RunMenu = $true [System.String]$Filter = '' Clear-Host Write-Host -Object '' Write-Host -Object '' while ($RunMenu) { # Render the list title if ($ListTitle -ne '') { Write-Host -Object $ListTitle } # Display filter if applied if ($Filter -ne '') { Write-Host -Object "Filter: $Filter" Write-Host -Object '' } # Render the list items foreach ($Item in ($Items | Get-FilteredItem)) { if ($Item._selected) { Write-Host -Object "$($Item._id)*) $($Item.$PropertyName)" -ForegroundColor Green } else { Write-Host -Object "$($Item._id)) $($Item.$PropertyName)" } } Write-Host -Object '' Write-Host -Object '' # Render the list options foreach ($Option in $Options) { if ($Option.display) { Write-Host -Object "$($Option.letter)" -ForegroundColor Yellow -NoNewline Write-Host -Object ": $($Option.description)" } } Write-Host -Object '' Write-Host -Object '' # Get user input [System.String]$UserInputPrompt = 'Enter selection' if ($MultiselectOption) { $UserInputPrompt = "Enter selection ($(($Items | Get-SelectedItem | Measure-Object).Count) selections)" } [System.String]$UserInput = Read-Host -Prompt $UserInputPrompt # Process the user input switch ($UserInput) { # Add filter if option is enabled { ($_ -eq 'f') -and ($FilterOption) } { $Filter = Read-Host -Prompt 'Enter filter' Clear-Host Write-Host -Object '' Write-Host -Object '' } # Reset filter if option is enabled { ($_ -eq 'r') -and ($FilterOption) } { $Filter = '' Clear-Host Write-Host -Object '' Write-Host -Object '' } # Select item in multi select mode / return item in single select mode { ($_ -match '^\d+$') -and (($Items | Get-FilteredItem)._id -contains $_) } { # Save the item id $ItemId = $_ # Get the item and set selected to true $Item = $Items | Where-Object -FilterScript { $_._id -eq $ItemId } $Item._selected = !$Item._selected # Return the item if single select mode if (!$MultiselectOption) { if (((($Items | Get-SelectedItem).Count -eq 0) -and $AllowEmptyReturn) -or (($Items | Get-SelectedItem).Count -ne 0)) { $ReturnObj.State = '%OK%' return } else { Clear-Host Write-Host -Object "Please select an item!" -ForegroundColor Yellow Write-Host -Object '' } } Clear-Host Write-Host -Object '' Write-Host -Object '' } # Select all items if multi select is enabled { ($_ -eq 'a') -and $MultiselectOption } { foreach ($Item in ($Items | Get-FilteredItem)) { $Item._selected = $true } Clear-Host Write-Host -Object '' Write-Host -Object '' } # Unselect all items if multi select is enabled { ($_ -eq 'u') -and $MultiselectOption } { foreach ($Item in ($Items | Get-FilteredItem)) { $Item._selected = $false } Clear-Host Write-Host -Object '' Write-Host -Object '' } # Cancel the selection if option is activated { ($_ -eq 'c' -and $CancelOption) } { $ReturnObj.State = '%CANCEL%' $RunMenu = $false } # Return all selected items if multi select mode is activated or empty return is allowed { ($_ -eq 'd' -and $MultiselectOption) -or ($_ -eq 'd' -and $AllowEmptyReturn) } { if (((($Items | Get-SelectedItem).Count -eq 0) -and $AllowEmptyReturn) -or (($Items | Get-SelectedItem).Count -ne 0)) { $ReturnObj.State = '%OK%' return } else { Clear-Host Write-Host -Object "Please select at least one item!" -ForegroundColor Yellow Write-Host -Object '' } } # If user input is not valid default { Clear-Host Write-Host -Object "Input '$_' is not valid!" -ForegroundColor Yellow Write-Host -Object '' } } } } End { # Return the selected items only if run menu equals true if ($RunMenu) { $ReturnObj.Items = @() + $Items | Get-SelectedItem } return $ReturnObj } } function Select-ItemFromTable { <# .Synopsis Offers the possibility to select multible values in a cli based menu table. .DESCRIPTION Offers the possibility to select multible values in a cli based menu table. A filter, cancel, multiselect and empty return option is available. The function will return the selected items. .PARAMETER TableTitle The title of the table. .PARAMETER Items The items to show in the table. .PARAMETER PropertyName The name of the property to render in the table. .PARAMETER MultiselectOption Enables the multiselect option. .PARAMETER CancelOption Enables the cancel option. .PARAMETER FilterOption Enables the filter option. .PARAMETER HideTableHeaders To hide the table headers in the output. .PARAMETER AllowEmptyReturn Enables the empty return option. .INPUTS None. You cannot pipe objects to Select-ItemFromTable. .OUTPUTS System.Management.Automation.PSObject[] Select-ItemFromTable returns the selected items as an object in the following format. [PSCustomObject]@{ Items = $null # Array of the items State = $null # %OK% / %CANCEL% } .EXAMPLE # Select an applicaiton to start [System.Array]$Applications = @( [PSCustomObject]@{Name = 'Notepad'; Path = "$($env:windir)\System32\notepad.exe" }, [PSCustomObject]@{Name = 'Calc'; Path = "$($env:windir)\System32\calc.exe" }, [PSCustomObject]@{Name = 'Explorer'; Path = "$($env:windir)\System32\Explorer.exe" } ) [PSCustomObject]$Application = Select-ItemFromTable -TableTitle 'Please select an applicaiton to start' -Items $Applications -PropertyName 'Name' Start-Process -FilePath $Application.Items.Path .EXAMPLE # Select multiple processes to get furhter detailes later $Processes = Select-ItemFromTable -TableTitle "Select process, press 'd' if done" -Items (Get-Process | Select-Object -First 10) -PropertyName 'Id', 'Handles', 'ProcessName' -MultiselectOption -CancelOption -FilterOption if ($Processes.State -eq '%OK%') { foreach ($Process in $Processes.Items) { $Process } } .LINK https://github.com/netcloud/powershell-cli-menu-helpers #> [OutputType([System.Management.Automation.PSObject[]])] Param( [System.String]$TableTitle, [System.Management.Automation.PSObject[]]$Items, [Parameter(Mandatory = $true)] [System.String[]]$PropertyName, [System.Management.Automation.SwitchParameter]$MultiselectOption, [System.Management.Automation.SwitchParameter]$CancelOption, [System.Management.Automation.SwitchParameter]$FilterOption, [System.Management.Automation.SwitchParameter]$HideTableHeaders, [System.Management.Automation.SwitchParameter]$AllowEmptyReturn = $false ) Begin { # Prepare the output object [PSCustomObject]$ReturnObj = [PSCustomObject]@{ Items = $null State = $null # %OK% / %CANCEL% } # Define the possible options [System.Array]$Options = @( [PSCustomObject]@{display = $MultiselectOption; letter = 'a'; description = 'Select all' }, [PSCustomObject]@{display = $MultiselectOption; letter = 'u'; description = 'Unselect all' }, [PSCustomObject]@{display = $FilterOption; letter = 'f'; description = 'Apply filter' }, [PSCustomObject]@{display = $FilterOption; letter = 'r'; description = 'Reset filter' }, [PSCustomObject]@{display = ($MultiselectOption -or $AllowEmptyReturn); letter = 'd'; description = 'Done selecting' }, [PSCustomObject]@{display = $CancelOption; letter = 'c'; description = 'Cancel' } ) # Add internal needed properties to the items for ($i = 1; $i -le $Items.Count; $i ++) { Add-Member -InputObject $Items[$i - 1] -MemberType NoteProperty -Name '_id' -Value $i -Force Add-Member -InputObject $Items[$i - 1] -MemberType NoteProperty -Name '_selected' -Value $false -Force } # Get lengt of the longest id [System.Int32]$IdLengt = ($Items._id | Sort-Object -Descending | Select-Object -First 1).Length + 2 # Set the table properties $TableProperty = @(@{Name = (' ' * $IdLengt); Expression = { if ($_._selected) { "$($_._id)*)" } else { "$($_._id))" } } }) + $PropertyName # Set filters filter Get-SelectedItem { if ($_._selected) { $_ } } filter Get-FilteredItem { if (($_ | Select-Object -Property $TableProperty | ConvertTo-Json -Compress | Out-String) -like "*$Filter*") { $_ } } } Process { # Display the table in a loop [System.Boolean]$RunMenu = $true [System.String]$Filter = '' Clear-Host Write-Host -Object '' Write-Host -Object '' while ($RunMenu) { # Render the table title if ($TableTitle -ne '') { Write-Host -Object $TableTitle Write-Host -Object '' } # Display filter if applied if ($Filter -ne '') { Write-Host -Object "Filter: $Filter" Write-Host -Object '' } # Render the items as a table if ($Items.Count -gt 0) { if (!$HideTableHeaders) { # Get the formated table with header as string [System.String]$Table = $Items | Get-FilteredItem | Select-Object -Property $TableProperty | Format-Table -AutoSize | Out-String # Get each line of the table $Rows = $Table.Split([System.Environment]::NewLine) | Where-Object -FilterScript { $_ -ne '' } # Print the table header Write-Host -Object $Rows[0] Write-Host -Object $Rows[1] # Print each row for ($i = 2; $i -lt $Rows.Count; $i++) { if (($Items | Get-FilteredItem)[$i - 2]._selected) { Write-Host -Object $Rows[$i] -ForegroundColor Green } else { Write-Host -Object $Rows[$i] } } } else { # Write blank line for header Write-Host -Object '' # Get the formated table without header as string [System.String]$Table = $Items | Get-FilteredItem | Select-Object -Property $TableProperty | Format-Table -HideTableHeaders -AutoSize | Out-String # Get each line of the table [System.Array]$Rows = @() $Rows += $Table.Split([System.Environment]::NewLine) | Where-Object -FilterScript { $_ -ne '' } # Print each row for ($i = 0; $i -lt $Rows.Count; $i++) { if (($Items | Get-FilteredItem)[$i]._selected) { Write-Host -Object $Rows[$i] -ForegroundColor Green } else { Write-Host -Object $Rows[$i] } } } } Write-Host -Object '' Write-Host -Object '' # Render the table options foreach ($Option in $Options) { if ($Option.display) { Write-Host -Object "$($Option.letter)" -ForegroundColor Yellow -NoNewline Write-Host -Object ": $($Option.description)" } } Write-Host -Object '' Write-Host -Object '' # Get user input [System.String]$UserInputPrompt = 'Enter selection' if ($MultiselectOption) { $UserInputPrompt = "Enter selection ($(($Items | Get-SelectedItem | Measure-Object).Count) selections)" } [System.String]$UserInput = Read-Host -Prompt $UserInputPrompt # Process the user input switch ($UserInput) { # Add filter if option is enabled { ($_ -eq 'f') -and ($FilterOption) } { $Filter = Read-Host -Prompt 'Enter filter' Clear-Host Write-Host -Object '' Write-Host -Object '' } # Reset filter if option is enabled { ($_ -eq 'r') -and ($FilterOption) } { $Filter = '' Clear-Host Write-Host -Object '' Write-Host -Object '' } # Select item in multi select mode / return item in single select mode { ($_ -match '^\d+$') -and (($Items | Get-FilteredItem)._id -contains $_) } { # Save the item id $ItemId = $_ # Get the item and set selected to true $Item = $Items | Where-Object -FilterScript { $_._id -eq $ItemId } $Item._selected = !$Item._selected # Return the item if single select mode if (!$MultiselectOption) { if (((($Items | Get-SelectedItem).Count -eq 0) -and $AllowEmptyReturn) -or (($Items | Get-SelectedItem).Count -ne 0)) { $ReturnObj.State = '%OK%' return } else { Clear-Host Write-Host -Object "Please select an item!" -ForegroundColor Yellow Write-Host -Object '' } } Clear-Host Write-Host -Object '' Write-Host -Object '' } # Select all items if multi select is enabled { ($_ -eq 'a') -and $MultiselectOption } { foreach ($Item in ($Items | Get-FilteredItem)) { $Item._selected = $true } Clear-Host Write-Host -Object '' Write-Host -Object '' } # Unselect all items if multi select is enabled { ($_ -eq 'u') -and $MultiselectOption } { foreach ($Item in ($Items | Get-FilteredItem)) { $Item._selected = $false } Clear-Host Write-Host -Object '' Write-Host -Object '' } # Cancel the selection if option is activated { ($_ -eq 'c' -and $CancelOption) } { $ReturnObj.State = '%CANCEL%' $RunMenu = $false } # Return all selected items if multi select mode is activated or empty return is allowed { ($_ -eq 'd' -and $MultiselectOption) -or ($_ -eq 'd' -and $AllowEmptyReturn) } { if (((($Items | Get-SelectedItem).Count -eq 0) -and $AllowEmptyReturn) -or (($Items | Get-SelectedItem).Count -ne 0)) { $ReturnObj.State = '%OK%' return } else { Clear-Host Write-Host -Object "Please select at least one item!" -ForegroundColor Yellow Write-Host -Object '' } } # If user input is not valid default { Clear-Host Write-Host -Object "Input '$_' is not valid!" -ForegroundColor Yellow Write-Host -Object '' } } } } End { # Return the selected items only if run menu equals true if ($RunMenu) { $ReturnObj.Items = @() + $Items | Get-SelectedItem } return $ReturnObj } } function Select-MenuEntryFromList { <# .Synopsis Offers the possibility to render a menu inside the cli and to select one entry. .DESCRIPTION Offers the possibility to render a menu inside the cli and to select one entry. The function will return the selected menu entry. .PARAMETER MenuTitle The title of the menu. .PARAMETER MenuEntries The entries to show inside the menu. .PARAMETER BackOption Enables the back option. .PARAMETER ExitOption Enables the exit option. .INPUTS None. You cannot pipe objects to Select-MenuEntryFromList. .OUTPUTS System.String Select-MenuEntryFromList returns the selected menu item as string in the following format. [PSCustomObject]@{ MenuEntry = $null # System.String State = $null # %OK% / %BACK% / %EXIT% } .EXAMPLE # Render a menu with back and exit option # Set the menu title and the menu entries [System.String[]]$MenuEntries = @('Menu 1', 'Menu 2', 'Menu 3') [System.String]$MenuTitle = "=============== Test Menu ===============" # Ask user for the menu entry [PSCustomObject]$SelectedMenuEntry = Select-MenuEntryFromList -MenuTitle $MenuTitle -MenuEntries $MenuEntries -ExitOption -BackOption # Do the action based on the selection switch ($SelectedMenuEntry.State) { '%OK%' { Write-Host -Object "Selected menu entry: $($SelectedMenuEntry.MenuEntry)" } '%BACK%' { Write-Host -Object "Back option selected" } '%EXIT%' { Write-Host -Object "Exit option selected" } } .LINK https://github.com/netcloud/powershell-cli-menu-helpers #> [OutputType([System.Management.Automation.PSObject[]])] Param( [System.String]$MenuTitle, [System.String[]]$MenuEntries, [System.Management.Automation.SwitchParameter]$BackOption, [System.Management.Automation.SwitchParameter]$ExitOption ) Begin { # Prepare the output object [PSCustomObject]$ReturnObj = [PSCustomObject]@{ MenuEntry = $null State = $null # %OK% / %BACK% / %EXIT% } # Define the possible options [System.Array]$Options = @( [PSCustomObject]@{display = $BackOption; letter = 'b'; description = 'Back' }, [PSCustomObject]@{display = $ExitOption; letter = 'e'; description = 'Exit' } ) } Process { # Display the list in a loop [System.Boolean]$RunMenu = $true Clear-Host Write-Host -Object '' Write-Host -Object '' while ($RunMenu) { # Render the menu title if ($MenuTitle -ne '') { Write-Host -Object $MenuTitle } # Render the menu entries for ($i = 1; $i -le $MenuEntries.Count; $i ++) { Write-Host -Object "$i) $($MenuEntries[$i - 1])" } Write-Host -Object '' Write-Host -Object '' # Render the list options foreach ($Option in $Options) { if ($Option.display) { Write-Host -Object "$($Option.letter)" -NoNewline -ForegroundColor Yellow Write-Host -Object ": $($Option.description)" } } Write-Host -Object '' Write-Host -Object '' # Get user input [System.String]$UserInput = Read-Host -Prompt 'Enter selection' # Get all menu entry id's [System.Int32[]]$MenuEntryIDs = @() if ($MenuEntries.Count -ne 0) { $MenuEntryIDs = (1..$MenuEntries.Count) } # Process the user input switch ($UserInput) { # Return selected menu entry { ($_ -match '^\d+$') -and ($MenuEntryIDs -contains $_) } { # Add the item to the return object $ReturnObj.State = '%OK%' $ReturnObj.MenuEntry = $MenuEntries[$_ - 1] return } # Return back if the option is activated { ($_ -eq 'b' -and $BackOption) } { $ReturnObj.State = '%BACK%' return } # Return exit if the option is activated { ($_ -eq 'e' -and $ExitOption) } { $ReturnObj.State = '%EXIT%' return } # If user input is not valid default { Clear-Host Write-Host -Object "Input '$_' is not valid!" -ForegroundColor Yellow Write-Host -Object '' } } } } End { # Return the object return $ReturnObj } } # SIG # Begin signature block # MIISiwYJKoZIhvcNAQcCoIISfDCCEngCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU1l7Wql4MgCPZ/eNXZyLPbgSN # /Zmggg5XMIIEHDCCAwSgAwIBAgIKIn/hjAADAAAm0zANBgkqhkiG9w0BAQsFADBM # MRIwEAYKCZImiZPyLGQBGRYCY2gxGDAWBgoJkiaJk/IsZAEZFghuZXRjbG91ZDEc # MBoGA1UEAxMTbmV0Y2xvdWQuY2ggUm9vdCBDQTAeFw0yMTAxMDYxMjE2MDJaFw0y # MzEyMDkwODEzMzBaMHsxCzAJBgNVBAYTAkNIMRMwEQYDVQQHEwpXaW50ZXJ0aHVy # MRQwEgYDVQQKEwtOZXRjbG91ZCBBRzEOMAwGA1UECxMFbmNEZXYxDjAMBgNVBAMT # BW5jRGV2MSEwHwYJKoZIhvcNAQkBFhJuY19kZXZAbmV0Y2xvdWQuY2gwgZ8wDQYJ # KoZIhvcNAQEBBQADgY0AMIGJAoGBAOZN3BE6WdimqN9zMlsEnhxijWS/vvvXfnNj # 9om0FWFxvPY8MDq5kg1nSPilnGGjrKw42Uzswo3FjH18RNu9xXFP2BNdpbSG9/00 # OyYEMs3i8d0bgrcYN4glbYLIQfE5o83OwjgekwXZHRFYRLAZqH37zkiNoE6suQBi # Rsv/3I8ZAgMBAAGjggFTMIIBTzALBgNVHQ8EBAMCB4AwPQYJKwYBBAGCNxUHBDAw # LgYmKwYBBAGCNxUIheWYYYOrnmaEiYsRh4H/CYPQoX4qh7P+Q4a7zQgCAWUCARQw # HQYDVR0OBBYEFKkBjB/3JfydHBCXjC8v1zaANJB0MB8GA1UdIwQYMBaAFG4vOrQ2 # gTM4WQh4BBTACZlkDJX6MEEGA1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9wa2kubmV0 # Y2xvdWQuY2gvQ0ExMy9uZXRjbG91ZFJvb3QyMDEzLmNybDBMBggrBgEFBQcBAQRA # MD4wPAYIKwYBBQUHMAKGMGh0dHA6Ly9wa2kubmV0Y2xvdWQuY2gvQ0ExMy9uZXRj # bG91ZFJvb3QyMDEzLmNydDATBgNVHSUEDDAKBggrBgEFBQcDAzAbBgkrBgEEAYI3 # FQoEDjAMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQAGuuUeP7gOF1oB # 1wzPepJyVZA28VhJATscbldy256atj30MH4RyVl6zxFaEh2icgUbRt+UPANBkIMT # s8BLWLLD829eW9JXcZRy3HYQkFW7aPfDYOLGI3CQcDuBE3bEXv4EPm6SCnoik5sF # v04zVM1Qp4kFtmRGuignjdOl/6Hs3v8AlXFrQh5jhFgBDgCFYYGMkNbWKCw/usgJ # AHN2Jxejoopj6G6PUNiJ6AwUqZbSpNcc7Yz+KQ+hqwNc5VTg3/n0WHkKIQs+WU/C # 1VfrTy+Qo5f4kgsVsmOZQu0ZVVyoDSKpxv+C0plBqqAGN+LrIJF3TgZe8kYLZRPL # +FefSoNEMIIE/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/hOvB46NJofrOp79Wz7pZdmGJX36ntI5nePk2mOHLKNpbh6aKLzCCBTEwggQZ # oAMCAQICEAqhJdbWMht+QeQF2jaXwhUwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UE # BhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2lj # ZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4X # DTE2MDEwNzEyMDAwMFoXDTMxMDEwNzEyMDAwMFowcjELMAkGA1UEBhMCVVMxFTAT # BgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEx # MC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBD # QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3QMu5LzY9/3am6gpnF # OVQoV7YjSsQOB0UzURB90Pl9TWh+57ag9I2ziOSXv2MhkJi/E7xX08PhfgjWahQA # OPcuHjvuzKb2Mln+X2U/4Jvr40ZHBhpVfgsnfsCi9aDg3iI/Dv9+lfvzo7oiPhis # EeTwmQNtO4V8CdPuXciaC1TjqAlxa+DPIhAPdc9xck4Krd9AOly3UeGheRTGTSQj # MF287DxgaqwvB8z98OpH2YhQXv1mblZhJymJhFHmgudGUP2UKiyn5HU+upgPhH+f # MRTWrdXyZMt7HgXQhBlyF/EXBu89zdZN7wZC/aJTKk+FHcQdPK/P2qwQ9d2srOlW # /5MCAwEAAaOCAc4wggHKMB0GA1UdDgQWBBT0tuEgHf4prtLkYaWyoiWyyBc1bjAf # BgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzASBgNVHRMBAf8ECDAGAQH/ # AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB5BggrBgEF # BQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBD # BggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2Ny # bDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDig # NoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDBQBgNVHSAESTBHMDgGCmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYc # aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sBwEwDQYJKoZI # hvcNAQELBQADggEBAHGVEulRh1Zpze/d2nyqY3qzeM8GN0CE70uEv8rPAwL9xafD # DiBCLK938ysfDCFaKrcFNB1qrpn4J6JmvwmqYN92pDqTD/iy0dh8GWLoXoIlHsS6 # HHssIeLWWywUNUMEaLLbdQLgcseY1jxk5R9IEBhfiThhTWJGJIdjjJFSLK8pieV4 # H9YLFKWA1xJHcLN11ZOFk362kmf7U2GJqPVrlsD0WGkNfMgBsbkodbeZY4UijGHK # eZR+WfyMD+NvtQEmtmyl7odRIeRYYJu6DC0rbaLEfrvEJStHAgh8Sa4TtuF8QkIo # xhhWz0E0tmZdtnR79VYzIi8iNrJLokqV2PWmjlIxggOeMIIDmgIBATBaMEwxEjAQ # BgoJkiaJk/IsZAEZFgJjaDEYMBYGCgmSJomT8ixkARkWCG5ldGNsb3VkMRwwGgYD # VQQDExNuZXRjbG91ZC5jaCBSb290IENBAgoif+GMAAMAACbTMAkGBSsOAwIaBQCg # eDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEE # AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJ # BDEWBBSWmZ2NoRhR1u0WzOkMZ1Vu5QAIeDANBgkqhkiG9w0BAQEFAASBgA5gY0px # BtXnRTmwpMCx3jD5z32pzQ1h7nvBsUyKKGqeDwWABRuMB9LqKJpUZsf6J6xbF7Ss # Cit8Kt3CGPu5geB6hV0TsDQ42oNx6I86VeU4aX90mS30L3tmv3Ddf1L0CNP4Dkmx # /BNIWt77PTxeyqM9fgJKu0I+rsQbJCyfw0o1oYICIDCCAhwGCSqGSIb3DQEJBjGC # Ag0wggIJAgEBMIGGMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0 # IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0ECEA1CSuC+Ooj/YEAhzhQA # 8N0wCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZI # hvcNAQkFMQ8XDTIxMDEwNzA3NTYwM1owIwYJKoZIhvcNAQkEMRYEFOVgxPg9ZUpe # 1KhUl6Y8h8oC9KRbMA0GCSqGSIb3DQEBAQUABIIBAGolr7oEPEFYAM78wHlqN7d1 # GgHILimA0aOY9ZU4vFOOQ8+TXw6IebkmPSKP919ZBLPWYXdV8LAh0kFYVu34c9Xc # TOXY6qxahYkHZd9+xilWylSNCbdcdt5yrzdQL8IA/GJeh+EhfX+RO935Yjjxqi4N # jBH3B3TxCfJzWWgpUWmE41OQhrSedUFSWYEhDPbaWbYbsmeE67A+Sjy+yT82Qpjc # PKe4QFVpmDHjaSWqkaLvugFc8i64IUcC3GRl6zLNaRlhuq2t4CCqNxX5ZjwHQQk9 # Ejzf1z8ja/S9FPtCRSGVutJweEN79y4bfbtItAVhaRCC1g17PeCyBnVUT4Z9JIM= # SIG # End signature block |