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 # MIIjigYJKoZIhvcNAQcCoIIjezCCI3cCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA6vFNCrDk3a1xk # GBS+P4DNPs1cmAPU2getLWungVtWtKCCDYUwggYDMIID66ADAgECAhMzAAABBGni # 27n7ig2DAAAAAAEEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMTgwNzEyMjAwODQ5WhcNMTkwNzI2MjAwODQ5WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQCbxZXyl/b/I2psnXNZczib07TjhK2NuD4l56C4IFpKkXA42BSovZrA/Q1rHuzh # /P8EPOJhYK5VamGS+9cAfZ7qaTbW/Vd5GZf+hJH2x1Wtpq4Ciu2xkUdWzUqHZkWn # MBsa7ax7awXSM4JzvsZvHMzU6BoFFQAukZe2S8hhZyKL5xMSaMIXFK8mWrbuVXN8 # 9USzIScGAOu1Nvn8JoqtP39EFMN6uyPIi96+ForBIaICAdl/mJLiMVOPh7GQJJsX # +hVNygFsEGxSAqKTX2IDQSSMcKdwLI1LL9czWVz9XeA/1+SEF7t9PnnTgkNiVEDI # m17PcBQ7YDxpP5835/gWkjOLAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUuhfjJWj0u9V7I6a4tnznpoKrV64w # VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh # dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzQzNzk2NjAfBgNVHSMEGDAW # gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw # MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx # XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB # ACnFggs5mSAM6CRbiTs4UJKDlduR8jvSpPDagVtzjmdIGrbJigd5WmzOw/xmmBey # u9emFrUDVoV7Kn0vQAZOnmnXaRQVjmP7zID12xGcUO5LAnFMawcF/mdT8Rm2bm4s # 8o/URSnhNgiyHHiBJ5aHmUIYd5TcxrydpNtWpjbQQ0hfQAR+Z+mI2ADH6zL/3gp3 # YANz/p6hxx3zwLMtYYfI8TeF3PxtPEsTShJ2tVBKTedd808h5JgSgYH+6Vyo/BSM # 0QKfZft2dbdiU8d92se6QuJueyZKI4Iy2I11HhFvi396BtWqHxilcBPn7midB7wG # 6YkDlgxq4iGrJQPYtwER4cQilikxfMNVTtAc50XGZgCKFSHExQFwHeJoATkPIiHJ # qHN/cNgs9PVp5UlsOaWiqcp7OdX5d28wc4OWwKOLruV/3WNN2hXLe/kd5Y7EOqpK # 9C1FZp/yXrhJFznj3x1JiWGLujOvXkLqGtT1UVPxpV2Sm4dnuHarBlXhrtWDrzn/ # IDGLXOb6tQfPhifHQQIjOW1ZTi7AeK86SWNs4njgI3bUK6hnADxlUlgw0njpeO3t # uyl9oh845exZx5OZRfkAiMpEekfWJkfN1AnCtXqQDD0WFn63lNtGUgBKHrk9aclR # ZWrVPxHELTeXX5LCDTEMmtZZd/BQSIeJdpPY831KsCLYMIIHejCCBWKgAwIBAgIK # YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm # aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw # OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD # VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG # 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la # UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc # 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D # dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+ # lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk # kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6 # A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd # X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL # 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd # sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3 # T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS # 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI # bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL # BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD # uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv # c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF # BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h # cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA # YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn # 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7 # v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b # pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/ # KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy # CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp # mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi # hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb # BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS # oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL # gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX # cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCFVswghVXAgEBMIGVMH4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p # Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAEEaeLbufuKDYMAAAAA # AQQwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIFI7 # NS/eL7J0HTF0r/Qsw6vwkP6WVNc3dedQIHWB9aimMEIGCisGAQQBgjcCAQwxNDAy # oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20wDQYJKoZIhvcNAQEBBQAEggEAKkfGP20giCIOz2xu/jNsLYzLnYxLKM0pfQY7 # SMbHDVXRd2vmT/HPPPSjwq79X9lTOnbghgF2qv9RgyW6R0ZYLg9D4r5FVS6vA8hN # aEUpwKSRJF4CqVI8VRHwLLxtNvoRPd7UIeWmFb1uDnGKkmzLnwy6Qgu48Vm8k4Ot # Zjg9XNa9qWa6oWlptgmZ/Mveo5JL2H6RaKiihSiO31ql3m7e3P61If5hj+O73g5v # MD1jy8jF5snRekk4Icezltm5i7gfJwXm2YcBKVNHJS8ngIjdt/e1159YGeQvis7I # vqjKQ/mLo+jMiTCIEH1PZe1QY/EJFq8HWEFcB07gKa2XRYT+LKGCEuUwghLhBgor # BgEEAYI3AwMBMYIS0TCCEs0GCSqGSIb3DQEHAqCCEr4wghK6AgEDMQ8wDQYJYIZI # AWUDBAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGE # WQoDATAxMA0GCWCGSAFlAwQCAQUABCCW7oXbvIp4mxCBCF7vv/rGTPMxeJZ8XkJC # SeAV2BHDRgIGW/4KdtE7GBMyMDE4MTIxNzIzMjgxOC43MTdaMASAAgH0oIHQpIHN # MIHKMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9z # b2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMg # VFNTIEVTTjpBQjQxLTRCMjctRjAyNjElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt # U3RhbXAgc2VydmljZaCCDjwwggTxMIID2aADAgECAhMzAAAA3IYTqAXYFYtHAAAA # AADcMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw # MB4XDTE4MDgyMzIwMjY1NFoXDTE5MTEyMzIwMjY1NFowgcoxCzAJBgNVBAYTAlVT # MQswCQYDVQQIEwJXQTEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z # b2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVy # YXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOkFCNDEtNEIy # Ny1GMDI2MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBzZXJ2aWNlMIIB # IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsPoXEjCNi8qS6Ww/tsTyq7Cb # dVKtpLF3QAbbQREFjmJ056Ggpzww68gwVJPKfxeXilueif7SmoYEUk/Ngm933VFz # oPfypWRMGAps+z1lPlfGZrgpsENMstKZzCz+oHjP9GV1vhebyF1yqmZ1EmwU08vy # XFcVcb7AQQsxX66/3HZEOezWQNBBxUR97v5AC4+GbE3MzYR5O3uIXIxatf/QE4pG # 9d1RZLMtLA/469WC5A+icvvI1dDJ41TKdcFp0c5adZThiT3XNlzO6bDoao2WhAXu # GLxDAKOkQ1zLDBKqm9NvkrjJ4ePHr6p20budDC6A0Ch1MFUwjsy3dp8P0qvslwID # AQABo4IBGzCCARcwHQYDVR0OBBYEFDrVvNEDVZ0OHNlKXJJ+dLgqaZieMB8GA1Ud # IwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0 # dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0 # YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKG # Pmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENB # XzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUH # AwgwDQYJKoZIhvcNAQELBQADggEBABwtIuWSLIAHwv0ne3ECr5kwzT6+64FXiqql # zFn0H75BQJruK+hgQzFy+8CWQfMJnzCnNi1YuEmIg2YpeHtGFj3CHa+p/sXztD7A # hKa+zT2z7bbo4vTrHnTCXya85tRhLzkW3q35z3v5x10S1UnfyKnVxUc0GWe2tpa2 # ttV29HyQQRL3Gn0+r1+F5YdrSqfNWgzUByszs2ZZUj7zLh7mMo/uknS3hdqz3lyE # KV8lIHrrY5w4+qX5yoteErJpyS7MSo29Bh0tzX5ArWKvK2oLPHeWvTsq8RYjZ4Vj # jMB1foXnysntWnrCt9EcYu3GzHDUBN9+K/62glOhRjx3F1p4LvgwggZxMIIEWaAD # AgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzET # MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV # TWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBD # ZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3 # MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw # DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x # JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkq # hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWl # CgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/Fg # iIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeR # X4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/Xcf # PfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogI # Neh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB # 5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvF # M2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAP # BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjE # MFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kv # Y3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEF # BQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w # a2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8E # gZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5t # aWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcC # AjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUA # bgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Pr # psz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOM # zPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCv # OA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v # /rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99 # lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1kl # D3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQ # Hm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30 # uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp # 25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HS # xVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi6 # 2jbb01+P3nSISRKhggLOMIICNwIBATCB+KGB0KSBzTCByjELMAkGA1UEBhMCVVMx # CzAJBgNVBAgTAldBMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv # ZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh # dGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046QUI0MS00QjI3 # LUYwMjYxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIHNlcnZpY2WiIwoB # ATAHBgUrDgMCGgMVAHgq8wD2Onemka/iTyB8ERMyTtcdoIGDMIGApH4wfDELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z # b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDfwj3qMCIY # DzIwMTgxMjE3MjMyMzIyWhgPMjAxODEyMTgyMzIzMjJaMHcwPQYKKwYBBAGEWQoE # ATEvMC0wCgIFAN/CPeoCAQAwCgIBAAICITgCAf8wBwIBAAICEXwwCgIFAN/Dj2oC # AQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEK # MAgCAQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQALtFChe9uyGzybsrB1Vb2ZJiE0 # 4S0v103NcLFWu/aHAjiRAjSiMdhAH3d+mtThn6Ln67IQ7ZFg9fLEaS4Y+M2ip3Q6 # pKx2szqv7M2Pdo8kxX+JWlQuvJ9WQYlSG9eWl9wWfgD/CzzHacmoy4pRYzjwEsOX # /4uKUgrN/3fP3gjnSjGCAw0wggMJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w # IFBDQSAyMDEwAhMzAAAA3IYTqAXYFYtHAAAAAADcMA0GCWCGSAFlAwQCAQUAoIIB # SjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIM3m # O56+8pCVGKSUJuUo97ddQpKmdT1sf0L6ER33y2EaMIH6BgsqhkiG9w0BCRACLzGB # 6jCB5zCB5DCBvQQgG8/ujUiuMWjU8VCLYM12DSowo3Js7CpNKIQ7Etnarl0wgZgw # gYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD # VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAANyGE6gF2BWL # RwAAAAAA3DAiBCBYNB/2oYjWku7c6+QnUwOeqnWRG9BRs9E8rWewDH/XMjANBgkq # hkiG9w0BAQsFAASCAQBxrAY3/TeWAdTGcs9CBGeIWtuDQ6O+Qsl8f9a/UHZta44A # DhLTFmO8EtQhZPSXoYCL/znOyhKgS2Wpl0xNHvQNhxo3hfgRjhfLFaxs4nqRmiiw # EBEt5lRXF9JLfLCR1Fa7VAaspDTAr149l7veNzVUh6oLZNDyD5GVy1/ir+cFg4/h # kJI7MhPLKZ2zCTs1fRdijclqKY/NE9yYrFihIdsC7I1nMu91pCGpvpVYmu6THVbY # rQt7g8Uw5CBHk2qsltDJZRf/OPaAE+E++9rkQSPrw6HPChbyzLT14neti7AbFLhb # PNEKvP1TYzSHflFnO4SU/2i8z2FJVeTmNmgZv6l4 # SIG # End signature block |