Private/log-analytics.ps1

function GetLogAnalyticsWorkspace ($ResourceGroup, $WorkspaceId) {
    # Try to find by workspace id
    if($null -ne $WorkspaceId) {
        $workspaces = Invoke-Az @("graph", "query", "-q", "Resources | where type == 'microsoft.operationalinsights/workspaces' and properties.customerId == '$WorkspaceId' | project name, workspaceId = properties.customerId, location, resourceGroup") | Convert-LinesToObject
    }

    # Try to find by resource group
    if($null -eq $workspaces -or $workspaces.count -eq 0) {
        $workspaces = Invoke-Az @("graph", "query", "-q", "Resources | where type == 'microsoft.operationalinsights/workspaces' and resourceGroup == '$ResourceGroup' | project name, workspaceId = properties.customerId, location, resourceGroup") | Convert-LinesToObject
    }

    if($workspaces.count -eq 1) {
        Write-Information "Found log analytics workspace $($workspaces.data[0].name)"
        return $workspaces.data[0]
    } elseif($workspaces.count -gt 1) {
        Write-Information "Found log analytics workspaces:"
        $workspaces.data | ForEach-Object { Write-Information $_.name }
        $potentialWorkspaceName = Read-Host "We have found more than one existing log analytics workspace in the resource group $ResourceGroup. Please enter the name of the workspace you want to use"

        $potentialWorkspace = $workspaces.data | Where-Object { $_.name -eq $potentialWorkspaceName }
        if($null -eq $potentialWorkspace) {
            Write-Error "We couldn't find a log analytics workspace with name $potentialWorkspaceName in resource group $ResourceGroup. Please try to re-run the script"
            throw "We couldn't find a log analytics workspace with name $potentialWorkspaceName in resource group $ResourceGroup. Please try to re-run the script"
        } else {
            return $potentialWorkspace
        }
    }
    else {
        Write-Warning "Unable to determine the log analytics workspace"
        return $null
    }
}

function GetDataCollectionRule {
    param(
        [Parameter(Mandatory, ParameterSetName = "ByResourceGroup")]
        [string]$ResourceGroup,
        [Parameter(Mandatory, ParameterSetName = "ByDcrId")]
        [string]$DcrId
    )

    if($PSCmdlet.ParameterSetName -eq 'ByDcrId') {
        Write-Verbose "Looking for data collection rule with id $DcrId"
        $dataCollectionRule = Invoke-Az @("graph", "query", "-q", "Resources | where type == 'microsoft.insights/datacollectionrules' and properties.immutableId == '$DcrId' | project id, name, location, resourceGroup, endpoints = properties.endpoints, immutableId = properties.immutableId") | Convert-LinesToObject
    }

    if($PSCmdlet.ParameterSetName -eq 'ByResourceGroup') {
        Write-Verbose "Looking for data collection rules in the resource group $ResourceGroup"
        $dataCollectionRule = Invoke-Az @("graph", "query", "-q", "Resources | where type == 'microsoft.insights/datacollectionrules' and resourceGroup == '$ResourceGroup' | project id, name, location, resourceGroup, endpoints = properties.endpoints, immutableId = properties.immutableId") | Convert-LinesToObject

        if($dataCollectionRule.count -gt 1) {
            Write-Information "Found data collection rules:"
            $dataCollectionRule.data | ForEach-Object { Write-Information $_.name }
            $potentialDcrName = Read-Host "We have found more than one existing data collection rule in the resource group $ResourceGroup. Please enter the data collection rule you would like to use"

            # Check if the selected DCR is in our results
            $potentialDcr = $dataCollectionRule.data | Where-Object { $_.name -eq $potentialDcrName }
            if($null -eq $potentialDcr) {
                Write-Error "We couldn't find a data collection rule with name $potentialDcrName in resource group $ResourceGroup. Please try to re-run the script"
                throw "We couldn't find a data collection rule with name $potentialDcrName in resource group $ResourceGroup. Please try to re-run the script"
            } else {
                return $potentialDcr
            }
        }
    }

    if($dataCollectionRule.count -eq 1) {
        Write-Information "Found data collection rule $($dataCollectionRule.data[0].name)"
        return $dataCollectionRule.data[0]
    } else {
        Write-Warning "Unable to determine the data collection rule"
        return $null
    }
}

function GetLogAnalyticsTable($ResourceGroup, $WorkspaceAccount, $SubscriptionId, $tableName) {
    $table = Invoke-Az -MaxRetries 0 -azCommand @("monitor", "log-analytics", "workspace", "table", "show", "--resource-group", $ResourceGroup, "--workspace-name", $($WorkspaceAccount.name), "--name", $tableName) | Convert-LinesToObject
    return $table
}

function ValidateLogAnalyticsTable($ResourceGroup, $WorkspaceAccount, $SubscriptionId) {
    $LogsTableColumnDefinitions = @(
        @{ name="TimeGenerated"; type="datetime" },
        @{ name="Timestamp"; type="string" },
        @{ name="Level"; type="string" },
        @{ name="Message"; type="string" },
        @{ name="Exception"; type="string" },
        @{ name="TenantIdentifier"; type="string" },
        @{ name="RequestUrl"; type="string" },
        @{ name="UserAgent"; type="string" },
        @{ name="LogCategory"; type="string" },
        @{ name="EventId"; type="string" },
        @{ name="Hostname"; type="string" },
        @{ name="WebsiteHostname"; type="string" },
        @{ name="WebsiteSiteName"; type="string" },
        @{ name="WebsiteSlotName"; type="string" },
        @{ name="BaseUrl"; type="string" },
        @{ name="TraceIdentifier"; type="string" }
    )
    # Generate column definition strings for the az command
    $LogsTableColumns = $LogsTableColumnDefinitions | ForEach-Object { "$($_.name)=$($_.type)" }

    # Try to find table
    $tableDetails = GetLogAnalyticsTable -ResourceGroup $ResourceGroup -WorkspaceAccount $WorkspaceAccount -SubscriptionId $SubscriptionId -tableName $LogsTableName
    if ($null -eq $tableDetails) {
        Write-Verbose "Table $LogsTableName does not exist in the workspace $($WorkspaceAccount.name). Creating it now."

        $azCommandToCreateWorkspaceTable = @("monitor", "log-analytics", "workspace", "table", "create", "--resource-group", $ResourceGroup, "--workspace-name", $($WorkspaceAccount.name), "--name", $LogsTableName)
        # We add the columns separately as they would end up as a single string in the command otherwise which would fail
        $azCommandToCreateWorkspaceTable += "--columns"
        $azCommandToCreateWorkspaceTable += $LogsTableColumns
        $null = Invoke-Az $azCommandToCreateWorkspaceTable

        Write-Information "Table $LogsTableName successfully created in the workspace $($WorkspaceAccount.name)"
    } else {
        # We have a table already, check if it is of the correct type
        if ($tableDetails.schema.tableSubType -ne 'DataCollectionRuleBased') {
            Write-Information "Table $LogsTableName exists but is not of type DataCollectionRuleBased. Found subType: $($tableDetails.schema.tableSubType)"
            Write-Information "Migrating to DataCollectionRuleBased table."

            $azCommandToMigrateWorkspaceTable = @("monitor", "log-analytics", "workspace", "table", "migrate", "--resource-group", $ResourceGroup, "--workspace-name", $($WorkspaceAccount.name), "--table-name", $LogsTableName)
            $null = Invoke-Az $azCommandToMigrateWorkspaceTable
        } else {
            Write-Verbose "Table $LogsTableName already exists in the workspace $($WorkspaceAccount.name) with the correct subtype"
        }

        # We have a table of the correct type, check if all columns are present
        $existingColumnNames = ($tableDetails.schema.columns | ForEach-Object { $_.name }) + ($tableDetails.schema.standardColumns | ForEach-Object { $_.name })
        $missingColumns = @()
        foreach ($columnDefinition in $LogsTableColumnDefinitions) {
            if (-not ($existingColumnNames -contains $columnDefinition.name)) {
                $missingColumns += $columnDefinition
            }
        }

        if ($missingColumns.Count -gt 0) {
            Write-Verbose "Could not find $($missingColumns.Count) columns in table $LogsTableName"
            Write-Verbose "Missing columns: $($missingColumns | ForEach-Object { $_.name } | Join-String -Separator ', ')"
            Write-Information "Updating table schema."
            $azCommandToUpdateWorkspaceTableSchema = @("monitor", "log-analytics", "workspace", "table", "update", "--resource-group", $ResourceGroup, "--workspace-name", $($WorkspaceAccount.name), "--name", $LogsTableName)
            # We add the columns separately as they would end up as a single string in the command otherwise which would fail
            $azCommandToUpdateWorkspaceTableSchema += "--columns"
            $azCommandToUpdateWorkspaceTableSchema += $LogsTableColumns
            $null = Invoke-Az $azCommandToUpdateWorkspaceTableSchema
        }
    }
}

