DownloadSdk.psm1

#########################################################################################
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# Download SDK Module
#
#########################################################################################

#requires -runasadministrator

using module .\Common.psm1

#region Module Constants

$script:moduleName   = "DownloadSdk"
$script:eventLogName = "AKSHCI"
$script:logFilePath  = $($env:ProgramData + "\downloadsdk\downloadsdk.log")

#endregion

Import-LocalizedData -BindingVariable "DwldSdkLocMessage" -FileName DownloadSdkLocalizationMessages
Import-LocalizedData -BindingVariable "GenericLocMessage" -FileName commonLocalizationMessages



#region Exported Functions

function Get-DownloadSdkCatalog
{
    <#
    .DESCRIPTION
        Calls into the Download SDK to retrieve the requested catalog.
        Returns the catalog content.
 
    .PARAMETER Provider
        Provider to use for the download (e.g. sfs).
 
    .PARAMETER Name
        Content name to retrieve the catalog for.
 
    .PARAMETER Audience
        Audience/ring to retrieve the catalog for. Default/empty is public.
 
    .PARAMETER Endpoint
        Specifies custom endpoint information for the download.
 
    .PARAMETER Timeout
        Timeout for the API call.
 
    .PARAMETER HTTPS
        If enabled, https/tls download URLS will be used (if supported by the download provider)
    #>


    [CmdletBinding()]
    param(
        [Parameter()]
        [String] $Provider = "sfs",

        [Parameter(Mandatory=$true)]
        [String] $Name,

        [String] $Audience = "",

        [Parameter()]
        [String] $Endpoint = "",

        [Parameter()]
        [String] $Timeout = "10m",

        [Parameter()]
        [Bool] $HTTPS = $false
    )

    trap
    {  
        Write-ErrorEvent -message $_
        if ($ErrorActionPreference -ne [System.Management.Automation.ActionPreference]::SilentlyContinue) { throw $_ }
    }

    $verboseOutput = Get-VerboseLoggingPreference
    $encoding = [system.Text.Encoding]::UTF8
    $providerBytes = $encoding.GetBytes($Provider)
    $timeoutBytes = $encoding.GetBytes($Timeout)
    $nameBytes = $encoding.GetBytes($Name)
    $audienceBytes = $encoding.GetBytes($Audience)
    $endpointBytes = $encoding.GetBytes($Endpoint)
    $output = New-Object System.IntPtr

    Write-Event -message $("Invoking GetCatalog - Name: $Name , Audience: $Audience , Endpoint: $Endpoint , HTTPS: $HTTPS , Timeout: $Timeout")
    $err = [DownloadSDK.API]::GetCatalog($providerBytes, $nameBytes, $audienceBytes, $endpointBytes, $HTTPS, $timeoutBytes, $verboseOutput, [ref]$output)

    return (Test-DownloadSDKResponse -Context "GetCatalog" -Err $err -Output $output)
}

