Framework/Listeners/RemoteReports/RemoteReportsListner.ps1

Set-StrictMode -Version Latest

class RemoteReportsListner: ListenerBase {

    hidden RemoteReportsListner() {
    }

    hidden static [RemoteReportsListner] $Instance = $null;

    static [RemoteReportsListner] GetInstance() {
        if ( $null  -eq [RemoteReportsListner]::Instance  ) {
            [RemoteReportsListner]::Instance = [RemoteReportsListner]::new();
        }
        return [RemoteReportsListner]::Instance
    }

    [void] RegisterEvents() {
        $this.UnregisterEvents();

        $this.RegisterEvent([AzSdkRootEvent]::GenerateRunIdentifier, {
            $currentInstance = [RemoteReportsListner]::GetInstance();
            try
            {
                $runIdentifier = [AzSdkRootEventArgument] ($Event.SourceArgs | Select-Object -First 1)
                $currentInstance.SetRunIdentifier($runIdentifier);
            }
            catch
            {
                $currentInstance.PublishException($_);
            }
        });

        $this.RegisterEvent([SVTEvent]::CommandStarted, {
            $currentInstance = [RemoteReportsListner]::GetInstance();
            try
            {
                $scanSource = [RemoteReportHelper]::GetScanSource();
                if($scanSource -ne [ScanSource]::Runbook) { return; }
                $invocationContext = [System.Management.Automation.InvocationInfo] $currentInstance.InvocationContext
                if(!$invocationContext.BoundParameters.ContainsKey("SubscriptionId")) {return;}
                $resources = "" | Select-Object "SubscriptionId", "ResourceGroups"
                $resources.SubscriptionId = $invocationContext.BoundParameters["SubscriptionId"]
                $resources.ResourceGroups = [System.Collections.ArrayList]::new()
                $resourcesFlat = Find-AzureRmResource
                $supportedResourceTypes = [SVTMapping]::GetSupportedResourceMap()
                # Not considering nested resources to reduce complexity
                $filteredResoruces = $resourcesFlat | where { $supportedResourceTypes.ContainsKey($_.ResourceType.ToLower()) }
                $grouped = $filteredResoruces | Group-Object {$_.ResourceGroupName} | Select-Object Name, Group
                foreach($group in $grouped){
                    $resourceGroup = "" | Select-Object Name, Resources
                    $resourceGroup.Name = $group.Name
                    $resourceGroup.Resources = [System.Collections.ArrayList]::new()
                    foreach($item in $group.Group){
                        $resource = "" | Select-Object Name, ResourceId, Feature
                        if($item.Name.Contains("/")){
                            $splitName = $item.Name.Split("/")
                            $resource.Name = $splitName[$splitName.Length - 1]
                        }
                        else{
                            $resource.Name = $item.Name;
                        }
                        $resource.ResourceId = $item.ResourceId
                        $resource.Feature = $supportedResourceTypes[$item.ResourceType.ToLower()]
                        $resourceGroup.Resources.Add($resource) | Out-Null
                    }
                    $resources.ResourceGroups.Add($resourceGroup) | Out-Null
                }
                [RemoteApiHelper]::PostResourceInventory($resources)
            }
            catch
            {
                $currentInstance.PublishException($_);
            }
        });

        $this.RegisterEvent([SVTEvent]::EvaluationCompleted, {
            $currentInstance = [RemoteReportsListner]::GetInstance();
            try
            {
                $settings = [ConfigurationManager]::GetAzSdkConfigData();
                if(!$settings.PublishVulnDataToApi) {return;}
                $invocationContext = [System.Management.Automation.InvocationInfo] $currentInstance.InvocationContext
                $featureGroup = [RemoteReportHelper]::GetFeatureGroup($invocationContext.MyCommand.Name)
                $SVTEventContexts = [SVTEventContext[]] $Event.SourceArgs
                if($featureGroup -eq [FeatureGroup]::Subscription){
                    [RemoteReportsListner]::ReportSubscriptionScan($currentInstance, $invocationContext, $SVTEventContexts)
                }elseif($featureGroup -eq [FeatureGroup]::Service){
                    [RemoteReportsListner]::ReportServiceScan($currentInstance, $invocationContext, $SVTEventContexts)
                }else{

                }
            }
            catch
            {
                $currentInstance.PublishException($_);
            }
        });
    }