function ValidateDCR($ResourceGroup, $WorkspaceAccount, $WorkspaceResourceId) {
    # Define the destinations JSON in a variable
    $destinations = @{
        "logAnalytics" = @(
            @{
                "WorkspaceResourceId" = "$WorkspaceResourceId";
                "name" = "$LogsDestinationName"
            }
        )
    }

    # Define the streamDeclarations JSON in a variable
    $streamDeclarations = @{
        "Custom-SCEPmanLogs" = @{
            "columns" = @(
                @{ "name" = "Timestamp"; "type" = "string" },
                @{ "name" = "Level"; "type" = "string" },
                @{ "name" = "Message"; "type" = "string" },
                @{ "name" = "Exception"; "type" = "string" },
                @{ "name" = "TenantIdentifier"; "type" = "string" },
                @{ "name" = "RequestUrl"; "type" = "string" },
                @{ "name" = "UserAgent"; "type" = "string" },
                @{ "name" = "LogCategory"; "type" = "string" },
                @{ "name" = "EventId"; "type" = "string" },
                @{ "name" = "Hostname"; "type" = "string" },
                @{ "name" = "WebsiteHostname"; "type" = "string" },
                @{ "name" = "WebsiteSiteName"; "type" = "string" },
                @{ "name" = "WebsiteSlotName"; "type" = "string" },
                @{ "name" = "BaseUrl"; "type" = "string" },
                @{ "name" = "TraceIdentifier"; "type" = "string" },
                @{ "name" = "TimeGenerated"; "type" = "Datetime" }
            )
        }
    }

    # Define the dataFlows JSON in a variable
    $dataFlows = @(
        @{
            "streams" = @("Custom-SCEPmanLogs");
            "destinations" = @("$LogsDestinationName");
            "outputStream" = "Custom-$LogsTableName"
        }
    )

    $destinationsJson = HashTable2AzJson -psHashTable $destinations
    $streamDeclarationsJson = HashTable2AzJson -psHashTable $streamDeclarations
    $dataFlowsJson = HashTable2AzJson -psHashTable $dataFlows

    $existingDcrDetails = Invoke-Az -MaxRetries 0 -azCommand @("monitor", "data-collection", "rule", "show", "--resource-group", $ResourceGroup, "--name", $DCRName) | Convert-LinesToObject

    # Check if we need to create the DCR
    if($null -eq $existingDcrDetails) {
        Write-Verbose "Data Collection Rule $DCRName does not exist in the resource group $ResourceGroup. Creating it now."

        # Create DCR
        $newDcrDetails = Invoke-Az @("monitor", "data-collection", "rule", "create", "--resource-group", $ResourceGroup, "--name", $DCRName, "--description", "Data Collection Rule for SCEPman logs", "--stream-declarations", $streamDeclarationsJson, "--destinations", $destinationsJson, "--data-flows", $dataFlowsJson, "--kind", "Direct", "--location", $($WorkspaceAccount.location), "--only-show-errors") | Convert-LinesToObject
        Write-Information "Data Collection Rule $DCRName successfully created"
        return $newDcrDetails
    }

    # Verify existing DCR configuration
    $DCRNeedsUpdate = $false

    # Verify destinations
    if($existingDcrDetails.destinations.logAnalytics.count -eq 0 -or $existingDcrDetails.destinations.logAnalytics[0].name -ne $LogsDestinationName -or $existingDcrDetails.destinations.logAnalytics[0].workspaceResourceId -ne $WorkspaceResourceId) {
        Write-Information "Data Collection Rule $DCRName exists but does not have the correct Log Analytics destination configured. Updating it now."
        $DCRNeedsUpdate = $true
    }

    # Verify streamDeclaration
    if($null -eq $existingDcrDetails.streamDeclarations.'Custom-SCEPmanLogs') {
        Write-Information "Data Collection Rule $DCRName exists but does not have the correct stream declarations configured. Updating it now."
        $DCRNeedsUpdate = $true
    }

    # Verify streamDeclarations columns
    if($null -ne $existingDcrDetails.streamDeclarations.'Custom-SCEPmanLogs') {
        $missingColumns = 0
        $streamDeclarations.'Custom-SCEPmanLogs'.columns | ForEach-Object {
            $columnName = $_.name
            $existingColumn = $existingDcrDetails.streamDeclarations.'Custom-SCEPmanLogs'.columns | Where-Object { $_.name -eq $columnName }
            if($null -eq $existingColumn) {
                $missingColumns++
            }
        }

        if($missingColumns -gt 0) {
            Write-Verbose "Data Collection Rule $DCRName is missing $missingColumns columns in the stream declaration Custom-SCEPmanLogs. Updating it now."
            $DCRNeedsUpdate = $true
        }
    }

    # Verify dataFlows
    if($existingDcrDetails.dataFlows.count -eq 0 -or $existingDcrDetails.dataFlows[0].outputStream -ne $dataFlows[0].outputStream) {
        Write-Verbose "Data Collection Rule $DCRName exists but does not have the correct data flows configured. Updating it now."
        $DCRNeedsUpdate = $true
    }

    if($existingDcrDetails.dataFlows[0].streams -ne $dataFlows[0].streams) {
        Write-Verbose "Data Collection Rule $DCRName exists but does not have the correct data flows streams configured. Updating it now."
        $DCRNeedsUpdate = $true
    }

    if($DCRNeedsUpdate) {
        # Update DCR
        $updatedDcrDetails = Invoke-Az @("monitor", "data-collection", "rule", "update", "--resource-group", $ResourceGroup, "--name", $DCRName, "--description", "Data Collection Rule for SCEPman logs", "--stream-declarations", $streamDeclarationsJson, "--destinations", $destinationsJson, "--data-flows-raw", $dataFlowsJson, "--kind", "Direct", "--only-show-errors") | Convert-LinesToObject
        Write-Information "Data Collection Rule $DCRName successfully updated"
        return $updatedDcrDetails
    } else {
        Write-Information "Data Collection Rule $DCRName already exists with the correct configuration. Skipping the creation/update of the DCR"
        return $existingDcrDetails
    }
}