function Get-DownloadSdkRelease
{
    <#
    .DESCRIPTION
        Calls into the Download SDK to download a release (e.g. images, packages, generic files, etc).
        Returns information about the downloaded release.
 
    .PARAMETER Provider
        Provider to use for the download (e.g. sfs).
 
    .PARAMETER Name
        Release name to be downloaded.
 
    .PARAMETER Version
        Release version to be downloaded. If unspecified, the latest version is downloaded.
 
    .PARAMETER Destination
        Destination directory to place the downloaded release files.
 
    .PARAMETER CatalogName
        Catalog name
 
    .PARAMETER Audience
        Audience/ring
 
    .PARAMETER Endpoint
        Specifies custom endpoint information for the download.
 
    .PARAMETER Parts
        How many parts to segment content downloads into (causes concurrent connections to the hosting server).
 
    .PARAMETER HTTPS
        If enabled, https/tls download URLS will be used (if supported by the download provider)
 
    .PARAMETER ForegroundPriority
        If enabled, foreground priority download URLs will be requested (if supported by the download provider). Foreground priority URLS are subject to less throttling by the CDN.
 
    .PARAMETER Timeout
        Timeout for the API call (e.g. 2h).
    #>


    [CmdletBinding()]
    param(
        [Parameter()]
        [String] $Provider = "sfs",

        [Parameter(Mandatory=$true)]
        [String] $Name,

        [Parameter()]
        [String] $Version,

        [Parameter()]
        [String] $Destination,

        [Parameter()]
        [String] $CatalogName,

        [Parameter()]
        [String] $Audience,

        [Parameter()]
        [String] $Endpoint = "",

        [Parameter()]
        [ValidateRange(1,10)]
        [Int] $Parts = 3,

        [Parameter()]
        [Bool] $HTTPS = $false,

        [Parameter()]
        [Bool] $ForegroundPriority = $false,

        [Parameter()]
        [String] $Timeout = "2h"
    )

    trap
    {  
        Write-ErrorEvent -message $_
        if ($ErrorActionPreference -ne [System.Management.Automation.ActionPreference]::SilentlyContinue) { throw $_ }
    }

    $verboseOutput = Get-VerboseLoggingPreference
    $encoding = [system.Text.Encoding]::UTF8
    $providerBytes = $encoding.GetBytes($Provider)
    $timeoutBytes = $encoding.GetBytes($Timeout)
    $nameBytes = $encoding.GetBytes($Name)
    $versionBytes = $encoding.GetBytes($Version)
    $destinationBytes = $encoding.GetBytes($Destination)
    $catalogBytes = $encoding.GetBytes($CatalogName)
    $audienceBytes = $encoding.GetBytes($Audience)
    $endpointBytes = $encoding.GetBytes($Endpoint)
    $output = New-Object System.IntPtr
    Write-Event -message $("Invoking GetRelease - Name: $Name , Version: $Version , Destination: $Destination , Catalog: $CatalogName , Audience: $Audience , Endpoint: $Endpoint , Parts: $Parts , HTTPS: $HTTPS , ForegroundPriority: $ForegroundPriority , Timeout: $Timeout")
    $err = [DownloadSDK.API]::GetRelease($providerBytes, $nameBytes, $versionBytes, $destinationBytes, $catalogBytes, $audienceBytes, $endpointBytes, $Parts, $HTTPS, $ForegroundPriority, $timeoutBytes, $verboseOutput, [ref]$output)

    return (Test-DownloadSDKResponse -Context "GetRelease" -Err $err -Output $output)
}

function Set-DownloadSdkProxy
{
    <#
    .DESCRIPTION
        Configures the environment with proxy server settings
 
    .PARAMETER Http
        HTTP proxy server configuration
 
    .PARAMETER Https
        HTTPS proxy server configuration
 
    .PARAMETER NoProxy
        Proxy server exemption list (no_proxy)
 
    .PARAMETER CerticateFile
        Path to a CA certificate file used to establish trust with a HTTPS proxy server
 
    .PARAMETER CertificateStore
        The certificate store to use for import of the CertificateFile. Default is "Cert:\CurrentUser\Root"
 
    .PARAMETER Scope
        The scope of the proxy settings, i.e. current process vs. current user vs. machine wide. Default is current process.
    #>


    [CmdletBinding()]
    param (
        [Parameter()]
        [String] $Http,

        [Parameter()]
        [String] $Https,

        [Parameter()]
        [String] $NoProxy,

        [Parameter()]
        [String] $CertificateFile,

        [Parameter()]
        [String] $CertificateStore = "Cert:\CurrentUser\Root",

        [Parameter()]
        [EnvironmentVariableTarget] $Scope = [EnvironmentVariableTarget]::Process
    )

    trap
    {  
        Write-ErrorEvent -message $_
        if ($ErrorActionPreference -ne [System.Management.Automation.ActionPreference]::SilentlyContinue) { throw $_ }
    }

    if ($CertificateFile -and $CertificateStore)
    {
        if (-not (Test-Path -Path $CertificateFile))
        {
            throw $([System.String]::Format([System.Globalization.CultureInfo]::InvariantCulture, $DwldSdkLocMessage.downloadsdk_certificate_not_found, $CertificateFile))
        }

        Import-Certificate -FilePath $CertificateFile -CertStoreLocation $CertificateStore | Out-Null
    }

    [Environment]::SetEnvironmentVariable("http_proxy", $Http, $Scope)
    [Environment]::SetEnvironmentVariable("https_proxy", $Https, $Scope)
    [Environment]::SetEnvironmentVariable("no_proxy", $NoProxy, $Scope)
}

function Get-DownloadSdkEventLog
{
    <#
    .DESCRIPTION
        Returns all of the DownloadSdk module events
    #>


    [CmdletBinding()]
    param()

    Get-WinEvent -ProviderName $script:moduleName -ErrorAction SilentlyContinue
}

