Microsoft.AzLocal.CSSTools.psm1

#################################################################
# #
# Copyright (C) Microsoft Corporation. All rights reserved. #
# #
#################################################################

[CmdletBinding()]
param (
    [Parameter(Mandatory = $false, Position = 0)]
    [Bool]$SkipStartupActions = $false
)
$skipExplicitlySet = $PSBoundParameters.ContainsKey('SkipStartupActions')
[void]$PSBoundParameters.Remove('SkipStartupActions')

# check if we are within a PSSession or runspace
# if we are and SkipStartupActions wasn't explicitly set, we skip the startup actions
if ($PSSenderInfo -and -not $skipExplicitlySet) {
    $SkipStartupActions = $true
}

#################################################################
# #
# STARTUP ACTIONS ON IMPORT #
# #
#################################################################

Import-LocalizedData -BindingVariable 'msg' -BaseDirectory "$PSScriptRoot\locale" -UICulture (Get-Culture) -WarningAction SilentlyContinue
$configurationData = Import-PowerShellDataFile -Path "$PSScriptRoot\config\Microsoft.AzLocal.CSSTools.Config.psd1"

New-Variable -Name 'CSSTools_AzsSupport' -Scope 'Global' -Force -Value @{
    Cache           = @{}
    Config          = $configurationData
    EnvironmentInfo = @{
        WindowsProductName = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name 'ProductName' -ErrorAction Ignore).ProductName
        OSDisplayVersion   = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name 'DisplayVersion' -ErrorAction Ignore).DisplayVersion
    }
    ModuleVersion   = $null
    DisconnectedOps = $false
}

#################################################################
# #
# ENUMS AND CLASSES #
# #
#################################################################

enum Component {
    OS
    AzureArcResourceBridge
}

#################################################################
# #
# FUNCTIONS #
# #
#################################################################

function Get-AzsSupportStampInformation {
    <#
    .SYNOPSIS
        Gets common stamp information
    .DESCRIPTION
        Queries for common stamp information properties such as DeplymentID, OEMVersion and CloudID
    .EXAMPLE
        PS> Get-AzsSupportStampInformation
    .OUTPUTS
        Outputs the Stamp Information
    #>


    [CmdletBinding()]
    param()

    try {
        $stampInfo = Get-StampInformation -ErrorAction Stop
        $stampInformation = [Ordered]@{
            DeploymentID           = $stampInfo.DeploymentID
            OemVersion             = $stampInfo.OemVersion
            StampVersion           = $stampInfo.StampVersion
            ServicesVersion        = $stampInfo.ServicesVersion
            PlatformVersion        = $stampInfo.PlatformVersion
            InitialDeployedVersion = $stampInfo.InitialDeployedVersion
            NetworkSchemaVersion   = $stampInfo.NetworkSchemaVersion
            Prefix                 = $stampInfo.Prefix
            CompanyName            = $stampInfo.CompanyName
            ServerSku              = $stampInfo.ServerSku
            Topology               = $stampInfo.Topology
            TimeZone               = $stampInfo.TimeZone
            HardwareOEM            = $stampInfo.HardwareOEM
            RegionName             = $stampInfo.RegionName
            DomainNetBIOSName      = $stampInfo.DomainNetBIOSName
            DomainFQDN             = $stampInfo.DomainFQDN
            NumberOfNodes          = $stampInfo.NumberOfNodes
            CloudID                = $stampInfo.CloudID
            RingName               = $stampInfo.RingName
            InstallationMethod     = $stampInfo.InstallationMethod
            HardwareClass          = $stampInfo.HardwareClass
        }
    }
    catch {
        $_ | Write-Error
    }

    return $stampInformation
}

function Get-ModuleVersion {
    $manifest = Test-ModuleManifest -Path "$PSScriptRoot\Microsoft.AzLocal.CSSTools.psd1"
    $Global:CSSTools_AzsSupport.ModuleVersion = $manifest.Version.ToString()
    return $manifest.Version.ToString()
}