function GetRuleIdName($SubscriptionId, $ResourceGroup) {
    $ruleIdName = "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroup/providers/Microsoft.Insights/dataCollectionRules/$DCRName"
    return $ruleIdName
}

function ConfigureLogIngestionAPIResources() {
    [CmdletBinding(SupportsShouldProcess=$true)]
    param (
        [Parameter(Mandatory=$true)]        [PSCustomObject]$WorkspaceAccount,
        [Parameter(Mandatory=$true)]        [string]$SubscriptionId
    )
    Write-Information "Installing az monitor control service extension"
    Invoke-Az @("extension", "add", "--name", "monitor-control-service", "--only-show-errors")

    # Create the new table
    if ($PSCmdlet.ShouldProcess("$WorkspaceAccount", "Validating log analytics workspace table and creating if it does not exist")) {
        ValidateLogAnalyticsTable -ResourceGroup $WorkspaceAccount.resourceGroup -WorkspaceAccount $WorkspaceAccount -SubscriptionId $SubscriptionId
    }

     # Create the DCR
    $workspaceResourceId = "/subscriptions/$SubscriptionId/resourceGroups/$($WorkspaceAccount.resourceGroup)/providers/microsoft.operationalinsights/workspaces/$($WorkspaceAccount.name)"
    if ($PSCmdlet.ShouldProcess("$WorkspaceAccount", "Validating Data Collection Rule and creating/updating if it does not exist or is misconfigured")) {
         $dcrDetails = ValidateDCR -ResourceGroup $WorkspaceAccount.resourceGroup -WorkspaceAccount $WorkspaceAccount -WorkspaceResourceId $workspaceResourceId
    }

    return $dcrDetails
}

function AddAppRoleAssignmentsForLogIngestionAPI($DcrResourceId, $ServicePrincipal, $SkipAppRoleAssignments = $false) {
    $azCommandToAssignRole = "az role assignment create --role 'Monitoring Metrics Publisher' --assignee-object-id $($ServicePrincipal) --assignee-principal-type ServicePrincipal --scope $DcrResourceId"
    if($SkipAppRoleAssignments) {
        Write-Warning "Skipping app role assignment (please execute manually): $azCommandToAssignRole"
        return
    }
    $null = ExecuteAzCommandRobustly -azCommand $azCommandToAssignRole
    Write-Verbose "Role 'Monitoring Metrics Publisher' assigned to service principal $ServicePrincipal for the scope of the Data Collection Rule with resource id $DcrResourceId"
}