    static [void] ReportSubscriptionScan(
        [RemoteReportsListner] $publisher, `
        [System.Management.Automation.InvocationInfo]  $invocationContext, `
        [SVTEventContext[]] $SVTEventContexts)
    {
        $SVTEventContext = $SVTEventContexts[0]
        $scanResult = [SubscriptionScanInfo]::new()
        $scanResult.ScanKind = [RemoteReportHelper]::GetSubscriptionScanKind($invocationContext.MyCommand.Name, $invocationContext.BoundParameters)
        $scanResult.SubscriptionId = $SVTEventContext.SubscriptionContext.SubscriptionId
        $scanResult.SubscriptionName = $SVTEventContext.SubscriptionContext.SubscriptionName
        $scanResult.Source = [RemoteReportHelper]::GetScanSource()
        $scanResult.ScannerVersion = $publisher.GetCurrentModuleVersion()
        # TODO: Figure out, temp using module version
        $scanResult.ControlVersion = $publisher.GetCurrentModuleVersion()
        $scanResult.Metadata = [Helpers]::ConvertToJsonCustomCompressed($SVTEventContext.SubscriptionContext.SubscriptionMetadata)
        $results = [System.Collections.ArrayList]::new()
        $SVTEventContexts | ForEach-Object {
            $context = $_
            if ($context.ControlItem.Enabled) {
                $result = [RemoteReportHelper]::BuildSubscriptionControlResult($context.ControlResults[0], $context.ControlItem)
                $results.Add($result)
            }
            else {
                $result = [SubscriptionControlResult]::new()
                $result.ControlId = $context.ControlItem.ControlID
                $result.ControlIntId = $context.ControlItem.Id
                $result.ActualVerificationResult = [VerificationResult]::Disabled
                $result.AttestationStatus = [AttestationStatus]::None
                $result.VerificationResult = [VerificationResult]::Disabled
                $results.Add($result)
            }
        }
        $scanResult.ControlResults = [SubscriptionControlResult[]] $results
        [RemoteApiHelper]::PostSubscriptionScanResult($scanResult)
    }

    static [void] ReportServiceScan(
        [RemoteReportsListner] $publisher, `
        [System.Management.Automation.InvocationInfo]  $invocationContext, `
        [SVTEventContext[]] $SVTEventContexts)
    {
        $SVTEventContextFirst = $SVTEventContexts[0]
        $scanResult = [ServiceScanInfo]::new()
        $scanResult.ScanKind = [RemoteReportHelper]::GetServiceScanKind($invocationContext.MyCommand.Name, $invocationContext.BoundParameters)
        $scanResult.SubscriptionId = $SVTEventContextFirst.SubscriptionContext.SubscriptionId
        $scanResult.SubscriptionName = $SVTEventContextFirst.SubscriptionContext.SubscriptionName
        $scanResult.Source = [RemoteReportHelper]::GetScanSource()
        $scanResult.ScannerVersion = $publisher.GetCurrentModuleVersion()
        # TODO: Figure out, temp using module version
        $scanResult.ControlVersion = $publisher.GetCurrentModuleVersion()
        $scanResult.Feature = $SVTEventContextFirst.FeatureName
        $scanResult.ResourceGroup = $SVTEventContextFirst.ResourceContext.ResourceGroupName
        $scanResult.ResourceName = $SVTEventContextFirst.ResourceContext.ResourceName
        $scanResult.ResourceId = $SVTEventContextFirst.ResourceContext.ResourceId
        $scanResult.Metadata = [Helpers]::ConvertToJsonCustomCompressed($SVTEventContextFirst.ResourceContext.ResourceMetadata)
        $results = [System.Collections.ArrayList]::new()
        $SVTEventContexts | ForEach-Object {
            $SVTEventContext = $_
            if (!$SVTEventContext.ControlItem.Enabled) {
                $result = [ServiceControlResult]::new()
                $result.ControlId = $SVTEventContext.ControlItem.ControlID
                $result.ControlIntId = $SVTEventContext.ControlItem.Id
                $result.ControlSeverity = $SVTEventContext.ControlItem.ControlSeverity
                $result.ActualVerificationResult = [VerificationResult]::Disabled
                $result.AttestationStatus = [AttestationStatus]::None
                $result.VerificationResult = [VerificationResult]::Disabled
                $results.Add($result)
            }
            elseif ($SVTEventContext.ControlResults.Count -eq 1 -and `
                ($scanResult.ResourceName -eq $SVTEventContext.ControlResults[0].ChildResourceName -or `
                    [string]::IsNullOrWhiteSpace($SVTEventContext.ControlResults[0].ChildResourceName)))
            {
                $result = [RemoteReportHelper]::BuildServiceControlResult($SVTEventContext.ControlResults[0], `
                    $false, $SVTEventContext.ControlItem)
                $results.Add($result)
            }
            elseif ($SVTEventContext.ControlResults.Count -eq 1 -and `
                $scanResult.ResourceName -ne $SVTEventContext.ControlResults[0].ChildResourceName)
            {
                $result = [RemoteReportHelper]::BuildServiceControlResult($SVTEventContext.ControlResults[0], `
                     $true, $SVTEventContext.ControlItem)
                $results.Add($result)
            }
            elseif ($SVTEventContext.ControlResults.Count -gt 1)
            {
                $SVTEventContext.ControlResults | Foreach-Object {
                    $result = [RemoteReportHelper]::BuildServiceControlResult($_ , `
                         $true, $SVTEventContext.ControlItem)
                    $results.Add($result)
                }
            }
        }
        $scanResult.ControlResults = [ServiceControlResult[]] $results
        [RemoteApiHelper]::PostServiceScanResult($scanResult)
    }
}

