Framework/Core/SVT/Services/CloudService.ps1

#
# CloudServices.ps1
#
Set-StrictMode -Version Latest 
class CloudService: SVTBase
{
    hidden [PSCloudService] $ResourceObject;
    hidden [bool] $hasClassicPermissions = $true;
    hidden [string] $cloudServiceAPIVersion = "2016-04-01"


    CloudService([string] $subscriptionId, [string] $resourceGroupName, [string] $resourceName): 
        Base($subscriptionId, $resourceGroupName, $resourceName) 
    { 
        $this.GetResourceObject();
    }

    CloudService([string] $subscriptionId, [SVTResource] $svtResource): 
        Base($subscriptionId, $svtResource) 
    { 
        $this.GetResourceObject();
    }

    hidden [PSObject] GetResourceObject()
    {
        if (-not $this.ResourceObject) {          
            $this.UpdateCloudServiceInstance()            
        }

        return $this.ResourceObject;
    }

    hidden [void] UpdateCloudServiceInstance()
    {
        #step 1: load data from ARM model
        $this.ResourceObject = [PSCloudService]::new($this.ResourceContext.ResourceName, $this.ResourceContext.ResourceGroupName)
        $this.ResourceObject.LoadCloudConfiguration();

        #step 2: load from classic config model
        try
        {        
            $ResourceAppIdURI = [WebRequestHelper]::ClassicManagementUri;
            $ClassicAccessToken = [Helpers]::GetAccessToken($ResourceAppIdURI)
            if($null -ne $ClassicAccessToken) 
            {
                $header = "Bearer " + $ClassicAccessToken
                $headers = @{"Authorization"=$header;"Content-Type"="application/json"; "x-ms-version" ="2013-08-01"}
                $uri = [string]::Format("{0}/{1}/services/hostedservices/{2}?embed-detail=true","https://management.core.windows.net", $this.SubscriptionContext.SubscriptionId ,$this.ResourceContext.ResourceName)        
                $cloudServiceResponse = Invoke-WebRequest -Method GET -Uri $uri -Headers $headers
                if($cloudServiceResponse.StatusCode -ge 200 -and $cloudServiceResponse.StatusCode -le 399)
                {             
                    if($null -ne $cloudServiceResponse.Content)
                    {                
                        [xml] $cloudService = $cloudServiceResponse.Content
                        $this.ResourceObject.LoadCloudConfigurationFromClassicConfig($cloudServiceResponse.Content);
                    }
                }            
            }
        }
        catch
        {
            $this.hasClassicPermissions = $false;
        }
    }

