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{'/'} # Ensure Session is logged-on to access Azure resources $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" } # 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) { } [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 # MIIdhQYJKoZIhvcNAQcCoIIddjCCHXICAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUAl5s3+nsr1x2dfIZJ8TeBWdS # 2vCgghhTMIIEwTCCA6mgAwIBAgITMwAAANjkdflFb0j3rgAAAAAA2DANBgkqhkiG # 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTcxMDAyMjI1NzU3 # WhcNMTkwMTAyMjI1NzU3WjCBsTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw # b3JhdGlvbjEMMAoGA1UECxMDQU9DMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo3 # MERELTRCNUItNDU2ODElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy # dmljZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMR2sf6C9y+kIdyj # 16QouyVvlvPjzdmE1FFIAb7gUl7UCknd2nlquXeGJHQdX22zmY18QH/8EjH8voTu # 57DqKJRFkqkD+PQ87+M4j2aW27QCHiHVATEHdHelT0ANUSoxETlAe4d6gd6sL/aA # wkqFSqTncLfVeAenMJ7Te3tLmLYBk59CI/Tmf2YCsU+Z0nQ0S0AH6IHAKbDLLUPZ # 1KW4d5Mmig1YMInsaoDHJvmuXyUZ6GxluZ7GX+WxF2XoxFRuMo6OWrCER3gnx/W3 # omzHOc1/C/oBI8hELBQH8uTJYqI8iGx8yqDyYETHoZNdH0oFeIOfAvVFlUYTE3JW # pbMtF0cCAwEAAaOCAQkwggEFMB0GA1UdDgQWBBSgHm6PHyXdykNng5Up+ne9UdYe # VjAfBgNVHSMEGDAWgBQjNPjZUkZwCu1A+3b7syuwwzWzDzBUBgNVHR8ETTBLMEmg # R6BFhkNodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9N # aWNyb3NvZnRUaW1lU3RhbXBQQ0EuY3JsMFgGCCsGAQUFBwEBBEwwSjBIBggrBgEF # BQcwAoY8aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNyb3Nv # ZnRUaW1lU3RhbXBQQ0EuY3J0MBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3 # DQEBBQUAA4IBAQCFDewTPdV6/bMFMK0kqgvI8Y7t1YvHrGmvpdA/Y2zx+ERd0g9d # ENtHTlfAPC1X15YlDXZNPdo7LY6wMJco/rXcjzFZ/tIvGHcIaQE52tJKW+pmXfrv # QWW4X3pQdbPTsCwcDSGPcDImnec0dathWPicWxBg1NIeSDDsdsqpESp0kSs9g9fL # QWUi9wHlFehburgOJCWpQ1jkNspUvJ7xMmtTTEIu6WPEDGHU8LxHraClsL0/BzPN # KE85uB3+5/yOurKU/V8kH/obxzB03XxI4QpbpU1D2yasOd7JVmCGEbHBRamtHVz6 # SnVVVviJUsoGV5/jdzHuXyUIy9LKSUwuTdykMIIGATCCA+mgAwIBAgITMwAAAMTp # ifh6gVDp/wAAAAAAxDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBTaWdu # aW5nIFBDQSAyMDExMB4XDTE3MDgxMTIwMjAyNFoXDTE4MDgxMTIwMjAyNFowdDEL # MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v # bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEeMBwGA1UEAxMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC # AQEAiIq4JMMHj5qAeRX8JmD8cogs+vSjl4iWRrejy1+JLzozLh6RePp8qR+CAbV6 # yxq8A8pG68WZ9/sEHfKFCv8ibqHyZz3FJxjlKB/1BJRBY+zjuhWM7ROaNd44cFRv # O+ytRQkwScG+jzCZDMt2yfdzlRZ30Yu7lMcIhSDtHqg18XHC4HQAS4rS3JHr1nj+ # jfqtYIg9vbkfrmKXv8WEsZCu1q8r01T7NdrNcZLmHv/scWvLfwh2dOAQUUjU8QDI # SEyjBzXlWQ39fJzI5lrjhfXWmg8fjqbkhBfB1sqfHQHH/UinE5IzlyFIMvjCJKIA # sr5TyoNuKVuB7zhugPO77BML6wIDAQABo4IBgDCCAXwwHwYDVR0lBBgwFgYKKwYB # BAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0OBBYEFMvWYoTPYDnq/2fCXNLIu6u3wxOY # MFIGA1UdEQRLMEmkRzBFMQ0wCwYDVQQLEwRNT1BSMTQwMgYDVQQFEysyMzAwMTIr # YzgwNGI1ZWEtNDliNC00MjM4LTgzNjItZDg1MWZhMjI1NGZjMB8GA1UdIwQYMBaA # FEhuZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFf # MjAxMS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEA # BhYf21fCUMgjT6JReNft+P3NvdXA8fkbVu1TyGlHBdXEy+zi/JlblV8ROCjABUUT # 4Jp5iLxmq9u76wJVI7c9I3hBba748QBalJmKHMwJldCaHEQwqaUWx7pHW/UrNIuf # j1g3w04cryLKEM3YghCpNfCuIsiPJKaBi98nHORmHYk+Lv9XA03BboOgMuu0sy9Q # Vl0GsRWMyB1jt3MM49Z6Jg8qlkWnMoM+lj5XSXcjif6xEMeK5QgVUcUrWjFbOWqW # qKSIa5Yob/HEruq9RRfMYk6BtVQaR46YpW3AbifG+CcfyO0gqQux8c4LmpTiap1p # g6E2120g/oXV/8O4lzYJ/j0UwZgUqcCGzO+CwatVJEMYtUiFeIbQ+dKdPxnZFInn # jZ9oJIhoO6nHgE4m5wghTGP9nJMVTTO1VmBP10q5OI7/Lt2xX6RDa8l4z7G7a4+D # bIdyquql+5/dGtY5/GTJbT4I5XyDsa28o7p7z5ZWpHpYyxJHYtIh7/w8xDEL9y8+ # ZKU3b2BQP7dEkE+gC4u+flj2x2eHYduemMTIjMtvR+HALpTtsfawMG3sakmo6ZZ2 # yL0IxP479a5zNwayVs8Z1Lv1lMqHHPKAagFPthuBc7PTWyI/OlgY34juZ8RJpy/c # JYs9XtDsNESRHbyRDHaCPu/E2C2hBAKOSPnv3QLPA6IwggYHMIID76ADAgECAgph # Fmg0AAAAAAAcMA0GCSqGSIb3DQEBBQUAMF8xEzARBgoJkiaJk/IsZAEZFgNjb20x # GTAXBgoJkiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBS # b290IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNzA0MDMxMjUzMDlaFw0yMTA0 # MDMxMzAzMDlaMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw # DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x # ITAfBgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQTCCASIwDQYJKoZIhvcN # AQEBBQADggEPADCCAQoCggEBAJ+hbLHf20iSKnxrLhnhveLjxZlRI1Ctzt0YTiQP # 7tGn0UytdDAgEesH1VSVFUmUG0KSrphcMCbaAGvoe73siQcP9w4EmPCJzB/LMySH # nfL0Zxws/HvniB3q506jocEjU8qN+kXPCdBer9CwQgSi+aZsk2fXKNxGU7CG0OUo # Ri4nrIZPVVIM5AMs+2qQkDBuh/NZMJ36ftaXs+ghl3740hPzCLdTbVK0RZCfSABK # R2YRJylmqJfk0waBSqL5hKcRRxQJgp+E7VV4/gGaHVAIhQAQMEbtt94jRrvELVSf # rx54QTF3zJvfO4OToWECtR0Nsfz3m7IBziJLVP/5BcPCIAsCAwEAAaOCAaswggGn # MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCM0+NlSRnAK7UD7dvuzK7DDNbMP # MAsGA1UdDwQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADCBmAYDVR0jBIGQMIGNgBQO # rIJgQFYnl+UlE/wq4QpTlVnkpKFjpGEwXzETMBEGCgmSJomT8ixkARkWA2NvbTEZ # MBcGCgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMkTWljcm9zb2Z0IFJv # b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5ghB5rRahSqClrUxzWPQHEy5lMFAGA1Ud # HwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3By # b2R1Y3RzL21pY3Jvc29mdHJvb3RjZXJ0LmNybDBUBggrBgEFBQcBAQRIMEYwRAYI # KwYBBQUHMAKGOGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWlj # cm9zb2Z0Um9vdENlcnQuY3J0MBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3 # DQEBBQUAA4ICAQAQl4rDXANENt3ptK132855UU0BsS50cVttDBOrzr57j7gu1BKi # jG1iuFcCy04gE1CZ3XpA4le7r1iaHOEdAYasu3jyi9DsOwHu4r6PCgXIjUji8FMV # 3U+rkuTnjWrVgMHmlPIGL4UD6ZEqJCJw+/b85HiZLg33B+JwvBhOnY5rCnKVuKE5 # nGctxVEO6mJcPxaYiyA/4gcaMvnMMUp2MT0rcgvI6nA9/4UKE9/CCmGO8Ne4F+tO # i3/FNSteo7/rvH0LQnvUU3Ih7jDKu3hlXFsBFwoUDtLaFJj1PLlmWLMtL+f5hYbM # UVbonXCUbKw5TNT2eb+qGHpiKe+imyk0BncaYsk9Hm0fgvALxyy7z0Oz5fnsfbXj # pKh0NbhOxXEjEiZ2CzxSjHFaRkMUvLOzsE1nyJ9C/4B5IYCeFTBm6EISXhrIniIh # 0EPpK+m79EjMLNTYMoBMJipIJF9a6lbvpt6Znco6b72BJ3QGEe52Ib+bgsEnVLax # aj2JoXZhtG6hE6a/qkfwEm/9ijJssv7fUciMI8lmvZ0dhxJkAj0tr1mPuOQh5bWw # ymO0eFQF1EEuUKyUsKV4q7OglnUa2ZKHE3UiLzKoCG6gW4wlv6DvhMoh1useT8ma # 7kng9wFlb4kLfchpyOZu6qeXzjEp/w7FW1zYTRuh2Povnj8uVRZryROj/TCCB3ow # ggVioAMCAQICCmEOkNIAAAAAAAMwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBS # b290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDExMB4XDTExMDcwODIwNTkwOVoX # DTI2MDcwODIxMDkwOVowfjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0 # b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh # dGlvbjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMTCC # AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKvw+nIQHC6t2G6qghBNNLry # tlghn0IbKmvpWlCquAY4GgRJun/DDB7dN2vGEtgL8DjCmQawyDnVARQxQtOJDXlk # h36UYCRsr55JnOloXtLfm1OyCizDr9mpK656Ca/XllnKYBoF6WZ26DJSJhIv56sI # UM+zRLdd2MQuA3WraPPLbfM6XKEW9Ea64DhkrG5kNXimoGMPLdNAk/jj3gcN1Vx5 # pUkp5w2+oBN3vpQ97/vjK1oQH01WKKJ6cuASOrdJXtjt7UORg9l7snuGG9k+sYxd # 6IlPhBryoS9Z5JA7La4zWMW3Pv4y07MDPbGyr5I4ftKdgCz1TlaRITUlwzluZH9T # upwPrRkjhMv0ugOGjfdf8NBSv4yUh7zAIXQlXxgotswnKDglmDlKNs98sZKuHCOn # qWbsYR9q4ShJnV+I4iVd0yFLPlLEtVc/JAPw0XpbL9Uj43BdD1FGd7P4AOG8rAKC # X9vAFbO9G9RVS+c5oQ/pI0m8GLhEfEXkwcNyeuBy5yTfv0aZxe/CHFfbg43sTUkw # p6uO3+xbn6/83bBm4sGXgXvt1u1L50kppxMopqd9Z4DmimJ4X7IvhNdXnFy/dygo # 8e1twyiPLI9AN0/B4YVEicQJTMXUpUMvdJX3bvh4IFgsE11glZo+TzOE2rCIF96e # TvSWsLxGoGyY0uDWiIwLAgMBAAGjggHtMIIB6TAQBgkrBgEEAYI3FQEEAwIBADAd # BgNVHQ4EFgQUSG5k5VAF04KqFzc3IrVtqMp1ApUwGQYJKwYBBAGCNxQCBAweCgBT # AHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgw # FoAUci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDov # L2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0 # MjAxMV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRSMFAwTgYIKwYBBQUHMAKG # Qmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0 # MjAxMV8yMDExXzAzXzIyLmNydDCBnwYDVR0gBIGXMIGUMIGRBgkrBgEEAYI3LgMw # gYMwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv # ZG9jcy9wcmltYXJ5Y3BzLmh0bTBABggrBgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwA # XwBwAG8AbABpAGMAeQBfAHMAdABhAHQAZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0B # AQsFAAOCAgEAZ/KGpZjgVHkaLtPYdGcimwuWEeFjkplCln3SeQyQwWVfLiw++MNy # 0W2D/r4/6ArKO79HqaPzadtjvyI1pZddZYSQfYtGUFXYDJJ80hpLHPM8QotS0LD9 # a+M+By4pm+Y9G6XUtR13lDni6WTJRD14eiPzE32mkHSDjfTLJgJGKsKKELukqQUM # m+1o+mgulaAqPyprWEljHwlpblqYluSD9MCP80Yr3vw70L01724lruWvJ+3Q3fMO # r5kol5hNDj0L8giJ1h/DMhji8MUtzluetEk5CsYKwsatruWy2dsViFFFWDgycSca # f7H0J/jeLDogaZiyWYlobm+nt3TDQAUGpgEqKD6CPxNNZgvAs0314Y9/HG8VfUWn # duVAKmWjw11SYobDHWM2l4bf2vP48hahmifhzaWX0O5dY0HjWwechz4GdwbRBrF1 # HxS+YWG18NzGGwS+30HHDiju3mUv7Jf2oVyW2ADWoUa9WfOXpQlLSBCZgB/QACnF # sZulP0V3HjXG0qKin3p6IvpIlR+r+0cjgPWe+L9rt0uX4ut1eBrs6jeZeRhL/9az # I2h15q/6/IvrC4DqaTuv/DDtBEyO3991bWORPdGdVk5Pv4BXIqF4ETIheu9BCrE/ # +6jMpF3BoYibV3FWTkhFwELJm3ZbCoBIa/15n8G9bW1qyVJzEw16UM0xggScMIIE # mAIBATCBlTB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgw # JgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExAhMzAAAAxOmJ # +HqBUOn/AAAAAADEMAkGBSsOAwIaBQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQB # gjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkE # MRYEFOqsmbeFLnG8gSHUv3StJaSr+w18MFAGCisGAQQBgjcCAQwxQjBAoBaAFABQ # AG8AdwBlAHIAUwBoAGUAbABsoSaAJGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9Q # b3dlclNoZWxsIDANBgkqhkiG9w0BAQEFAASCAQBMFb/66IYRSKc6v6OzH1CyV6LJ # 9e66BwBJrMKRH5ZRNyI6U1DqGRVZdoFCtYJ4okaVAYDX8n7eQwsQaiv7COk/Xcuy # nlN9N46gT4WDJtwl197LcPO2M4rhd4kI9OCR3Z7M4FLdrNDkE5vX4p+OkymO7xUk # O4qk9lXiCqMcGTilAhgBbmXUTkm3D5BPez9uQf/9PvpvO891BPfdOHYiU5XJl6Jq # bVtecdny4jdT/l5ij/9nTTS34bnFPDZ2oJeR8Qvb/px5LkGVgZgQRQZY5w2N+m1R # qKOkJJf3qne9tWk3YNmJuXuqllwB9HZImTRHbS2IztqvgGApa45NIY4bskOFoYIC # KDCCAiQGCSqGSIb3DQEJBjGCAhUwggIRAgEBMIGOMHcxCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xITAfBgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0 # YW1wIFBDQQITMwAAANjkdflFb0j3rgAAAAAA2DAJBgUrDgMCGgUAoF0wGAYJKoZI # hvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTgwNDMwMjE1OTU4 # WjAjBgkqhkiG9w0BCQQxFgQUI2R70wvfZAUrggTqkYT37Ycm0P0wDQYJKoZIhvcN # AQEFBQAEggEAnt29VA3l60h+3uaNvod2yt5yxU8D/jnloebisOSXvMuLwoz3vxcE # WtUvI4sc/OXCv8oqVGRsJgIIQcj5J0RFDSIt4fEFhMgMKuZXpmjgXHF9sThgSBG8 # 4SxgXpxtR76V0EKVXj1EAmcvp+yMMZOsKsn7wDjxmFPZ65Vi4v3DQ1kGf9LJ4NDZ # rfsWk2FcdWitD8RFXLIBXfcTLB37Rs3tWHEDANlK3pph+hKQwdF3xo6ZmYejy7At # 51182jAE/YuMxA3WxxzA4rVYuFhrjSQn97nOc6DKeryrwCUVdtzuEkQF+v7ThDGY # EDhcrT2ZWSwavCxNRP6A7kz+5mc37HI1yw== # SIG # End signature block |