# SIG # Begin signature block
# MIIj/gYJKoZIhvcNAQcCoIIj7zCCI+sCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBDFSNhs33Ge7ox
# RBRUi8iE/sHFA2Eo4gGSOd7WwYw1jqCCDZMwggYRMIID+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
# wTCCFb0CAQEwgZUwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAA
# AI6HkaRXGl/KPgAAAAAAjjANBglghkgBZQMEAgEFAKCBsDAZBgkqhkiG9w0BCQMx
# DAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkq
# hkiG9w0BCQQxIgQgDntjbHxG7KSS0rVe46nihRWrhQi0/OjmOeGbAF2/SeowRAYK
# KwYBBAGCNwIBDDE2MDSgEoAQAEEAegBTAEQASwAyADUAMqEegBxodHRwczovL2Fr
# YS5tcy9henNka29zc2RvY3MgMA0GCSqGSIb3DQEBAQUABIIBAGahwZuWj9jDmvrh
# KVUPEPAukOB9ONKE/CqVHs3TvAEyWPK/Jhn+hjuBw/9I527+HuDXlRNLDSk9UUzk
# 8XZTKZGKkEoC+AukYIRXH5VJDYSeSVDxV3YT7DRnRAT2HRxM5e7CXnY4UG8+f1mY
# Fpcn8Va9XhHrw4Gl753ICH65IKNu5V8121nogar9a+fbrpsJhn+K/0/kn5bJyM61
# jfC8EjYPF0I1DXZy0eoa4tb102M7KQjYmLXiIKatWViKF6uuc7Wna/QXPgba/Jnd
# pYQ/jiA4hh5mDW0bwQFdICQu5s+FRwqjxHjCu1Fs4aYDOVoljkXgwLLv2X4hII0S
# bdBcuP6hghNJMIITRQYKKwYBBAGCNwMDATGCEzUwghMxBgkqhkiG9w0BBwKgghMi
# MIITHgIBAzEPMA0GCWCGSAFlAwQCAQUAMIIBOQYLKoZIhvcNAQkQAQSgggEoBIIB
# JDCCASACAQEGCisGAQQBhFkKAwEwMTANBglghkgBZQMEAgEFAAQgAcVUolKWU/qV
# bcC9yUTRMZGUFf5/QXawJR7cxhrZtCsCBlmSITMXzxgSMjAxNzA5MDUwOTM3MjQu
# MDJaMASAAgH0oIG5pIG2MIGzMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
# cmF0aW9uMQ0wCwYDVQQLEwRNT1BSMScwJQYDVQQLEx5uQ2lwaGVyIERTRSBFU046
# MTQ4Qy1DNEI5LTIwNjYxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNl
# cnZpY2Wggg7QMIIGcTCCBFmgAwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsF
# ADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
# B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UE
# AxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcN
# MTAwNzAxMjEzNjU1WhcNMjUwNzAxMjE0NjU1WjB8MQswCQYDVQQGEwJVUzETMBEG
# A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj
# cm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFt
# cCBQQ0EgMjAxMDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkdDbx3
# EYo6IOz8E5f1+n9plGt0VBDVpQoAgoX77XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEf
# QRsalR3OCROOfGEwWbEwRA/xYIiEVEMM1024OAizQt2TrNZzMFcmgqNFDdDq9UeB
# zb8kYDJYYEbyWEeGMoQedGFnkV+BVLHPk0ySwcSmXdFhE24oxhr5hoC732H8RsEn
# HSRnEnIaIYqvS2SJUGKxXf13Hz3wV3WsvYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9
# buWayrGo8noqCjHw2k4GkbaICDXoeByw6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzA
# yURdXhacAQVPIk0CAwEAAaOCAeYwggHiMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1Ud
# DgQWBBTVYzpcijGQ80N7fEYbxTNoWoVtVTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBi
# AEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV
# 9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3Js
# Lm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAx
# MC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2
# LTIzLmNydDCBoAYDVR0gAQH/BIGVMIGSMIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYB
# BQUHAgEWMWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVm
# YXVsdC5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AUABvAGwAaQBj
# AHkAXwBTAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAAfm
# iFEN4sbgmD+BcQM9naOhIW+z66bM9TG+zwXiqf76V20ZMLPCxWbJat/15/B4vceo
# niXj+bzta1RXCCtRgkQS+7lTjMz0YBKKdsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDI
# r79/xn/yN31aPxzymXlKkVIArzgPF/UveYFl2am1a+THzvbKegBvSzBEJCI8z+0D
# pZaPWSm8tv0E4XCfMkon/VWvL/625Y4zu2JfmttXQOnxzplmkIz/amJ/3cVKC5Em
# 4jnsGUpxY517IW3DnKOiPPp/fZZqkHimbdLhnPkd/DjYlPTGpQqWhqS9nhquBEKD
# uLWAmyI4ILUl5WTs9/S/fmNZJQ96LjlXdqJxqgaKD4kWumGnEcua2A5HmoDF0M2n
# 0O99g/DhO3EJ3110mCIIYdqwUB5vvfHhAN/nMQekkzr3ZUd46PioSKv33nJ+YWtv
# d6mBy6cJrDm77MbL2IK0cs0d9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3g
# My4SKfXAL1QnIffIrE7aKLixqduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1
# mYovG8chr1m1rtxEPJdQcdeh0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9Y
# BS7vDaBQNdrvCScc1bN+NR4Iuto229Nfj950iEkSMIIE2jCCA8KgAwIBAgITMwAA
# ALRDOhz+trpSiQAAAAAAtDANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1T
# dGFtcCBQQ0EgMjAxMDAeFw0xNjA5MDcxNzU2NThaFw0xODA5MDcxNzU2NThaMIGz
# MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk
# bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMQ0wCwYDVQQLEwRN
# T1BSMScwJQYDVQQLEx5uQ2lwaGVyIERTRSBFU046MTQ4Qy1DNEI5LTIwNjYxJTAj
# BgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggEiMA0GCSqGSIb3
# DQEBAQUAA4IBDwAwggEKAoIBAQDggU+7tdEwOj+DALfMVp/3m6y6s11kER6C1nrX
# 7iD7s9EIAWOXV6fC4kxWqLVX26DG37PRGLEefpGsGRlRbXP+ni1tJEIgxMjvRmnQ
# bxxMYWqUMw+UPtuibyUqvxnSzgM6UhWARWUb/c+1/zeyaGaZZa3u/76BTUOeC3gJ
# 1iqPPYq0BzPZsFAkUe9/9STUFQyPdhjYVry1baMpdNh1B0hAGY5mGJECAnAbQdv5
# J6EZdcaWqPpBL7t6xTSmMKCXk8cabABagraMAGeSy8xN0myp48ReeQsBla6opLki
# /vlFXj99GRthnDd02aNRxe5I2VQzFINfsucPe7AfyZe+mYVxAgMBAAGjggEbMIIB
# FzAdBgNVHQ4EFgQUDJOrRdRsC3cv8ytX8+kkxIcH9F8wHwYDVR0jBBgwFoAU1WM6
# XIoxkPNDe3xGG8UzaFqFbVUwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5t
# aWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljVGltU3RhUENBXzIwMTAt
# MDctMDEuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNUaW1TdGFQQ0FfMjAxMC0wNy0w
# MS5jcnQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkqhkiG
# 9w0BAQsFAAOCAQEAArVhW6Cn0mqsJi+2wjSjdPuoe5Cxgi2oiRJdpPaCC1k9J+d6
# HXks+Mtyz0dr72/e65Jt7q/7XqGRhHjjX1F7xJcx4FCN7bqZ94gqv1Fq4iPkN0fd
# ZuLFhQjs/nVx63ptSYklIR2djhbkWKTmqJW1m7SToYosuJwhOrwBUR+Y4J/z7epQ
# zLs3hClq8CJspU+uExF5ZmRwJ6MM+rTeTLtQfsSff+mBUQTerhRf5g4MEIG6Rqw7
# YhLntdEKMPDTKez603Axbgp6JFHCIuYOIrdDUapTVSL1JLXn03V4KaE6W2kK4K18
# mc+ftJIoB36qcMQyhltKDthEtvU+Zx95w/IrU6GCA3kwggJhAgEBMIHjoYG5pIG2
# MIGzMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMQ0wCwYDVQQL
# EwRNT1BSMScwJQYDVQQLEx5uQ2lwaGVyIERTRSBFU046MTQ4Qy1DNEI5LTIwNjYx
# JTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiJQoBATAJBgUr
# DgMCGgUAAxUAB8CVl64uTm7J03X22YlRmIsgbTqggcIwgb+kgbwwgbkxCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIxJzAl
# BgNVBAsTHm5DaXBoZXIgTlRTIEVTTjo0REU5LTBDNUUtM0UwOTErMCkGA1UEAxMi
# TWljcm9zb2Z0IFRpbWUgU291cmNlIE1hc3RlciBDbG9jazANBgkqhkiG9w0BAQUF
# AAIFAN1YrQQwIhgPMjAxNzA5MDUwNDU2MzZaGA8yMDE3MDkwNjA0NTYzNlowdzA9
# BgorBgEEAYRZCgQBMS8wLTAKAgUA3VitBAIBADAKAgEAAgIHOgIB/zAHAgEAAgIc
# GDAKAgUA3Vn+hAIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMBoAow
# CAIBAAIDB6EgoQowCAIBAAIDB6EgMA0GCSqGSIb3DQEBBQUAA4IBAQAvBjrv03bW
# XJjK/TYz2Goa1YqrDOjkv2MUnDNUhI+IHXUDjiqZLY3RUbQ2MuumhJh5UFByinHy
# roykRJzCgEtj2OfkoESNN9bE7IwRehU8/TXMwnU+pepUM1B54evC0GLl7AQH6we8
# V6eKJAstq+5Fk4suL4wntIjZoiJ9zGTaDNLLOPQ3BakVRkfy4oGFY32pczQgmiM9
# LDxh4mpyNocDwzaVaIPOgsW6G+immRdTmNAD6Ls+mNJTsZH1zXbmJrD0b7JJwEH9
# ZVswBuGbb1xjA0bgAnRxaEk/1P5x0l0Wpq/05/3VXvDLYTEAzn6FPI72gH7yuOSm
# Lx4YJg5PA7nCMYIC9TCCAvECAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
# IDIwMTACEzMAAAC0Qzoc/ra6UokAAAAAALQwDQYJYIZIAWUDBAIBBQCgggEyMBoG
# CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgZaFPnItz
# YnDFAe3Kiw3/g4bH3Ydk/u5XxVhq9NIw49IwgeIGCyqGSIb3DQEJEAIMMYHSMIHP
# MIHMMIGxBBQHwJWXri5ObsnTdfbZiVGYiyBtOjCBmDCBgKR+MHwxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU
# aW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAAtEM6HP62ulKJAAAAAAC0MBYEFG9yRO7E
# uoQyn6nve0w6Uv/w8wHgMA0GCSqGSIb3DQEBCwUABIIBANkR/GEgpWO9Kgvr4a7R
# Qby4hImtx7uvf6KHrPNbUsBLVwTL4Z6MUykZWHdvRBv5kEdjqUTKFPCz+xYAfb84
# oHjJHXeMG0iPmOSpeEDmH882ilrVQdRAuZg1hcGIDKoWunswOMJqSaYFsw45srAT
# 73VtEL60I9/05KeR8CvB2HNu4mZ0tBoe2vaa3d7FbazU5D6ex3twbnx2EDSXr6bO
# qipoCREazr1lSo4iA5N0Ti5wA6X8Fp7eO1HiAX3hLW8NVIbbXUiNh1rzQpIpTS7N
# /QjYqKk1p2ARkWCQgrz/o3cvTpC7ZNZc1cvIfcYr87S9rNzgZubwGy1T0PT1N88M
# 8hU=
# SIG # End signature block