function Set-LoggingConfigInAppSettings {
    [CmdletBinding(SupportsShouldProcess=$true)]
    # No settings are passed but a group of defined settings is applied/removed, so plural noun is appropriate here
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    param (
        [Parameter(Mandatory=$true)]        [string]$SubscriptionId,
        [Parameter(Mandatory=$true)]        [string]$ResourceGroup,
        [Parameter(Mandatory=$true)]        [string]$AppServiceName,
        [Parameter(Mandatory=$false)]        [System.Collections.IList]$servicePrincipals,
        [Parameter(Mandatory=$false)]        [string]$DeploymentSlotName,
        [Parameter(Mandatory=$false)]        [System.Collections.IList]$DeploymentSlots,
        [switch]$SkipAppRoleAssignments
    )
    # Check if we have an existing logging configuration
    $existingWorkspaceId = ReadAppSetting -ResourceGroup $ResourceGroup -AppServiceName $AppServiceName -SettingName "AppConfig:LoggingConfig:WorkspaceId" -Slot $DeploymentSlotName
    $existingDcrRuleId = ReadAppSetting -ResourceGroup $ResourceGroup -AppServiceName $AppServiceName -SettingName "AppConfig:LoggingConfig:RuleId" -Slot $DeploymentSlotName

    # Decide whether we create a DCR or not based on existing logging configuration
    if (-not [string]::IsNullOrEmpty($existingWorkspaceId) -and [string]::IsNullOrEmpty($existingDcrRuleId)) {
        Write-Information "Missing Log Ingestion API configuration detected while using existing log analytics workspace. Proceeding to configure Log Ingestion API resources."
        # Get LAW resource details
        $workspaceAccount = GetLogAnalyticsWorkspace -ResourceGroup $ResourceGroup -WorkspaceId $existingWorkspaceId

        if ($null -eq $workspaceAccount) {
            Write-Warning "Could not find the log analytics workspace with id $existingWorkspaceId. Please check if the workspace still exists or if the app setting is configured correctly. Skipping Log Ingestion API configuration."
            return
        }

        # Validate the log table and create or validate the DCR in the workspace resource group
        $dcrDetails = ConfigureLogIngestionAPIResources -WorkspaceAccount $workspaceAccount -SubscriptionId $SubscriptionId
    } elseif (-not [string]::IsNullOrEmpty($existingDcrRuleId)) {
        Write-Information "Existing Log Ingestion API configuration detected. Validate permissions"
        # Get DCR details
        $dcrDetails = GetDataCollectionRule -DcrId $existingDcrRuleId

        if ($null -eq $dcrDetails) {
            Write-Warning "Unable to find existing Data Collection Rule with id $existingDcrRuleId"
            return
        }
    } else {
        Write-Information "Neither existing log analytics workspace nor existing Log Ingestion API configuration detected. Check if we have a log analytics workspace in the resource group."

        # Try to find LAW in our resource group
        $workspaceAccount = GetLogAnalyticsWorkspace -ResourceGroup $ResourceGroup

        if ($null -eq $workspaceAccount) {
            Write-Information "No existing log analytics workspace found. Skipping logging configuration."
            return
        }

        # Validate the log table and create or validate the DCR in the workspace resource group
        $dcrDetails = ConfigureLogIngestionAPIResources -WorkspaceAccount $workspaceAccount -SubscriptionId $SubscriptionId
    }

    if($null -eq $dcrDetails -or [string]::IsNullOrEmpty($dcrDetails.immutableId) -or [string]::IsNullOrEmpty($dcrDetails.endpoints.logsIngestion)) {
        Write-Warning "Unable to configure Log Ingestion API due to missing Data Collection Rule details. Skipping Log Ingestion API configuration."
        return
    }

    $SettingsToRemove = @("AppConfig:LoggingConfig:WorkspaceId", "AppConfig:LoggingConfig:SharedKey")
    $SettingsToAdd = @(
        @{ name='AppConfig:LoggingConfig:DataCollectionEndpointUri'; value=$($DcrDetails.endpoints.logsIngestion) },
        @{ name='AppConfig:LoggingConfig:RuleId'; value=$($DcrDetails.immutableId) }
    )

    if([String]::IsNullOrEmpty($DeploymentSlotName)) {
        # In case we do not have a deployment slot, we just update the app settings of the app service
        # If we got a deployment slot, it will be handled in the slots loop below
        Write-Information "Configuring Log Ingestion API settings in App Service $AppServiceName"
        if ($PSCmdlet.ShouldProcess($AppServiceName, "Setting Log Ingestion API app settings in the App Service")) {
            RemoveAppSettings -AppServiceName $AppServiceName -ResourceGroup $ResourceGroup -SettingNames $SettingsToRemove
            SetAppSettings -AppServiceName $AppServiceName -ResourceGroup $ResourceGroup -Settings $SettingsToAdd
        }
    }

    ForEach($tempDeploymentSlot in $DeploymentSlots) {
        Write-Information "Configuring Log Ingestion API settings in App Service $AppServiceName in slot $tempDeploymentSlot"
        if ($PSCmdlet.ShouldProcess("$AppServiceName/$tempDeploymentSlot", "Setting Log Ingestion API app settings in the App Service Slot")) {
            RemoveAppSettings -AppServiceName $AppServiceName -ResourceGroup $ResourceGroup -SettingNames $SettingsToRemove -Slot $tempDeploymentSlot
            SetAppSettings -AppServiceName $AppServiceName -ResourceGroup $ResourceGroup -Settings $SettingsToAdd -Slot $tempDeploymentSlot
        }
    }

    # If we receive principals, we also assign the correct RBAC roles
    # This will only happen during the SCEPman call which will then also include the principal of CM
    if($servicePrincipals) {
        Foreach($principal in $servicePrincipals) {
            if ($PSCmdlet.ShouldProcess($principal, "Adding app role assignment for Monitoring Metrics Publisher role")) {
                AddAppRoleAssignmentsForLogIngestionAPI -DcrResourceId $dcrDetails.id -ServicePrincipal $principal -SkipAppRoleAssignments $SkipAppRoleAssignments
            }
        }
    }
}
# SIG # Begin signature block
# MIIv6gYJKoZIhvcNAQcCoIIv2zCCL9cCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBCHJyTGrdIeiJA
# DO7Fz4bbJQU5fMGOEROxfKYZ7sX8NqCCFA4wggVyMIIDWqADAgECAhB2U/6sdUZI
# k/Xl10pIOk74MA0GCSqGSIb3DQEBDAUAMFMxCzAJBgNVBAYTAkJFMRkwFwYDVQQK
# ExBHbG9iYWxTaWduIG52LXNhMSkwJwYDVQQDEyBHbG9iYWxTaWduIENvZGUgU2ln
# bmluZyBSb290IFI0NTAeFw0yMDAzMTgwMDAwMDBaFw00NTAzMTgwMDAwMDBaMFMx
# CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSkwJwYDVQQD
# EyBHbG9iYWxTaWduIENvZGUgU2lnbmluZyBSb290IFI0NTCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBALYtxTDdeuirkD0DcrA6S5kWYbLl/6VnHTcc5X7s
# k4OqhPWjQ5uYRYq4Y1ddmwCIBCXp+GiSS4LYS8lKA/Oof2qPimEnvaFE0P31PyLC
# o0+RjbMFsiiCkV37WYgFC5cGwpj4LKczJO5QOkHM8KCwex1N0qhYOJbp3/kbkbuL
# ECzSx0Mdogl0oYCve+YzCgxZa4689Ktal3t/rlX7hPCA/oRM1+K6vcR1oW+9YRB0
# RLKYB+J0q/9o3GwmPukf5eAEh60w0wyNA3xVuBZwXCR4ICXrZ2eIq7pONJhrcBHe
# OMrUvqHAnOHfHgIB2DvhZ0OEts/8dLcvhKO/ugk3PWdssUVcGWGrQYP1rB3rdw1G
# R3POv72Vle2dK4gQ/vpY6KdX4bPPqFrpByWbEsSegHI9k9yMlN87ROYmgPzSwwPw
# jAzSRdYu54+YnuYE7kJuZ35CFnFi5wT5YMZkobacgSFOK8ZtaJSGxpl0c2cxepHy
# 1Ix5bnymu35Gb03FhRIrz5oiRAiohTfOB2FXBhcSJMDEMXOhmDVXR34QOkXZLaRR
# kJipoAc3xGUaqhxrFnf3p5fsPxkwmW8x++pAsufSxPrJ0PBQdnRZ+o1tFzK++Ol+
# A/Tnh3Wa1EqRLIUDEwIrQoDyiWo2z8hMoM6e+MuNrRan097VmxinxpI68YJj8S4O
# JGTfAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G
# A1UdDgQWBBQfAL9GgAr8eDm3pbRD2VZQu86WOzANBgkqhkiG9w0BAQwFAAOCAgEA
# Xiu6dJc0RF92SChAhJPuAW7pobPWgCXme+S8CZE9D/x2rdfUMCC7j2DQkdYc8pzv
# eBorlDICwSSWUlIC0PPR/PKbOW6Z4R+OQ0F9mh5byV2ahPwm5ofzdHImraQb2T07
# alKgPAkeLx57szO0Rcf3rLGvk2Ctdq64shV464Nq6//bRqsk5e4C+pAfWcAvXda3
# XaRcELdyU/hBTsz6eBolSsr+hWJDYcO0N6qB0vTWOg+9jVl+MEfeK2vnIVAzX9Rn
# m9S4Z588J5kD/4VDjnMSyiDN6GHVsWbcF9Y5bQ/bzyM3oYKJThxrP9agzaoHnT5C
# JqrXDO76R78aUn7RdYHTyYpiF21PiKAhoCY+r23ZYjAf6Zgorm6N1Y5McmaTgI0q
# 41XHYGeQQlZcIlEPs9xOOe5N3dkdeBBUO27Ql28DtR6yI3PGErKaZND8lYUkqP/f
# obDckUCu3wkzq7ndkrfxzJF0O2nrZ5cbkL/nx6BvcbtXv7ePWu16QGoWzYCELS/h
# AtQklEOzFfwMKxv9cW/8y7x1Fzpeg9LJsy8b1ZyNf1T+fn7kVqOHp53hWVKUQY9t
# W76GlZr/GnbdQNJRSnC0HzNjI3c/7CceWeQIh+00gkoPP/6gHcH1Z3NFhnj0qinp
# J4fGGdvGExTDOUmHTaCX4GUT9Z13Vunas1jHOvLAzYIwggboMIIE0KADAgECAhB3
# vQ4Ft1kLth1HYVMeP3XtMA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNVBAYTAkJFMRkw
# FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSkwJwYDVQQDEyBHbG9iYWxTaWduIENv
# ZGUgU2lnbmluZyBSb290IFI0NTAeFw0yMDA3MjgwMDAwMDBaFw0zMDA3MjgwMDAw
# MDBaMFwxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTIw
# MAYDVQQDEylHbG9iYWxTaWduIEdDQyBSNDUgRVYgQ29kZVNpZ25pbmcgQ0EgMjAy
# MDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMsg75ceuQEyQ6BbqYoj
# /SBerjgSi8os1P9B2BpV1BlTt/2jF+d6OVzA984Ro/ml7QH6tbqT76+T3PjisxlM
# g7BKRFAEeIQQaqTWlpCOgfh8qy+1o1cz0lh7lA5tD6WRJiqzg09ysYp7ZJLQ8LRV
# X5YLEeWatSyyEc8lG31RK5gfSaNf+BOeNbgDAtqkEy+FSu/EL3AOwdTMMxLsvUCV
# 0xHK5s2zBZzIU+tS13hMUQGSgt4T8weOdLqEgJ/SpBUO6K/r94n233Hw0b6nskEz
# IHXMsdXtHQcZxOsmd/KrbReTSam35sOQnMa47MzJe5pexcUkk2NvfhCLYc+YVaMk
# oog28vmfvpMusgafJsAMAVYS4bKKnw4e3JiLLs/a4ok0ph8moKiueG3soYgVPMLq
# 7rfYrWGlr3A2onmO3A1zwPHkLKuU7FgGOTZI1jta6CLOdA6vLPEV2tG0leis1Ult
# 5a/dm2tjIF2OfjuyQ9hiOpTlzbSYszcZJBJyc6sEsAnchebUIgTvQCodLm3HadNu
# twFsDeCXpxbmJouI9wNEhl9iZ0y1pzeoVdwDNoxuz202JvEOj7A9ccDhMqeC5LYy
# AjIwfLWTyCH9PIjmaWP47nXJi8Kr77o6/elev7YR8b7wPcoyPm593g9+m5XEEofn
# GrhO7izB36Fl6CSDySrC/blTAgMBAAGjggGtMIIBqTAOBgNVHQ8BAf8EBAMCAYYw
# EwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4E
# FgQUJZ3Q/FkJhmPF7POxEztXHAOSNhEwHwYDVR0jBBgwFoAUHwC/RoAK/Hg5t6W0
# Q9lWULvOljswgZMGCCsGAQUFBwEBBIGGMIGDMDkGCCsGAQUFBzABhi1odHRwOi8v
# b2NzcC5nbG9iYWxzaWduLmNvbS9jb2Rlc2lnbmluZ3Jvb3RyNDUwRgYIKwYBBQUH
# MAKGOmh0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2NvZGVzaWdu
# aW5ncm9vdHI0NS5jcnQwQQYDVR0fBDowODA2oDSgMoYwaHR0cDovL2NybC5nbG9i
# YWxzaWduLmNvbS9jb2Rlc2lnbmluZ3Jvb3RyNDUuY3JsMFUGA1UdIAROMEwwQQYJ
# KwYBBAGgMgECMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24u
# Y29tL3JlcG9zaXRvcnkvMAcGBWeBDAEDMA0GCSqGSIb3DQEBCwUAA4ICAQAldaAJ
# yTm6t6E5iS8Yn6vW6x1L6JR8DQdomxyd73G2F2prAk+zP4ZFh8xlm0zjWAYCImbV
# YQLFY4/UovG2XiULd5bpzXFAM4gp7O7zom28TbU+BkvJczPKCBQtPUzosLp1pnQt
# pFg6bBNJ+KUVChSWhbFqaDQlQq+WVvQQ+iR98StywRbha+vmqZjHPlr00Bid/XSX
# hndGKj0jfShziq7vKxuav2xTpxSePIdxwF6OyPvTKpIz6ldNXgdeysEYrIEtGiH6
# bs+XYXvfcXo6ymP31TBENzL+u0OF3Lr8psozGSt3bdvLBfB+X3Uuora/Nao2Y8nO
# ZNm9/Lws80lWAMgSK8YnuzevV+/Ezx4pxPTiLc4qYc9X7fUKQOL1GNYe6ZAvytOH
# X5OKSBoRHeU3hZ8uZmKaXoFOlaxVV0PcU4slfjxhD4oLuvU/pteO9wRWXiG7n9dq
# cYC/lt5yA9jYIivzJxZPOOhRQAyuku++PX33gMZMNleElaeEFUgwDlInCI2Oor0i
# xxnJpsoOqHo222q6YV8RJJWk4o5o7hmpSZle0LQ0vdb5QMcQlzFSOTUpEYck08T7
# qWPLd0jV+mL8JOAEek7Q5G7ezp44UCb0IXFl1wkl1MkHAHq4x/N36MXU4lXQ0x72
# f1LiSY25EXIMiEQmM2YBRN/kMw4h3mKJSAfa9TCCB6gwggWQoAMCAQICDF3VjaKN
# us83AvC1UTANBgkqhkiG9w0BAQsFADBcMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQ
# R2xvYmFsU2lnbiBudi1zYTEyMDAGA1UEAxMpR2xvYmFsU2lnbiBHQ0MgUjQ1IEVW
# IENvZGVTaWduaW5nIENBIDIwMjAwHhcNMjUxMTI3MTcwNDI2WhcNMjcxMTI4MTcw
# NDI2WjCCAQwxHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRIwEAYDVQQF
# EwlIUkIgMTIzODExEzARBgsrBgEEAYI3PAIBAxMCREUxFzAVBgsrBgEEAYI3PAIB
# AhMGSGVzc2VuMSIwIAYLKwYBBAGCNzwCAQETEU9mZmVuYmFjaCBhbSBNYWluMQsw
# CQYDVQQGEwJERTEPMA0GA1UECBMGSGVzc2VuMRowGAYDVQQHExFPZmZlbmJhY2gg
# YW0gTWFpbjEZMBcGA1UECQwQS2Fpc2Vyc3RyYcOfZSAzOTEXMBUGA1UEChMOZ2x1
# ZWNra2FuamEgQUcxFzAVBgNVBAMTDmdsdWVja2thbmphIEFHMIICIjANBgkqhkiG
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAkQoXi0dUFVttodx+Ydj1O6EZZqgDdlSGDA/6
# x1UCkMrWNVEW+LdbUGU8KW7fUcKPCAcDJNrXfXxZeBht2G4pPvhaMz/kBdSK6bI1
# sqo1WSN//beapdUefQpq/wgnUneq13tEJQAke6EWdLyidObcogBSp9wCXBbMWsTO
# utgCONjyu8AilmzRY+94lO7VwUA2LGGPX8FRAEt5AMzifsEo2lIEKiDou2H8HUUC
# PibiChiuT3oGIDYYnCA/RzS44E0cAuAzlD3NQNCeIDzfoFiUD8mAC1gYU6i8yIej
# jUGl8+kpbpBYjgzwbsiCBn0rDhrlpJ3MHkZCrp82kzWK0l7c3ukNvdlGcU4tKdXk
# AHgpJecdYUDvz9iaYFvYEivF+Jg+Tc8ZnzsP5/q3KKw4g0QiJ+MXgvwJx8OSvAKW
# tkwkLxgE9oxufs3Y8xsmwyWqxWDBcyzzvs6yISnUaeTtGmyB8BsEbahDFrxHhV6U
# nwxNpJ+iM+j08J1tNIW0AXjY6ojGOIC8IIL+EiK34MXJ6Jxy22mntMnc6ztK6c7H
# IKiRHIPX4jXtg7IYRS/k5muuIt/xKzN7qtF9xJbaZi8jRE6fgWDwszLJUMHSLthh
# yKTsUEvuqZ79WnSHErg26EPQYirAY/IFt7Z7+3SDW2WI8uG2qY6hkpE0hm+/F3uS
# M+s98jUCAwEAAaOCAbYwggGyMA4GA1UdDwEB/wQEAwIHgDCBnwYIKwYBBQUHAQEE
# gZIwgY8wTAYIKwYBBQUHMAKGQGh0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20v
# Y2FjZXJ0L2dzZ2NjcjQ1ZXZjb2Rlc2lnbmNhMjAyMC5jcnQwPwYIKwYBBQUHMAGG
# M2h0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29tL2dzZ2NjcjQ1ZXZjb2Rlc2lnbmNh
# MjAyMDBVBgNVHSAETjBMMEEGCSsGAQQBoDIBAjA0MDIGCCsGAQUFBwIBFiZodHRw
# czovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAHBgVngQwBAzAJBgNV
# HRMEAjAAMEcGA1UdHwRAMD4wPKA6oDiGNmh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5j
# b20vZ3NnY2NyNDVldmNvZGVzaWduY2EyMDIwLmNybDATBgNVHSUEDDAKBggrBgEF
# BQcDAzAfBgNVHSMEGDAWgBQlndD8WQmGY8Xs87ETO1ccA5I2ETAdBgNVHQ4EFgQU
# q/cn5ijjtp0mG1yoiF02hg4dx4IwDQYJKoZIhvcNAQELBQADggIBAJ1TZv/rvy2w
# jANcL/kb6rTk+/6L7l49UghLghUKFVfrdEEc+21iexA7zlkvhM0TrhdiFU7TjDky
# InPctzsDlqwUhawEx4PT8ZkZkZzm25YWaqtZH44st/Fz59KiG+85NUdRd+0cL3Y8
# NR66z3xfI6K3W/nrIcE6RHm/opOM+L02Hd2MBligLnoFYcTvR3NPCA21A6+IOaYM
# n5YZzNKFXWry8ZHpWjnE4u9mxHYpS1zu2aIkwL8mfYM5moYoh0PAcp9XA5Sm4KrV
# LeIzZ3HIy4EzLCbFBP+OGFpkqq8pTtmYItG+g1rYEg5a8egrY83zJMHazaTFBgRI
# MNXCgeMZhC8O6NsAtbj3FSbiYKg1hNwZzHYL+uL3jcPZjuUoOpmvXu67xWs4ZfdT
# Mluy5E7FyWwtnOjr/04EXWyKATYMDIkd47Wqam/ZB7umF5T5YPnmTlv18ArEXuVQ
# EEpS/cN90DtRz2OGruu+V9bg3fk6NKDJLve8detDOTTBN0C/bFGxI5YLHmwVAdaq
# pz3t14ShRjVcxP7aN0bEL3YOuQvjnjQGe29H6n/MPf8UG4WYMd+a8qIP4HROLJq0
# YJylzYBglqoQeQC/OG+PtWTvL9oByPVYNc+llAuap/xmWSLZgAqPbi+PAfow69Lg
# bppHUCnJhNkXD/mJ4qB0KvPG+bzL19dEMYIbMjCCGy4CAQEwbDBcMQswCQYDVQQG
# EwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEyMDAGA1UEAxMpR2xvYmFs
# U2lnbiBHQ0MgUjQ1IEVWIENvZGVTaWduaW5nIENBIDIwMjACDF3VjaKNus83AvC1
# UTANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkG
# CSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEE
# AYI3AgEVMC8GCSqGSIb3DQEJBDEiBCCKIz2j9a3zeZldluY1f/7WTKA2BsCNcEDk
# ZTFWVJMYSzANBgkqhkiG9w0BAQEFAASCAgA73SEtm+n+eh7aCYI+ItbXTNaF8jO/
# xBt9VGnsC/B3jSduxHS9u0FjwtWxNCaPYPp3J40Ii1jMtZ6WdrIRk+UsTLoza33K
# hqXY/XGzhIkftj+e+GS/lbxkBavTR+NPjM3shWPZNUxjLhZSNiZIYM9DIfr0SBcU
# /ZvsMYrgferrBZ3RrrE2NeWtLO78bTyhEyjCAaxQpx0ing9meYk2Vtk6Fr5wZDFl
# krC9eiC/L1PG+VqtAV6LXBrCTAdNHPPivYX8AOAcaJwUXI7BNU3DFoFgiiCd0P9L
# WaGt1EeuQakzjZIsqUiHOX0z2ecv9AGQ6G/Q0FLCTL1q4pKcv58ek5tLobA124ab
# g0t6zm+e5Ge0BfLqoyLlfzWaxwLy1GQg4rnWwseYj+OeTQ9dBbkuJbrFWY6V8t8D
# GTCpeI/u8/+Jbg1YiGBrd0nW/KTwtr2H0Xp/yPMfvqivqmPILBunwyPk1bG2Skx6
# 1wE9lCSKVdkc4bict6HPxMa9qM2QiGc1MSseDRs6MeOqdxC4O/iK+ZYGf0hk/Y0M
# qRPVUSjTrp4U3rR+IOlcr5/ZDmPJu9/OkPvjqz0agZ4yh5PdvqC6j543AeiaZJu7
# ws6rMNjnG8XLMDfN3KqlVqp9gR02/uoUjNv/oq4H8YqRdvI3LY24Ey28LIYe7LbB
# av0GDYq4XUdx5KGCGBAwghgMBgorBgEEAYI3AwMBMYIX/DCCF/gGCSqGSIb3DQEH
# AqCCF+kwghflAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFhBgsqhkiG9w0BCRABBKCC
# AVAEggFMMIIBSAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUABCBcxIGM
# 8/fX/6tQzJapTBsvORmAyYyodBmTfEciigo/QgIGagxE8CujGBIyMDI2MDYwMTEz
# MTg0Mi4xNFowBIACAfSggeGkgd4wgdsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX
# YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
# Q29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlv
# bnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo3ODAwLTA1RTAtRDk0NzE1MDMG
# A1UEAxMsTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZSBTdGFtcGluZyBBdXRob3Jp
# dHmggg8hMIIHgjCCBWqgAwIBAgITMwAAAAXlzw//Zi7JhwAAAAAABTANBgkqhkiG
# 9w0BAQwFADB3MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
# cmF0aW9uMUgwRgYDVQQDEz9NaWNyb3NvZnQgSWRlbnRpdHkgVmVyaWZpY2F0aW9u
# IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMjAwHhcNMjAxMTE5MjAzMjMx
# WhcNMzUxMTE5MjA0MjMxWjBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBU
# aW1lc3RhbXBpbmcgQ0EgMjAyMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
# ggIBAJ5851Jj/eDFnwV9Y7UGIqMcHtfnlzPREwW9ZUZHd5HBXXBvf7KrQ5cMSqFS
# HGqg2/qJhYqOQxwuEQXG8kB41wsDJP5d0zmLYKAY8Zxv3lYkuLDsfMuIEqvGYOPU
# RAH+Ybl4SJEESnt0MbPEoKdNihwM5xGv0rGofJ1qOYSTNcc55EbBT7uq3wx3mXht
# VmtcCEr5ZKTkKKE1CxZvNPWdGWJUPC6e4uRfWHIhZcgCsJ+sozf5EeH5KrlFnxpj
# KKTavwfFP6XaGZGWUG8TZaiTogRoAlqcevbiqioUz1Yt4FRK53P6ovnUfANjIgM9
# JDdJ4e0qiDRm5sOTiEQtBLGd9Vhd1MadxoGcHrRCsS5rO9yhv2fjJHrmlQ0EIXmp
# 4DhDBieKUGR+eZ4CNE3ctW4uvSDQVeSp9h1SaPV8UWEfyTxgGjOsRpeexIveR1MP
# TVf7gt8hY64XNPO6iyUGsEgt8c2PxF87E+CO7A28TpjNq5eLiiunhKbq0XbjkNoU
# 5JhtYUrlmAbpxRjb9tSreDdtACpm3rkpxp7AQndnI0Shu/fk1/rE3oWsDqMX3jjv
# 40e8KN5YsJBnczyWB4JyeeFMW3JBfdeAKhzohFe8U5w9WuvcP1E8cIxLoKSDzCCB
# Ou0hWdjzKNu8Y5SwB1lt5dQhABYyzR3dxEO/T1K/BVF3rV69AgMBAAGjggIbMIIC
# FzAOBgNVHQ8BAf8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFGtp
# KDo1L0hjQM972K9J6T7ZPdshMFQGA1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUF
# BwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3Np
# dG9yeS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBT
# AHUAYgBDAEEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTIftJqhSobyhmY
# BAcnz1AQT2ioojCBhAYDVR0fBH0wezB5oHegdYZzaHR0cDovL3d3dy5taWNyb3Nv
# ZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwSWRlbnRpdHklMjBWZXJpZmlj
# YXRpb24lMjBSb290JTIwQ2VydGlmaWNhdGUlMjBBdXRob3JpdHklMjAyMDIwLmNy
# bDCBlAYIKwYBBQUHAQEEgYcwgYQwgYEGCCsGAQUFBzAChnVodHRwOi8vd3d3Lm1p
# Y3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMElkZW50aXR5JTIw
# VmVyaWZpY2F0aW9uJTIwUm9vdCUyMENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIw
# MjAyMC5jcnQwDQYJKoZIhvcNAQEMBQADggIBAF+Idsd+bbVaFXXnTHho+k7h2ESZ
# JRWluLE0Oa/pO+4ge/XEizXvhs0Y7+KVYyb4nHlugBesnFqBGEdC2IWmtKMyS1OW
# IviwpnK3aL5JedwzbeBF7POyg6IGG/XhhJ3UqWeWTO+Czb1c2NP5zyEh89F72u9U
# Iw+IfvM9lzDmc2O2END7MPnrcjWdQnrLn1Ntday7JSyrDvBdmgbNnCKNZPmhzoa8
# PccOiQljjTW6GePe5sGFuRHzdFt8y+bN2neF7Zu8hTO1I64XNGqst8S+w+RUdie8
# fXC1jKu3m9KGIqF4aldrYBamyh3g4nJPj/LR2CBaLyD+2BuGZCVmoNR/dSpRCxlo
# t0i79dKOChmoONqbMI8m04uLaEHAv4qwKHQ1vBzbV/nG89LDKbRSSvijmwJwxRxL
# LpMQ/u4xXxFfR4f/gksSkbJp7oqLwliDm/h+w0aJ/U5ccnYhYb7vPKNMN+SZDWyc
# U5ODIRfyoGl59BsXR/HpRGtiJquOYGmvA/pk5vC1lcnbeMrcWD/26ozePQ/TWfNX
# KBOmkFpvPE8CH+EeGGWzqTCjdAsno2jzTeNSxlx3glDGJgcdz5D/AAxw9Sdgq/+r
# Y7jjgs7X6fqPTXPmaCAJKVHAP19oEjJIBwD1LyHbaEgBxFCogYSOiUIr0Xqcr1nJ
# fiWG2GwYe6ZoAF1bMIIHlzCCBX+gAwIBAgITMwAAAFck05XgounJMQAAAAAAVzAN
# BgkqhkiG9w0BAQwFADBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1l
# c3RhbXBpbmcgQ0EgMjAyMDAeFw0yNTEwMjMyMDQ2NTNaFw0yNjEwMjIyMDQ2NTNa
# MIHbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQL
# ExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxk
# IFRTUyBFU046NzgwMC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJs
# aWMgUlNBIFRpbWUgU3RhbXBpbmcgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF
# AAOCAg8AMIICCgKCAgEAsWylCpMIfbizJLY1kPXO2cmX2HRWvRbAmeKSZ5ex7/jC
# ymdV7Eap+Ic2iqRtWDkKKe5gL6JV80wtn5C2qHJLPxUYFKNG3UkHkAI21MoCN+YW
# nhT8K/YuPib6+6970jdbeFKIiZMWwd5hnpX9J3jeteuEdXbp/DfFBK15JuD3JOzW
# uF2suQCPgqYjQPk/gpq+3KCKtXJRbXSCSJ9YtITU2IHwmfdE7l2PfZ154w041po+
# fDeTj0gJOzcV/Jv56Q0M+w19jAKo/I5PEzrLV1IPQnmP4or1X4RbJXk8ONXyOOfX
# OxK2VLpNxgklK1yAezbFP2uzqihaXkW1h9GQLGENKESnezwgdRaLNNaYtm8AT/pZ
# HYJ35mZVqkZdMIckpQHJk/F1fSLyDKeKtH4TC4cc3ESKUMgItq07ZZm74JCsfhmr
# Q1ijVNDi1Sln+QBamgC7WviZbkQnceQRq9DY+6hANwOrasAZUiVr2kPuj1jHDOXz
# UG4O9QTK70P/oXSqZAN1oTv3UfF8JTGmAxg+l1ZPOz50MY96HBDw/3bI/wBGNvLk
# 6fLVnrxGN5B5unF/lYvjjWbIUdyBPVQnPOKXu08SRHbY19M1HoWX6PNZv+vzSeqV
# eWWHKdKjC3GjVjbbGpi+JLbiyaKRSwEqo49tJLvu69cQ7dWsbksai4TURnVj2mMC
# AwEAAaOCAcswggHHMB0GA1UdDgQWBBSOg8leLTUOAglIZ+bjXpiD7RKSpzAfBgNV
# HSMEGDAWgBRraSg6NS9IY0DPe9ivSek+2T3bITBsBgNVHR8EZTBjMGGgX6Bdhlto
# dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBQ
# dWJsaWMlMjBSU0ElMjBUaW1lc3RhbXBpbmclMjBDQSUyMDIwMjAuY3JsMHkGCCsG
# AQUFBwEBBG0wazBpBggrBgEFBQcwAoZdaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBQdWJsaWMlMjBSU0ElMjBUaW1lc3Rh
# bXBpbmclMjBDQSUyMDIwMjAuY3J0MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAww
# CgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQDAgeAMGYGA1UdIARfMF0wUQYMKwYBBAGC
# N0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
# a2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTAIBgZngQwBBAIwDQYJKoZIhvcNAQEM
# BQADggIBAHJ1wHY86Zk5SUBDPY25d/u9YJVaaNa71uxjX4cyO/XJ4uPENCSOwkRT
# nNogPLxTD0Fg3z4TFf/2T/0IFSxdtWVtTjhzrn+WLInzeRawUhTCFVrPBJKEWVsh
# m+Ig7/nB7JbJN88+ltImBbL5kT1StBLfG6UksAcDbNSQww90CUXhGueBxlnSvjkA
# X1ohiN16y1bB2s0rvQx8Csepl2CuBefTfDrMGzW/tzNx5YaK2D8OWweqTWZcGlJO
# 4YjZNI83cTrQghfHl/8AXOHj8cWL3wEFltQQs2xeRYAb3Kdnl7oIWKKXWaBYJY5P
# 3QPsiC+DTMp7ejdYKTrb396f3gr+wL/Ms5/Z3vIWZPJJv18qNw40fUNveRnwzMQn
# x8dM2bGuXXQZ5y7P8aXT4HJMo349qZtn4XQwiUE/DDp++MUL0kgjvd/Deo7Xr371
# PFPPYb4TboZhjV1x9+wCHDoOpNCBt+VuXU78ytJdKzQ1Jv2cEP1F9H9/wSLsMDUv
# WME7u9mGElOPDZPMVr8AuBEuLdbTSEdaLwsZBplzxLBcgxhZ/Cs30yBhuE3QhqT1
# YDZ2pa56RexPA2SasPcToT6gJgJ6E06BmZ2zQTNvWOjs5XQqHbYuXcoeDcwe2UaC
# 7EDOGD8GmLE9LiqtQsuQCM7v7I2xR+sPZT2Ax/85HjIkM+3MzTK1MYIHQzCCBz8C
# AQEweDBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcg
# Q0EgMjAyMAITMwAAAFck05XgounJMQAAAAAAVzANBglghkgBZQMEAgEFAKCCBJww
# EQYLKoZIhvcNAQkQAg8xAgUAMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAc
# BgkqhkiG9w0BCQUxDxcNMjYwNjAxMTMxODQyWjAvBgkqhkiG9w0BCQQxIgQgE3ab
# XVNW2QVwdpfzX4pi634UqyQohbEBGHtxJOD797owgbkGCyqGSIb3DQEJEAIvMYGp
# MIGmMIGjMIGgBCD1PJ9ktQVuTGWIbKLO4f1VUOlUU29ARCEpDZmFTHjbUjB8MGWk
# YzBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
# MTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0Eg
# MjAyMAITMwAAAFck05XgounJMQAAAAAAVzCCA14GCyqGSIb3DQEJEAISMYIDTTCC
# A0mhggNFMIIDQTCCAikCAQEwggEJoYHhpIHeMIHbMQswCQYDVQQGEwJVUzETMBEG
# A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj
# cm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBP
# cGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046NzgwMC0wNUUwLUQ5
# NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWUgU3RhbXBpbmcg
# QXV0aG9yaXR5oiMKAQEwBwYFKw4DAhoDFQD9LzE5nEJRAUE2Ss3xaKKPXHnLw6Bn
# MGWkYzBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcg
# Q0EgMjAyMDANBgkqhkiG9w0BAQsFAAIFAO3H5s8wIhgPMjAyNjA2MDExMTA5MDNa
# GA8yMDI2MDYwMjExMDkwM1owdDA6BgorBgEEAYRZCgQBMSwwKjAKAgUA7cfmzwIB
# ADAHAgEAAgI/cjAHAgEAAgITMDAKAgUA7ck4TwIBADA2BgorBgEEAYRZCgQCMSgw
# JjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3
# DQEBCwUAA4IBAQCRDp49fBQ4qF8wumAQEuY4//amPlIBWfJ+aLSOuXKuuJSvFXkL
# p9DTAWZqj+nDAQfpglUwTr6pEWDfCKudxpr+/wqbNxEVE/PKlTaCWR+bAoKW0Jqx
# 7zObyDu64wF26fVutT1bdqeq5vGAoFH4W6Ralgqmmh33pnEWBM86w5UQzJIgZ8CH
# OGiTSuxGHAxchLVGVY6QW0/e1hdLR3WXHzJPpyTg34o7PiIvxKu2Ax/zWgTu6MRM
# hkd3wch1qd0C0vvJaAzyy6KBLoaRFajdxjZHkvkeI6XEJHBBuTALm5bbx20TJLZv
# xJW6w0FPgNIDBAhC3749sjkivFQ+rikLAu+dMA0GCSqGSIb3DQEBAQUABIICAKXG
# 0uIeMzNV+x10CgpQc1zGK0rf5vjmcGmPUY5XZY5zs/BP2wgUZ9s2SpbqJqmo4Ry9
# 4Djv7THs9FetO1Vle6sxdverja86ozvP1fxmDKe8fYz/7BKrIedfXWoHyvkSwdT/
# 8uCyFsR6y3bc117j9pXONU67l7CcyGZnPdN7q0SZdD/gPvcMcdyxQR7ruQtpTvtV
# 6dRjNQaNBI9tiqsC8a8bVYe7ojJaA44mIWAq6lAufbAmJJjYQBWp1Glqzvrt/Cgv
# N7OIohjZ2N8W+kLY6IdQGeLO8KlaNiz2J40T/ToaRPgv5KL5ECez4wl3gUtJ/CC+
# j6eZflCr5+17TzeC0+ICXYs1axR098/24pU+Rm1EsxDz1mL4fvO4+0jVbSRUHB0n
# 9JOZBy4vLfajWNtdwGkaemHHVYcWNw3DuT0n0TtW4If96FEN2vu4Pa5/pZCpsu7P
# aKNXLmaX5wdD0tWeWWwbI40wgvF7Sg+YBpn60tKqHRGOmxpTKGsyzgNbNt2FRT8Q
# 4noH682VEkPg3m5qDBi6ME12GbRt/XI+WXd96feumeZErKQ2u6v2X01DYhzV+eiH
# QPvLM1NH4B9t34BJvSoj+jSZVRk4aTdTiQgg0hqGCxhvKKqx32ZKhe82lZBxlseK
# utAFxXz2/iRDb9ad8dwIrFzRgzjcKWz6wTLSEo1B
# SIG # End signature block