function Get-EntryText {
@'
 
#################################################################################
                _ _ _
               / \ _____ _ _ __ ___ | | ___ ___ __ _| |
              / _ \ |_ / | | | '__/ _ \ | | / _ \ / __/ _` | |
             / ___ \ / /| |_| | | | __/ | |__| (_) | (_| (_| | |
            /_/ \_\/___|\__,_|_| \___| |_____\___/ \___\__,_|_|
 
#################################################################################
 
Provide feedback or suggestions to azlocaldiagfeedback@microsoft.com.
 
Tool Tips:
    List CSSTools commands: Get-Command -Module Microsoft.AzLocal.CSSTools
    Get help with examples: Get-Help 'Verb-Command' -Full
    Check for common issues: Invoke-AzsSupportInsight
    Check for new updates: Find-Module -Name Microsoft.AzLocal.CSSTools
    Install latest version: Update-Module -Name Microsoft.AzLocal.CSSTools -Force
 
Clean up the working directory after you are done to reclaim disk space:
    Clear-AzsSupportDirectory
 
'@
 | Write-Host -ForegroundColor:Green

    # display primary stamp info properties
    $stampInfo = Get-AzsSupportStampInformation
    if ($stampInfo) {
        $stampInfo += @{
            CSSToolsVersion = $Global:CSSTools_AzsSupport.ModuleVersion
            Region          = $Global:CSSTools_AzsSupport.EnvironmentInfo.Region
            DisconnectedOps = $Global:CSSTools_AzsSupport.EnvironmentInfo.DisconnectedOps
        }

        $maxKeyLength = ($stampInfo.Keys | Measure-Object -Property Length -Maximum).Maximum
        $stampInfo.Keys | ForEach-Object {
            $key = $_.PadRight($maxKeyLength)
            $value = "N/A"
            if (![string]::IsNullOrEmpty($stampInfo[$_])) {
                $value = $stampInfo[$_]
            }

            # Print aligned output
            "{0} --> {1}" -f $key, $value | Write-Host -ForegroundColor:Gray
        }
    }
    else {
        $msg.stampInfoNotAvailable | Write-Warning
    }
    "" | Write-Host
}

function New-AzsSupportDataBundle {
    <#
        .SYNOPSIS
        Creates a support data bundle for Azure Stack HCI.
        .DESCRIPTION
        This function collects various types of diagnostic data from an Azure Stack HCI cluster and compiles it into a support data bundle. The data collected can include cluster commands, node commands, events, registry information, and specific folders. The function supports both automatic data collection based on predefined components and manual data collection based on user-specified parameters.
        .PARAMETER Component
        Specifies the Azure Stack HCI component for which to automatically collect data. Valid values are defined in the Component enum.
        .PARAMETER ClusterCommands
        An array of cluster-level commands to run and include in the data bundle.
        .PARAMETER NodeCommands
        An array of node-level commands to run on each cluster node and include in the data bundle.
        .PARAMETER NodeEvents
        An array of event log queries to run on each cluster node and include in the data bundle.
        .PARAMETER NodeRegistry
        An array of registry paths to query on each cluster node and include in the data bundle.
        .PARAMETER NodeFolders
        An array of folder paths to collect from each cluster node and include in the data bundle.
        .PARAMETER ComputerName
        An array of computer names (cluster nodes) on which to run the specified commands and collect data. If not specified, defaults to all cluster nodes.
        .EXAMPLE
        PS C:\> New-AzsSupportDataBundle -Component "OS"
        Automatically collects a predefined set of diagnostic data related to the operating system component of Azure Stack HCI and compiles it into a support data bundle.
        .EXAMPLE
        PS C:\> New-AzsSupportDataBundle -NodeCommands @("Get-Process", "Get-Service") -ComputerName @("Node01", "Node02")
        Collects the output of "Get-Process" and "Get-Service" commands from Node01 and Node02 and includes it in the support data bundle.
        .NOTES
        This function requires administrative privileges to run. The collected data may contain sensitive information, so ensure that the support data bundle is handled securely and shared only with authorized personnel.
    #>


    [CmdletBinding()]
    param (
        # AUTOMATIC DATA COLLECTION SPECS
        [Parameter(ParameterSetName = 'DataCollectAuto')]
        [Component] $Component,

        # MANUAL DATA COLLECTION SPECS
        [Parameter(ParameterSetName = 'DataCollectManual')]
        [array] $ClusterCommands,
        [Parameter(ParameterSetName = 'DataCollectManual')]
        [array] $NodeCommands,
        [Parameter(ParameterSetName = 'DataCollectManual')]
        [array] $NodeEvents,
        [Parameter(ParameterSetName = 'DataCollectManual')]
        [array] $NodeRegistry,
        [Parameter(ParameterSetName = 'DataCollectManual')]
        [array] $NodeFolders,
        [Parameter(ParameterSetName = 'DataCollectManual')]
        [array] $ComputerName
    )

    Trace-Output -Level:Information -Message $msg.startingNewDataBundle
    $runtime = Register-CommandRuntime

    switch ($PSCmdlet.ParameterSetName.ToLower()) {
        "datacollectmanual" {

            if(($NodeCommands -or $NodeEvents -or $NodeRegistry -or $NodeFolders) -and (-Not $ComputerName)) {
                Trace-Output -Level:Error -Message $msg.errComputerNameNotSupplied
            } else {
                Invoke-DataCollection `
                    -runtime            $runtime `
                    -clusterCommands    $ClusterCommands `
                    -nodeCommands       $NodeCommands `
                    -nodeEvents         $NodeEvents `
                    -nodeRegistry       $NodeRegistry `
                    -nodeFolders        $NodeFolders `
                    -ComputerName       $ComputerName
            }

        }

        "datacollectauto" {
            Trace-Output -Level:Information -Message $msg.startingAutomaticCollection
            Invoke-AutoDataCollection -runtime $runtime -Component $Component
        }

        Default {}
    }

}

function Invoke-DataCollection() {
    param(
        [string] $runtime,
        [array] $ClusterCommands,
        [array] $NodeCommands,
        [array] $NodeEvents,
        [array] $NodeRegistry,
        [array] $NodeFolders,
        [array] $ComputerName
    )

    Trace-Output -Level:Information -Message $msg.startingDataCollection
    $name = "SupportDataBundle"

    # important default information we want to always collect.
    $NodeCommands = $NodeCommands + @("Get-ChildItem env:*", "gpresult /h STORAGE_DEST/gpresultoutput.html")

    # manually collecting data
    Collect-SupportData `
        -runtime            $runtime `
        -clusterCommands    $ClusterCommands `
        -nodeCommands       $NodeCommands `
        -nodeEvents         $NodeEvents `
        -nodeRegistry       $NodeRegistry `
        -nodeFolders        $NodeFolders `
        -ComputerName       $ComputerName `
        -customName         $name
}

function Invoke-AutoDataCollection() {
    param(
        [string] $runtime,
        [Component] $Component
    )
    $storage = Get-WorkingDirectory
    $storageTemp = ('{0}\temp' -f $storage)

    if((Test-Path -path $storageTemp) -eq $false) {
        New-Item -Type:Directory -Path $storageTemp | Out-Null
    }

    Trace-Output -Level:Verbose -Message $Component

    switch ($Component) {
        ([Component]::OS) {
            # Automatic OS log collection
            $cmd = Get-Command -Name "Send-DiagnosticData" -ErrorAction Ignore

            if($cmd) {
                Collect-SupportData `
                    -nodeCommands @('Send-DiagnosticData -SaveToPath STORAGE_DEST -FromDate ((Get-Date).AddDays(-1)) -ToDate (Get-Date) -CollectSddc:$true') `
                    -ComputerName (Get-ClusterNode)
            } else {
                Trace-Output -Level:Error -Message $msg.errSendDiagDataNotAvailable
            }
        }
        ([Component]::AzureArcResourceBridge) {
            Trace-Output -Level:Verbose -Message "Starting Resource Bridge Data Collection"
            Trace-Output -Level:Information -Message $msg.arcApplianceLogStart
            $destPath = ("{0}\SupportDataBundle-{1}" -f $storage, (Get-Date -Format "HH-mm_dd-MM-yyyy"))

            $azTenant = Read-Host -Prompt $msg.questionTenantLogin

            Trace-Output -Level:Information -Message $msg.arcApplianceLogConfig
            # get environment information
            $azStackInfo = Get-AzureStackHCI
            $azStackUri = $azStackInfo.AzureResourceUri.split("/")
            $azSub = $azStackUri[2] # xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx
            $azReg = $azStackUri[4] # sample-rg

            $arcHciConfigObject = Get-ArcHciConfig
            $arcHciConfigPath = ("{0}/hci-resource.yaml" -f $arcHciConfigObject.workingDir)
            $arcHciConfig = Get-Content -Path $arcHciConfigPath
            $arcHciConfig = $arcHciConfig.trim()
            $arcHciConfigApplianceName = ""


            foreach($arcHciConfigEntry in $arcHciConfig) {
                if($arcHciConfigEntry.indexOf("name:") -ne -1){
                    $arcHciConfigApplianceName = $arcHciConfigEntry.split(":")[1].trim()
                }
            }

            Trace-Output -Level:Information -Message $msg.arcApplianceLogLogin
            az login --tenant $azTenant --use-device-code
            az account set --subscription $azSub

            Trace-Output -Level:Information -Message $msg.arcApplianceLogCollectionStart
            az arcappliance get-credentials -g $azReg -n $arcHciConfigApplianceName --overwrite-existing --credentials-dir $storageTemp

            Get-ChildItem -path $storageTemp | ForEach-Object {
                Icacls $storageTemp /c /t /Inheritance:d                | Out-Null
                Icacls $storageTemp /c /t /Grant ${env:UserName}:F      | Out-Null
                TakeOwn /F $storageTemp                                 | Out-Null
                Icacls $storageTemp /c /t /Grant:r ${env:UserName}:F    | Out-Null
                Icacls $storageTemp /c /t /Remove:g Administrator "Authenticated Users" BUILTIN\Administrators BUILTIN Everyone System Users | Out-Null
            } | Out-Null

            az arcappliance logs hci `
            --cloudagent $arcHciConfigObject.cloudFqdn `
            --credentials-dir $storageTemp `
            --ip $arcHciConfigObject.controlPlaneIP `
            --kubeconfig ("{0}\kubeconfig" -f $arcHciConfigObject.workingDir) `
            --loginconfigfile ("{0}\kvatoken.tok" -f $arcHciConfigObject.workingDir) `
            --out-dir $destPath

            if($destPath) {
                $destZipPath = ("{0}.zip" -f $destPath)
                Compress-Archive -Path $destPath -DestinationPath ("{0}.zip" -f $destZipPath)
                Remove-Item -Path $destPath -Recurse -Force
                Trace-Output -Level:Success -Message ($msg.CollectionDataEnd -f $destZipPath)
            } else {
                Trace-Output -Level:Error -Message $msg.arcApplianceLogCollectionError
            }

            Remove-Item -Path $storageTemp -Recurse -Force
        }
        Default {
            Trace-Output -Level:Error -Message $msg.errComponentNotFound
        }
    }
}

function Confirm-AzsSupportOSVersion {
    <#
    .SYNOPSIS
        Validates the OS version against a specified version or minimum version.
    .DESCRIPTION
        This function checks the current OS version against a specified version or minimum version.
        It throws an error if the current OS version does not match the specified version or is below the minimum version.
    .PARAMETER Version
        The exact OS version to confirm against the current OS version.
    .PARAMETER MinimumVersion
        The minimum OS version that the current OS version must meet or exceed.
    .EXAMPLE
        Confirm-AzsSupportOSVersion -Version "23H2"
        # This will throw a terminating exception if the current OS version is not "23H2".
    .EXAMPLE
        Confirm-AzsSupportOSVersion -MinimumVersion "22H2"
        # This will throw a terminating exception if the current OS version is below "22H2".
    #>

    param(
        [Parameter(Mandatory = $true, ParameterSetName = 'ConfirmOSVersion')]
        [ValidateSet("22H2", "23H2", "24H2", "25H2")]
        [string]$Version,

        [Parameter(Mandatory = $true, ParameterSetName = 'ConfirmMinimumOSVersion')]
        [ValidateSet("22H2", "23H2", "24H2", "25H2")]
        [string]$MinimumVersion
    )

    $osOrder = @("22H2", "23H2", "24H2", "25H2")
    $currentVersion = $Global:CSSTools_AzsSupport.EnvironmentInfo.OSDisplayVersion

    switch ($PSCmdlet.ParameterSetName) {
        'ConfirmOSVersion' {
            if ($currentVersion -ne $Version) {
                throw ($msg.osNotSupported -f $Version)
            }
        }
        'ConfirmMinimumOSVersion' {
            $minIndex = $osOrder.IndexOf($MinimumVersion)
            $curIndex = $osOrder.IndexOf($currentVersion)
            if ($curIndex -lt 0) {
                throw ($msg.osNotSupportedGeneric)
            }
            if ($curIndex -lt $minIndex) {
                throw ($msg.osNotSupported -f $MinimumVersion)
            }
        }
    }
}

function Install-AzsSupportModule {
    <#
    .SYNOPSIS
        Install the AzsSupport Module to remote computers if not installed or version mismatch.
    .DESCRIPTION
        This function checks if the Microsoft.AzLocal.CSSTools module is installed on the specified remote computers and if the version matches the local version. If the module is not installed or there is a version mismatch, it copies the module from the local computer to the remote computer. It also has an option to force the installation, which will copy the module regardless of the current state on the remote computer.
    .PARAMETER ComputerName
        Type the NetBIOS name, an IP address, or a fully qualified domain name of one or more remote computers.
    .PARAMETER Credential
        Specifies a user account that has permission to perform this action. The default is the current user.
        Type a user name, such as User01 or Domain01\User01, or enter a PSCredential object generated by the Get-Credential cmdlet. If you type a user name, you're prompted to enter the password.
    .PARAMETER Force
        Forces a cleanup and re-install of the module on the remote computer.
    .EXAMPLE
        PS> Install-AzsSupportModule -ComputerName @('Node01', 'Node02')
 
        Checks each remote computer for the installed module version and copies the local module if missing or outdated.
 
    .EXAMPLE
        PS> $cred = Get-Credential
        PS> Install-AzsSupportModule -ComputerName 'Node01' -Credential $cred -Force
 
        Forces a reinstall of the module on the remote computer by copying the local module regardless of remote version.
 
    .OUTPUTS
        System.Void
 
        This cmdlet does not return objects. It writes progress and status/error messages.
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [System.String[]]$ComputerName,

        [Parameter(Mandatory = $false)]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty,

        [Parameter(Mandatory = $false)]
        [switch]$Force
    )

    begin {
        $moduleName = 'Microsoft.AzLocal.CSSTools'
        $moduleDirpath = (Split-Path -Path (Get-Module -Name $moduleName).Path -Parent)

        # if we have multiple modules installed on the current workstation,
        # abort the operation because side by side modules can cause some interop issues to the remote nodes
        $localModule = Get-Module -Name $moduleName
        if ($localModule.Count -gt 1) {
            throw ($msg.installSupportModuleMultipleVersions -f $moduleName)
        }

        $getModuleVersionSB = {
            param ([string]$arg0)
            try {
                # Get the latest version of Microsoft.AzLocal.CSSTools Module installed
                $version = (Get-Module -Name $arg0 -ListAvailable -ErrorAction Ignore | Sort-Object Version -Descending)[0].Version.ToString()
            }
            catch {
                # in some instances, the module will not be available and as such we want to skip the noise and return
                # a string back to the remote call command which we can do proper comparison against
                $version = '0.0.0.0'
            }
            return $version
        }

        # typically PowerShell modules will be installed in the following directory configuration:
        # $env:ProgramFiles\WindowsPowerShell\Modules\{module}\{version}
        # $env:USERPROFILE\Documents\WindowsPowerShell\Modules\{module}\{version}
        # so we default to Leaf of the path being {module} as PSGet will handle the versioning so we only ever do import in the following format:
        # Import-Module {module} (if using default PowerShell module path)
        # Import-Module C:\{path}\{module} (if using custom PowerShell module path)
        # so we need to ensure that we are copying the module to the correct path on the remote computer
        [System.String]$destinationPathDir = $moduleDirpath
    }
    process {
        $totalComputers = $ComputerName.Count
        $currentComputer = 0
        
        $ComputerName | ForEach-Object {
            $computer = $_
            $currentComputer++
            $percentComplete = [math]::Min([math]::Round(($currentComputer / $totalComputers) * 100, 0), 99)
            
            Write-Progress -Activity "Installing $moduleName" -Status "Processing $computer ($currentComputer of $totalComputers)" -PercentComplete $percentComplete -Id 1
            
            try {
                # check to see if the computer is local, if so, we will skip the operation
                if (Test-ComputerNameIsLocal -ComputerName $computer) {
                    ($msg.installSupportModuleSkipUpdate -f $computer) | Trace-Output
                    return # exit the current iteration of the loop and move to the next computer
                }

                if (!$Force) {
                    Write-Progress -Activity "Installing $moduleName" -Status "Checking version on $computer" -PercentComplete $percentComplete -CurrentOperation "Getting installed version" -Id 1
                    ($msg.installSupportModuleGetVersion -f $computer, $moduleName) | Trace-Output

                    # use Invoke-Command here, as we do not want to create a cached session for the remote computers
                    # as it will impact scenarios where we need to import the module on the remote computer for remote sessions
                    try {
                        $remoteModuleVersion = Invoke-Command -ComputerName $computer -Credential $Credential -ScriptBlock $getModuleVersionSB -ArgumentList @($moduleName) -ErrorAction Stop
                    }
                    catch {
                        # if we are unable to connect to the remote computer, we will skip the operation
                        $_ | Trace-Exception
                        ($msg.installSupportModuleUnableToConnect -f $computer) | Trace-Output
                        return # exit the current iteration of the loop and move to the next computer
                    }

                    if ($remoteModuleVersion) {
                        # if the remote module version is greater or equal to the local module version, then we do not need to update
                        ($msg.installSupportModuleVersionCheck -f $computer, $remoteModuleVersion, $localModule.Version.ToString()) | Trace-Output

                        if ([version]$remoteModuleVersion -ge [version]$localModule.Version) {
                            return # exit the current iteration of the loop and move to the next computer
                        }
                    }
                }

                Write-Progress -Activity "Installing $moduleName" -Status "Updating $computer" -PercentComplete $percentComplete -CurrentOperation "Copying module files (version $($localModule.Version))" -Id 1
                ($msg.installSupportModuleUpdateStart -f $computer, $moduleName, $localModule.Version.ToString()) | Trace-Output
                Copy-FileToRemoteComputer -Path $localModule.ModuleBase -ComputerName $computer -Destination $destinationPathDir -Credential $Credential -Recurse -Force

                Write-Progress -Activity "Installing $moduleName" -Status "Cleaning up $computer" -PercentComplete $percentComplete -CurrentOperation "Removing PS sessions" -Id 1
                # ensure that we destroy the current pssessions for the computer to prevent any caching issues
                # we will want to remove any existing PSSessions for the remote computers
                Remove-AzsSupportPSSession -ComputerName $computer
            }
            catch {
                $_ | Trace-Exception
                $_ | Write-Error
            }
        }
    }
    end {
        Write-Progress -Activity "Installing $moduleName" -Completed -Id 1
    }
}

#################################################################
# #
# SECONDARY STARTUP ACTIONS ON IMPORT #
# #
#################################################################

$null = Get-ModuleVersion
try {
    $cloudData = azcmagent show -j | ConvertFrom-Json
    if ($cloudData) {
        $Global:CSSTools_AzsSupport.EnvironmentInfo.Region = $cloudData.location

        if ($cloudData.Region -notin $Global:CSSTools_AzsSupport.Config.AzureRegions) {
            $Global:CSSTools_AzsSupport.EnvironmentInfo.DisconnectedOps = $true
        }
    }
}
catch {
    Trace-Output -Level:Warning -Message $msg.azcmagentFailed
}

# print the entry text if we are not skipping the startup actions
if (!$SkipStartupActions) {
    Get-EntryText

    Write-Host "" # just a spacer line
}

Set-Location -Path (Get-AzsSupportWorkingDirectory)

# Remove any existing PSSessions that were created by this module
# This is to ensure that we do not have any stale sessions that could cause issues
# when running commands in the module.
Remove-AzsSupportPSSession

# SIG # Begin signature block
# MIIoLAYJKoZIhvcNAQcCoIIoHTCCKBkCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCACVdtl4t4HsynA
# vzfiVuSGV41LVXq5DJwHi5FuSQDBfqCCDXYwggX0MIID3KADAgECAhMzAAAEhV6Z
# 7A5ZL83XAAAAAASFMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjUwNjE5MTgyMTM3WhcNMjYwNjE3MTgyMTM3WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDASkh1cpvuUqfbqxele7LCSHEamVNBfFE4uY1FkGsAdUF/vnjpE1dnAD9vMOqy
# 5ZO49ILhP4jiP/P2Pn9ao+5TDtKmcQ+pZdzbG7t43yRXJC3nXvTGQroodPi9USQi
# 9rI+0gwuXRKBII7L+k3kMkKLmFrsWUjzgXVCLYa6ZH7BCALAcJWZTwWPoiT4HpqQ
# hJcYLB7pfetAVCeBEVZD8itKQ6QA5/LQR+9X6dlSj4Vxta4JnpxvgSrkjXCz+tlJ
# 67ABZ551lw23RWU1uyfgCfEFhBfiyPR2WSjskPl9ap6qrf8fNQ1sGYun2p4JdXxe
# UAKf1hVa/3TQXjvPTiRXCnJPAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUuCZyGiCuLYE0aU7j5TFqY05kko0w
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwNTM1OTAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBACjmqAp2Ci4sTHZci+qk
# tEAKsFk5HNVGKyWR2rFGXsd7cggZ04H5U4SV0fAL6fOE9dLvt4I7HBHLhpGdE5Uj
# Ly4NxLTG2bDAkeAVmxmd2uKWVGKym1aarDxXfv3GCN4mRX+Pn4c+py3S/6Kkt5eS
# DAIIsrzKw3Kh2SW1hCwXX/k1v4b+NH1Fjl+i/xPJspXCFuZB4aC5FLT5fgbRKqns
# WeAdn8DsrYQhT3QXLt6Nv3/dMzv7G/Cdpbdcoul8FYl+t3dmXM+SIClC3l2ae0wO
# lNrQ42yQEycuPU5OoqLT85jsZ7+4CaScfFINlO7l7Y7r/xauqHbSPQ1r3oIC+e71
# 5s2G3ClZa3y99aYx2lnXYe1srcrIx8NAXTViiypXVn9ZGmEkfNcfDiqGQwkml5z9
# nm3pWiBZ69adaBBbAFEjyJG4y0a76bel/4sDCVvaZzLM3TFbxVO9BQrjZRtbJZbk
# C3XArpLqZSfx53SuYdddxPX8pvcqFuEu8wcUeD05t9xNbJ4TtdAECJlEi0vvBxlm
# M5tzFXy2qZeqPMXHSQYqPgZ9jvScZ6NwznFD0+33kbzyhOSz/WuGbAu4cHZG8gKn
# lQVT4uA2Diex9DMs2WHiokNknYlLoUeWXW1QrJLpqO82TLyKTbBM/oZHAdIc0kzo
# STro9b3+vjn2809D0+SOOCVZMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# 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
# /Xmfwb1tbWrJUnMTDXpQzTGCGgwwghoIAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAASFXpnsDlkvzdcAAAAABIUwDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIN7WVmZZ/3b/rhe+1VZqXyqt
# z2mlckWa86oQxFt0UuV2MEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEAELJ5A3RgHUVGPeu/GraKVGi/GWyPZxy/OuPLWwMpkhsbzaKEajeCaH96
# vNfE1dodNflUNG8DIN3kUMsG+tU3sxlrHif4S0W1Bq5dI3dxIGN+U1mJeCx4kZBA
# mJ0jw9E5yJecH6feJXw1j/CtnpxEaXij591jZhTKZDY3CtcAh5KkcLmSOfSCKExY
# JHfKTVLr8rbbP0FVgTxcifh0pCaR6WmB377nqXKRmQJX/gRozX6qm3gT4R2JToe2
# AvoRHQUI9toLoxeiMWqpo20WZASdbzO3ETMWDu0ucSLzT1RA+h/S0xO2IGq3NG9B
# 5StPUGu1t2XsH3Q/jlkqHpgwmE1EHaGCF5YwgheSBgorBgEEAYI3AwMBMYIXgjCC
# F34GCSqGSIb3DQEHAqCCF28wghdrAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCDMwR/FRy+9HnD/GgODfl7oleZbdFJsyvJ+YmdQvknaEQIGaZ2arZKx
# GBMyMDI2MDIyNDE4NDcwMS4wNThaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046MzMwMy0w
# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
# ghHsMIIHIDCCBQigAwIBAgITMwAAAg9XmkcUQOZG5gABAAACDzANBgkqhkiG9w0B
# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yNTAxMzAxOTQz
# MDRaFw0yNjA0MjIxOTQzMDRaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046MzMwMy0wNUUwLUQ5NDcxJTAjBgNV
# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQCl6DTurxf66o73G0A2yKo1/nYvITBQsd50F52SQzo2
# cSrt+EDEFCDlSxZzWJD7ujQ1Z1dMbMT6YhK7JUvwxQ+LkQXv2k/3v3xw8xJ2mhXu
# wbT+s1WOL0+9g9AOEAAM6WGjCzI/LZq3/tzHr56in/Z++o/2soGhyGhKMDwWl4J4
# L1Fn8ndtoM1SBibPdqmwmPXpB9QtaP+TCOC1vAaGQOdsqXQ8AdlK6Vuk9yW9ty7S
# 0kRP1nXkFseM33NzBu//ubaoJHb1ceYPZ4U4EOXBHi/2g09WRL9QWItHjPGJYjuJ
# 0ckyrOG1ksfAZWP+Bu8PXAq4s1Ba/h/nXhXAwuxThpvaFb4T0bOjYO/h2LPRbdDM
# cMfS9Zbhq10hXP6ZFHR0RRJ+rr5A8ID9l0UgoUu/gNvCqHCMowz97udo7eWODA7L
# aVv81FHHYw3X5DSTUqJ6pwP+/0lxatxajbSGsm267zqVNsuzUoF2FzPM+YUIwiOp
# gQvvjYIBkB+KUwZf2vRIPWmhAEzWZAGTox/0vj4eHgxwER9fpThcsbZGSxx0nL54
# Hz+L36KJyEVio+oJVvUxm75YEESaTh1RnL0Dls91sBw6mvKrO2O+NCbUtfx+cQXY
# S0JcWZef810BW9Bn/eIvow3Kcx0dVuqDfIWfW7imeTLAK9QAEk+oZCJzUUTvhh2h
# YQIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFJnUMQ2OtyAhLR/MD2qtJ9lKRP9ZMB8G
# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQBTowbo1bUE7fXTy+uW9m58qGEXRBGVMEQi
# FEfSui1fhN7jS+kSiN0SR5Kl3AuV49xOxgHo9+GIne5Mpg5n4NS5PW8nWIWGj/8j
# kE3pdJZSvAZarXD4l43iMNxDhdBZqVCkAYcdFVZnxdy+25MRY6RfaGwkinjnYNFA
# 6DYL/1cxw6Ya4sXyV7FgPdMmxVpffnPEDFv4mcVx3jvPZod7gqiDcUHbyV1gaND3
# PejyJ1MGfBYbAQxsynLX1FUsWLwKsNPRJjynwlzBT/OQbxnzkjLibi4h4dOwcN+H
# 4myDtUSnYq9Xf4YvFlZ+mJs5Ytx4U9JVCyW/WERtIEieTvTRgvAYj/4Mh1F2Elf8
# cdILgzi9ezqYefxdsBD8Vix35yMC5LTnDUoyVVulUeeDAJY8+6YBbtXIty4phIki
# hiIHsyWVxW2YGG6A6UWenuwY6z9oBONvMHlqtD37ZyLn0h1kCkkp5kcIIhMtpzEc
# PkfqlkbDVogMoWy80xulxt64P4+1YIzkRht3zTO+jLONu1pmBt+8EUh7DVct/33t
# uW5NOSx56jXQ1TdOdFBpgcW8HvJii8smQ1TQP42HNIKIJY5aiMkK9M2HoxYrQy2M
# oHNOPySsOzr3le/4SDdX67uobGkUNerlJKzKpTR5ZU0SeNAu5oCyDb6gdtTiaN50
# lCC6m44sXjCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
# 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/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNP
# MIICNwIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjMzMDMtMDVFMC1EOTQ3MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQBe
# tIzj2C/MkdiI03EyNsCtSOMdWqCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA7UgZJDAiGA8yMDI2MDIyNDEyMzM0
# MFoYDzIwMjYwMjI1MTIzMzQwWjB2MDwGCisGAQQBhFkKBAExLjAsMAoCBQDtSBkk
# AgEAMAkCAQACARcCAf8wBwIBAAICEhkwCgIFAO1JaqQCAQAwNgYKKwYBBAGEWQoE
# AjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkq
# hkiG9w0BAQsFAAOCAQEABHcXfuZxQFmOLEA77u6Ha72pO85O0FkvpOX12d3jtK8w
# 1CMXsPbp+oeMKFmcmiTtz2JCnF0EGG8Kuycc6RynAatwf0227Y7s2BB99u6Tz75n
# 7SKaJrjmsiUWmK6s6kJkxldJUJluar9I6d1r381JRSo2MgtbQnCFwOWhjGNK+LAm
# s06d83uQMqxDr7YEh02S676cvFKTcdLcm1kPIbhJVxxYs+cqeJgAf5hpkQBjA6pA
# zgtsbhTfz67RJgO68PYjLGzoVgSJUX2ZbQaqlXwxaF9FShFMEJlDCXG1paX9/kcT
# 9/R5fGHCtFz1nCDB3ENZSgYAChFYKaqZFoaH3ImOhTGCBA0wggQJAgEBMIGTMHwx
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1p
# Y3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAACD1eaRxRA5kbmAAEAAAIP
# MA0GCWCGSAFlAwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQw
# LwYJKoZIhvcNAQkEMSIEIGRj7Zj/DRhk+tCyRUO69V2GUcjY1CD6uJxm+KOlTBy1
# MIH6BgsqhkiG9w0BCRACLzGB6jCB5zCB5DCBvQQg3Ud3lSYqebsVbvE/eeIax8cm
# 3jFHxe74zGBddzSKqfgwgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0Eg
# MjAxMAITMwAAAg9XmkcUQOZG5gABAAACDzAiBCBg13uyEN/XoF2zMZDoJitbEFtN
# ctbARvhSc6k0GD/KQjANBgkqhkiG9w0BAQsFAASCAgAt2ALMvosbkzWQ9rlZpOTp
# tiYzMFNakYfOeihXMoBF6wVftT9jBKFgPpBYGSpn83MQ+lGGVMZUS1wSeTdwbIn7
# 0dZi01XoqBwoi1DUKX7ToCKXkqw4N9f9ugXC4g/xlQ9V9u7Wj+WhRzAstD28O5WA
# fYZUl2Wi9RtoUPucG/93OR0kEl9SOnr+8FBKoek/xpzwZGOSl4yp/8oGN6HWYoe2
# c808Imtnf29u31j/ldK2faJ/o3+UsA3qglk1Ks3AALtd/J610+YfYYpN8f7DZ7ie
# L0c3Ohs3TXHeemRf4quiRx4dU9HCfKktE2Vpe+R3cFiI+oirkyB3ruZAcAQj+oO7
# 9nWRwzDIipJQoJRXAGLB9phQnQvVB/aqquL1Va4XkLDDEQvev8fJsVafmlLqZ0OM
# CM1FT74KIuF4YNIvmdj+3rWMVRBPmGxuYxFSnMUBvuwrFQ6kpJM454n69DnmsN+l
# HgNcnelTbbpim3vsUynufS9AuOGc36uGQa8RGwMO1zKgBFgy5ifpnJLqUEKmAzsD
# UfV6fqeg/l0mKDje69jtxqu/t1ot2TqgBlyqjSgkAK2wTEUfta6qTM0A0Pz0DbWN
# RvMgvRcKw4xZouePsTyVbfBVSvs3j+JiAjMV4fX5/G9EufjphlOs2tjiTkQMlCrs
# 9esJUxrfSs1fpJgqb7HZ6Q==
# SIG # End signature block