Param([int]$which=0) if(!(get-command DataSeries -EA 0)){ $null = [Reflection.Assembly]::LoadWIthPartialName("System.Windows.Forms") # To get the Double-Click time # Add-BootsContentProperty 'DataPoints', 'Series' # Add-BootsFunction -Assembly "~\Documents\WindowsPowershell\Libraries\WPFVisifire.Charts.dll" } function global:New-GraphLabel { PARAM ( [String]$Label = "Name", [String]$Value = "Length", [ScriptBlock]$DoubleClickAction = $null, [Int]$max = $null, [Int]$width = 200, [double]$margin = 2, [Int]$DoubleClickTime = $([System.Windows.Forms.SystemInformation]::DoubleClickTime), $InputObject ) BEGIN { $maxx = $max; $global:DoubleClickTime = $DoubleClickTime } PROCESS { if($_){ $InputObject = $_ } if(!$maxx){ $maxx=@($InputObject)[0].$Value } foreach($io in $InputObject) { ## This is the core part of the script ... ## For each input, generate a grid panel with a label and a rectangle in the background GridPanel -tag @{item=$io; action=$DoubleClickAction} -width $Width -margin $margin $( Label $io.$Label Rectangle -HorizontalAlignment Left -Fill "#9F00" ` -Width ($Width * ($io."$Value" / $maxx)) ) -On_MouseLeftButtonDown { if($this.Tag.Action) { # They passed in a doubleclick action, so lets handle it if($global:ClickTime -and ([DateTime]::Now - $ClickTime).TotalMilliseconds -lt $DoubleClickTime) { # We invoke the scriptblock # and pass it the original input object # and the grid panel object &$This.Tag.Action $this.Tag.Item $this } else { $global:ClickTime = [DateTime]::Now } } } } } } function Get-BootsInput { Param([string]$Prompt = "Please enter your name:") Boots { Border -BorderThickness 4 -BorderBrush "#BE8" -Background "#EFC" ( StackPanel -Margin 10 $( Label $Prompt StackPanel -Orientation Horizontal $( TextBox -Width 150 -On_KeyDown { if($_.Key -eq "Return") { Write-BootsOutput $global:textbox.Text $BootsWindow.Close() } } | Tee -Variable global:textbox Button "Ok" -On_Click { Write-BootsOutput $global:textbox.Text $BootsWindow.Close() } ) ) ) } -On_Load { Invoke-BootsWindow $global:textbox { $global:textbox.Focus() } } ` -WindowStyle None -AllowsTransparency ` -On_PreviewMouseLeftButtonDown { if($_.Source -notmatch ".*\.(TextBox|Button)") { $BootsWindow.DragMove() } } } Set-Alias GraphLabel New-GraphLabel -Scope Global if(!(gcm Microsoft.PowerShell.Utility\Get-Random -EA 0)) { $global:randor = new-object random function global:Get-Random([int]$min,[int]$max=$([int]::MaxValue)){ if($min) { $global:randor.Next($min,$max) } else { $global:randor.Next($max) } } } switch($which) { 0 { @" This script just runs the various demo scripts I've written to test Boots. You need to pass it a number (between 1 and 29) for the sample to run! "@ } 1 { New-BootsWindow -SizeToContent WidthAndHeight -Content { Button -Content "Push Me" } } 2 { Boots { Button -Content "Push Me" } } 3 { Boots { StackPanel { Button "A bed of clams" Button "A coalition of cheetas" Button "A gulp of swallows" } } } 4 { Boots { "A bed of clams", "A coalition of cheetas", "A gulp of swallows" | Button | StackPanel } } 5 { Boots { "A bed of clams", "A coalition of cheetas", "A gulp of swallows" | StackPanel | Button } } 6 { Boots { StackPanel -Margin 5 -Background Pink $( Button -Margin 2 "A bed of clams" Button -Margin 2 "A coalition of cheetas" Button -Margin 2 "A gulp of swallows" ) } } 7 { Boots { "A bed of clams", "A coalition of cheetas", "A gulp of swallows" | Button -Margin 2 | StackPanel -Margin 5 -Background Pink } } 8 { Boots { Ellipse -Width 60 -Height 80 -Margin "20,10,60,20" -Fill Black } } 9 { Boots { Canvas -Height 100 -Width 100 -Children $( Rectangle -Margin "10,10,0,0" -Width 45 -Height 45 -Stroke Purple -StrokeThickness 2 -Fill Red Polygon -Stroke Pink -StrokeThickness 2 -Fill DarkRed -Points "10,60", "50,60", "50,50", "65,65", "50,80", "50,70", "10,70", "10,60" ) } } 10 { Boots { Image -Source http://data.powerisers.de/gallery/files/855/IMG_3298.jpg -MaxWidth 400 | } -Title "Now those are some powerful boots!" -Async } 11 { Boots { StackPanel -Margin 10 -Children $( TextBlock "A Question" -FontSize 42 -FontWeight Bold -Foreground "#FF0088" TextBlock -FontSize 24 -Inlines $( Bold "Q. " "Are you starting to dig " Hyperlink "PowerBoots?" -NavigateUri http://huddledmasses.org/tag/powerboots/ ` -On_RequestNavigate { [Diagnostics.Process]::Start( $this.NavigateUri ) } ) TextBlock -FontSize 16 -Inlines $( Span -FontSize 24 -FontWeight Bold -Inlines "A. " "Leave me alone, I'm hacking here!" ) ) } } 12 { Boots { $global:Count = 0 WrapPanel { Button "Push Me" -On_Click { $global:Count++ $global:label.Content = "You clicked the button ${global:Count} times!" } Label "Nothing pushed so far" | Tee -variable global:label } } -Title "Test App" -On_Closing { $global:BootsOutput = $global:Count; rm variable:Count } } 13 { Boots { WrapPanel -On_Load { $Count = 0 } { Button "Push Me" -On_Click { Write-BootsOutput (++$count) $global:block.Inlines.Clear(); $global:block.Inlines.Add("You clicked the button $count times!") } TextBlock "Nothing pushed so far" -VerticalAlignment Center | Tee-Object -Variable global:block } } } 14 { ## This syntax only works in PowerSHell 2 running as MTA ## because it requires making a RadialGradientBrush outside the boots thread... ## TODO: In a future release, make all the parameters take (optional) scriptblocks to be evaluated in-thread # Boots -Background $( # RadialGradientBrush { # GradientStop -Offset 0 -Color "#F00" # GradientStop -Offset 1 -Color "#F90" # } # ) { # Label "Boots" -HorizontalAlignment Center ` # -VerticalAlignment Center ` # -Foreground White -Margin 80 ` # -FontWeight Bold -FontSize 40 # } Boots { Label "Boots" -HorizontalAlignment Center ` -VerticalAlignment Center ` -Foreground White -Margin 80 ` -FontWeight Bold -FontSize 40 } -async -passthru | Invoke-BootsWindow -Element {$_} { $BootsWindow.Background = RadialGradientBrush { GradientStop -Offset 0 -Color "#F00" GradientStop -Offset 1 -Color "#F90" } } } 15 { Boots { TextBox -Width 220 } -Title "Enter your name" -On_Closing { Write-BootsOutput $BootsWindow.Content.Text } } 16 { Get-BootsInput } 17 { ## Example 1: list of processes with most RAM usage ## DoubleClickAction is `kill` Boots { ps | sort PM -Desc | Select -First 20 | GraphLabel ProcessName PM { Kill $Args[0].Id -WhatIf $global:panel.Children.Remove($Args[1]) } | StackPanel | Tee -Var global:panel } } 18 { ## Example 2: list of images, with file size indicated ## DoubleClickAction is `open` Boots { ls ~/Pictures/ -recurse -Include *.jpg | Select -First 10 | ## For the sake of the demo, just 10 Sort Length -Desc | % { if(!$Max){$Max=$_.Length} StackPanel -Width 200 -Margin 5 $( Image -Source $_.FullName GraphLabel Name Length -Max $Max -IO $_ { [Diagnostics.Process]::Start( $args[0].FullName ) } ) } | WrapPanel } -Width 800 } 19 { Boots { Chart -MinWidth 200 -MinHeight 150 -Theme Theme3 { DataSeries { DataPoint -YValue (Get-Random 100) DataPoint -YValue (Get-Random 100) DataPoint -YValue (Get-Random 100) DataPoint -YValue (Get-Random 100) } } } -Title "Sample, Theme 3" } 20 { [int]$tk = Invoke-Http get http://google.com/search -with @{q="TCL Tk"} | Receive-Http Text "//div[@id='ssb']//b[3]" [int]$shoes = Invoke-Http get http://google.com/search -with @{q="Ruby Shoes"} | Receive-Http Text "//div[@id='ssb']//b[3]" [int]$boots = Invoke-Http get http://google.com/search -with @{q="PowerShell PowerBoots"} | Receive-Http Text "//div[@id='ssb']//b[3]" Boots { Chart -MinHeight 300 -MinWidth 400 { DataSeries -RenderAs Bar { DataPoint -YValue $tk -AxisXLabel Tk -Href http://google.com/search?q=TCL+Tk DataPoint -YValue $shoes -AxisXLabel Shoes -Href http://google.com/search?q=Ruby+Shoes DataPoint -YValue $boots -AxisXLabel Boots -Href http://google.com/search?q=PowerSHell+PowerBoots } } } } 21 { $ad=New-Object DirectoryServices.DirectorySearcher [ADSI]'' # Set a limit or TimeOut, PageSize lets us get more later $ad.PageSize = 200 # ADSI field names are awful. # l = location, l=* returns only users with locations set $ad.Filter = "(&(objectClass=Person)(l=*))" $results = $ad.FindAll().GetEnumerator() | ForEach { $_ } $users = $results | ForEach { $_.GetDirectoryEntry() } # "l" is a PropertyValueCollection, use the first value $users | Group-Object {$_.l[0]} | ForEach { DataPoint -YValue ([int]$_.Count) -AxisXLabel $_.Name }| DataSeries -RenderAs Doughnut | Chart -Height 300 -Width 300 | Boots -Title "AD Users by Location" } 22 { Boots { ls | ForEach { DataPoint -YValue ([DateTime]::Now - $_.LastWriteTime).TotalDays ` -ZValue ($_.Length/1KB) ` -AxisXLabel $_.Name -Tag $_ ` -On_MouseLeftButtonUp { if($this.Tag) { Write-BootsOutput $this.Tag; $global:series.DataPoints.Remove($this) } } } | DataSeries -RenderAs Bubble -ToolTipText "#AxisXLabel`nAge: #YValue days, Size: #ZValue Kb" | Tee-Object -Variable global:series | Chart -MinHeight 350 -MinWidth 600 -Theme Theme3 } | Remove-Item -Confirm } 23 { # Write-Host "We're going to ask for your password here, so we can upload an image via FTP" # $credential = Get-Credential if($PsVersionTable) { ## BUG BUG: Setting boolan properties isn't working in PowerShell 1 Write-Host "Using PowerShell 2 Version" -Fore Cyan New-BootsImage VisiFire-BootsImage.jpg { Chart -Width 200 -Height 150 -Theme Theme3 -Watermark:$false -Animation:$false -Series { DataSeries { 1..(Get-Random -min 3 -max 6) | ForEach-Object { DataPoint -YValue (Get-Random 100) } } } } #| ForEach-Object { # Send-FTP HuddledMasses.org $credential -LocalFile $_ -Remotefile "$imgPath/$($_.Name)" # [Windows.Clipboard]::SetText( "!http://huddledmasses.org/images/PowerBoots/$($_.Name)!" ) #} } else { Write-Host "Using PowerShell 1 Version" -Fore Cyan Boots -Title "ScreenCapWindow" { Chart -Width 200 -Height 150 -Theme Theme3 -Watermark:$false -Animation:$false -Series { DataSeries { 1..(Get-Random -min 3 -max 6) | ForEach-Object { DataPoint -YValue (Get-Random 100) } } } | tee -var global:chart } -Async sleep 5 Export-BootsImage VisiFire-BootsImage.jpg $global:chart Remove-BootsWIndow "ScreenCapWindow" } } 24 { # Write-Host "We're going to ask for your password here, so we can upload an image via FTP" # $credential = Get-Credential New-BootsImage BootsImage-Screenshot.jpg { StackPanel -Margin "10,5,10,5" { Label "Please enter your name:" StackPanel -Orientation Horizontal { TextBox -Width 150 -On_KeyDown { if($_.Key -eq "Return") { Write-BootsOutput $global:textbox.Text $BootsWindow.Close() } } | Tee-Object -Variable global:textbox Button "Ok" -Padding "5,0,5,0" -Margin "2,0,0,0" -On_Click { Write-BootsOutput $textbox.Text $BootsWindow.Close() } } } } #| ForEach-Object { #Send-FTP HuddledMasses.org $credential -LocalFile $_ -Remotefile "$imgPath/$($_.Name)" #[Windows.Clipboard]::SetText( "!http://huddledmasses.org/images/PowerBoots/$($_.Name)!" ) #} } 25 { Boots -Async { StackPanel -Margin 10 { TextBlock "The Question" -FontSize 42 -FontWeight Bold -Foreground "#FF0088" TextBlock -FontSize 24 { Hyperlink { Bold "Q. " "Can PowerBoots do async threads?" } -NavigateUri " " -On_RequestNavigate { $global:Answer.Visibility = "Visible" } } TextBlock -FontSize 16 { Span "A. " -FontSize 24 -FontWeight Bold "Oh yes we can!" } -Visibility Collapsed | Tee -Variable global:Answer } } } 26 { # This works with just the PoshWpf snapin $global:Splash = New-BootsWindow -Async -Passthru -Content {$Args[0].Content} -On_MouseDown { $this.DragMove() } -SourceTemplate '' # Imagine this is your script, working ... Start-Sleep 3 # And now you're done, and want to close it Invoke-BootsWindow $Splash { $global:Splash.Close() } } 27 { ## This requires PowerBoots which is (as of this writing) is still v2 only... $global:Splash = Boots -Async -Passthru -Content { Image -Height 177 -Source http://dilbert.com/dyn/str_strip/000000000/00000000/0000000/000000/40000/1000/200/41215/41215.strip.print.gif } -WindowStyle None -AllowsTransparency -Opacity 0.8 -Topmost -WindowStartupLocation CenterOwner -ShowInTaskbar:$False -On_MouseDown { $this.DragMove() } # Imagine this is your script, working ... Start-Sleep 3 # And now you're done, and want to close it Invoke-BootsWindow $Splash { $global:Splash.Close() } } 28 { Write-Host "Initializing Performance Counters, please have patience" -fore Cyan ### Import PoshWpf module Import-Module PowerBoots ### Or, on v1: # Add-PSSnapin PoshWpf $global:cpu = new-object System.Diagnostics.PerformanceCounter "Processor", "% Processor Time", "_Total" $global:ram = new-object System.Diagnostics.PerformanceCounter "Memory", "Available KBytes" ## get initial values, because the counters don't work until the second call $null = $global:cpu.NextValue() $null = $global:ram.NextValue() $global:maxram = (gwmi Win32_OperatingSystem).TotalVisibleMemorySize Write-Host "Loading XAML window..." -fore Cyan ## Load the XAML and show the window. It won't be updating itself yet... $global:clock = New-BootsWindow -Async -Passthru -Content { $Args[0].Content } -FileTemplate "$PowerBootsPath\Samples\clock.xaml" ## Create a script block which will update the UI by changing the Resources! $counter = 0; $global:updateBlock = { # Update the clock $global:clock.Resources["Time"] = [DateTime]::Now.ToString("hh:MM.ss") # We only want to update the counters at most once a second # Otherwise their values are invalid and ... # The CPU counter fluctuates from 0 to the real number if( $counter++ -eq 4 ) { $counter = 0 # Update the CPU counter with the absolute value and the percentage $cu = $global:cpu.NextValue() $global:clock.Resources.CpuP = ($cu / 100) $global:clock.Resources.Cpu = "{0:0.0}%" -f $cu # Update the RAM counter with the absolute value and the percentage $rm = $global:ram.NextValue() $global:clock.Resources.RamP = ($rm / $global:maxram) $global:clock.Resources.Ram = "{0:0.00}Mb" -f ($rm/1MB) } } ## Now we need to call that scriptblock on a timer. That's easy, but it ## must be done on the window's thread, so we use Invoke-BootsWindow. ## Notice the first argument is the window we want to run the script in Invoke-BootsWindow $clock { ## We'll create a timer $global:timer = new-object System.Windows.Threading.DispatcherTimer ## Which will fire 4 times every second $timer.Interval = [TimeSpan]"0:0:0.25" ## And will invoke the $updateBlock $timer.Add_Tick( $global:updateBlock ) ## Now start the timer running $timer.Start() } ## And just like that, the $UpdateBlock is running 4x a second ## and the clock is working. Pretty cool, right? # # ## If we wanted to, say, handle mouse events to let you drag the window or close it ... # Invoke-BootsWindow $clock { # $clock.Add_MouseLeftButtonDown( { # $_.Handled = $true # $clock.DragMove() # WPF Magic! # } ) # $clock.Add_MouseRightButtonDown( { # $_.Handled = $true # $timer.Stop() # we'd like to stop that timer now, thanks. # $clock.Close() # and close the windows # } ) # } Register-BootsEvent $clock -Event MouseLeftButtonDown -Action { $_.Handled = $true $clock.DragMove() # WPF Magic! } Register-BootsEvent $clock -Event MouseRightButtonDown -Action { $_.Handled = $true $timer.Stop() # we'd like to stop that timer now, thanks. $clock.Close() # and close the windows } } } # SIG # Begin signature block # MIILCQYJKoZIhvcNAQcCoIIK+jCCCvYCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUTDTaCJLXpXyxb6a8QFdj/vUQ # fPCgggbgMIIG3DCCBMSgAwIBAgIJALPpqDj9wp7xMA0GCSqGSIb3DQEBBQUAMIHj # MQswCQYDVQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxEjAQBgNVBAcTCVJvY2hl # c3RlcjEhMB8GA1UEChMYaHR0cDovL0h1ZGRsZWRNYXNzZXMub3JnMSgwJgYDVQQL # Ex9TY3JpcHRpbmcgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MTcwNQYDVQQDEy5odHRw # Oi8vSHVkZGxlZE1hc3Nlcy5vcmcgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MScwJQYJ # KoZIhvcNAQkBFhhKYXlrdWxASHVkZGxlZE1hc3Nlcy5vcmcwHhcNMDkwMzE1MTkx # OTE5WhcNMTAwMzE1MTkxOTE5WjCBqzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5l # dyBZb3JrMRIwEAYDVQQHEwlSb2NoZXN0ZXIxITAfBgNVBAoTGGh0dHA6Ly9IdWRk # bGVkTWFzc2VzLm9yZzESMBAGA1UECxMJU2NyaXB0aW5nMRUwEwYDVQQDEwxKb2Vs # IEJlbm5ldHQxJzAlBgkqhkiG9w0BCQEWGEpheWt1bEBIdWRkbGVkTWFzc2VzLm9y # ZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPfqxOG9TQN+qZjZ6KfM # +zBK0YpjeyPL/cFgiGBhiIdYWTBtkbZydFr3IiERKRsUJ0/SKFbhf0C3Bvd/neTJ # qiZjH4D6xkrfdLlWMmmSXXqjSt48jZp+zfCAIaF8K84e9//7lMicdVFE6VcgoATZ # /eMKQky4JvphJpzDHYPLxLJQrKd0pjDDwspjdX5RedWkzeZBG7VfBnebLWUzgnMX # IxRQKfFCMryQDP8weceOnJjfJEf2FYmdpsEg5EKKKbuHsQCMVTxfteKdPvh1oh05 # 1GWyPsvEPh4auJUT8pAVvrdxq+/O9KW/UV01UxjRYM1vdklNw8g7mkJTrrHjSjl7 # tuugCnJjt5kN6v/OaUtRRMR68O85bSTVGOxJGCHUKlyuuTx9tnfIgy4siFYX1Ve8 # xwaAdN3haTon3UkWzncHOq3reCIVF0luwRZu7u+TnOAnz2BRlt+rcT0O73GN20Fx # gyN2f5VGBbw1KuS7T8XZ0TFCspUdgwAcmTGuEVJKGhVcGAvNlLx+KPc5dba4qEfs # VZ0MssC2rALC1z61qWuucb5psHYhuD2tw1SrztywuxihIirZD+1+yKE4LsjkM1zG # fQwDO/DQJwkdByjfB2I64p6mk36OlZAFxVfRBpXSCzdzbgKpuPsbtjkb5lGvKjE1 # JFVls1SHLJ9q80jHz6yW7juBAgMBAAGjgcgwgcUwHQYDVR0OBBYEFO0wLZyg+qGH # Z4WO8ucEGNIdU1T9MB8GA1UdIwQYMBaAFN2N42ZweJLF1mz0j70TMxePMcUHMAkG # A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgTwMCoGA1UdJQEB/wQgMB4GCCsGAQUF # BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMwCwYDVR0PBAQDAgTwMCwGCWCGSAGG+EIB # DQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQUF # AAOCAgEAmKihxd6KYamLG0YLvs/unUTVJ+NW3jZP16R28PpmidY/kaBFOPhYyMl2 # bBGQABe7LA5rpHFAs0F56gYETNoFk0qREVvaoz9u18VfLb0Uwqtnq0P68L4c7p2q # V3nKmWjeI6H7BAyFuogxmMH5TGDfiqrrVSuh1LtPbkV2Wtto0SAxP0Ndyts2J8Ha # vu/2rt0Ic5AkyD+RblFPtzkCC/MLVwSNAiDSKGRPRrLaiGxntEzR59GRyf2vwhGg # oAXUqcJ/CVeHCP6qdSTM39Ut3RmMZHXz5qY8bvLgNYL6MtcJAx+EeUhW497alzm1 # jInXdbikIh0d/peTSDyLbjS8CPFFtS6Z56TDGMf+ouTpEA16otcWIPA8Zfjq+7n7 # iBHjeuy7ONoJ2VDNgqn9B+ft8UWRwnJbyB85T83OAGf4vyhCPz3Kg8kWxY30Bhnp # Fayc6zQKCpn5o5T0/a0BBHwAyMfr7Lhav+61GpzzG1KfAw58N2GV8KCPKNEd3Zdz # y07aJadroVkW5R+35mSafKRJp5pz20GDRwZQllqGH1Y/UJFEiI0Bme9ecbl2vzNp # JjHyl/jLVzNVrBI5Zwb0lCLsykApgNY0yrwEqaiqwcxq5nkXFDhDPQvbdulihSo0 # u33fJreCm2fFyGbTuvR61goSksAvLQhvijLAzcKqWKG+laOtYpAxggOTMIIDjwIB # ATCB8TCB4zELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMRIwEAYDVQQH # EwlSb2NoZXN0ZXIxITAfBgNVBAoTGGh0dHA6Ly9IdWRkbGVkTWFzc2VzLm9yZzEo # MCYGA1UECxMfU2NyaXB0aW5nIENlcnRpZmljYXRlIEF1dGhvcml0eTE3MDUGA1UE # AxMuaHR0cDovL0h1ZGRsZWRNYXNzZXMub3JnIENlcnRpZmljYXRlIEF1dGhvcml0 # eTEnMCUGCSqGSIb3DQEJARYYSmF5a3VsQEh1ZGRsZWRNYXNzZXMub3JnAgkAs+mo # OP3CnvEwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJ # KoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQB # gjcCARUwIwYJKoZIhvcNAQkEMRYEFKUABmyCqDvz845MGq7Vwjt2FqgcMA0GCSqG # SIb3DQEBAQUABIICAAa0SfszAKnyNtUj8J4/QxAfciGNi19uZc6tXYiSmkz0AriS # KtLq9hqRcfiL/ypHc1WNtaPEAaeUEcWnUT1KZO4XmI0I81iGf/O9OO2+Khav7vkJ # 4OolvhA+JOZxsC8TDRY5YI49Q2QBZYw19uEsUrugCBk4lp0+YtCt33GjiQQmdMhi # ClUyzb3bS8A2f9IvjDYWMyM8BLjIcldmk3qJQEOxjKdatutz4FVL1/LSDB4Qz1cR # X9alxUohkm7pfp6FC/YJm8eQiRviDx1SleZVsH8bhIF+k4NjF+9+a+xTa5ZTm36W # JEMA5grYoqrf8G9v+8QqqhEm+MlsP92aYmcXUkzz8c6q9A11PSASgJ/ohm/huqcj # JSDVrrMSgUR9Y72Y/5t+D76XywYthX4oUHAcd4n59b1/uEr8YCxCnlu5NrbTnLq7 # iANVFOqZgmm+QOaTa86tWvfVxVBtdZcii4h1qvZWI9L8kGlXIN1dlhMcuHu+FatE # sXpPzRg0SWtud5aE3AKWn8mvYOn4Pw7so9qrK2FI02w36G2FdsEisFRCzqxv5rmQ # Gtw93mo5T2n7UC7n0ARaz7ClD0JKUeQILxvqJZhzMDbmcGH2okQ5eP9hMqr2xyvy # MjaBfZbmkgMVdDK9j9s5nCvGwtVrEnqIgQjDKJ/C0NghQylKTbGdEzdp4jNA # SIG # End signature block