AzurePSDriveStorageAccount.psm1
using namespace Microsoft.PowerShell.SHiPS [SHiPSProvider(UseCache=$true)] class StorageAccounts : SHiPSDirectory { StorageAccounts() : base ($this.GetType()) { } StorageAccounts([string]$name): base($name) { } [object[]] GetChildItem() { $obj = @() @(Az.Storage\Get-AzStorageAccount).Foreach{ $obj += [StorageAccount]::new($($_.StorageAccountName), $_) } return $obj } } [SHiPSProvider(UseCache=$true)] class StorageAccount : SHiPSDirectory { Hidden [object]$data = $null StorageAccount ([string]$name, [object]$data) : base ($name) { $this.data = $data } [object[]] GetChildItem() { $obj = @() $ev = $null if ($this.data.PrimaryEndpoints.Blob -ne $null) { try { $result=Az.Storage\Get-AzStorageContainer -Context $this.data.Context -ErrorAction SilentlyContinue -ErrorVariable ev if($ev) { Write-Verbose $ev.Exception }else{ $obj+=[Blobs]::new($this.data, $result); } } catch { Write-Verbose $_.Exception } } if ($this.data.PrimaryEndpoints.File -ne $null) { try { $result=Az.Storage\Get-AzStorageShare -Context $this.data.Context -ErrorAction SilentlyContinue -ErrorVariable ev if ($ev) { Write-Verbose $ev.Exception } else { $obj+=[Files]::new($this.data, $result) } } catch { Write-Verbose $_.Exception } } if ($this.data.PrimaryEndpoints.Table -ne $null) { try { $result=Az.Storage\Get-AzStorageTable -Context $this.data.Context -ErrorAction SilentlyContinue -ErrorVariable ev if ($ev){ Write-Verbose $ev.Exception } else { $obj+=[Tables]::new($this.data, $result); } } catch { Write-Verbose $_.Exception } } if ($this.data.PrimaryEndpoints.Queue -ne $null) { try { $result=Az.Storage\Get-AzStorageQueue -Context $this.data.Context -ErrorAction SilentlyContinue -ErrorVariable ev if ($ev) { Write-Verbose $ev.Exception } else { $obj+=[Queues]::new($this.data, $result); } } catch { Write-Verbose $_.Exception } } return $obj; } } [SHiPSProvider(UseCache=$true)] class Blobs : SHiPSDirectory { Hidden [object]$data = $null Hidden [object]$result = $null Blobs ([object]$data, [object]$result) : base ($this.GetType()) { $this.data = $data $this.result = $result } [object[]] GetChildItem() { if(-not $this.result) { Write-Debug "AzurePSDrive: No Blobs." return $null } $obj = @() $this.result | ForEach-Object{ $obj+= [Blob]::new($_.Name, $_); } return $obj } [object] SetContent([string]$content, [string]$path) { Write-Error -Message "Set-Content is not supported under 'Blobs'. Try again under Files\<Share> directory." return $null } } [SHiPSProvider(UseCache=$true)] class Files : SHiPSDirectory { Hidden [object]$data = $null Hidden [object]$result = $null Files ([object]$data, [object]$result) : base ($this.GetType()) { $this.data = $data $this.result = $result } [object[]] GetChildItem() { if(-not $this.result) { Write-Debug "AzurePSDrive: No Files found." return $null } <# ConnectionString from cmdlet returns something like below: BlobEndpoint=https://<accountname>.blob.core.windows.net/;QueueEndpoint=https://<accountname>.queue.core.windows.net/; TableEndpoint=https://<accountname>.table.core.windows.net/;FileEndpoint=https://<accountname>.file.core.windows.net/;AccountName=<accountname>;AccountKey=<token> #> # Parse the orginal connection string, extract FileEndpoint, and make it net use-able. $conectstring = $this.data.Context.ConnectionString -split ';' $accountInfo=$conectstring | Where-Object { $_ -match 'AccountName' -or $_ -match 'AccountKey'} $fileEndPoint = $conectstring | Where-Object {$_ -match 'FileEndpoint'} $fileshare = $fileEndPoint if($fileEndPoint) { $index = $fileEndPoint.IndexOf('//') if ($index -gt 0) { $temp = $fileEndPoint.Substring($index) if($temp) { $fileshare = $temp.Replace('/', '\') } } } return $this.result | ForEach-Object { [FileShare]::new($_.Name, $this.data.Context, "$fileshare$($_.Name);$($accountInfo)"); } } [object] SetContent([string]$content, [string]$path) { Write-Error -Message "Set-Content is not supported under 'Files'. Try again under its sub-directories." return $null } } [SHiPSProvider(UseCache=$true)] class Tables : SHiPSDirectory { Hidden [object]$data = $null Hidden [object]$result = $null Tables ([object]$data, [object]$result) : base ($this.GetType()) { $this.data = $data $this.result = $result } [object[]] GetChildItem() { return @($this.result | Sort-Object Name) } [object] SetContent([string]$content, [string]$path) { Write-Error -Message "Set-Content is not supported under 'Tables'. Try again under Files\<Share> directory." return $null } } [SHiPSProvider(UseCache=$true)] class Queues : SHiPSDirectory { Hidden [object]$data = $null Hidden [object]$result = $null Queues ([object]$data, [object]$result) : base ($this.GetType()) { $this.data = $data $this.result = $result } [object[]] GetChildItem() { return @($this.result | Sort-Object Name) } [object] SetContent([string]$content, [string]$path) { Write-Error -Message "Set-Content is not supported under 'Queues'. Try again under Files\<Share> directory." return $null } } [SHiPSProvider(UseCache=$true)] class FileShare : SHiPSDirectory { Hidden [string]$shareName = $null [object]$Context = $null [string]$ConnectionString = $null FileShare ([string]$name, [object]$context, [string]$connectionString) : base ($name) { $this.shareName = $name $this.context = $context $this.ConnectionString = $connectionString } [object[]] GetChildItem() { $obj = @() Az.Storage\Get-AzStorageFile -Context $this.context -ShareName $this.shareName | ForEach-Object { if($_.GetType().Name -eq "CloudFileDirectory") { $obj+=[FileFolder]::new($_.Name, $this.shareName, $_.Name, $this.context, $_) } else { $obj+=[FileShareLeaf]::new($_.Name, $this.shareName, $null, $this.context) } } return $obj } [object] SetContent([string]$content, [string]$path) { $leafName = SetContentUtility -Content $content -Path $path -ShareName $this.shareName -FolderName $null -Context $this.context if($leafName) { # Returning the currently object so that the SHiPS can cache it return [FileShareLeaf]::new($leafName, $this.shareName, $null, $this.context) } return $null } } class FileShareLeaf : SHiPSLeaf { Hidden [string]$fileName = $null Hidden [string]$shareName = $null Hidden [object]$context = $null Hidden [string]$folderName = $null Hidden [string]$filePath = $null FileShareLeaf([string]$name, [string]$shareName, [string]$folderName, [object]$context): base($name) { $this.context = $context $this.fileName = $name $this.shareName = $shareName $this.folderName = $folderName if($this.folderName) { $this.filePath = join-path $this.folderName $this.fileName } else { $this.filePath = $this.fileName } } [object] GetContent() { $tmpfile = $null try { $tmpfile = [System.IO.Path]::GetTempFileName() Write-Verbose "Calling Get-AzStorageFilecontent -Path $($this.filePath) -ShareName $($this.shareName) -Destination $tmpfile ..." -Verbose $ev = $null Az.Storage\Get-AzStorageFilecontent -Path $this.filePath -Context $this.context -ShareName $this.shareName -Destination $tmpfile -Force -ErrorVariable ev if(-not $ev) { $bp = $this.ProviderContext.BoundParameters if($bp.ContainsKey('Path')) { $null = $bp.Remove('Path') } return Microsoft.PowerShell.Management\Get-Content -Path $tmpfile @bp } return $null } finally { if(Test-Path $tmpfile) { Microsoft.PowerShell.Management\Remove-Item -Path $tmpfile -Force -ErrorAction SilentlyContinue } } } [object] SetContent([string]$content, [string]$path) { $leafName = SetContentUtility -Content $content -Path $path -ShareName $this.shareName -FolderName $this.folderName -Context $this.context if($leafName) { # Returning the currently object so that the SHiPS can cache it return $this } return $null } } [SHiPSProvider(UseCache=$true)] class FileFolder : SHiPSDirectory { Hidden [string]$folderName = $null Hidden [object]$cloudFileDirectory = $null Hidden [object]$context = $null Hidden [string]$shareName = $null FileFolder ([string]$name, [string]$shareName, [string]$dir, [object]$context, [object]$cloudFileDirectory) : base ($name) { $this.folderName = $dir $this.cloudFileDirectory = $cloudFileDirectory $this.context = $context $this.shareName = $shareName } [object[]] GetChildItem() { $obj = @() Az.Storage\Get-AzStorageFile -Directory $this.cloudFileDirectory | ForEach-Object { if($_.GetType().Name -eq "CloudFileDirectory") { if($this.folderName) { $dir = Microsoft.PowerShell.Management\Join-path -Path $this.folderName -ChildPath $_.Name } else { $dir=$_.Name } $obj+=[FileFolder]::new($_.Name, $this.shareName, $dir, $this.context, $_) } else { $obj+=[FileShareLeaf]::new($_.Name, $this.shareName, $this.folderName, $this.context ) } } return $obj } [object] SetContent([string]$content, [string]$path) { Write-Verbose "Folder = $($this.folderName), CurrentNode = $($this.name)" $leafName = SetContentUtility -Content $content -Path $path -ShareName $this.shareName -FolderName $this.folderName -Context $this.context # Returning the currently object so that the SHiPS can cache it if($leafName) { return [FileShareLeaf]::new($leafName, $this.shareName, $this.folderName, $this.context) } return $null } } [SHiPSProvider(UseCache=$true)] class Blob : SHiPSDirectory { Hidden [object]$data = $null Blob ([string]$name, [object]$data) : base ($name) { $this.data = $data } [object[]] GetChildItem() { return @(Az.Storage\Get-AzStorageBlob -Context $this.data.Context -Container $this.data.Name | Sort-Object Name) } } Function SetContentUtility() { param( [string]$Content, [string]$Path, [string]$ShareName, [string]$FolderName, [object]$Context ) # Save the text content to a local temp file because the Set-AzureStorageFileContent cmdlet takes file only $tmpfile = [System.IO.Path]::GetTempFileName() try { Microsoft.PowerShell.Management\Set-Content -Path $tmpfile -Value $Content # $content is the 'Value' passed in from Set-Content # $path is the full path. e.g., Azure:\<subscription>\StorageAccounts\<myaccount>\Files\<Share>\hello.ps1". # Get the file share target path for Set-AzStorageFileContent # strip off from the path until the share name $restPath = $Path -replace "^.*$ShareName" if(-not $restPath) { Write-Error -Message "Set-Content is not supported on FileShare: $Path. Only files are supported." return $null } $destionation = $restPath.TrimStart('/\') if(-not $destionation) { Write-Error -Message "Set-Content is not supported on FileShare: $Path. Only files are supported." return $null } Write-Verbose "Folder = $FolderName, Path = $path, Destionation = $destionation" if($FolderName -eq $destionation) { Write-Error -Message "Set-Content is not supported on directory path: '$FolderName'. Only files are supported." return $null } # See details https://docs.microsoft.com/en-us/powershell/module/azure.storage/set-azurestoragefilecontent?view=azurermps-6.8.1 Write-Verbose "Calling Set-AzStorageFileContent -ShareName $ShareName -Source $tmpfile -Path $destionation" -Verbose $ev = $null Az.Storage\Set-AzStorageFileContent -Context $Context -ShareName $ShareName -Source $tmpfile -Path $destionation -Force -ErrorVariable ev if($ev) { return $null } return (Microsoft.PowerShell.Management\Split-Path $Path -Leaf) } finally { if($tmpfile) { Microsoft.PowerShell.Management\Remove-Item $tmpfile -Force -ErrorAction SilentlyContinue } } } # SIG # Begin signature block # MIIdnAYJKoZIhvcNAQcCoIIdjTCCHYkCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUw8YUD2SkUHweZoble+82b1IR # fP+gghhqMIIE2jCCA8KgAwIBAgITMwAAAPNnPYNhmA8cpgAAAAAA8zANBgkqhkiG # 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTgwODIzMjAxOTU2 # WhcNMTkxMTIzMjAxOTU2WjCByjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw # b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEm # MCQGA1UECxMdVGhhbGVzIFRTUyBFU046RjZGRi0yREE3LUJCNzUxJTAjBgNVBAMT # HE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQCum1v/6NysKcNZwQxKEIrpa4cW1fG9VgjInuWglPN9slvs # /xUw5hWjBeXIWNpPPfCgg8biPUIuMOTfTnUQHeHGCt3RJHnvkZnt1Sa9YG+qasp0 # Tfj3Ugo8zF4ByEaHquIgP6ps17kkDh7hXrysVjWFU0qBBTf+04dANvYXNNoTNyPh # udDx2O3MS9kINlmzjvOVMDH+j+y7bKkIKdvxhVGvTjPfAH7UjtYtYWe+IFnkBzdf # riO+UOrVLXtkVolXP6ytINIQD1G5dmB6h1Q5l9r6EJ5MWc1ifuOuhGxIEZXrHmer # 6C4VU84Gf16oBGmH7zAsencfYkBO3mtXQuuFeo4zAgMBAAGjggEJMIIBBTAdBgNV # HQ4EFgQUrMOQPcGQ7gcjCPw0JXGsOdef8hYwHwYDVR0jBBgwFoAUIzT42VJGcArt # QPt2+7MrsMM1sw8wVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5taWNyb3Nv # ZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljcm9zb2Z0VGltZVN0YW1wUENBLmNy # bDBYBggrBgEFBQcBAQRMMEowSAYIKwYBBQUHMAKGPGh0dHA6Ly93d3cubWljcm9z # b2Z0LmNvbS9wa2kvY2VydHMvTWljcm9zb2Z0VGltZVN0YW1wUENBLmNydDATBgNV # HSUEDDAKBggrBgEFBQcDCDANBgkqhkiG9w0BAQUFAAOCAQEAZ8mAl+WwiGichsW2 # 7b42Swis3D6yaoCpJ2PPLzsydU8EoazOckFVZl2c5AOJNnzE6PEuAKQxZU0/B1XL # oIDcdSP4ErtqC1Pa7mIf7NHbVZDPCEaIu74f7iWpq/L3zEiEAhXmyUVzRim+ntmZ # hwaFCVmaGtu0c2HP/RoF9U1Pjk2UMmlTdELZjwwcLpOmgswAxz2su+iqyLH381L1 # 6QkaPHuQq9bzbZoE80wk5QpaGfRgxzV1sCDBRuRhHHlPedvmFMLZ/xwAzPmKrYRg # dG+mzu2EmFCjm+UGrJwoXJK3CM+9Wds3uln3hnftCWV5v6jlC1dGiDrlRigksgTm # J/YEFDCCBf8wggPnoAMCAQICEzMAAAEDXiUcmR+jHrgAAAAAAQMwDQYJKoZIhvcN # AQELBQAwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV # BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYG # A1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMTAeFw0xODA3MTIy # MDA4NDhaFw0xOTA3MjYyMDA4NDhaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xHjAcBgNVBAMTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjCCASIw # DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANGUdjbmhqs2/mn5RnyLiFDLkHB/ # sFWpJB1+OecFnw+se5eyznMK+9SbJFwWtTndG34zbBH8OybzmKpdU2uqw+wTuNLv # z1d/zGXLr00uMrFWK040B4n+aSG9PkT73hKdhb98doZ9crF2m2HmimRMRs621TqM # d5N3ZyGctloGXkeG9TzRCcoNPc2y6aFQeNGEiOIBPCL8r5YIzF2ZwO3rpVqYkvXI # QE5qc6/e43R6019Gl7ziZyh3mazBDjEWjwAPAf5LXlQPysRlPwrjo0bb9iwDOhm+ # aAUWnOZ/NL+nh41lOSbJY9Tvxd29Jf79KPQ0hnmsKtVfMJE75BRq67HKBCMCAwEA # AaOCAX4wggF6MB8GA1UdJQQYMBYGCisGAQQBgjdMCAEGCCsGAQUFBwMDMB0GA1Ud # DgQWBBRHvsDL4aY//WXWOPIDXbevd/dA/zBQBgNVHREESTBHpEUwQzEpMCcGA1UE # CxMgTWljcm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xFjAUBgNVBAUTDTIz # MDAxMis0Mzc5NjUwHwYDVR0jBBgwFoAUSG5k5VAF04KqFzc3IrVtqMp1ApUwVAYD # VR0fBE0wSzBJoEegRYZDaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j # cmwvTWljQ29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNybDBhBggrBgEFBQcBAQRV # MFMwUQYIKwYBBQUHMAKGRWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv # Y2VydHMvTWljQ29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNydDAMBgNVHRMBAf8E # AjAAMA0GCSqGSIb3DQEBCwUAA4ICAQCf9clTDT8NJuyiRNgN0Z9jlgZLPx5cxTOj # pMNsrx/AAbrrZeyeMxAPp6xb1L2QYRfnMefDJrSs9SfTSJOGiP4SNZFkItFrLTuo # LBWUKdI3luY1/wzOyAYWFp4kseI5+W4OeNgMG7YpYCd2NCSb3bmXdcsBO62CEhYi # gIkVhLuYUCCwFyaGSa/OfUUVQzSWz4FcGCzUk/Jnq+JzyD2jzfwyHmAc6bAbMPss # uwculoSTRShUXM2W/aDbgdi2MMpDsfNIwLJGHF1edipYn9Tu8vT6SEy1YYuwjEHp # qridkPT/akIPuT7pDuyU/I2Au3jjI6d4W7JtH/lZwX220TnJeeCDHGAK2j2w0e02 # v0UH6Rs2buU9OwUDp9SnJRKP5najE7NFWkMxgtrYhK65sB919fYdfVERNyfotTWE # cfdXqq76iXHJmNKeWmR2vozDfRVqkfEU9PLZNTG423L6tHXIiJtqv5hFx2ay1//O # kpB15OvmhtLIG9snwFuVb0lvWF1pKt5TS/joynv2bBX5AxkPEYWqT5q/qlfdYMb1 # cSD0UaiayunR6zRHPXX6IuxVP2oZOWsQ6Vo/jvQjeDCy8qY4yzWNqphZJEC4Omek # B1+g/tg7SRP7DOHtC22DUM7wfz7g2QjojCFKQcLe645b7gPDHW5u5lQ1ZmdyfBrq # UvYixHI/rjCCBgcwggPvoAMCAQICCmEWaDQAAAAAABwwDQYJKoZIhvcNAQEFBQAw # XzETMBEGCgmSJomT8ixkARkWA2NvbTEZMBcGCgmSJomT8ixkARkWCW1pY3Jvc29m # dDEtMCsGA1UEAxMkTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # MB4XDTA3MDQwMzEyNTMwOVoXDTIxMDQwMzEzMDMwOVowdzELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEhMB8GA1UEAxMYTWljcm9zb2Z0IFRpbWUt # U3RhbXAgUENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn6Fssd/b # SJIqfGsuGeG94uPFmVEjUK3O3RhOJA/u0afRTK10MCAR6wfVVJUVSZQbQpKumFww # JtoAa+h7veyJBw/3DgSY8InMH8szJIed8vRnHCz8e+eIHernTqOhwSNTyo36Rc8J # 0F6v0LBCBKL5pmyTZ9co3EZTsIbQ5ShGLieshk9VUgzkAyz7apCQMG6H81kwnfp+ # 1pez6CGXfvjSE/MIt1NtUrRFkJ9IAEpHZhEnKWaol+TTBoFKovmEpxFHFAmCn4Tt # VXj+AZodUAiFABAwRu233iNGu8QtVJ+vHnhBMXfMm987g5OhYQK1HQ2x/PebsgHO # IktU//kFw8IgCwIDAQABo4IBqzCCAacwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E # FgQUIzT42VJGcArtQPt2+7MrsMM1sw8wCwYDVR0PBAQDAgGGMBAGCSsGAQQBgjcV # AQQDAgEAMIGYBgNVHSMEgZAwgY2AFA6sgmBAVieX5SUT/CrhClOVWeSkoWOkYTBf # MRMwEQYKCZImiZPyLGQBGRYDY29tMRkwFwYKCZImiZPyLGQBGRYJbWljcm9zb2Z0 # MS0wKwYDVQQDEyRNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmC # EHmtFqFKoKWtTHNY9AcTLmUwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC5t # aWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvbWljcm9zb2Z0cm9vdGNlcnQu # Y3JsMFQGCCsGAQUFBwEBBEgwRjBEBggrBgEFBQcwAoY4aHR0cDovL3d3dy5taWNy # b3NvZnQuY29tL3BraS9jZXJ0cy9NaWNyb3NvZnRSb290Q2VydC5jcnQwEwYDVR0l # BAwwCgYIKwYBBQUHAwgwDQYJKoZIhvcNAQEFBQADggIBABCXisNcA0Q23em0rXfb # znlRTQGxLnRxW20ME6vOvnuPuC7UEqKMbWK4VwLLTiATUJndekDiV7uvWJoc4R0B # hqy7ePKL0Ow7Ae7ivo8KBciNSOLwUxXdT6uS5OeNatWAweaU8gYvhQPpkSokInD7 # 9vzkeJkuDfcH4nC8GE6djmsKcpW4oTmcZy3FUQ7qYlw/FpiLID/iBxoy+cwxSnYx # PStyC8jqcD3/hQoT38IKYY7w17gX606Lf8U1K16jv+u8fQtCe9RTciHuMMq7eGVc # WwEXChQO0toUmPU8uWZYsy0v5/mFhsxRVuidcJRsrDlM1PZ5v6oYemIp76KbKTQG # dxpiyT0ebR+C8AvHLLvPQ7Pl+ex9teOkqHQ1uE7FcSMSJnYLPFKMcVpGQxS8s7Ow # TWfIn0L/gHkhgJ4VMGboQhJeGsieIiHQQ+kr6bv0SMws1NgygEwmKkgkX1rqVu+m # 3pmdyjpvvYEndAYR7nYhv5uCwSdUtrFqPYmhdmG0bqETpr+qR/ASb/2KMmyy/t9R # yIwjyWa9nR2HEmQCPS2vWY+45CHltbDKY7R4VAXUQS5QrJSwpXirs6CWdRrZkocT # dSIvMqgIbqBbjCW/oO+EyiHW6x5PyZruSeD3AWVviQt9yGnI5m7qp5fOMSn/DsVb # XNhNG6HY+i+ePy5VFmvJE6P9MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg # Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03 # a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr # rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg # OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy # 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9 # sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh # dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k # A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB # w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn # Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90 # lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w # ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o # ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD # VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa # BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny # bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG # AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV # HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG # AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl # AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb # C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l # hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6 # I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0 # wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560 # STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam # ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa # J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah # XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA # 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt # Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr # /Xmfwb1tbWrJUnMTDXpQzTGCBJwwggSYAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAAEDXiUcmR+jHrgAAAAAAQMwCQYFKw4DAhoFAKCB # sDAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYK # KwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUyAqajwv0qflANIoufqxjPJryGmsw # UAYKKwYBBAGCNwIBDDFCMECgFoAUAFAAbwB3AGUAcgBTAGgAZQBsAGyhJoAkaHR0 # cDovL3d3dy5taWNyb3NvZnQuY29tL1Bvd2VyU2hlbGwgMA0GCSqGSIb3DQEBAQUA # BIIBAAYLvHz4Y78qiu2U3a77j9BLefoxilLMsHQM2J5vwE8UKVCryIOer6+IJ04E # WPc0pEQmLlEj/zxrIxToUUjaMbia1SqQPi+AIdNXaAQOIrFEo6jjkyQzuB1NUblr # JwjuAm3VqOdYQz/+P22MUkdWQLMtXuwSC1F0v7qFO3JmzPjR7sWTstcbrvgsSLnT # J+P4OLTmyMrwO5IB7jn6jcIWF0veIojC7kkwjuYCOI6Ji2SFbVNpX/rHZiYMHJ9u # qk6hmPzRsghdp6KQxMESV/F8FYCG4hAwCIV7YB7JcjFByQ9kyyPjBVPryumVisxP # 4hYn4vP0ukICDa3eEC/Jhbe02uWhggIoMIICJAYJKoZIhvcNAQkGMYICFTCCAhEC # AQEwgY4wdzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV # BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEhMB8G # A1UEAxMYTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBAhMzAAAA82c9g2GYDxymAAAA # AADzMAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqG # SIb3DQEJBTEPFw0xODA5MjExNzMzNThaMCMGCSqGSIb3DQEJBDEWBBT9EBk1gX41 # 6vZYwGOWBjmeMctTeDANBgkqhkiG9w0BAQUFAASCAQCjK1d3zjIIzIEsfUWj3LqT # neb+hGWAHLQXttc2ITZPzDI7hU7FP+N+K8wDK3gUc6hMSka67ToPAiwuVhc3p36z # q2t4xNMuQSih7v3eAisNGpdFjKBas2IPaTnwUKwgd9ja5i/xW8WvDngXjRYY/T6o # pKr0icxtyzFUw6vi2MUeIQ5eMV4EQO2MCYTL4nd1q1sX2FpzK2OULhRsyF9g8d+e # FRSBAM5tfr9Dw+0QqOTb+wdlM9IGgywt8H1XgxgNWCTVaDDBwKPTj0DbmBf98YTS # 0gWW5Un0UiZuWiz3bjqrSmnOA1JisqQDJwC4A60WmSs8f9fAu4lX7pXooXLcv7E1 # SIG # End signature block |