AzurePSDrive.psm1
using namespace Microsoft.PowerShell.SHiPS using module .\AzurePSDriveResource.psm1 using module .\AzurePSDriveStorageAccount.psm1 using module .\AzurePSDriveVM.psm1 using module .\AzurePSDriveWebApp.psm1 $script:AzureRM_Profile = if($IsCoreCLR){'AzureRM.Profile.NetCore'}else{'AzureRM.Profile'} $script:AzureRM_Resources = if($IsCoreCLR){'AzureRM.Resources.Netcore'}else{'AzureRM.Resources'} $script:pathPattern = [System.IO.Path]::Combine('Azure:', '*', 'ResourceGroups', '*') $script:pathSeparator = if([System.IO.Path]::DirectorySeparatorChar -eq '\'){'\\'}else{'/'} # Automatically pick resource group when inside resourcegroups of Azure drive $Global:PSDefaultParameterValues['*-AzureRM*:ResourceGroupName'] = {if($pwd -like $script:pathPattern){($pwd -split $script:pathSeparator)[3]}} [SHiPSProvider(UseCache=$true)] class Azure : SHiPSDirectory { Azure([string]$name): base($name) { # Ensure Session is logged-on to access Azure resources # This is done in the constructor so that it is a runtime check and not done during module import. $context = (& "$script:AzureRM_Profile\Get-AzureRmContext") if ([string]::IsNullOrEmpty($($context.Account))) { throw "Ensure that session has access to Azure resources - use $script:AzureRM_Profile\Add-AzureRMAccount or $script:AzureRM_Profile\Login-AzureRMAccount" } } [object[]] GetChildItem() { $obj = @() $defaultTenantId = $null # Cloud Shell provides us with a default directory for Azure -> that maps to a tenant # This is provided in the form of tenantId in env variable ACC_TID if (-not $env:ACC_TID) { # Default tenantId not provided (perhaps provider is being run standalone => not in Cloud Shell) $tenant = (& "$script:AzureRM_Profile\Get-AzureRmTenant") if (($tenant -eq $null) -or ($tenant.Count -eq 0)) { throw ('Unable to obtain tenant for the account. Check your subscription to ensure there is at least one tenant') } # Use the first tenant, since this maps to the default directory chosen by the user via Portal $defaultTenantId = $tenant[0].Id Write-Verbose "Using TenantId '$($tenant[0].TenantId)'" Write-Verbose "To change default tenant: Use AzureRM.profile\Get-AzureRmTenant to retrieve your tenants corresponding to directories and set environment variable 'ACC_TID' to desired tenant" Write-Verbose "Reload AzurePSDrive provider OR use 'dir -Force' when navigating the subscription" } else { Write-Verbose "Using TenantId '$($env:ACC_TID)' from 'ACC_TID' environment variable..." $defaultTenantId = $env:ACC_TID } $subscriptions = $((& "$script:AzureRM_Profile\Get-AzureRmSubscription" -TenantId $defaultTenantId) | Sort-Object -Property Name) $subGroup = $subscriptions | Group-Object -Property Name foreach ($subscription in $subscriptions) { $obj += [Subscription]::new($subscription.Name, $subscription.Name, $subscription.Id, $subscription.TenantId, $subscription.State) } return $obj; } } [SHiPSProvider(UseCache=$true)] class Subscription : SHiPSDirectory { [string]$SubscriptionName = $null [string]$SubscriptionId = $null [string]$TenantId = $null [string]$State = $null Subscription ([string]$subNameWithTenantId, [string]$subName, [string]$subId, [string]$tenantId, [string]$state) : base ($subNameWithTenantId) { $this.SubscriptionName = $subName $this.SubscriptionId = $subId $this.TenantId = $tenantId $this.State = $state } [object[]] GetChildItem() { & "$script:AzureRM_Profile\Select-AzureRmSubscription" -SubscriptionName $this.SubscriptionName -TenantId $this.TenantId $obj = @() $obj+=[AllResources]::new(); $obj+=[ResourceGroups]::new("ResourceGroups", $this.SubscriptionName, $this.SubscriptionId, $this.TenantId, $this.State) $obj+=[StorageAccounts]::new(); $obj+=[VirtualMachines]::new(); $obj+=[WebApps]::new(); return $obj; } } [SHiPSProvider(UseCache=$true)] class ResourceGroups : SHiPSDirectory { [string]$SubscriptionName = $null [string]$SubscriptionId = $null [string]$TenantId = $null [string]$State = $null [object[]]$rgs ResourceGroups ([string]$name, [string]$subName, [string]$subId, [string]$tenantId, [string]$state) : base ($name) { $this.SubscriptionName = $subName $this.SubscriptionId = $subId $this.TenantId = $tenantId $this.State = $state } [object[]] GetChildItem() { #AzureRM.profile\Select-AzureRmSubscription -SubscriptionName $this.SubscriptionName -TenantId $this.TenantId $obj = @() $subId = $this.SubscriptionId @(& "$script:AzureRM_Resources\Get-AzureRmResourceGroup").Foreach{ $obj += [ResourceGroup]::new($subId, $_.ResourceGroupName, $_.Location, $_.ProvisioningState); } return $obj; } } [SHiPSProvider(UseCache=$true)] class ResourceGroup : SHiPSDirectory { [string]$SubscriptionId = $null [string]$ResourceGroupName = $null [string]$Location = $null [string]$ProvisioningState = $null ResourceGroup ([string]$subscriptionId, [string]$name, [string]$location, [string]$provisioningState) : base ($name) { $this.SubscriptionId = $subscriptionId $this.ResourceGroupName = $name $this.Location = $location $this.ProvisioningState = $provisioningState } [object[]] GetChildItem() { $obj = @() $resourceTypes = @(& "$script:AzureRM_Resources\Get-AzureRmResource" | Where-Object {$_.ResourceGroupName -eq $this.ResourceGroupName} | select-Object -Property ResourceType -Unique).ForEach{$_.ResourceType.Split('/')[0]} | Select-Object -Unique foreach ($resourceType in $resourceTypes) { $tempObj = [ResourceProvider]::new($resourceType, $this.ResourceGroupName); $obj += $tempObj } return $obj; } } [SHiPSProvider(UseCache=$true)] class ResourceProvider : SHiPSDirectory { [string]$providerNamespace = $null [string]$resourceGroupName = $null ResourceProvider([string]$name): base($name) { } ResourceProvider ([string]$name, [string]$resourceGroupName) : base ($name) { $this.providerNamespace = $name $this.resourceGroupName = $resourceGroupName } [object[]] GetChildItem() { $obj = @() $resourceTypeTokens = @() @(& "$script:AzureRM_Resources\Get-AzureRmResource" | Where-Object {$_.ResourceGroupName -eq $this.resourceGroupName} | Select-Object -Property ResourceType -Unique).ForEach{ $providerNS = $_.ResourceType.Split('/')[0] $resourceType = $_.ResourceType.Substring($_.ResourceType.IndexOf('/')+1) $resourceType = $resourceType.Replace('/','-') if ($this.providerNamespace -eq $providerNS) { $resourceTypeTokens += $resourceType } } foreach ($resourceTypeToken in ($resourceTypeTokens | Select-Object -Unique)) { $tempObj = [ResourceType]::new($resourceTypeToken, $this.providerNamespace, $this.resourceGroupName); $obj += $tempObj } return $obj; } } [SHiPSProvider(UseCache=$true)] class ResourceType : SHiPSDirectory { [string]$resourceTypeName = $null [string]$resourceType = $null [string]$resourceGroupName = $null [string]$providerNamespace = $null [object]$Properties = $null ResourceType([string]$name): base($name) { } ResourceType ([string]$name, [string]$providerNamespace, [string]$resourceGroupName) : base ($name) { $this.resourceTypeName = $name $this.resourceGroupName = $resourceGroupName $this.providerNamespace = $providerNamespace $this.resourceType = $providerNamespace + '/' + $this.resourceTypeName.Replace('-', '/') } [object[]] GetChildItem() { $obj = @() $azureRMResourceParams = @{'ResourceGroupName'="$($this.resourceGroupName)"} $azureRMResourceParams += @{'ResourceType'="$($this.resourceType)"} $azureRMResourceParams += @{'ExpandProperties'=$true} if ($this.ProviderContext.Filter) { $azureRMResourceParams += @{'ODataQuery'=(Get-ODataQueryFilter -filter $this.ProviderContext.Filter)} } @(& "$script:AzureRM_Resources\Get-AzureRmResource" @azureRMResourceParams).Foreach{ if ($_.PSTypeNames.Contains('Microsoft.Network.networkSecurityGroups')) { $typeName = $_.PSTypeNames[$_.PSTypeNames.IndexOf('Microsoft.Network.networkSecurityGroups')] foreach ($securityRule in $_.Properties.securityRules) { $tempObj = $securityRule 1..2 | ForEach-Object {$tempObj.PSTypeNames.RemoveAt(0)} $tempObj.PSTypeNames.Insert(0, $typeName + '.Rules') $obj += $tempObj } foreach ($defaultSecurityRule in $_.Properties.defaultSecurityRules) { $tempObj = $defaultSecurityRule 1..2 | ForEach-Object {$tempObj.PSTypeNames.RemoveAt(0)} $tempObj.PSTypeNames.Insert(0, $typeName + '.Rules') $obj += $tempObj } } elseif ($_.PSTypeNames.Contains('Microsoft.Network.routeTables')) { $typeName = $_.PSTypeNames[$_.PSTypeNames.IndexOf('Microsoft.Network.routeTables')] foreach ($route in $_.Properties.routes) { $tempObj = $route 1..2 | ForEach-Object {$tempObj.PSTypeNames.RemoveAt(0)} $tempObj.PSTypeNames.Insert(0, $typeName + '.routes') $obj += $tempObj } } else { $tempObj = $_ 1..2 | ForEach-Object {$tempObj.PSTypeNames.RemoveAt(0)} $obj += $tempObj } } return $obj; } } #region Utilities # Given the filter string, return corresponding OData query filter in the format '$filter=<Name> <operator> <Value>' # Else, return null for invalid cases function Get-ODataQueryFilter { [OutputType([string])] param ( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $filter ) if ('*' -eq $filter) { return $null } if ($filter.Contains('*')) { if ($filter.StartsWith('*') -and $filter.EndsWith('*')) { return "`$filter=substringof(Name, $filter.Replace('*', '')) eq true" } elseif ($dynamicParameters.Filter.StartsWith('*') -and (-not $dynamicParameters.Filter.EndsWith('*'))) { return "`$filter=EndsWith(Name, $filter.Replace('*', ''))" } elseif ($dynamicParameters.Filter.EndsWith('*') -and (-not $dynamicParameters.Filter.StartsWith('*'))) { return "`$filter=StartsWith(Name, $filter.Replace('*', ''))" } else { $filterTokens = $filter.Split('*') return "`$filter=StartsWith(Name, $filterTokens[0])" } } return $null } #endregion # SIG # Begin signature block # MIIjOQYJKoZIhvcNAQcCoIIjKjCCIyYCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU38BKJWKt13ADatMwxjBrUnW1 # GvOggh4HMIIE2jCCA8KgAwIBAgITMwAAAOdIFbo9kmu+3AAAAAAA5zANBgkqhkiG # 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTgwMTMxMTkwMzA5 # WhcNMTgwOTA3MTkwMzA5WjCByjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAw # DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x # LTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEm # MCQGA1UECxMdVGhhbGVzIFRTUyBFU046QTI0MC00QjgyLTEzMEUxJTAjBgNVBAMT # HE1pY3Jvc29mdCBUaW1lLVN0YW1wIHNlcnZpY2UwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQDMp9j7gZ5MlOq2SDpndZh+CYb9vq30TqocAVEDAcvH2v9J # mJU6VemqWp+5Rn/5stiWlACt2KOXzjwmvJTYfFsXS9E4OFWj2okRtlcIxZhrs2Km # FLqiZgGA0VR1wC1HWX4dSEqlLOI6hKi7VF2ieP4ihT6ESO3pSnzCoEpEeRG6eHds # tIxdoJ2BQBYg47NPD8XjOXPCpQTG7Q1eDEGBaeCIDW7hU/OPEM92Q9qlIFeMj7ok # 0f0EsBeSSuFnlyM63wWUIcr4VlAluqF1eFWOgmaFKgYfBQs77/upDY4N9PtIV+pA # Kvw53l31/wZCRFcR2n/YV1Uvt1wTWvH4Bqsg07c5AgMBAAGjggEJMIIBBTAdBgNV # HQ4EFgQUrbvUvBXRCTGrDOnDJeleAuatctwwHwYDVR0jBBgwFoAUIzT42VJGcArt # QPt2+7MrsMM1sw8wVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5taWNyb3Nv # ZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljcm9zb2Z0VGltZVN0YW1wUENBLmNy # bDBYBggrBgEFBQcBAQRMMEowSAYIKwYBBQUHMAKGPGh0dHA6Ly93d3cubWljcm9z # b2Z0LmNvbS9wa2kvY2VydHMvTWljcm9zb2Z0VGltZVN0YW1wUENBLmNydDATBgNV # HSUEDDAKBggrBgEFBQcDCDANBgkqhkiG9w0BAQUFAAOCAQEAYBRDItxtl0ET2whe # bDv6AXIO9f+YnQ6h4R3eEuJcgv/om3NtSylJzN8X1h1c3XEAZDUSfNXvKwpn4hpk # l3GL4o1zlKcYHZMfFp6xCFOTHh0EN4ZAmW0gh1m60Kv9v98BNfPKyXDA9mgNiQtw # 3I+HISmm2EH8zb6uUPLS7C27fH0JjAKMrcxZDcJK6rTFse2Al8aZrY7RA4yJhDC6 # GoIsPPxe74LGsef3Lg505bT9V1bSguIR+/xJeoMmQEGp64Yn+/aIkQ8QvbQHsHlX # Xok1BhjQ24EB5A65qLmDeabhgwXBmAwuPRJxKKTLeCGosjIzMyF+wKNSIAi8bz1Z # R2/+MzCCBZkwggOBoAMCAQICEHmtFqFKoKWtTHNY9AcTLmUwDQYJKoZIhvcNAQEF # BQAwXzETMBEGCgmSJomT8ixkARkWA2NvbTEZMBcGCgmSJomT8ixkARkWCW1pY3Jv # c29mdDEtMCsGA1UEAxMkTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9y # aXR5MB4XDTAxMDUwOTIzMTkyMloXDTIxMDUwOTIzMjgxM1owXzETMBEGCgmSJomT # 8ixkARkWA2NvbTEZMBcGCgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMk # TWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIICIjANBgkqhkiG # 9w0BAQEFAAOCAg8AMIICCgKCAgEA8136gGfUWqepDCyQINA1CDx1hM23B4mcidre # zsNg+pFoWp6UcSkYdnzC4MgldpQOWPoENDbm36/3gLrpWAsrk+WdBeN3IpH3NGQ8 # IpEdXuEJkLwU/vx1WBnhebcHkqOuiFkI2J8HygNY/GgpbTLX0qjLS/zhC0gyT+br # uK1P5FxvE5SZ25XVdduoGreUkbR3W/VIDI9qeX0UcAR9ba+Q9dpw2Ee3v5svbOcF # t+ERYKx5kRR8xdam5OF+1cN+5ZLSPAC1NoLeeeFt87Vu+J8zyctSfXOYNtuLoWui # lZebo97CTSb/BpZnJQbI56zk7hIzlTGZyDUITjTKeVPVtb5jMllANsClTgRNPdtb # BzPkWL/vP1Nk2EJZNVf9D0V8JARNntY4dBGXIpDOaER0km/VS2+whuPHNkKg0PzB # wFr5o2G5MEdxlgoWsJHAQpXvEH8oauMqH7HkzQM/d3EExyD8SQ8dRYik18t+iK2O # LexF28RRBMkq/OyGnpoRl1vezlOI5uK3/ayVwihA2+8EkN+BMznZskWlI4cGpVWJ # MbsGLWAOQRh9Hy61l8sR6xXVJKWU7xUUif1Lc/oyW/zRMwD5WWJwBzLqLqtALXvK # 3SFnGzCZjxaqI6hB0bBuEZs2xN5AdJzhWGXBYB56WzjIj7sEJnzUFkDltmtsqob9 # AL/OwTUCAwEAAaNRME8wCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD # VR0OBBYEFA6sgmBAVieX5SUT/CrhClOVWeSkMBAGCSsGAQQBgjcVAQQDAgEAMA0G # CSqGSIb3DQEBBQUAA4ICAQDFEU0DOmDdXVIRd4+yuzbIsgW/tLeo2CCdXBMDthwi # +gYTNbbIY9SaR28mV9JV8QSxJl/WqVBooLzSuG7Mw+ms3xnNeKxZdKxmNDbEGz5s # OEwzDjASDaMm/lFTAP+vWk6EDQ8f5G0FLk6FS41sM29U0mSrv1CvfXo5oDftYwMP # /BMGzhY21FQ7lRtRYjrlTRfUBTmSmieoW6q97Lu+4yCJYHFsVrOlE9BtDiN+lQPt # aD3y2GO4a0226DC14cqUS/eiql2ZMLI9p8JRbCggASQnK0sAt50Ra3C+shCCvAyb # aNCNOySHqpkocp0zX1mQvfXek546Ylo0OeKIVR25BrDBiWst12nDGRI2hNDJoNr/ # L2l4suV62uvXDMD3vWMXuDkTOKI2W3vyhVZqHWRiwTjiqr9RZqKU9RKcZiIQa/K3 # MJIt8inwPTsUQ2ii8ZwpN8vOOCAlbXxn834kEiQDCIFH7KWel/UY18+71e92lu/9 # zttWnZWgQvmXWOHXMSLTX1nmPm4iAOpDhLYl29nzCFZowGRrHXzstpOiYlduLtjn # WI/EMUkm3d4pNYf1MHFwWxQ8ab2JEn3rLqP+2H+eglpSCivBQyvZMIifyBD7iY3m # oYV1M35snttzE2RiaaUvfcqWbZ/4BE0wkj1uIRQhyT3gw/2Ka51K/dGhnZlDdz+w # 2jCCBf8wggPnoAMCAQICEzMAAAEDXiUcmR+jHrgAAAAAAQMwDQYJKoZIhvcNAQEL # BQAwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT # B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UE # AxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMTAeFw0xODA3MTIyMDA4 # NDhaFw0xOTA3MjYyMDA4NDhaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xHjAcBgNVBAMTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjCCASIwDQYJ # KoZIhvcNAQEBBQADggEPADCCAQoCggEBANGUdjbmhqs2/mn5RnyLiFDLkHB/sFWp # JB1+OecFnw+se5eyznMK+9SbJFwWtTndG34zbBH8OybzmKpdU2uqw+wTuNLvz1d/ # zGXLr00uMrFWK040B4n+aSG9PkT73hKdhb98doZ9crF2m2HmimRMRs621TqMd5N3 # ZyGctloGXkeG9TzRCcoNPc2y6aFQeNGEiOIBPCL8r5YIzF2ZwO3rpVqYkvXIQE5q # c6/e43R6019Gl7ziZyh3mazBDjEWjwAPAf5LXlQPysRlPwrjo0bb9iwDOhm+aAUW # nOZ/NL+nh41lOSbJY9Tvxd29Jf79KPQ0hnmsKtVfMJE75BRq67HKBCMCAwEAAaOC # AX4wggF6MB8GA1UdJQQYMBYGCisGAQQBgjdMCAEGCCsGAQUFBwMDMB0GA1UdDgQW # BBRHvsDL4aY//WXWOPIDXbevd/dA/zBQBgNVHREESTBHpEUwQzEpMCcGA1UECxMg # TWljcm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xFjAUBgNVBAUTDTIzMDAx # Mis0Mzc5NjUwHwYDVR0jBBgwFoAUSG5k5VAF04KqFzc3IrVtqMp1ApUwVAYDVR0f # BE0wSzBJoEegRYZDaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwv # TWljQ29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNybDBhBggrBgEFBQcBAQRVMFMw # UQYIKwYBBQUHMAKGRWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy # dHMvTWljQ29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNydDAMBgNVHRMBAf8EAjAA # MA0GCSqGSIb3DQEBCwUAA4ICAQCf9clTDT8NJuyiRNgN0Z9jlgZLPx5cxTOjpMNs # rx/AAbrrZeyeMxAPp6xb1L2QYRfnMefDJrSs9SfTSJOGiP4SNZFkItFrLTuoLBWU # KdI3luY1/wzOyAYWFp4kseI5+W4OeNgMG7YpYCd2NCSb3bmXdcsBO62CEhYigIkV # hLuYUCCwFyaGSa/OfUUVQzSWz4FcGCzUk/Jnq+JzyD2jzfwyHmAc6bAbMPssuwcu # loSTRShUXM2W/aDbgdi2MMpDsfNIwLJGHF1edipYn9Tu8vT6SEy1YYuwjEHpqrid # kPT/akIPuT7pDuyU/I2Au3jjI6d4W7JtH/lZwX220TnJeeCDHGAK2j2w0e02v0UH # 6Rs2buU9OwUDp9SnJRKP5najE7NFWkMxgtrYhK65sB919fYdfVERNyfotTWEcfdX # qq76iXHJmNKeWmR2vozDfRVqkfEU9PLZNTG423L6tHXIiJtqv5hFx2ay1//OkpB1 # 5OvmhtLIG9snwFuVb0lvWF1pKt5TS/joynv2bBX5AxkPEYWqT5q/qlfdYMb1cSD0 # UaiayunR6zRHPXX6IuxVP2oZOWsQ6Vo/jvQjeDCy8qY4yzWNqphZJEC4OmekB1+g # /tg7SRP7DOHtC22DUM7wfz7g2QjojCFKQcLe645b7gPDHW5u5lQ1ZmdyfBrqUvYi # xHI/rjCCBgcwggPvoAMCAQICCmEWaDQAAAAAABwwDQYJKoZIhvcNAQEFBQAwXzET # MBEGCgmSJomT8ixkARkWA2NvbTEZMBcGCgmSJomT8ixkARkWCW1pY3Jvc29mdDEt # MCsGA1UEAxMkTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X # DTA3MDQwMzEyNTMwOVoXDTIxMDQwMzEzMDMwOVowdzELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjEhMB8GA1UEAxMYTWljcm9zb2Z0IFRpbWUtU3Rh # bXAgUENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn6Fssd/bSJIq # fGsuGeG94uPFmVEjUK3O3RhOJA/u0afRTK10MCAR6wfVVJUVSZQbQpKumFwwJtoA # a+h7veyJBw/3DgSY8InMH8szJIed8vRnHCz8e+eIHernTqOhwSNTyo36Rc8J0F6v # 0LBCBKL5pmyTZ9co3EZTsIbQ5ShGLieshk9VUgzkAyz7apCQMG6H81kwnfp+1pez # 6CGXfvjSE/MIt1NtUrRFkJ9IAEpHZhEnKWaol+TTBoFKovmEpxFHFAmCn4TtVXj+ # AZodUAiFABAwRu233iNGu8QtVJ+vHnhBMXfMm987g5OhYQK1HQ2x/PebsgHOIktU # //kFw8IgCwIDAQABo4IBqzCCAacwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU # IzT42VJGcArtQPt2+7MrsMM1sw8wCwYDVR0PBAQDAgGGMBAGCSsGAQQBgjcVAQQD # AgEAMIGYBgNVHSMEgZAwgY2AFA6sgmBAVieX5SUT/CrhClOVWeSkoWOkYTBfMRMw # EQYKCZImiZPyLGQBGRYDY29tMRkwFwYKCZImiZPyLGQBGRYJbWljcm9zb2Z0MS0w # KwYDVQQDEyRNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCEHmt # FqFKoKWtTHNY9AcTLmUwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC5taWNy # b3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvbWljcm9zb2Z0cm9vdGNlcnQuY3Js # MFQGCCsGAQUFBwEBBEgwRjBEBggrBgEFBQcwAoY4aHR0cDovL3d3dy5taWNyb3Nv # ZnQuY29tL3BraS9jZXJ0cy9NaWNyb3NvZnRSb290Q2VydC5jcnQwEwYDVR0lBAww # CgYIKwYBBQUHAwgwDQYJKoZIhvcNAQEFBQADggIBABCXisNcA0Q23em0rXfbznlR # TQGxLnRxW20ME6vOvnuPuC7UEqKMbWK4VwLLTiATUJndekDiV7uvWJoc4R0Bhqy7 # ePKL0Ow7Ae7ivo8KBciNSOLwUxXdT6uS5OeNatWAweaU8gYvhQPpkSokInD79vzk # eJkuDfcH4nC8GE6djmsKcpW4oTmcZy3FUQ7qYlw/FpiLID/iBxoy+cwxSnYxPSty # C8jqcD3/hQoT38IKYY7w17gX606Lf8U1K16jv+u8fQtCe9RTciHuMMq7eGVcWwEX # ChQO0toUmPU8uWZYsy0v5/mFhsxRVuidcJRsrDlM1PZ5v6oYemIp76KbKTQGdxpi # yT0ebR+C8AvHLLvPQ7Pl+ex9teOkqHQ1uE7FcSMSJnYLPFKMcVpGQxS8s7OwTWfI # n0L/gHkhgJ4VMGboQhJeGsieIiHQQ+kr6bv0SMws1NgygEwmKkgkX1rqVu+m3pmd # yjpvvYEndAYR7nYhv5uCwSdUtrFqPYmhdmG0bqETpr+qR/ASb/2KMmyy/t9RyIwj # yWa9nR2HEmQCPS2vWY+45CHltbDKY7R4VAXUQS5QrJSwpXirs6CWdRrZkocTdSIv # MqgIbqBbjCW/oO+EyiHW6x5PyZruSeD3AWVviQt9yGnI5m7qp5fOMSn/DsVbXNhN # G6HY+i+ePy5VFmvJE6P9MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkqhkiG # 9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO # BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEy # MDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw # MTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29k # ZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC # AgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03a8YS # 2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akrrnoJ # r9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0RrrgOGSs # bmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy4BI6 # t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9sbKv # kjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAhdCVf # GCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8kA/DR # elsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTBw3J6 # 4HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmnEyim # p31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90lfdu # +HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0wggHp # MBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2oynUC # lTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0T # AQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBaBgNV # HR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9w # cm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsGAQUF # BwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3Br # aS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNVHSAE # gZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5t # aWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsGAQUF # BwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABlAG0A # ZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKbC5YR # 4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11lhJB9 # i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6I/MT # faaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0wI/z # Rive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560STkK # xgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQamASoo # PoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGaJ+HN # pZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ahXJbY # ANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA9Z74 # v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33VtY5E9 # 0Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr/Xmf # wb1tbWrJUnMTDXpQzTGCBJwwggSYAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTECEzMAAAEDXiUcmR+jHrgAAAAAAQMwCQYFKw4DAhoFAKCBsDAZ # BgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYB # BAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUw/0QYL/JUsxiBvA5pjl8cKGHEIgwUAYK # KwYBBAGCNwIBDDFCMECgFoAUAFAAbwB3AGUAcgBTAGgAZQBsAGyhJoAkaHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL1Bvd2VyU2hlbGwgMA0GCSqGSIb3DQEBAQUABIIB # ALcQjliyIRXdC6rzGIPaUxCldNFx1+Z0b2lhUdauqRg+lcx6GJl6HKhsf+DhjAPg # ki4jQm4V/GfunmjAM4SjBVVnyJuiiEyyNPMpm1Ef9aLD0j8VBTYp21BxMGDXMOcx # gzpj86qsOwreiyLYc/gyJavNMRE5eQMD4uqOwQUCNNaWwle50Tj+r/q+S3q4XFWp # qdqJG3yOuSoGCBP1Bs6/+5QMQirSj7tGvR01Pyo5Wf+21d2O8cVGvbjg0rC1x31i # uR/ChFZCdYggJcDblLx0ZlbPKlgdHZvqEZ7hpQywI8baXlQal//cRCfBCZ0PTwVo # xPSuHMukVdFJVa7uZ+g68CGhggIoMIICJAYJKoZIhvcNAQkGMYICFTCCAhECAQEw # gY4wdzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT # B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEhMB8GA1UE # AxMYTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBAhMzAAAA50gVuj2Sa77cAAAAAADn # MAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3 # DQEJBTEPFw0xODA3MTcyMjUwMDJaMCMGCSqGSIb3DQEJBDEWBBQclpa3egr47+dp # 3XUXem0TOqqqLjANBgkqhkiG9w0BAQUFAASCAQC9uJo7nqjTJnBWOPzraIkYLzE2 # CYhk5KXZru/tvk9yE456uE5+9UQ0i8nmryeXmwlPOCP//d69xynCRJ8ou7QvCeJS # isuoF3pISD+J2Ep0Rx8n4wKSQQ/Xv3fbKSTfvv67fxNYzaAZR7s4/X3451iwJYeG # 1i4bZUXmuDNPbzlZWG9q78RuArr2IEP+D154miO3KyCBxaPyRifkywDQIYTH73Zo # gkI3pYf5IYvc1/UsBkNWgy7fwHqtuwlFgAQ0RMHOrtGl9QnorWwADo0q2hxlMJT4 # dr82d3+zzizj+qCAw2nMXPUlh1gd39lTyXDPt8xex5gQnS3NYrtbCXpsmMRA # SIG # End signature block |