Framework/Core/AzSKADOInfo/ControlsInfo.ps1

using namespace System.Management.Automation
Set-StrictMode -Version Latest

class ControlsInfo: CommandBase
{
    hidden [string] $ResourceTypeName
    hidden [string] $ResourceType
    hidden [bool] $OnlyBaselineControls
    hidden [bool] $OnlyPreviewBaselineControls
    hidden [PSObject] $ControlSettings
    hidden [string[]] $Tags = @();
    hidden [string[]] $FilterTags = @();
    hidden [string[]] $ControlIds = @();
    hidden [bool] $Full
    hidden [string] $SummaryMarkerText = "------"
    hidden [string] $ControlSeverity
    hidden [string] $ControlIdContains

    ControlsInfo([string] $organizationName, [InvocationInfo] $invocationContext, [string] $resourceTypeName, [string] $controlIdString, [bool] $OnlyBaselineControls,[bool] $OnlyPreviewBaselineControls,
                    [string] $filterTagsString, [bool] $full, [string] $controlSeverity, [string] $controlIdContains) :  Base($organizationName, $invocationContext)
    {
        $this.ResourceTypeName = $resourceTypeName;
        $this.OnlyBaselineControls = $OnlyBaselineControls;
        $this.OnlyPreviewBaselineControls = $OnlyPreviewBaselineControls
        $this.Full = $full;
        $this.ControlSeverity = $controlSeverity;
        $this.ControlIdContains = $controlIdContains

        if(-not [string]::IsNullOrEmpty($controlIdString))
        {
            $this.ControlIds = $this.ConvertToStringArray($controlIdString);
        }
        if($this.Full)
        {
            $this.DoNotOpenOutputFolder = $true;
        }
    }

