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'} # Automatically pick resource group when inside resourcegroups of Azure drive $Global:PSDefaultParameterValues['*-AzureRM*:ResourceGroupName'] = {if($pwd -like 'Azure:\*\ResourceGroups\*'){($pwd -split '\\')[3]}} [SHiPSProvider(UseCache=$true)] class Azure : SHiPSDirectory { Azure([string]$name): base($name) { } [object[]] GetChildItem() { $obj = @() $defaultTenantId = $null # CloudShell 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 cloudshell) $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 atleast 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 $azureRMResourceParams = @{'ResourceId'="/subscriptions/$subId/resourceGroups"} if ($this.ProviderContext.Filter) { $azureRMResourceParams += @{'ODataQuery'=(Get-ODataQueryFilter -filter if($this.ProviderContext.Filter))} } @(& "$script:AzureRM_Resources\Get-AzureRmResource" @azureRMResourceParams).Foreach{ $obj += [ResourceGroup]::new($subId, $_.Name, $_.Location, $_.Properties.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 # MIIarQYJKoZIhvcNAQcCoIIanjCCGpoCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUkaOl5RFkCO+iz4t4f8mZ1+Lf # w6SgghWAMIIEwjCCA6qgAwIBAgITMwAAAL6kD/XJpQ7hMAAAAAAAvjANBgkqhkiG # 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTYwOTA3MTc1ODQ5 # WhcNMTgwOTA3MTc1ODQ5WjCBsjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw # b3JhdGlvbjEMMAoGA1UECxMDQU9DMScwJQYDVQQLEx5uQ2lwaGVyIERTRSBFU046 # ODQzRC0zN0Y2LUYxMDQxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNl # cnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCROfFjRVxKmgTC # tN14U6jxq1vAK7TBi39qS2BIU56Xw1IeOFNjg7bw6O8DMLr04Ghia8ath6lj3yab # PSyXiYULrfk/7PkLUAqDbr6CFA/kuvoLYmePEgYKgI2vtruq05MABGYyw4WpUfLt # chCNiBYWawyrdeHaw80xvfUrb7cDAU8st94bIkgyboaDN7f3oIzQHqyxok8XSSaZ # JKTyqNtEtDo7p6ZJ3ygCa98lCk/SjpVnLkGlX0lJ3y/H2FM28gNnfQZQO8Pe0ICv # 3KCpi4CPqx9LEuPgQoJrYK573I1LJlbjTV+l73UHPbo2w40W9L1SGu5UWrwNb6tZ # qk4RwEvJAgMBAAGjggEJMIIBBTAdBgNVHQ4EFgQUHG4NXaJsQp0+3x29Li7nwpc0 # kH8wHwYDVR0jBBgwFoAUIzT42VJGcArtQPt2+7MrsMM1sw8wVAYDVR0fBE0wSzBJ # oEegRYZDaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv # TWljcm9zb2Z0VGltZVN0YW1wUENBLmNybDBYBggrBgEFBQcBAQRMMEowSAYIKwYB # BQUHMAKGPGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljcm9z # b2Z0VGltZVN0YW1wUENBLmNydDATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkqhkiG # 9w0BAQUFAAOCAQEAbmBxbLeCqxsZFPMYFz/20DMP8Q12dH/1cNQursRMH0Yg0cTw # Ln1IF3DGypfHZJwbyl9HWNVf+2Jq05zMajfjxiEu+khzmMnA9/BJ1utPwR0nPyyL # bN+0IGBMfYLeIAdC81e0CW9TpWpc6lH/jgWbhviUt4Mvt2DQMWIQ7WwJAdBeGjCn # tLINPxC9RmHysFGexMsXS+hYNR2z/h/PmvsNwhq7CtM6bM71ZvYFaBSCmtdQ8/KQ # CPiN6acb2V/28VuZEwjq3GFAJfcKMvhssewRgCYsKxhvWZHUkBrUxWnsvxNCOWPp # enBiVSYl5nT9jBoVoTDChMITR35gr//DmhzXszCCBOswggPToAMCAQICEzMAAAF4 # JVq1zSPGX5UAAQAAAXgwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjEjMCEGA1UEAxMaTWljcm9zb2Z0IENvZGUgU2ln # bmluZyBQQ0EwHhcNMTcwODExMjAxMTE1WhcNMTgwODExMjAxMTE1WjCBgjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEMMAoGA1UECxMDQU9DMR4w # HAYDVQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQCZbh1TVaudsrIbXUPPB9c8S+E+dKSbskHKYlG6SGTH8jhT # hpuvGiAO87F2b9GHVN+DvszaMkGy/xQgHaGEJLfpnb3kpakic7E0bjDHdG4KnHRb # no/wfUkGLfS79o+cw//RY8Ck6yE+0czDBcxp0Gbw5JyGP+KFqvzRR/3Tv3nt/5x0 # 5ZnEOHYP+eDVikDvn/DH+oxxtiCfX3tkvtm/yX4eOb47YdmYKQjCgz2+Nil/lupY # vU0QFIjvke3jshqQINDng/vO9ys2qA0ex/q5hlLKQTST99dGoM86Ge6F723ReToq # KnGLN8kiCG7uNapOAIQrpCHZq96CVumiaA5ZvxU9AgMBAAGjggFgMIIBXDATBgNV # HSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUjuhtD3FD7tk/RKloJFX05cpgLjcw # UQYDVR0RBEowSKRGMEQxDDAKBgNVBAsTA0FPQzE0MDIGA1UEBRMrMjI5ODAzKzFh # YmY5ZTVmLWNlZDAtNDJlNi1hNjVkLWQ5MzUwOTU5ZmUwZTAfBgNVHSMEGDAWgBTL # EejK0rQWWAHJNy4zFha5TJoKHzBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3Js # Lm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNDb2RTaWdQQ0FfMDgt # MzEtMjAxMC5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY0NvZFNpZ1BDQV8wOC0zMS0y # MDEwLmNydDANBgkqhkiG9w0BAQUFAAOCAQEAYnG/oHG/xgZYR8NAMHZ/vE9GM0e4 # 7YdhuTea2uY7pSGwM707wp8Wan0Fa6evK1PWfcd/XNOh2BpEv5o8RmKDoEsG0ECP # 13Jug7cklfKreBVHQ+Djg43VVFLZpuo7aOAVK6wjlcnpPUtn+SfH9K0aM2FjDKVJ # FW6XFKXBat5R+Zp6uOxWTxpSeMTeDC5zF6IY6ogR1uzU+9EQoRlAvkwX6po+exEL # nMLr4++P+fqOxIU+PODIoB8ijClAqwwKvLlMPa3qlrNHt+LweTMu7lvGC/RA18wU # zzXAeomuZ03blUw+bkOiVgWOk4S0RN7EnW7zjJV8gd/+G2dbToUi1cB/fTCCBbww # ggOkoAMCAQICCmEzJhoAAAAAADEwDQYJKoZIhvcNAQEFBQAwXzETMBEGCgmSJomT # 8ixkARkWA2NvbTEZMBcGCgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMk # TWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDgzMTIy # MTkzMloXDTIwMDgzMTIyMjkzMloweTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEjMCEGA1UEAxMaTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0Ew # ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCycllcGTBkvx2aYCAgQpl2 # U2w+G9ZvzMvx6mv+lxYQ4N86dIMaty+gMuz/3sJCTiPVcgDbNVcKicquIEn08Gis # TUuNpb15S3GbRwfa/SXfnXWIz6pzRH/XgdvzvfI2pMlcRdyvrT3gKGiXGqelcnNW # 8ReU5P01lHKg1nZfHndFg4U4FtBzWwW6Z1KNpbJpL9oZC/6SdCnidi9U3RQwWfjS # jWL9y8lfRjFQuScT5EAwz3IpECgixzdOPaAyPZDNoTgGhVxOVoIoKgUyt0vXT2Pn # 0i1i8UU956wIAPZGoZ7RW4wmU+h6qkryRs83PDietHdcpReejcsRj1Y8wawJXwPT # AgMBAAGjggFeMIIBWjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLEejK0rQW # WAHJNy4zFha5TJoKHzALBgNVHQ8EBAMCAYYwEgYJKwYBBAGCNxUBBAUCAwEAATAj # BgkrBgEEAYI3FQIEFgQU/dExTtMmipXhmGA7qDFvpjy82C0wGQYJKwYBBAGCNxQC # BAweCgBTAHUAYgBDAEEwHwYDVR0jBBgwFoAUDqyCYEBWJ5flJRP8KuEKU5VZ5KQw # UAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9j # cmwvcHJvZHVjdHMvbWljcm9zb2Z0cm9vdGNlcnQuY3JsMFQGCCsGAQUFBwEBBEgw # RjBEBggrBgEFBQcwAoY4aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0 # cy9NaWNyb3NvZnRSb290Q2VydC5jcnQwDQYJKoZIhvcNAQEFBQADggIBAFk5Pn8m # Rq/rb0CxMrVq6w4vbqhJ9+tfde1MOy3XQ60L/svpLTGjI8x8UJiAIV2sPS9MuqKo # VpzjcLu4tPh5tUly9z7qQX/K4QwXaculnCAt+gtQxFbNLeNK0rxw56gNogOlVuC4 # iktX8pVCnPHz7+7jhh80PLhWmvBTI4UqpIIck+KUBx3y4k74jKHK6BOlkU7IG9KP # cpUqcW2bGvgc8FPWZ8wi/1wdzaKMvSeyeWNWRKJRzfnpo1hW3ZsCRUQvX/TartSC # Mm78pJUT5Otp56miLL7IKxAOZY6Z2/Wi+hImCWU4lPF6H0q70eFW6NB4lhhcyTUW # X92THUmOLb6tNEQc7hAVGgBd3TVbIc6YxwnuhQ6MT20OE049fClInHLR82zKwexw # o1eSV32UjaAbSANa98+jZwp0pTbtLS8XyOZyNxL0b7E8Z4L5UrKNMxZlHg6K3RDe # ZPRvzkbU0xfpecQEtNP7LN8fip6sCvsTJ0Ct5PnhqX9GuwdgR2VgQE6wQuxO7bN2 # edgKNAltHIAxH+IOVN3lofvlRxCtZJj/UBYufL8FIXrilUEnacOTj5XJjdibIa4N # XJzwoq6GaIMMai27dmsAHZat8hZ79haDJLmIz2qoRzEvmtzjcT3XAH5iR9HOiMm4 # GPoOco3Boz2vAkBq/2mbluIQqBC0N1AI1sM9MIIGBzCCA++gAwIBAgIKYRZoNAAA # AAAAHDANBgkqhkiG9w0BAQUFADBfMRMwEQYKCZImiZPyLGQBGRYDY29tMRkwFwYK # CZImiZPyLGQBGRYJbWljcm9zb2Z0MS0wKwYDVQQDEyRNaWNyb3NvZnQgUm9vdCBD # ZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcwNDAzMTI1MzA5WhcNMjEwNDAzMTMw # MzA5WjB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEwHwYD # VQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQCfoWyx39tIkip8ay4Z4b3i48WZUSNQrc7dGE4kD+7Rp9FM # rXQwIBHrB9VUlRVJlBtCkq6YXDAm2gBr6Hu97IkHD/cOBJjwicwfyzMkh53y9Gcc # LPx754gd6udOo6HBI1PKjfpFzwnQXq/QsEIEovmmbJNn1yjcRlOwhtDlKEYuJ6yG # T1VSDOQDLPtqkJAwbofzWTCd+n7Wl7PoIZd++NIT8wi3U21StEWQn0gASkdmEScp # ZqiX5NMGgUqi+YSnEUcUCYKfhO1VeP4Bmh1QCIUAEDBG7bfeI0a7xC1Un68eeEEx # d8yb3zuDk6FhArUdDbH895uyAc4iS1T/+QXDwiALAgMBAAGjggGrMIIBpzAPBgNV # HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQjNPjZUkZwCu1A+3b7syuwwzWzDzALBgNV # HQ8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwgZgGA1UdIwSBkDCBjYAUDqyCYEBW # J5flJRP8KuEKU5VZ5KShY6RhMF8xEzARBgoJkiaJk/IsZAEZFgNjb20xGTAXBgoJ # kiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBSb290IENl # cnRpZmljYXRlIEF1dGhvcml0eYIQea0WoUqgpa1Mc1j0BxMuZTBQBgNVHR8ESTBH # MEWgQ6BBhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0 # cy9taWNyb3NvZnRyb290Y2VydC5jcmwwVAYIKwYBBQUHAQEESDBGMEQGCCsGAQUF # BzAChjhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jvc29m # dFJvb3RDZXJ0LmNydDATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkqhkiG9w0BAQUF # AAOCAgEAEJeKw1wDRDbd6bStd9vOeVFNAbEudHFbbQwTq86+e4+4LtQSooxtYrhX # AstOIBNQmd16QOJXu69YmhzhHQGGrLt48ovQ7DsB7uK+jwoFyI1I4vBTFd1Pq5Lk # 541q1YDB5pTyBi+FA+mRKiQicPv2/OR4mS4N9wficLwYTp2OawpylbihOZxnLcVR # DupiXD8WmIsgP+IHGjL5zDFKdjE9K3ILyOpwPf+FChPfwgphjvDXuBfrTot/xTUr # XqO/67x9C0J71FNyIe4wyrt4ZVxbARcKFA7S2hSY9Ty5ZlizLS/n+YWGzFFW6J1w # lGysOUzU9nm/qhh6YinvopspNAZ3GmLJPR5tH4LwC8csu89Ds+X57H2146SodDW4 # TsVxIxImdgs8UoxxWkZDFLyzs7BNZ8ifQv+AeSGAnhUwZuhCEl4ayJ4iIdBD6Svp # u/RIzCzU2DKATCYqSCRfWupW76bemZ3KOm+9gSd0BhHudiG/m4LBJ1S2sWo9iaF2 # YbRuoROmv6pH8BJv/YoybLL+31HIjCPJZr2dHYcSZAI9La9Zj7jkIeW1sMpjtHhU # BdRBLlCslLCleKuzoJZ1GtmShxN1Ii8yqAhuoFuMJb+g74TKIdbrHk/Jmu5J4PcB # ZW+JC33Iacjmbuqnl84xKf8OxVtc2E0bodj6L54/LlUWa8kTo/0xggSXMIIEkwIB # ATCBkDB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSMwIQYD # VQQDExpNaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQQITMwAAAXglWrXNI8ZflQAB # AAABeDAJBgUrDgMCGgUAoIGwMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwG # CisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTv3yvb # V+Yvmhu4rvFkFNeB4zDOGjBQBgorBgEEAYI3AgEMMUIwQKAWgBQAUABvAHcAZQBy # AFMAaABlAGwAbKEmgCRodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vUG93ZXJTaGVs # bCAwDQYJKoZIhvcNAQEBBQAEggEAHxJOUQFdJwxTf7vYKq/197bz8HNcDmmiyxrY # qVfY4inVYrU1M/7w4bU8qGAIk/DwCGv0Qt0yvWGQADnuRe9rrzJ/Ru/YUkz5dHsc # ChIwBPJPd3IS47IVaD31yBdRvq73WSoIo4zhF3q3EyG//5IoP+NgP5dbr9tZISwz # OYoV9c/M4WVprYzrKOavh5KBdsS8WzaU7dvg8NgCwI8sJY7VD7fFFAwrGJG6WL9d # KgXT/XgRlCEl7SICWypTlvCi0KxR49UFHmEjNC4uwOzzN7VqUQNoKTLkYLo5iOaF # zXBPFHsqGCw4kXq5kfQizdn/a1STaIz1+P7XQH/U0tLInzKcUqGCAigwggIkBgkq # hkiG9w0BCQYxggIVMIICEQIBATCBjjB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMSEwHwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EC # EzMAAAC+pA/1yaUO4TAAAAAAAL4wCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzEL # BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE3MTAxNjIzMzU0NFowIwYJKoZI # hvcNAQkEMRYEFKhRDqW6AJFdziX+5lBQ5ep0w1MSMA0GCSqGSIb3DQEBBQUABIIB # ADUeN5po6bTZMB91NABRFezJ2ynMgZkbV+tF/OVvPROa/YO8xHaXexB0N+NOswwA # 5DfWLozmW3hZlQDYX7XBhaElnqyxDGLPoFr0t2PCarOW/Xn3nLprKvrizwCbySx0 # q2Yzx7BXOe4fqOyyE5rAsSlAzqwTRyBYv/yW8Mq4mwPWt7t4lLZQPWS8SDKaARkB # lXQ78URH2ie8S2gfyaO/mAjzgFu8cR7Ee5/n98QihWLHyqv+jPVtTc3izSJu5O3+ # uB9gP92neMf3WtNZZyFjqi7WTjXRv8FC7qkhz2rIP7+QY9vZNAhpCQDQv4otXaDX # TcJudVvY5Qkj6feDTqkKu8s= # SIG # End signature block |