function Get-DownloadSdkLogs
{
    <#
    .DESCRIPTION
        Collects DownloadSdk logs
 
    .PARAMETER Path
        Path to store the logs
    #>


    [CmdletBinding()]
    param (
        [Parameter()]
        [String] $Path
    )

    $logDir = [io.Path]::Combine($Path, $script:moduleName)
    New-Item -ItemType Directory -Force -Path $logDir | Out-Null

    Get-Command -Module $script:moduleName | Sort-Object -Property Source > $($logDir+"\moduleinfo.txt")

    if (Test-Path -Path $script:logFilePath)
    {
        Copy-Item -Path $script:logFilePath -Destination $logDir
    }
}

#endregion

#region Helper functions

function Write-ErrorEvent
{
    <#
    .DESCRIPTION
        Writes an error event to the Download SDK event log.
 
    .PARAMETER message
        The error message to be logged.
    #>


    param (
        [Parameter(Mandatory=$true)]
        [String] $message
    )

    Write-EventLog -LogName $script:eventLogName -Source $script:moduleName -EventID 100 -EntryType Error -Message $message
}

function Write-Event
{
    <#
    .DESCRIPTION
        Writes a regular event to the Download SDK event log.
 
    .PARAMETER message
        The message to be logged.
    #>


    param (
        [Parameter(Mandatory=$true)]
        [String] $message
    )

    Write-EventLog -LogName $script:eventLogName -Source $script:moduleName -EventID 1 -EntryType Information -Message $message
}

function Get-VerboseLoggingPreference
{
    <#
    .DESCRIPTION
        Returns a boolean to indicate if verbose logging is true or false. When verbose logging is true, the module will allow
        DownloadSDK dll to output to stdout (DEBUG level messages). When verbose logging is false, there will be no output sent
        to stdout. For local powershell execution, the verbosity is inherited from the session (e.g. if -Verbose flag was passed).
        For remote executions and AsJob executions, verbosity is always set to false/low (no output sent to stdout) and DEBUG level
        mesages will instead be logged to file (downloadsdk.log). This decision for remote/job executions is due to an issue under
        investigation with golang OSS regarding cshared stdout causing powershell jobs to fail.
    #>


    # Only proceed if we are running in a local session (check will return false when running remotely or AsJob)
    if (-not $PSSenderInfo) {
      return ($VerbosePreference -eq [System.Management.Automation.ActionPreference]::Continue)
    }

    return $false
}

#endregion

#region Download SDK Wrappers