    [MessageData[]] GetControlDetails()
    {
        [MessageData[]] $returnMsgs = @();
        $resourcetypes = @()
        $SVTConfig = @{}
        $allControls = @()
        $controlSummary = @()

        # Filter Control for Resource Type / Resource Type Name
        if([string]::IsNullOrWhiteSpace($this.ResourceType) -and [string]::IsNullOrWhiteSpace($this.ResourceTypeName))
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default);
            $this.PublishCustomMessage([Constants]::DefaultControlInfoCmdMsg, [MessageType]::Default);
            $this.DoNotOpenOutputFolder = $true;
            return $returnMsgs;
        }

        #throw if user has set params for ResourceTypeName and ResourceType
        #Default value of ResourceTypeName is All.
        if($this.ResourceTypeName -ne [ResourceTypeName]::All -and -not [string]::IsNullOrWhiteSpace($this.ResourceType)){
            throw [SuppressedException] "Both the parameters 'ResourceTypeName' and 'ResourceType' contains values. You should use only one of these parameters."
        }

        if (-not [string]::IsNullOrEmpty($this.ResourceType))
        {
            $resourcetypes += ([SVTMapping]::AzSKADOResourceMapping |
                    Where-Object { $_.ResourceType -eq $this.ResourceType } | Select-Object JsonFileName, ResourceTypeName)
        }
        elseif($this.ResourceTypeName -ne [ResourceTypeName]::All)
        {
            $resourcetypes += ([SVTMapping]::AzSKADOResourceMapping |
                    Where-Object { $_.ResourceTypeName -eq $this.ResourceTypeName } | Select-Object JsonFileName, ResourceTypeName)
        }
        else
        {
            $resourcetypes += ([SVTMapping]::AzSKADOResourceMapping | Sort-Object ResourceTypeName | Select-Object JsonFileName, ResourceTypeName)
        }

        # Fetch control Setting data
        $this.ControlSettings = [ConfigurationManager]::LoadServerConfigFile("ControlSettings.json");

        # Filter control for baseline controls
        $baselineControls = @();
        $baselineControls += $this.ControlSettings.BaselineControls.ResourceTypeControlIdMappingList | Select-Object ControlIds | ForEach-Object {  $_.ControlIds }




        if($this.OnlyBaselineControls)
        {
            $this.ControlIds = $baselineControls
        }

        $previewBaselineControls = @();

        if([Helpers]::CheckMember($this.ControlSettings,"PreviewBaselineControls.ResourceTypeControlIdMappingList") )
        {
            $previewBaselineControls += $this.ControlSettings.PreviewBaselineControls.ResourceTypeControlIdMappingList | Select-Object ControlIds | ForEach-Object {  $_.ControlIds }
        }


        if($this.OnlyPreviewBaselineControls)
        {
            #If preview baseline switch is passed and there is no preview baseline control list present then throw exception
            if (($previewBaselineControls | Measure-Object).Count -eq 0 -and -not $this.OnlyBaselineControls)
            {
                throw ([SuppressedException]::new(("There are no preview baseline controls defined for this policy."), [SuppressedExceptionType]::Generic))
            }

            $this.ControlIds += $previewBaselineControls

        }

        $resourcetypes | ForEach-Object{
                    $currentResource = $_;
                    $controls = [ConfigurationManager]::GetSVTConfig($currentResource.JsonFileName);

                    # Filter control for enable only, Second filter to fetch controls from comonsvt only for specific resource type
                    $controls.Controls = ($controls.Controls | Where-Object { $_.Enabled -eq $true -and $_.Id.StartsWith($currentResource.ResourceTypeName) } )

                    # Filter control for ControlIds
                    if ([Helpers]::CheckMember($controls, "Controls") -and $this.ControlIds.Count -gt 0)
                    {
                        $controls.Controls = ($controls.Controls | Where-Object { $this.ControlIds -contains $_.ControlId })
                    }

                    # Filter control for ControlId Contains
                    if ([Helpers]::CheckMember($controls, "Controls") -and (-not [string]::IsNullOrEmpty($this.ControlIdContains)))
                    {
                        $controls.Controls = ($controls.Controls | Where-Object { $_.ControlId -Match $this.ControlIdContains })
                    }

                    # Filter control for Tags
                    if ([Helpers]::CheckMember($controls, "Controls") -and $this.Tags.Count -gt 0)
                    {
                        $controls.Controls = ($controls.Controls | Where-Object { ((Compare-Object $_.Tags $this.Tags -PassThru -IncludeEqual -ExcludeDifferent) | Measure-Object).Count -gt 0 })
                    }

                    # Filter control for ControlSeverity
                    if ([Helpers]::CheckMember($controls, "Controls") -and (-not [string]::IsNullOrEmpty($this.ControlSeverity)))
                    {
                        $controls.Controls = ($controls.Controls | Where-Object { $this.ControlSeverity -eq $_.ControlSeverity })
                    }

                    if ([Helpers]::CheckMember($controls, "Controls") -and $controls.Controls.Count -gt 0)
                    {
                        if (-not $SVTConfig.ContainsKey($controls.FeatureName)) {
                        $SVTConfig.Add($currentResource.ResourceTypeName, @($controls.Controls))
                        }
                    }
                }

        if($SVTConfig.Keys.Count -gt 0)
        {

            $SVTConfig.Keys  | Foreach-Object {
                $featureName = $_
                $SVTConfig[$_] | Foreach-Object {
                    $_.Description = $global:ExecutionContext.InvokeCommand.ExpandString($_.Description)
                    $_.Recommendation = $global:ExecutionContext.InvokeCommand.ExpandString($_.Recommendation)
                    if($_.FixControl)
                    {
                        $fixControl = "Yes"
                    }
                    else
                    {
                        $fixControl = "No"
                    }

                    if($baselineControls -contains $_.ControlID)
                    {
                        $isBaselineControls = "Yes"
                    }
                    else
                    {
                        $isBaselineControls = "No"
                    }

                    if($previewBaselineControls -contains $_.ControlID)
                    {
                        $isPreviewBaselineControls = "Yes"
                    }
                    else
                    {
                        $isPreviewBaselineControls = "No"
                    }

                    $ControlSeverity = $_.ControlSeverity
                    if([Helpers]::CheckMember($this.ControlSettings,"ControlSeverity.$ControlSeverity"))
                    {
                        $_.ControlSeverity = $this.ControlSettings.ControlSeverity.$ControlSeverity
                    }
                    else
                    {
                        $_.ControlSeverity = $ControlSeverity
                    }

                    $ctrlObj = New-Object -TypeName PSObject
                    $ctrlObj | Add-Member -NotePropertyName FeatureName -NotePropertyValue $featureName
                    $ctrlObj | Add-Member -NotePropertyName ControlID -NotePropertyValue $_.ControlID
                    $ctrlObj | Add-Member -NotePropertyName Description -NotePropertyValue $_.Description
                    $ctrlObj | Add-Member -NotePropertyName ControlSeverity -NotePropertyValue $_.ControlSeverity
                    $ctrlObj | Add-Member -NotePropertyName IsBaselineControl -NotePropertyValue $isBaselineControls
                    $ctrlObj | Add-Member -NotePropertyName IsPreviewBaselineControl -NotePropertyValue $isPreviewBaselineControls
                    $ctrlObj | Add-Member -NotePropertyName Rationale -NotePropertyValue $_.Rationale
                    $ctrlObj | Add-Member -NotePropertyName Recommendation -NotePropertyValue $_.Recommendation
                    $ctrlObj | Add-Member -NotePropertyName Automated -NotePropertyValue $_.Automated
                    $ctrlObj | Add-Member -NotePropertyName SupportsAutoFix -NotePropertyValue $fixControl
                    $tags = [system.String]::Join(", ", $_.Tags)
                    $ctrlObj | Add-Member -NotePropertyName Tags -NotePropertyValue $tags

                    $allControls += $ctrlObj

                    if($this.Full)
                    {
                        $this.PublishCustomMessage([Helpers]::ConvertObjectToString($ctrlObj, $true), [MessageType]::Info);
                        $this.PublishCustomMessage([Constants]::SingleDashLine, [MessageType]::Info);
                    }
                }

                $ctrlSummary = New-Object -TypeName PSObject
                $ctrlSummary | Add-Member -NotePropertyName FeatureName -NotePropertyValue $featureName
                $ctrlSummary | Add-Member -NotePropertyName Total -NotePropertyValue ($SVTConfig[$_]).Count
                $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Critical') -NotePropertyValue (($SVTConfig[$_] | Where-Object { $_.ControlSeverity -eq $this.GetControlSeverity("Critical") })|Measure-Object).Count
                $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('High') -NotePropertyValue (($SVTConfig[$_] | Where-Object { $_.ControlSeverity -eq $this.GetControlSeverity("High") })|Measure-Object).Count
                $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Medium') -NotePropertyValue (($SVTConfig[$_] | Where-Object { $_.ControlSeverity -eq $this.GetControlSeverity("Medium") })|Measure-Object).Count
                $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Low') -NotePropertyValue (($SVTConfig[$_] | Where-Object { $_.ControlSeverity -eq $this.GetControlSeverity("Low") })|Measure-Object).Count
                $controlSummary += $ctrlSummary
            }

            $controlCSV = New-Object -TypeName WriteCSVData
            $controlCSV.FileName = 'Control_Details_' + [String] $this.InvocationContext.Mycommand.ModuleName + "_" + [String] $this.GetCurrentModuleVersion()
            $controlCSV.FileExtension = 'csv'
            $controlCSV.FolderPath = ''
            $controlCSV.MessageData = $allControls| Sort-Object FeatureName, ControlSeverity

            $this.PublishAzSKRootEvent([AzSKRootEvent]::WriteCSV, $controlCSV);
        }
        else
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default);
            $this.PublishCustomMessage("No controls have been found.");
            $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default);
        }

        if($controlSummary.Count -gt 0)
        {
            $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default);
            $this.PublishCustomMessage("Summary of controls available in " + $this.InvocationContext.Mycommand.ModuleName +" "+  $this.GetCurrentModuleVersion(), [MessageType]::Default)
            $this.PublishCustomMessage([Constants]::DoubleDashLine, [MessageType]::Default);

            $ctrlSummary = New-Object -TypeName PSObject
            $ctrlSummary | Add-Member -NotePropertyName FeatureName -NotePropertyValue "Total"
            $ctrlSummary | Add-Member -NotePropertyName Total -NotePropertyValue ($controlSummary | Measure-Object 'Total' -Sum).Sum

            $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Critical') -NotePropertyValue ($controlSummary | Measure-Object "$($this.GetControlSeverity('Critical'))" -Sum).Sum
            $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('High') -NotePropertyValue ($controlSummary | Measure-Object "$($this.GetControlSeverity('High'))" -Sum).Sum
            $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Medium') -NotePropertyValue ($controlSummary | Measure-Object "$($this.GetControlSeverity('Medium'))" -Sum).Sum
            $ctrlSummary | Add-Member -NotePropertyName $this.GetControlSeverity('Low') -NotePropertyValue ($controlSummary | Measure-Object "$($this.GetControlSeverity('Low'))" -Sum).Sum

            $totalSummaryMarker = New-Object -TypeName PSObject
            $totalSummaryMarker | Add-Member -NotePropertyName FeatureName -NotePropertyValue $this.SummaryMarkerText
            $totalSummaryMarker | Add-Member -NotePropertyName Total -NotePropertyValue $this.SummaryMarkerText
            $totalSummaryMarker | Add-Member -NotePropertyName $this.GetControlSeverity('Critical') -NotePropertyValue $this.SummaryMarkerText
            $totalSummaryMarker | Add-Member -NotePropertyName $this.GetControlSeverity('High') -NotePropertyValue $this.SummaryMarkerText
            $totalSummaryMarker | Add-Member -NotePropertyName $this.GetControlSeverity('Medium') -NotePropertyValue $this.SummaryMarkerText
            $totalSummaryMarker | Add-Member -NotePropertyName $this.GetControlSeverity('Low') -NotePropertyValue $this.SummaryMarkerText

            $controlSummary += $totalSummaryMarker
            $controlSummary += $ctrlSummary

            $this.PublishCustomMessage(($controlSummary | Format-Table | Out-String), [MessageType]::Default)
        }

        $returnMsgs += [MessageData]::new("Returning ADO Control Info.");
        return $returnMsgs
    }

    [string] GetControlSeverity($ControlSeverityFromServer)
    {
        if([Helpers]::CheckMember($this.ControlSettings,"ControlSeverity.$ControlSeverityFromServer"))
        {
            $ControlSeverityFromServer = $this.ControlSettings.ControlSeverity.$ControlSeverityFromServer
        }
        return $ControlSeverityFromServer
    }
}