    hidden [ControlResult] CheckCloudServiceHttpCertificateSSLOnInstanceEndpoints([ControlResult] $controlResult)
    {
        if($this.hasClassicPermissions)
        {
            $isCompliant = $true;
            $nonCompliantInstanceEndpoints = @();
            if($null -ne $this.ResourceObject -and $null -ne $this.ResourceObject.RoleInstances)
            {
                $this.ResourceObject.RoleInstances | Foreach-Object{
                    $roleInstance = $_;
                    if($null -ne $roleInstance)
                    {
                        $roleInstance.InstanceEndpoints | ForEach-Object {
                            $instanceEndpoint = $_
                            if($instanceEndpoint.Protocol -eq "http")
                            {
                                $isCompliant = $false;
                                $nonCompliantInstanceEndpoints += $_
                            }
                        }
                    }
                }
            }
            if($isCompliant)
            {
                $controlResult.VerificationResult = [VerificationResult]::Passed;
            }
            else
            {
                #$controlResult.AddMessage([VerificationResult]::Failed, "Instance endpoints of cloud service must have http disabled.",$nonCompliantInstanceEndpoints, $true, "InstanceEndpoints");
                $controlResult.AddMessage([VerificationResult]::Failed,  "Instance endpoints of cloud service must have http disabled.",$nonCompliantInstanceEndpoints);
            }   
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Manual,  "Don't have the required permissions to scan the cloud service.");
        }
        return $controlResult;
    }

    hidden [ControlResult] CheckCloudServiceHttpCertificateSSLOnInputEndpoints([ControlResult] $controlResult)
    {        
        $InputEndpoints = @();
        if($null -ne $this.ResourceObject -and $null -ne $this.ResourceObject.DeploymentSlots)
        {
            $this.ResourceObject.DeploymentSlots | ForEach-Object {
                $DeploymentSlot = $_;
                if($null -ne $DeploymentSlot -and $null -ne $DeploymentSlot.Roles)
                {
                    $DeploymentSlot.Roles | ForEach-Object {
                        $Role = $_;
                        if($null -ne $Role.InputEndpoints)
                        {
                            $Role.InputEndpoints | ForEach-Object {
                                $inpEp = $_;
                                $inputEndpoint = "" | SELECT SlotName, RoleName, PublicIpAddress, PrivatePort, PublicPort, Protocol, VirtualIpName, IsCompliant
                                $inputEndpoint.SlotName = $DeploymentSlot.SlotName;
                                $inputEndpoint.RoleName = $Role.RoleName;        
                                $inputEndpoint.PublicIpAddress = $inpEp.PublicIpAddress;        
                                $inputEndpoint.PrivatePort = $inpEp.PrivatePort;        
                                $inputEndpoint.PublicPort = $inpEp.PublicPort;        
                                $inputEndpoint.Protocol = $inpEp.Protocol;        
                                $inputEndpoint.VirtualIpName = $inpEp.VirtualIpName;    
                                $inputEndpoint.IsCompliant = "False"
                                if($inpEp.protocol -eq "https")
                                {
                                    $inputEndpoint.IsCompliant = "True"
                                }
                                $InputEndpoints += $inputEndpoint
                            }
                        }
                    }
                }
            }
        }
        
        if(($InputEndpoints | Where-Object { $_.IsCompliant -eq "False"} | Measure-Object).Count -gt 0)
        {
            $controlResult.AddMessage([VerificationResult]::Failed,  "There are active non SSL enabled input endpoints.", $InputEndpoints);                
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Passed,  "There are no active non SSL enabled input endpoints.", $InputEndpoints);                
        }
        return $controlResult;
    }

    hidden [ControlResult] CheckCloudServiceInstanceEndpoints([ControlResult] $controlResult)
    {
        if($this.hasClassicPermissions)
        {            
            $instanceEndpoints = @();
            if($null -ne $this.ResourceObject -and $null -ne $this.ResourceObject.DeploymentSlots)
            {
                $this.ResourceObject.DeploymentSlots | ForEach-Object {
                    $DeploymentSlot = $_;
                    if($null -ne $DeploymentSlot -and $null -ne $DeploymentSlot.Roles)
                    {
                        $DeploymentSlot.Roles | ForEach-Object {
                            $Role = $_;
                            if($null -ne $Role.RoleInstances)
                            {
                                $Role.RoleInstances | ForEach-Object {
                                    $instanceEndpoints += $_
                                }
                            }
                        }
                    }
                }
            }
            #$controlResult.AddMessage([VerificationResult]::Verify, "Validate the IP Settings configured for the instance endpoints on cloud service.", $instanceEndpoints, $true, "InstanceEndpoints" );
            $controlResult.AddMessage([VerificationResult]::Verify,  "Validate the IP Settings configured for the instance endpoints on cloud service.", $instanceEndpoints);
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Manual,  "Don't have the required permissions to scan the cloud service.");
        }
        return $controlResult;
    }

    hidden [ControlResult] CheckCloudServiceInputEndpoints([ControlResult] $controlResult)
    {
        $InputEndpoints = @();
        if($null -ne $this.ResourceObject -and $null -ne $this.ResourceObject.DeploymentSlots)
        {
            $this.ResourceObject.DeploymentSlots | ForEach-Object {
                $DeploymentSlot = $_;
                if($null -ne $DeploymentSlot -and $null -ne $DeploymentSlot.Roles)
                {
                    $DeploymentSlot.Roles | ForEach-Object {
                        $Role = $_;
                        if($null -ne $Role.InputEndpoints)
                        {
                            $Role.InputEndpoints | ForEach-Object {
                                $InputEndpoints += $_
                            }
                        }
                    }
                }
            }
        }
        #$controlResult.AddMessage([VerificationResult]::Verify, "Remove any un-used internal endpoints from your cloud service.", $inputEndpoints, $true, "InputEndpoints" );
        $controlResult.AddMessage([VerificationResult]::Verify,  "Remove any un-used input endpoints from your cloud service.", $InputEndpoints);
        return $controlResult;
    }

    hidden [ControlResult] CheckCloudServiceRemoteDebuggingStatus([ControlResult] $controlResult)
    {
        if($this.hasClassicPermissions)
        {
            $isCompliant = $true;
            $nonCompliantInstanceEndpoints = @();
            if($null -ne $this.ResourceObject -and $null -ne $this.ResourceObject.DeploymentSlots)
            {
                $this.ResourceObject.DeploymentSlots | ForEach-Object {
                    $DeploymentSlot = $_;
                    if($null -ne $DeploymentSlot -and $null -ne $DeploymentSlot.Roles)
                    {
                        $DeploymentSlot.Roles | ForEach-Object {
                            $Role = $_;
                            if($null -ne $Role.RoleInstances)
                            {
                                $Role.RoleInstances | ForEach-Object {
                                    $roleInstance = $_;
                                    if($null -ne $roleInstance)
                                    {
                                        $roleInstance.InstanceEndpoints | ForEach-Object {
                                            $instanceEndpoint = $_
                                            if($instanceEndpoint.Name -like "Microsoft.WindowsAzure.Plugins.RemoteDebugger*")
                                            {
                                                $isCompliant = $false;
                                                $nonCompliantInstanceEndpoints += $_
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }            

            if($isCompliant)
            {
                $controlResult.VerificationResult = [VerificationResult]::Passed;
            }
            else
            {
                #$controlResult.AddMessage([VerificationResult]::Failed, "Remote debugging endpoints enabled on cloud service.", $nonCompliantInstanceEndpoints, $true, "InstanceEndpoints");
                $controlResult.AddMessage([VerificationResult]::Failed,  "Remote debugging endpoints enabled on cloud service.", $nonCompliantInstanceEndpoints);
            }   
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Manual,  "Don't have the required permissions to scan the cloud service.");            
        }
        return $controlResult;
    }

    hidden [ControlResult] CheckCloudServiceAntiMalwareStatus([ControlResult] $controlResult)
    {
        if($this.hasClassicPermissions)
        {
            $isCompliant = $false;
            $extensions = @{};
            if($null -ne $this.ResourceObject -and $null -ne $this.ResourceObject.DeploymentSlots)
            {
                $this.ResourceObject.DeploymentSlots | ForEach-Object {
                    $DeploymentSlot = $_;
                    if($null -ne $DeploymentSlot -and $null -ne $DeploymentSlot.Roles)
                    {
                        $DeploymentSlot.Roles | ForEach-Object {
                            $Role = $_;
                            if($null -ne $Role.Extensions)
                            {
                                $Role.Extensions | ForEach-Object {
                                    $extension = $_;
                                    $extensions.Add($DeploymentSlot.SlotName + "->" + $extension.RoleName,"Disabled");
                                    if($null -ne $extension -and $null -ne $extension.ExtensionId)
                                    {
                                        $extension.ExtensionId | ForEach-Object {
                                            $extensionId = $_
                                            if($extensionId.Id -like "*Antimalware*")
                                            {
                                                $extensions[$DeploymentSlot.SlotName + "->" + $extension.RoleName] = "Enabled"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }            

            if($extensions.Count -gt 0)
            {
                if(($extensions.Values | Where-Object { $_ -eq "Disabled"} | Measure-Object).Count -le 0)
                {
                    $controlResult.VerificationResult = [VerificationResult]::Passed;
                }
                else
                {
                    $controlResult.AddMessage([VerificationResult]::Failed,  "Antimalware extension is not enabled on cloud service.", $extensions);
                }
            }
            else
            {
                $controlResult.VerificationResult = [VerificationResult]::Passed;
            }
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Manual,  "Don't have the required permissions to scan the cloud service.");            
        }
        return $controlResult;
    }

    hidden [ControlResult] CheckCloudServiceOSPatchStatus([ControlResult] $controlResult)
    {
        $OSPatchVersions = @();
        $isCompliant = $true;
        if($null -ne $this.ResourceObject -and $null -ne $this.ResourceObject.DeploymentSlots)
        {
            $this.ResourceObject.DeploymentSlots | ForEach-Object {
                $DeploymentSlot = $_;
                if(-not $DeploymentSlot.IsOSAutoUpdateTurnedOn)
                {
                    $isCompliant = $false;
                }
            }
        }
        
        if(-not $isCompliant)
        {
            $controlResult.AddMessage([VerificationResult]::Failed,  "Cloud service is not set up for automatic OS updates.");                
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Passed,  "Cloud service is enabled with automatic OS updates");                
        }
        return $controlResult;
    }

    hidden [ControlResult] CheckCloudServiceRemoteDesktopAccess([ControlResult] $controlResult)
    {
        if($this.hasClassicPermissions)
        {
            $extensions = @{};
            if($null -ne $this.ResourceObject -and $null -ne $this.ResourceObject.DeploymentSlots)
            {
                $this.ResourceObject.DeploymentSlots | ForEach-Object {
                    $DeploymentSlot = $_;
                    if($null -ne $DeploymentSlot -and $null -ne $DeploymentSlot.Roles)
                    {
                        $DeploymentSlot.Roles | ForEach-Object {
                            $Role = $_;
                            if($null -ne $Role.Extensions)
                            {
                                $Role.Extensions | ForEach-Object {
                                    $extension = $_;
                                    $extensions.Add($DeploymentSlot.SlotName + "->" + $extension.RoleName,"Disabled");
                                    if($null -ne $extension -and $null -ne $extension.ExtensionId)
                                    {
                                        $extension.ExtensionId | ForEach-Object {
                                            $extensionId = $_
                                            if($extensionId.Id -like "*RDP*")
                                            {
                                                $extensions[$DeploymentSlot.SlotName + "->" + $extension.RoleName] = "Enabled"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }            

            if($extensions.Count -gt 0)
            {
                if(($extensions.Values | Where-Object { $_ -eq "Enabled"} | Measure-Object).Count -le 0)
                {
                    $isCompliant = $true;
                }
                else
                {
                    $isCompliant = $false;
                    $controlResult.AddMessage("Remote desktop endpoints are enabled on cloud service.", $extensions);
                }
            }
            else
            {
                $isCompliant = $true;
            } 
            #$b.ServiceConfiguration.Role[0].ConfigurationSettings.Setting.SyncRoot["Microsoft.WindowsAzure.Plugins.RemoteAccess.Enabled"]
            $nonCompliantInstanceEndpoints = @();
            if($isCompliant)
            {
                if($null -ne $this.ResourceObject -and $null -ne $this.ResourceObject.DeploymentSlots)
                {
                    $this.ResourceObject.DeploymentSlots | ForEach-Object {
                        $DeploymentSlot = $_;
                        if($null -ne $DeploymentSlot -and $null -ne $DeploymentSlot.Roles)
                        {
                            $DeploymentSlot.Roles | ForEach-Object {
                                $Role = $_;
                                if($null -ne $Role.RoleInstances)
                                {
                                    $Role.RoleInstances | ForEach-Object {
                                        $roleInstance = $_;
                                        if($null -ne $roleInstance)
                                        {
                                            $roleInstance.InstanceEndpoints | ForEach-Object {
                                                $instanceEndpoint = $_
                                                if($instanceEndpoint.Name -like "Microsoft.WindowsAzure.Plugins.RemoteForwarder*")
                                                {
                                                    $isCompliant = $false;
                                                    $nonCompliantInstanceEndpoints += $_
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }                
            }            

            if($isCompliant)
            {
                $controlResult.VerificationResult = [VerificationResult]::Passed;
            }
            else
            {
                $controlResult.VerificationResult = [VerificationResult]::Failed;
            }   
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Manual,  "Don't have the required permissions to scan the cloud service.");            
        }
        return $controlResult;
    }
}

# SIG # Begin signature block
# MIIkAgYJKoZIhvcNAQcCoIIj8zCCI+8CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBpZpxxqg5EKsZb
# gsrLjLzkpOSczK7JiggM3RVipLqHkqCCDZMwggYRMIID+aADAgECAhMzAAAAjoeR
# pFcaX8o+AAAAAACOMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMTYxMTE3MjIwOTIxWhcNMTgwMjE3MjIwOTIxWjCBgzEL
# MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
# bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjENMAsGA1UECxMETU9Q
# UjEeMBwGA1UEAxMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMIIBIjANBgkqhkiG9w0B
# AQEFAAOCAQ8AMIIBCgKCAQEA0IfUQit+ndnGetSiw+MVktJTnZUXyVI2+lS/qxCv
# 6cnnzCZTw8Jzv23WAOUA3OlqZzQw9hYXtAGllXyLuaQs5os7efYjDHmP81LfQAEc
# wsYDnetZz3Pp2HE5m/DOJVkt0slbCu9+1jIOXXQSBOyeBFOmawJn+E1Zi3fgKyHg
# 78CkRRLPA3sDxjnD1CLcVVx3Qv+csuVVZ2i6LXZqf2ZTR9VHCsw43o17lxl9gtAm
# +KWO5aHwXmQQ5PnrJ8by4AjQDfJnwNjyL/uJ2hX5rg8+AJcH0Qs+cNR3q3J4QZgH
# uBfMorFf7L3zUGej15Tw0otVj1OmlZPmsmbPyTdo5GPHzwIDAQABo4IBgDCCAXww
# HwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0OBBYEFKvI1u2y
# FdKqjvHM7Ww490VK0Iq7MFIGA1UdEQRLMEmkRzBFMQ0wCwYDVQQLEwRNT1BSMTQw
# MgYDVQQFEysyMzAwMTIrYjA1MGM2ZTctNzY0MS00NDFmLWJjNGEtNDM0ODFlNDE1
# ZDA4MB8GA1UdIwQYMBaAFEhuZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEsw
# SaBHoEWGQ2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0Nv
# ZFNpZ1BDQTIwMTFfMjAxMS0wNy0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsG
# AQUFBzAChkVodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01p
# Y0NvZFNpZ1BDQTIwMTFfMjAxMS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkq
# hkiG9w0BAQsFAAOCAgEARIkCrGlT88S2u9SMYFPnymyoSWlmvqWaQZk62J3SVwJR
# avq/m5bbpiZ9CVbo3O0ldXqlR1KoHksWU/PuD5rDBJUpwYKEpFYx/KCKkZW1v1rO
# qQEfZEah5srx13R7v5IIUV58MwJeUTub5dguXwJMCZwaQ9px7eTZ56LadCwXreUM
# tRj1VAnUvhxzzSB7pPrI29jbOq76kMWjvZVlrkYtVylY1pLwbNpj8Y8zon44dl7d
# 8zXtrJo7YoHQThl8SHywC484zC281TllqZXBA+KSybmr0lcKqtxSCy5WJ6PimJdX
# jrypWW4kko6C4glzgtk1g8yff9EEjoi44pqDWLDUmuYx+pRHjn2m4k5589jTajMW
# UHDxQruYCen/zJVVWwi/klKoCMTx6PH/QNf5mjad/bqQhdJVPlCtRh/vJQy4njpI
# BGPveJiiXQMNAtjcIKvmVrXe7xZmw9dVgh5PgnjJnlQaEGC3F6tAE5GusBnBmjOd
# 7jJyzWXMT0aYLQ9RYB58+/7b6Ad5B/ehMzj+CZrbj3u2Or2FhrjMvH0BMLd7Hald
# G73MTRf3bkcz1UDfasouUbi1uc/DBNM75ePpEIzrp7repC4zaikvFErqHsEiODUF
# he/CBAANa8HYlhRIFa9+UrC4YMRStUqCt4UqAEkqJoMnWkHevdVmSbwLnHhwCbww
# ggd6MIIFYqADAgECAgphDpDSAAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYD
# VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe
# MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3Nv
# ZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5
# MDlaFw0yNjA3MDgyMTA5MDlaMH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIw
# MTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQ
# TTS68rZYIZ9CGypr6VpQqrgGOBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULT
# iQ15ZId+lGAkbK+eSZzpaF7S35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYS
# L+erCFDPs0S3XdjELgN1q2jzy23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494H
# DdVceaVJKecNvqATd76UPe/74ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZ
# PrGMXeiJT4Qa8qEvWeSQOy2uM1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5
# bmR/U7qcD60ZI4TL9LoDho33X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGS
# rhwjp6lm7GEfauEoSZ1fiOIlXdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADh
# vKwCgl/bwBWzvRvUVUvnOaEP6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON
# 7E1JMKerjt/sW5+v/N2wZuLBl4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xc
# v3coKPHtbcMojyyPQDdPweGFRInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqw
# iBfenk70lrC8RqBsmNLg1oiMCwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMC
# AQAwHQYDVR0OBBYEFEhuZOVQBdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQM
# HgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1Ud
# IwQYMBaAFHItOgIxkEO5FAVO4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0
# dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0Nl
# ckF1dDIwMTFfMjAxMV8wM18yMi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUF
# BzAChkJodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0Nl
# ckF1dDIwMTFfMjAxMV8wM18yMi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGC
# Ny4DMIGDMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtp
# b3BzL2RvY3MvcHJpbWFyeWNwcy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcA
# YQBsAF8AcABvAGwAaQBjAHkAXwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZI
# hvcNAQELBQADggIBAGfyhqWY4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4s
# PvjDctFtg/6+P+gKyju/R6mj82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKL
# UtCw/WvjPgcuKZvmPRul1LUdd5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7
# pKkFDJvtaPpoLpWgKj8qa1hJYx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft
# 0N3zDq+ZKJeYTQ49C/IIidYfwzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4
# MnEnGn+x9Cf43iw6IGmYslmJaG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxv
# FX1Fp3blQCplo8NdUmKGwx1jNpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG
# 0QaxdR8UvmFhtfDcxhsEvt9Bxw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf
# 0AApxbGbpT9Fdx41xtKiop96eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkY
# S//WsyNodeav+vyL6wuA6mk7r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrv
# QQqxP/uozKRdwaGIm1dxVk5IRcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIV
# xTCCFcECAQEwgZUwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAA
# AI6HkaRXGl/KPgAAAAAAjjANBglghkgBZQMEAgEFAKCBsDAZBgkqhkiG9w0BCQMx
# DAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkq
# hkiG9w0BCQQxIgQg2t0M18Svt+lt9N13lIp19JFR6aYHoRW+xHMC2eQBpvUwRAYK
# KwYBBAGCNwIBDDE2MDSgEoAQAEEAegBTAEQASwAyADUAMqEegBxodHRwczovL2Fr
# YS5tcy9henNka29zc2RvY3MgMA0GCSqGSIb3DQEBAQUABIIBADXtDv/X75KxGCfK
# dg32NY8zANdvH1f6dkD7N/Be54Xa3JIuAQEXQzL33yf0bgiH7qXejRbhlWJlW7h9
# X3DFbz8EibWnKaHAByYppXfFHDdUGRZ9SKRyBD9Y/mXMAeL7tZbtNvgnGXZx16gb
# vw6PUm0b4DCqDZcSRbTnXsEkC/YZfTnkLsqSeOhwcUZSC6s42zW9wf690PJcRj9Q
# 8cSpS5nlx+IctGUe4W6HKDEk8b9OccnIvOPKPSGOgJ/odpyzTY2IA10BQxYdYlVu
# bdC2XcVVWlS3c9fi5Fjkf94d5goSzyTxealaizp7qGjwcCpqha9eoz/dZBKa8rjy
# Ji4lwtyhghNNMIITSQYKKwYBBAGCNwMDATGCEzkwghM1BgkqhkiG9w0BBwKgghMm
# MIITIgIBAzEPMA0GCWCGSAFlAwQCAQUAMIIBPQYLKoZIhvcNAQkQAQSgggEsBIIB
# KDCCASQCAQEGCisGAQQBhFkKAwEwMTANBglghkgBZQMEAgEFAAQgy4MQ3Jqj7VuP
# 5i3NmlBHJhMTAAwE5INVEMxsuaNOTKwCBlmSONxRDhgTMjAxNzA5MDUwOTM3MTUu
# NDE5WjAHAgEBgAIB9KCBuaSBtjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0Ug
# RVNOOjdEMkUtMzc4Mi1CMEY3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFt
# cCBTZXJ2aWNloIIO0DCCBnEwggRZoAMCAQICCmEJgSoAAAAAAAIwDQYJKoZIhvcN
# AQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAw
# BgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEw
# MB4XDTEwMDcwMTIxMzY1NVoXDTI1MDcwMTIxNDY1NVowfDELMAkGA1UEBhMCVVMx
# EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT
# FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUt
# U3RhbXAgUENBIDIwMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCp
# HQ28dxGKOiDs/BOX9fp/aZRrdFQQ1aUKAIKF++18aEssX8XD5WHCdrc+Zitb8BVT
# JwQxH0EbGpUdzgkTjnxhMFmxMEQP8WCIhFRDDNdNuDgIs0Ldk6zWczBXJoKjRQ3Q
# 6vVHgc2/JGAyWGBG8lhHhjKEHnRhZ5FfgVSxz5NMksHEpl3RYRNuKMYa+YaAu99h
# /EbBJx0kZxJyGiGKr0tkiVBisV39dx898Fd1rL2KQk1AUdEPnAY+Z3/1ZsADlkR+
# 79BL/W7lmsqxqPJ6Kgox8NpOBpG2iAg16HgcsOmZzTznL0S6p/TcZL2kAcEgCZN4
# zfy8wMlEXV4WnAEFTyJNAgMBAAGjggHmMIIB4jAQBgkrBgEEAYI3FQEEAwIBADAd
# BgNVHQ4EFgQU1WM6XIoxkPNDe3xGG8UzaFqFbVUwGQYJKwYBBAGCNxQCBAweCgBT
# AHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgw
# FoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDov
# L2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0
# XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0
# cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAx
# MC0wNi0yMy5jcnQwgaAGA1UdIAEB/wSBlTCBkjCBjwYJKwYBBAGCNy4DMIGBMD0G
# CCsGAQUFBwIBFjFodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vUEtJL2RvY3MvQ1BT
# L2RlZmF1bHQuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAFAAbwBs
# AGkAYwB5AF8AUwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4IC
# AQAH5ohRDeLG4Jg/gXEDPZ2joSFvs+umzPUxvs8F4qn++ldtGTCzwsVmyWrf9efw
# eL3HqJ4l4/m87WtUVwgrUYJEEvu5U4zM9GASinbMQEBBm9xcF/9c+V4XNZgkVkt0
# 70IQyK+/f8Z/8jd9Wj8c8pl5SpFSAK84Dxf1L3mBZdmptWvkx872ynoAb0swRCQi
# PM/tA6WWj1kpvLb9BOFwnzJKJ/1Vry/+tuWOM7tiX5rbV0Dp8c6ZZpCM/2pif93F
# SguRJuI57BlKcWOdeyFtw5yjojz6f32WapB4pm3S4Zz5Hfw42JT0xqUKloakvZ4a
# rgRCg7i1gJsiOCC1JeVk7Pf0v35jWSUPei45V3aicaoGig+JFrphpxHLmtgOR5qA
# xdDNp9DvfYPw4TtxCd9ddJgiCGHasFAeb73x4QDf5zEHpJM692VHeOj4qEir995y
# fmFrb3epgcunCaw5u+zGy9iCtHLNHfS4hQEegPsbiSpUObJb2sgNVZl6h3M7COaY
# LeqN4DMuEin1wC9UJyH3yKxO2ii4sanblrKnQqLJzxlBTeCG+SqaoxFmMNO7dDJL
# 32N79ZmKLxvHIa9Zta7cRDyXUHHXodLFVeNp3lfB0d4wwP3M5k37Db9dT+mdHhk4
# L7zPWAUu7w2gUDXa7wknHNWzfjUeCLraNtvTX4/edIhJEjCCBNowggPCoAMCAQIC
# EzMAAACiTI4d2qkhfIQAAAAAAKIwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTAwHhcNMTYwOTA3MTc1NjQ5WhcNMTgwOTA3MTc1NjQ5
# WjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
# B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjENMAsGA1UE
# CxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNOOjdEMkUtMzc4Mi1CMEY3
# MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIBIjANBgkq
# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApgF3BXvDfQ52aL3GqIPGgnsBcKiwaoRy
# T1SObb5nIGq+7C3dL0dx4ZL9dGJrvnTbhTbbNMjHaQrmNhJJQEe4QTRZYj3xE6eu
# CQEo0RRYYx85sGg2BNhZ2k1b4JFxEvxBsw3OwXKhFSb285lb6OCKrhB1qjnX8Q7y
# CcExdQwpKind7I43Kt9rquMyuNhNe8hxEJDBvjqGGQvo6a0fuDQjrWGMli77Pkwv
# QmXGCx6xsFjCa5vnz4sEx5NBneZ5uOX3llfcgMUFBQCmQSI3Fvm060esLzmt0MXT
# DETXCVtp0QnzAytjJ1oHkPTvjKMzJY03LD8lmbPzFT6mkur5URjl1QIDAQABo4IB
# GzCCARcwHQYDVR0OBBYEFG672cHC2hawfK3CU3/n0BcTPbxXMB8GA1UdIwQYMBaA
# FNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9j
# cmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0YVBDQV8y
# MDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENBXzIwMTAt
# MDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJ
# KoZIhvcNAQELBQADggEBADWZV20z9kidnkHczKlg7lxHSFQRCoa5Vz+nbZiOynxp
# pmqWg845sr1kDpkwu77c4HWCa0Ip4YVEjjF7c2hZeZidV7QWB/yiKbyjcIIhJh1l
# SxnmiSpVza+6kmreyJoJAlslFpfHq7la2vTzoBuCcKpKxka1eoDEYkKD93FaZCsm
# /fOOIwtOFvIb8tA1CkPaPPOpGpGKxDV42RCoYwajZH+svyjuqBwVeI+g98Jxxdi4
# ks6ql3I5TA9oZEROyoblLcuyArEoPf0ZvwDWSNPfDbTtDCSQRRS8lXk6A+xjhjw0
# 7nGyPS5qeZCCtusbGlm7r4uLefGp/Uox8jxqGxVdOsahggN5MIICYQIBATCB46GB
# uaSBtjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjENMAsG
# A1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNOOjdEMkUtMzc4Mi1C
# MEY3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiUKAQEw
# CQYFKw4DAhoFAAMVAF4vF+lxhNIyy+zXXko7+E63h+n1oIHCMIG/pIG8MIG5MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMQ0wCwYDVQQLEwRNT1BS
# MScwJQYDVQQLEx5uQ2lwaGVyIE5UUyBFU046NTdGNi1DMUUwLTU1NEMxKzApBgNV
# BAMTIk1pY3Jvc29mdCBUaW1lIFNvdXJjZSBNYXN0ZXIgQ2xvY2swDQYJKoZIhvcN
# AQEFBQACBQDdWK1sMCIYDzIwMTcwOTA1MDQ1ODIwWhgPMjAxNzA5MDYwNDU4MjBa
# MHcwPQYKKwYBBAGEWQoEATEvMC0wCgIFAN1YrWwCAQAwCgIBAAICDnkCAf8wBwIB
# AAICGLQwCgIFAN1Z/uwCAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoD
# AaAKMAgCAQACAxbjYKEKMAgCAQACAwehIDANBgkqhkiG9w0BAQUFAAOCAQEAcmGj
# BBTr+m5dd4eEDdc2UUFm4Al/CGHzZYgdOFKvfZ1/YnsnH6MMuoUgAwG6+EhEWyMD
# oFUbsyNGdUyXXN9eQPDmjT4Gk1Tl7cQHgHEKVmqElgVAyDISE3V3CvqYlypCasYl
# iuOt/aE+EiBterVmkPPEB+XFz1M+WMFEjjA/l/9zTQj9XYjey4415ox5/k4TT02B
# GUr+0OcU1/7BzL3CqEHRpal9ES6i7+8jFsm8xgi7ifMZSTVeFlcw0AzO38+YUc7T
# +othjWn50Ll0INYWIE1uHMP6M+hGN9fD8TK0WdhaKP59pbcMpd9d3kjG+sNeggSh
# bwcVPJiNzcVIaGbjxDGCAvUwggLxAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwAhMzAAAAokyOHdqpIXyEAAAAAACiMA0GCWCGSAFlAwQCAQUAoIIB
# MjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEILIS
# we3quvQdDjFEXVS+LvwZ85N9xaQkTOSzI1pFfsCaMIHiBgsqhkiG9w0BCRACDDGB
# 0jCBzzCBzDCBsQQUXi8X6XGE0jLL7NdeSjv4TreH6fUwgZgwgYCkfjB8MQswCQYD
# VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe
# MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3Nv
# ZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAKJMjh3aqSF8hAAAAAAAojAWBBTM
# BEq1o6Nbw5EBNOEoqaWczrIaQDANBgkqhkiG9w0BAQsFAASCAQCjIEN4Hy0YawgJ
# DwE0kz8Q1jjb/1xws/4EiB7r21PrHVWtqXlOvsytuqABD/c/Ra9TwJVwKIaik91r
# DlIowEr63eYQhpMyWUuMravag9CC3LN8OdDkpIF2l3ePzSaakTlcE9tfTkueIp10
# 1srTXWRa7Lkqj8WU58+FrGBlbyboCHsgDh+G616CBOVu73RXzVlYX9pSiIewXDnY
# E0OxF0fwJc3gbbq9ACI4POrhGVtpoA2PkJ0FcA4mj6W/4nvZ4px6mjdbOO2mcCLX
# sUeHUoZYFCTGNrJh3qOY7lv0EkrYLyeL7y5aB3VlVWT+aQKhoodkqlKG5xVu5tYC
# tOt9BiGq
# SIG # End signature block