function Initialize-DownloadSDK
{
    <#
    .DESCRIPTION
        Initialize the DownloadSDK types (once per session).
    #>


    try
    {
        [DownloadSDK.API] | Out-Null
    }
    catch
    {
        $path = $($MyInvocation.PSScriptRoot) -replace [RegEx]::Escape("\"), "\\"

        $signature = @"
[DllImport("$path\\downloadsdk.dll")]
public static extern IntPtr GetCatalog([In] byte[] provider, [In] byte[] name, [In] byte[] audience, [In] byte[] endpoint, [In] bool https, [In] byte[] timeout, [In] bool verbose, ref IntPtr output);
 
[DllImport("$path\\downloadsdk.dll")]
public static extern IntPtr GetRelease([In] byte[] provider, [In] byte[] name, [In] byte[] version, [In] byte[] destination, [In] byte[] catalog, [In] byte[] audience, [In] byte[] endpoint, [In] byte parts, [In] bool https, [In] bool foregroundPriority, [In] byte[] timeout, [In] bool verbose, ref IntPtr output);
"@


        Add-Type -MemberDefinition $signature -Name API -Namespace DownloadSDK
    }
}

function Test-DownloadSDKResponse
{
    <#
    .DESCRIPTION
        Tests the response from a DownloadSDK API call to see if it failed or succeeded.
        In the success case, it will return an object from the response JSON output.
        In the failure case, it will throw an exception with relevant information.
 
    .PARAMETER Err
        The Err response returned by a API call.
 
    .PARAMETER Output
        The JSON output returned by a API call.
 
    .PARAMETER Context
        A context string to provide context to our event logging of which API call failed.
    #>


    param(
        [System.IntPtr] $Err,
        [System.IntPtr] $Output,
        [String] $Context
    )

    if ($Err -ne [System.Intptr]::Zero)
    {
        $errString = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($Err)
        throw $([System.String]::Format([System.Globalization.CultureInfo]::InvariantCulture, $DwldSdkLocMessage.downloadsdk_error_by_api_call, $Context, $errString))        
    }
    
    if ($Output -ne [System.Intptr]::Zero)
    {
        $outputStr = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($Output)
        return ($outputStr | ConvertFrom-Json)
    }

    return $null
}

function Test-DownloadSdkEndpoints {
    <#
    .DESCRIPTION
        Test if DownloadSDK endpoints are reachable from Host
         
    .PARAMETER proxySettings
        Test will use proxy settings to test endpoints if its not null
 
    .PARAMETER https
        If true, https download endpoints will be tested, otherwise http endpoints will be tested
    #>

    
    param (
        [ProxySettings] $proxySettings,
        [Bool] $https = $false
    )

    write-Host $DwldSdkLocMessage.downloadsdk_validation_firewall_testing -ForegroundColor Yellow

    $request = @("https://msk8s.api.cdp.microsoft.com")

    if ($https) {
        $request += "https://msk8s.sb.tlu.dl.delivery.mp.microsoft.com"
    } else {
        $request += "http://msk8s.b.tlu.dl.delivery.mp.microsoft.com"
    }

    $testFailed = $false

    foreach($url in $request){
        try {
            Get-URLResponseCode -URL $url -proxySettings $proxySettings | Out-Null
            Write-Host $([System.String]::Format([System.Globalization.CultureInfo]::InvariantCulture, $DwldSdkLocMessage.downloadsdk_validation_connection_result, $url, $DwldSdkLocMessage.downloadsdk_validataion_succeeded)) -ForegroundColor Green
        }
        catch {
            $testFailed = $true
            Write-Host $([System.String]::Format([System.Globalization.CultureInfo]::InvariantCulture, $DwldSdkLocMessage.downloadsdk_validation_connection_result, $url, $DwldSdkLocMessage.downloadsdk_validataion_failed)) -ForegroundColor Red
        }
    }

    if ($testFailed){
        Write-Host ''
        Write-Host ''
        Write-Host $DwldSdkLocMessage.downloadsdk_validation_firewall_failure -ForegroundColor red
        Write-Host ''

        Write-Host $([System.String]::Format([System.Globalization.CultureInfo]::InvariantCulture, $DwldSdkLocMessage.downloadsdk_validation_recommend_actions_header , $DwldSdkLocMessage.downloadsdk_validation_firewall_recommend_actions)) -ForegroundColor Yellow
        
        return [pscustomobject]@{
            'TestName' = "Validate DownloadSDK Host Firewall URL Requirements"
            'Category' = "DownloadSDK Host";
            'TestResult' = "Failed";
            'Details' = $DwldSdkLocMessage.downloadsdk_validation_firewall_failure;
        }
    }else{
        Write-Host ''
        Write-Host $DwldSdkLocMessage.downloadsdk_validation_firewall_success -ForegroundColor Green
        Write-Host ''
        
        return [pscustomobject]@{
            'TestName' = "Validate DownloadSDK Host Firewall URL Requirements"
            'Category' = "DownloadSDK Host";
            'TestResult' = "Success";
            'Details' = $DwldSdkLocMessage.downloadsdk_validation_firewall_success;
        }
    }
}

function Test-DownloadSdkConfiguration
{
    <#
    .SYNOPSIS
        Runs validation tests against DownloadSdk and host configuration
    .DESCRIPTION
        Runs validation tests against DownloadSdk and host configuration
    .PARAMETER Ignore
        Specifies which tests or category of tests to ignore during the validation test run. All others tests or category of tests will run.
    .PARAMETER Include
        Specifies which tests or category of tests to include during the validation test run. Only the tests or category of tests specified here will run.
    .PARAMETER List
        Causes the cmdlet to list the tests and test categories. This command will not run any test.
    .PARAMETER Skip
        Causes the cmdlet not to generate report file.
    .PARAMETER proxySettings
        Proxy settings for downloadSDK.
    .PARAMETER https
        If true, https download URLs will be tested, otherwise http download URLs will be tested
    #>

    [CmdletBinding(PositionalBinding=$False, SupportsShouldProcess, ConfirmImpact = 'Low')]
    param (
        [Parameter()]
        [String[]] $Ignore,

        [Parameter()]
        [String[]] $Include,

        [Parameter()]
        [Switch] $List,

        [Parameter()]
        [Switch] $Skip,

        [Parameter()]
        [ProxySettings] $proxySettings,

        [Parameter()]
        [Bool] $https = $false
    )

    $downloadSdkTests = Get-DownloadSdkValidationTests
    if ($List) {
        $downloadSdkTests | select-object -Property Category, TestName, Description
        return
    }

    $downloadSdkTestToRun = @()

    if ($Include.length -gt 0) {
        $includedTests = $downloadSdkTests | Where-Object {$_.Category -in $Include -or $_.TestName -in $Include}
        $downloadSdkTestToRun += $includedTests
    } else {
        $downloadSdkTestToRun = $downloadSdkTests
    }
    
    if ($Ignore.length -gt 0) {
        $downloadSdkTestToRun = $downloadSdkTestToRun | Where-Object {$_.Category -notin $Ignore -and $_.TestName -notin $Ignore}
    }

    $dateTime = get-date -Format "dd.MM.yyyy HH:mm:ss"
    Write-Host  $([System.String]::Format([System.Globalization.CultureInfo]::InvariantCulture, $DwldSdkLocMessage.downloadsdk_validation_start, $dateTime))

    $testResults = @()
    $overallResult = $true

    $totalTests = ($downloadSdkTestToRun | measure).Count
    $current = 1
    foreach($downloadSdkTest in $downloadSdkTestToRun) {
        $startTime = Get-Date
        Write-Host '===============================================================================' -ForegroundColor DarkYellow
        $outputHeader = "Test ({0} of {1}): `"{2}`". Category: {3}" -f $current,$totalTests,$downloadSdkTest.TestName,$downloadSdkTest.Category
        Write-Host ''
        Write-Host $outputHeader -ForegroundColor DarkYellow

        $testFunction = $downloadSdkTest.TestFunction
        try {
            $testReport = Invoke-Expression "$testFunction -proxySettings `$proxySettings -https:`$https"
        } catch {
            $testReport = [pscustomobject]@{
                'TestName' = $downloadSdkTest.TestName;
                'Category' = $downloadSdkTest.Category;
                'TestResult' = "Failed";
                'Details' = $_.Exception.Message
            }
        }
        $testResults += $testReport
        
        if ($testReport.TestResult -eq "Failed") {
            $overallResult = $false
            Write-Host "Test Failed" -ForegroundColor Red
            Write-Host "Details:"$testReport.Details -ForegroundColor Red
            Write-Host "Recommendation:"$testReport.Recommendation -ForegroundColor Red
        } else {
            Write-Host "Test Succeeded" -ForegroundColor Green
            Write-Host "Details:"$testReport.Details -ForegroundColor Green
            Write-Host "Recommendation:"$testReport.Recommendation -ForegroundColor Green
        }
        $current++
        $testExecutionTime = ((Get-Date) - $startTime).TotalMilliseconds
        Write-Host $([System.String]::Format([System.Globalization.CultureInfo]::InvariantCulture, $DwldSdkLocMessage.downloadsdk_validation_test_time, $testExecutionTime)) -ForegroundColor DarkYellow
        Write-Host ''
    }

    Write-Host $([System.String]::Format([System.Globalization.CultureInfo]::InvariantCulture, $DwldSdkLocMessage.downloadsdk_validation_end, $dateTime))

    if ($overallResult) {
        Write-Host ''
        Write-Host '====================================================='
        Write-Host ' '$DwldSdkLocMessage.downloadsdk_validation_test_success_summary    -ForegroundColor Green 
        Write-Host '====================================================='
        Write-Host ''
    } else {
        Write-Host ''
        Write-Host '====================================================='
        Write-Host ' '$DwldSdkLocMessage.downloadsdk_validation_test_failure_summary    -ForegroundColor Red 
        Write-Host '====================================================='
        Write-Host ''
    }
    if (-not($Skip)) {
        $testResults | ConvertTo-Html -Title $DwldSdkLocMessage.downloadsdk_validation_report_title | Out-File -FilePath downloadsdk_validation_report.html
        $reportFileName = "downloadsdk_validation_report.html"
        Write-Host $([System.String]::Format([System.Globalization.CultureInfo]::InvariantCulture, $DwldSdkLocMessage.downloadsdk_validation_report_check, $reportFileName)) -ForegroundColor Yellow 
    }

    return $testResults
}

function Get-DownloadSdkValidationTests()
{
    $downloadSdkTests = @()

    # Test category "DownloadSDK Host"
    $downloadSDKEndpointsTest = [ordered]@{
        'TestName' = "Validate DownloadSDK Host Firewall URL Requirements"
        'Category' = "DownloadSDK Host";
        'Description' = "Validate DownloadSDK Host Firewall URL Requirements";
        'TestFunction' = "Test-DownloadSdkEndpoints" 
    }
    $downloadSdkTests += New-Object -TypeName PsObject -Property $downloadSDKEndpointsTest

    return $downloadSdkTests
}

#endregion

#region Module initialization

New-EventLog -LogName $script:eventLogName -Source $script:moduleName -ErrorAction Ignore

Initialize-DownloadSDK

#endregion

# SIG # Begin signature block
# MIIoKgYJKoZIhvcNAQcCoIIoGzCCKBcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDCNEZkfzRnFxrK
# lPi58SJrdgWs5zIXmzqcduxqerUYJKCCDXYwggX0MIID3KADAgECAhMzAAAEBGx0
# Bv9XKydyAAAAAAQEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTE0WhcNMjUwOTExMjAxMTE0WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQC0KDfaY50MDqsEGdlIzDHBd6CqIMRQWW9Af1LHDDTuFjfDsvna0nEuDSYJmNyz
# NB10jpbg0lhvkT1AzfX2TLITSXwS8D+mBzGCWMM/wTpciWBV/pbjSazbzoKvRrNo
# DV/u9omOM2Eawyo5JJJdNkM2d8qzkQ0bRuRd4HarmGunSouyb9NY7egWN5E5lUc3
# a2AROzAdHdYpObpCOdeAY2P5XqtJkk79aROpzw16wCjdSn8qMzCBzR7rvH2WVkvF
# HLIxZQET1yhPb6lRmpgBQNnzidHV2Ocxjc8wNiIDzgbDkmlx54QPfw7RwQi8p1fy
# 4byhBrTjv568x8NGv3gwb0RbAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU8huhNbETDU+ZWllL4DNMPCijEU4w
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwMjkyMzAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAIjmD9IpQVvfB1QehvpC
# Ge7QeTQkKQ7j3bmDMjwSqFL4ri6ae9IFTdpywn5smmtSIyKYDn3/nHtaEn0X1NBj
# L5oP0BjAy1sqxD+uy35B+V8wv5GrxhMDJP8l2QjLtH/UglSTIhLqyt8bUAqVfyfp
# h4COMRvwwjTvChtCnUXXACuCXYHWalOoc0OU2oGN+mPJIJJxaNQc1sjBsMbGIWv3
# cmgSHkCEmrMv7yaidpePt6V+yPMik+eXw3IfZ5eNOiNgL1rZzgSJfTnvUqiaEQ0X
# dG1HbkDv9fv6CTq6m4Ty3IzLiwGSXYxRIXTxT4TYs5VxHy2uFjFXWVSL0J2ARTYL
# E4Oyl1wXDF1PX4bxg1yDMfKPHcE1Ijic5lx1KdK1SkaEJdto4hd++05J9Bf9TAmi
# u6EK6C9Oe5vRadroJCK26uCUI4zIjL/qG7mswW+qT0CW0gnR9JHkXCWNbo8ccMk1
# sJatmRoSAifbgzaYbUz8+lv+IXy5GFuAmLnNbGjacB3IMGpa+lbFgih57/fIhamq
# 5VhxgaEmn/UjWyr+cPiAFWuTVIpfsOjbEAww75wURNM1Imp9NJKye1O24EspEHmb
# DmqCUcq7NqkOKIG4PVm3hDDED/WQpzJDkvu4FrIbvyTGVU01vKsg4UfcdiZ0fQ+/
# V0hf8yrtq9CkB8iIuk5bBxuPMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
# /Xmfwb1tbWrJUnMTDXpQzTGCGgowghoGAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAAQEbHQG/1crJ3IAAAAABAQwDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIMZReQMopffSgn1j3GC0T1WN
# tGRnjPHJQRHy6mCX/koNMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEAXoDKh5UqYrPOOegwFUZK4lIC2pcQyr8Ts2ccLuAGmPa/wbZgvWYgIx6S
# kjdpVCPmnaxOvgIWuvGv38lRxHOEM6lEeNglTTk2qwcKrsFQfWxfm5qBMo6Xc4i8
# TDRG5teMSPKXx8r+ECBXbPoj+2Q678RhNE3IU1LNIi4tTXwsvJKuHbdRxsRUCEwS
# zy0o13mPCKB57OQWxoZjJp7RF33lqx86/s8r1JMrxjvtLvjKdyEIOXSSjDZLC49u
# jKhWAr1JzZhUqOGFaKRJgDJ5pwwJCSrKltO7v+y8WgGhXiHjvLu7utGod2SDDRDZ
# mpC/svN4hP7cZ/U50edE9Hh0vYOtzaGCF5QwgheQBgorBgEEAYI3AwMBMYIXgDCC
# F3wGCSqGSIb3DQEHAqCCF20wghdpAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCB4CuP02E+fqBKHgYMCcdDI3QTnTFgYjRgfxNVDEPFDnAIGZ5ItURFs
# GBMyMDI1MDIwNTIyNTEzOC45NzhaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046OEQwMC0w
# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
# ghHqMIIHIDCCBQigAwIBAgITMwAAAfPFCkOuA8wdMQABAAAB8zANBgkqhkiG9w0B
# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMzEyMDYxODQ2
# MDJaFw0yNTAzMDUxODQ2MDJaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046OEQwMC0wNUUwLUQ5NDcxJTAjBgNV
# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQD+n6ba4SuB9iSO5WMhbngqYAb+z3IfzNpZIWS/sgfX
# hlLYmGnsUtrGX3OVcg+8krJdixuNUMO7ZAOqCZsXUjOz8zcn1aUD5D2r2PhzVKjH
# tivWGgGj4x5wqWe1Qov3vMz8WHsKsfadIlWjfBMnVKVomOybQ7+2jc4afzj2XJQQ
# SmE9jQRoBogDwmqZakeYnIx0EmOuucPr674T6/YaTPiIYlGf+XV2u6oQHAkMG56x
# YPQikitQjjNWHADfBqbBEaqppastxpRNc4id2S1xVQxcQGXjnAgeeVbbPbAoELhb
# w+z3VetRwuEFJRzT6hbWEgvz9LMYPSbioHL8w+ZiWo3xuw3R7fJsqe7pqsnjwvni
# P7sfE1utfi7k0NQZMpviOs//239H6eA6IOVtF8w66ipE71EYrcSNrOGlTm5uqq+s
# yO1udZOeKM0xY728NcGDFqnjuFPbEEm6+etZKftU9jxLCSzqXOVOzdqA8O5Xa3E4
# 1j3s7MlTF4Q7BYrQmbpxqhTvfuIlYwI2AzeO3OivcezJwBj2FQgTiVHacvMQDgSA
# 7E5vytak0+MLBm0AcW4IPer8A4gOGD9oSprmyAu1J6wFkBrf2Sjn+ieNq6Fx0tWj
# 8Ipg3uQvcug37jSadF6q1rUEaoPIajZCGVk+o5wn6rt+cwdJ39REU43aWCwn0C+X
# xwIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFMNkFfalEVEMjA3ApoUx9qDrDQokMB8G
# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQDfxByP/NH+79vc3liO4c7nXM/UKFcAm5w6
# 1FxRxPxCXRXliNjZ7sDqNP0DzUTBU9tS5DqkqRSiIV15j7q8e6elg8/cD3bv0sW4
# Go9AML4lhA5MBg3wzKdihfJ0E/HIqcHX11mwtbpTiC2sgAUh7+OZnb9TwJE7pbEB
# PJQUxxuCiS5/r0s2QVipBmi/8MEW2eIi4mJ+vHI5DCaAGooT4A15/7oNj9zyzRAB
# TUICNNrS19KfryEN5dh5kqOG4Qgca9w6L7CL+SuuTZi0SZ8Zq65iK2hQ8IMAOVxe
# wCpD4lZL6NDsVNSwBNXOUlsxOAO3G0wNT+cBug/HD43B7E2odVfs6H2EYCZxUS1r
# gReGd2uqQxgQ2wrMuTb5ykO+qd+4nhaf/9SN3getomtQn5IzhfCkraT1KnZF8TI3
# ye1Z3pner0Cn/p15H7wNwDkBAiZ+2iz9NUEeYLfMGm9vErDVBDRMjGsE/HqqY7QT
# STtDvU7+zZwRPGjiYYUFXT+VgkfdHiFpKw42Xsm0MfL5aOa31FyCM17/pPTIKTRi
# KsDF370SwIwZAjVziD/9QhEFBu9pojFULOZvzuL5iSEJIcqopVAwdbNdroZi2HN8
# nfDjzJa8CMTkQeSfQsQpKr83OhBmE3MF2sz8gqe3loc05DW8JNvZ328Jps3LJCAL
# t0rQPJYnOzCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNN
# MIICNQIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjhEMDAtMDVFMC1EOTQ3MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQBu
# +gYs2LRha5pFO79g3LkfwKRnKKCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA603OJTAiGA8yMDI1MDIwNTExNDY0
# NVoYDzIwMjUwMjA2MTE0NjQ1WjB0MDoGCisGAQQBhFkKBAExLDAqMAoCBQDrTc4l
# AgEAMAcCAQACAhVxMAcCAQACAhMQMAoCBQDrTx+lAgEAMDYGCisGAQQBhFkKBAIx
# KDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZI
# hvcNAQELBQADggEBAHkREu6zOyQPjsWJGWRDpzMXjk/sHHl26YnCkltp92PeAwGz
# V/Exzfr1/HZdfqys1UXS2AQDFCzvocu+0eACIULgLEjpJPkXe5HFkDZynjOWua7t
# 3DtGqKWtwunzHHC0DhGIa1g9boWQiETzYZ7R6L94RIiAQWoR+RKVSmQmcsOZh0fX
# IJcs5KJv/RYfYpE8ejTCfRC9jS3IAs0mM0L9lXnXvXitzUyrUtQx42bhjMH3HOA1
# w+d6FZwkrzJ4f45A2ZerYEBTeDI9m3yS927t8w3QKvC4qr/cDfzQkkRC1aGhBXdg
# /z9VKg8HYpYw1+I0aRcF34K/aJlguul5vgeME1QxggQNMIIECQIBATCBkzB8MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy
# b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAfPFCkOuA8wdMQABAAAB8zAN
# BglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8G
# CSqGSIb3DQEJBDEiBCCcxaF/4M5j6DrDlKZlmQBx+X6PriZ7Pjoux8F8cH02fjCB
# +gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIBi82TSLtuG4Vkp8wBmJk/T+RAh8
# 41sG/aDOwxg6O2LoMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
# MTACEzMAAAHzxQpDrgPMHTEAAQAAAfMwIgQg2aI5cvzdSbJGGd1pdGco4QuODZ/f
# 4pDEyUTIeymHJocwDQYJKoZIhvcNAQELBQAEggIAJMulrH4BEVfQGtO4DFXaza83
# Zr5z9Cxvdq0i3E8AidvsLlWk6HCKPjgyT9qiI5AF6sTIqsKvj/9ZsRqGIexhnRpa
# cOuUfZJX2aprU5WLMPE6HbR5/1nPGSV/Z9sRAcyPNh07a05GgUIKqvy+KTAhRx4a
# iE+3KZzpaCeItAKUOmxN5W+rEpMcy4jUaPfEbvjD/65ISsYtXkGGfw/RFcg6Io4D
# YJzxDfa1rg7rVVoddZgzTQeo3rBwm08x9GL1SwL3YMgge6pHX7uxHYOjPNS3l8Hl
# 92hWCJpuopX6MmzlljtqG1sUTRBVmTEBNG4SJ7pe2I1pyvJCZI5P5s8CB3vlf2IM
# ZvuBdXDX2afYZdNSgQDJ2UGmQ8xRZDWuzmfHMT+1nUJ/fuJ9NKJajMNMZMef3nX4
# Lg6jQsMLzZcB0dHLB2HSlIYcqaJHKelUA1bo+14VZC3toBFACWp+W7stoRIlnPLv
# yayHTG+yFhN9tGR9xhgDwrVvVf8KcHoDdYToki6ujdOQBw21cTdanIhJo9ymi6Jn
# JE5E04c7hbbPB0JtSyWdBDZd5sGPINrdz2ujD5vJgxkSj97elEIBDGGrp2e9iLdB
# hDDxFyEufPeq1YB1gcfnzt6wljEq5ncKKefhojxlg5zDjCTdDI3GuNGZriM6ozPi
# JqGx8ZclgeRlkL5hWtI=
# SIG # End signature block