class WriteCSVData
{
    [string] $FileName = ""
    [string] $FileExtension = ""
    [string] $FolderPath = ""
    [PSObject] $MessageData
}
# SIG # Begin signature block
# MIIoOwYJKoZIhvcNAQcCoIIoLDCCKCgCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBnLbk5tJ6eeKtg
# nZVJATJk38xh0EJFfYSv7QObEFbX3KCCDYUwggYDMIID66ADAgECAhMzAAADri01
# UchTj1UdAAAAAAOuMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjMxMTE2MTkwODU5WhcNMjQxMTE0MTkwODU5WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQD0IPymNjfDEKg+YyE6SjDvJwKW1+pieqTjAY0CnOHZ1Nj5irGjNZPMlQ4HfxXG
# yAVCZcEWE4x2sZgam872R1s0+TAelOtbqFmoW4suJHAYoTHhkznNVKpscm5fZ899
# QnReZv5WtWwbD8HAFXbPPStW2JKCqPcZ54Y6wbuWV9bKtKPImqbkMcTejTgEAj82
# 6GQc6/Th66Koka8cUIvz59e/IP04DGrh9wkq2jIFvQ8EDegw1B4KyJTIs76+hmpV
# M5SwBZjRs3liOQrierkNVo11WuujB3kBf2CbPoP9MlOyyezqkMIbTRj4OHeKlamd
# WaSFhwHLJRIQpfc8sLwOSIBBAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUhx/vdKmXhwc4WiWXbsf0I53h8T8w
# VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
# dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzUwMTgzNjAfBgNVHSMEGDAW
# gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw
# MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx
# XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB
# AGrJYDUS7s8o0yNprGXRXuAnRcHKxSjFmW4wclcUTYsQZkhnbMwthWM6cAYb/h2W
# 5GNKtlmj/y/CThe3y/o0EH2h+jwfU/9eJ0fK1ZO/2WD0xi777qU+a7l8KjMPdwjY
# 0tk9bYEGEZfYPRHy1AGPQVuZlG4i5ymJDsMrcIcqV8pxzsw/yk/O4y/nlOjHz4oV
# APU0br5t9tgD8E08GSDi3I6H57Ftod9w26h0MlQiOr10Xqhr5iPLS7SlQwj8HW37
# ybqsmjQpKhmWul6xiXSNGGm36GarHy4Q1egYlxhlUnk3ZKSr3QtWIo1GGL03hT57
# xzjL25fKiZQX/q+II8nuG5M0Qmjvl6Egltr4hZ3e3FQRzRHfLoNPq3ELpxbWdH8t
# Nuj0j/x9Crnfwbki8n57mJKI5JVWRWTSLmbTcDDLkTZlJLg9V1BIJwXGY3i2kR9i
# 5HsADL8YlW0gMWVSlKB1eiSlK6LmFi0rVH16dde+j5T/EaQtFz6qngN7d1lvO7uk
# 6rtX+MLKG4LDRsQgBTi6sIYiKntMjoYFHMPvI/OMUip5ljtLitVbkFGfagSqmbxK
# 7rJMhC8wiTzHanBg1Rrbff1niBbnFbbV4UDmYumjs1FIpFCazk6AADXxoKCo5TsO
# zSHqr9gHgGYQC2hMyX9MGLIpowYCURx3L7kUiGbOiMwaMIIHejCCBWKgAwIBAgIK
# YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV
# BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv
# c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm
# aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw
# OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD
# VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la
# UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc
# 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D
# dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+
# lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk
# kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6
# A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd
# X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL
# 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd
# sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3
# T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS
# 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI
# bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL
# BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD
# uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv
# c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf
# MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf
# MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF
# BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h
# cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA
# YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn
# 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7
# v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b
# pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/
# KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy
# CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp
# mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi
# hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb
# BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS
# oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL
# gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX
# cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCGgwwghoIAgEBMIGVMH4x
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAOuLTVRyFOPVR0AAAAA
# A64wDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIBPt
# aZ30eeUhJBFA6Fq09/VgCRyW+guxtH8mMMBxerMfMEIGCisGAQQBgjcCAQwxNDAy
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20wDQYJKoZIhvcNAQEBBQAEggEAKuTvF9iTOFRd0i6iphCIZT5WRq2AxFtFTR2e
# SVSLcgR/DBdHpbrC4PVD+rjkp071ok7sbgrL2+Aggefkegu0QJKqwBvMnVEjeQSz
# yvWmnXlnjrukMo/atoHb3sKDW6mzECgZ1zp3OzahrXbZpWn0VvomHwNV5yKxcLRM
# Zi/oupcWayCJ7jDsh57qtwqf3Jv9s+3IQ1tBX4LDtkCztMbCLMCR4ZRha6TvLkiw
# J4o7PUpoEBCbnjM7M+fCM+w0TMAIPnsMC1P8bKcNDYwqYh6UvXz+wJyJbxwMsWpk
# OGoWppFinpp7V6q8k6O98sBaePi5/OW8A0qErBcqGewu65CbzaGCF5YwgheSBgor
# BgEEAYI3AwMBMYIXgjCCF34GCSqGSIb3DQEHAqCCF28wghdrAgEDMQ8wDQYJYIZI
# AWUDBAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGE
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCBMgpAhkb2mDm1tq4ST8boUSILootlsC/Fb
# KJYIOZkbRgIGZeeoHOyzGBIyMDI0MDMxMjA2NTUzOS4yMlowBIACAfSggdGkgc4w
# gcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsT
# HE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQg
# VFNTIEVTTjo5MjAwLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt
# U3RhbXAgU2VydmljZaCCEe0wggcgMIIFCKADAgECAhMzAAAB5y6PL5MLTxvpAAEA
# AAHnMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
# MB4XDTIzMTIwNjE4NDUxOVoXDTI1MDMwNTE4NDUxOVowgcsxCzAJBgNVBAYTAlVT
# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVy
# aWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo5MjAwLTA1
# RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCC
# AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMJXny/gi5Drn1c8zUO1pYy/
# 38dFQLmR2IQXz1gE/r9GfuSOoyRnkRJ6Z/kSWLgIu1BVJ59GkXWPtLkssqKwxY4Z
# FotxpVsZN9yYjW8xEnW3MzAI0igKr+/LxYfxB1XUH8Bvmwr5D3Ii/MbDjtN9c8Tx
# GWtq7Ar976dafAy3TrRqQRmIknPVWHUuFJgpqI/1nbcRmYYRMJaKCQpty4CeG+Hf
# Ksxrz24F9p4dBkQcZCp2yQzjwQFxZJZ2mJJIGIDHKEdSRuSeX08/O0H9JTHNFmNT
# NYeD1t/WapnRwiIBYLQSMrs42GVB8pJEdUsos0+mXf/5QvheNzRi92pzzyA4tSv/
# zhP3/Ermvza6W9GnYDz9qv1wbhbvrnS4poDFECaAviEqAhfn/RogCxvKok5ro4gZ
# IX1r4N9eXUulA80pHv3axwXu2MPlarAi6J9L1hSIcy9EuOMqTRJIJX+alcLQGg+S
# Tlqx/GuslsKwl48dI4RuWknNGbNo/o4xfBFytvtNcVA6xOQq6qRa+9gg+9XMLrxQ
# z4yyQs+V3V6p044wrtJtt/a0ZJl/f6I7BZAxxZcH2DDmArcAhgrTxaQkm7LM+p+K
# 2C5t1EKZiv0JWw065b7AcNgaFyIkMXYuSuOQVSNRxdIgl31/ayxiK1n0K6sZXvgF
# Bx+vGO+TUvyO+03ua6UjAgMBAAGjggFJMIIBRTAdBgNVHQ4EFgQUz/7gmICfNjh2
# kR/9mWuHUrvej1gwHwYDVR0jBBgwFoAUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXwYD
# VR0fBFgwVjBUoFKgUIZOaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j
# cmwvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3JsMGwG
# CCsGAQUFBwEBBGAwXjBcBggrBgEFBQcwAoZQaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIw
# MjAxMCgxKS5jcnQwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcD
# CDAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQELBQADggIBAHSh8NuT6WVaLVwL
# qex+J7km2nT2jpvoBEKm+0M+rYoU/6GL5Q00/ssZyIq5ySpcKYFMUiF8F4ZLG+Tr
# JyiR1CvfzXmkQ5phZOce9DT7yErLzqvUXit8G7igcHlxPLTxPiiGsb85gb8H+A2f
# PQ6Xq/u7+oSPPjzNdnpmXEobJnAqYplZoF3YNgTDMql0uQHGzoDp6dZlHSNj6rkV
# 1tXjmCEZMqBKvkQIA6csPieMnB+MirSZFlbANlChe0lJpUdK7aUdAvdgcQWKS6dt
# RMl818EMsvsa/6xOZGINmTLk4DGgsbaBpN+6IVt+mZJ89yCXkI5TN8xCfOkp9fr4
# WQjRBA2+4+lawNTyxH66eLZWYOjuuaomuibiKGBU10tox81Sq8EvlmJIrXOZoQsE
# n1r5g6MTmmZJqtbmwZufuJWQXZb0lAg4fq0ZYsUlLkezfrNqGSgeHyIP3rct4aNm
# qQW6wppRbvbIyP/LFN4YQM6givfmTBfGvVS77OS6vbL4W41jShmOmnOn3kBbWV6E
# /TFo76gFXVd+9oK6v8Hk9UCnbHOuiwwRRwDCkmmKj5Vh8i58aPuZ5dwZBhYDxSav
# wroC6j4mWPwh4VLqVK8qGpCmZ0HMAwao85Aq3U7DdlfF6Eru8CKKbdmIAuUzQrnj
# qTSxmvF1k+CmbPs7zD2Acu7JkBB7MIIHcTCCBVmgAwIBAgITMwAAABXF52ueAptJ
# mQAAAAAAFTANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNh
# dGUgQXV0aG9yaXR5IDIwMTAwHhcNMjEwOTMwMTgyMjI1WhcNMzAwOTMwMTgzMjI1
# WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCAiIwDQYJKoZIhvcNAQEB
# BQADggIPADCCAgoCggIBAOThpkzntHIhC3miy9ckeb0O1YLT/e6cBwfSqWxOdcjK
# NVf2AX9sSuDivbk+F2Az/1xPx2b3lVNxWuJ+Slr+uDZnhUYjDLWNE893MsAQGOhg
# fWpSg0S3po5GawcU88V29YZQ3MFEyHFcUTE3oAo4bo3t1w/YJlN8OWECesSq/XJp
# rx2rrPY2vjUmZNqYO7oaezOtgFt+jBAcnVL+tuhiJdxqD89d9P6OU8/W7IVWTe/d
# vI2k45GPsjksUZzpcGkNyjYtcI4xyDUoveO0hyTD4MmPfrVUj9z6BVWYbWg7mka9
# 7aSueik3rMvrg0XnRm7KMtXAhjBcTyziYrLNueKNiOSWrAFKu75xqRdbZ2De+JKR
# Hh09/SDPc31BmkZ1zcRfNN0Sidb9pSB9fvzZnkXftnIv231fgLrbqn427DZM9itu
# qBJR6L8FA6PRc6ZNN3SUHDSCD/AQ8rdHGO2n6Jl8P0zbr17C89XYcz1DTsEzOUyO
# ArxCaC4Q6oRRRuLRvWoYWmEBc8pnol7XKHYC4jMYctenIPDC+hIK12NvDMk2ZItb
# oKaDIV1fMHSRlJTYuVD5C4lh8zYGNRiER9vcG9H9stQcxWv2XFJRXRLbJbqvUAV6
# bMURHXLvjflSxIUXk8A8FdsaN8cIFRg/eKtFtvUeh17aj54WcmnGrnu3tz5q4i6t
# AgMBAAGjggHdMIIB2TASBgkrBgEEAYI3FQEEBQIDAQABMCMGCSsGAQQBgjcVAgQW
# BBQqp1L+ZMSavoKRPEY1Kc8Q/y8E7jAdBgNVHQ4EFgQUn6cVXQBeYl2D9OXSZacb
# UzUZ6XIwXAYDVR0gBFUwUzBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYz
# aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnku
# aHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIA
# QwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2
# VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwu
# bWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEw
# LTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93
# d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYt
# MjMuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCdVX38Kq3hLB9nATEkW+Geckv8qW/q
# XBS2Pk5HZHixBpOXPTEztTnXwnE2P9pkbHzQdTltuw8x5MKP+2zRoZQYIu7pZmc6
# U03dmLq2HnjYNi6cqYJWAAOwBb6J6Gngugnue99qb74py27YP0h1AdkY3m2CDPVt
# I1TkeFN1JFe53Z/zjj3G82jfZfakVqr3lbYoVSfQJL1AoL8ZthISEV09J+BAljis
# 9/kpicO8F7BUhUKz/AyeixmJ5/ALaoHCgRlCGVJ1ijbCHcNhcy4sa3tuPywJeBTp
# kbKpW99Jo3QMvOyRgNI95ko+ZjtPu4b6MhrZlvSP9pEB9s7GdP32THJvEKt1MMU0
# sHrYUP4KWN1APMdUbZ1jdEgssU5HLcEUBHG/ZPkkvnNtyo4JvbMBV0lUZNlz138e
# W0QBjloZkWsNn6Qo3GcZKCS6OEuabvshVGtqRRFHqfG3rsjoiV5PndLQTHa1V1QJ
# sWkBRH58oWFsc/4Ku+xBZj1p/cvBQUl+fpO+y/g75LcVv7TOPqUxUYS8vwLBgqJ7
# Fx0ViY1w/ue10CgaiQuPNtq6TPmb/wrpNPgkNWcr4A245oyZ1uEi6vAnQj0llOZ0
# dFtq0Z4+7X6gMTN9vMvpe784cETRkPHIqzqKOghif9lwY1NNje6CbaUFEMFxBmoQ
# tB1VM1izoXBm8qGCA1AwggI4AgEBMIH5oYHRpIHOMIHLMQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmlj
# YSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046OTIwMC0wNUUw
# LUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoB
# ATAHBgUrDgMCGgMVALNyBOcZqxLB792u75w97U0X+/BDoIGDMIGApH4wfDELMAkG
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z
# b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQELBQACBQDpmg8OMCIY
# DzIwMjQwMzExMjMxNTI2WhgPMjAyNDAzMTIyMzE1MjZaMHcwPQYKKwYBBAGEWQoE
# ATEvMC0wCgIFAOmaDw4CAQAwCgIBAAICJbgCAf8wBwIBAAICEyYwCgIFAOmbYI4C
# AQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEK
# MAgCAQACAwGGoDANBgkqhkiG9w0BAQsFAAOCAQEAhY1ZYdzCKdA5eWBUM3oZ3PJg
# B3LEWVuVf1UecBMRA7YWcU9pO2qmXBrL0VV4c8T2k4Dz2qO7zsiufWXZ01ISJg9s
# 3TKk3hmWKjQLnFjfWkuw79W5eDyd9RouvpOVrs2iYgS3bvTmVihgdkSZoQ+DHj9K
# HGtQvucv461v6DBgCBHzBV736DXe/+TD8C5vJnTjY0CPw9U+/ohdYhv+kL9tar1e
# QQCyVVskJTIzKw830coCqSgO3ldLf4vMv+gE4fZZLxVO1D1OCJHlgzjrIKJ3Ppd4
# U4juRoLPiqn0JP7KpmnMHAEi8TZkNtURACrQhH7k10xJ2xM8oP//OOVijp940jGC
# BA0wggQJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB
# 5y6PL5MLTxvpAAEAAAHnMA0GCWCGSAFlAwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMx
# DQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIB5/emxHRkUo3cV4i53Kbbuq
# nsPb4trq8Jj9IITWXjDvMIH6BgsqhkiG9w0BCRACLzGB6jCB5zCB5DCBvQQg5TZd
# DXZqhv0N4MVcz1QUd4RfvgW/QAG9AwbuoLnWc60wgZgwgYCkfjB8MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQg
# VGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAecujy+TC08b6QABAAAB5zAiBCCZZ/1W
# UDtTzf7/6phTSvMaADlD788UvG966Vr+OajzFjANBgkqhkiG9w0BAQsFAASCAgBt
# ZuCvil8sHS3NydAKr80nLxUkaQvr7BEnA0ZDy0LWVWVl86vTXcXt8czMzLVzBLyf
# Xixf9XbO/AZwbMbvI1irYAThVB9OlNn6tBZmlRkR8JOFIGTOO7cuy1POltzDlfqh
# 3/f/Va/xRHRDfnT/84uwVTqh7Y8jE5niA6jOrwxPi3tlNtG9L7KxhJuUt4cQIDM7
# D2O74Qjh/S2zr0SFniHWQ6KKvHUTPE7y2NZPY1CUcxyXdD0hPb6e8554/+PRvn+j
# 0qm+HEQvhcNnC9wVRVreQokO6VUU224OXeBU5DglygL0E1RoWfQYie6QRo13bua4
# 1kEywGECXte7/YDXM43fbfJEamsgMxuNrqT0eY+8APoaQ6KazCV/iJlaHaCKGd/D
# PMsNL2cVaqSzNf/clkFdNh3h1+LesuEOWDFhigOfeVrjotLwjyK7q8A6yinSylqt
# 8ZQC1NldwDSeTJO5/6lmyofTFhuQ3tA7UvajbjNAwndmaiQZdAmfSm5uPHvzCD5k
# jIxb3aUNpulnY6IA9UnQSaEjH/ZR3ahp5Ln5ctbzqS22IuXMiENEL7yG9YyOnhkx
# Npcqs6c0tdmpoJZcE0VitZ3rfU1GLIpQttcPhQA/+UJ0iWv0tdDFn8Ek95cQwjcU
# y75PkY+SK0wInwjCc2wNBo+oSS7dnEbhb42WqFk56w==
# SIG # End signature block