functions/MergeDriver/Merge-LabelFile.ps1

<#
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
#>

#Requires -Version 7.0
<#
.SYNOPSIS
    Git merge driver and standalone sorter for AxLabel translation files.
 
.DESCRIPTION
    Merge-driver mode (invoked automatically by git during a merge):
        Performs a 3-way merge of label files, producing an alphabetically sorted
        result. Per-label comments (a line starting with " ;" immediately before
        the label definition) are kept with their label. Unresolvable conflicts are
        written as standard git conflict markers and the script exits 1 so git marks
        the file as conflicted.
 
    Standalone / pipeline mode (no -Base/-Ours/-Theirs supplied):
        Scans the repository for every file matching
            **/AxLabelFile/LabelResources/*/*.label.txt
        and sorts each file's entries alphabetically in-place.
 
    Label file format
    -----------------
        LabelId=value
         ;optional comment ← belongs to the label line before it
 
    Register the merge driver in git config once per clone (or in a pipeline step):
        git config merge.d365fo-label.name "AxLabel file merger"
        git config merge.d365fo-label.driver "pwsh -File D365GitOps/functions/MergeDriver/Merge-LabelFile.ps1 -Base %O -Ours %A -Theirs %B -MarkerSize %L -FilePath %P"
 
    Alternatively, install the D365GitOps module and run:
        Register-D365MergeDriver
 
.PARAMETER Base
    [Merge-driver] Ancestor (base) version of the file. Supplied as %O by git.
 
.PARAMETER Ours
    [Merge-driver] Current-branch version. Supplied as %A by git.
    The merged result is written back to this path.
 
.PARAMETER Theirs
    [Merge-driver] Other-branch version. Supplied as %B by git.
 
.PARAMETER MarkerSize
    [Merge-driver] Width of conflict-marker lines. Supplied as %L by git. Default: 7.
 
.PARAMETER FilePath
    [Merge-driver] Repository-relative path of the file. Supplied as %P by git.
    Used only for diagnostic messages.
 
.PARAMETER RepoRoot
    [Standalone] Root directory to search for label files.
    Defaults to the current working directory.
 
.EXAMPLE
    # Run from a pipeline to sort every label file in the repository:
    pwsh -File D365GitOps/functions/MergeDriver/Merge-LabelFile.ps1 -RepoRoot $(Build.SourcesDirectory)
#>


[CmdletBinding(DefaultParameterSetName = 'Standalone')]
param(
    # ── Merge-driver mode ────────────────────────────────────────────────────
    [Parameter(Mandatory, ParameterSetName = 'MergeDriver')]
    [string]$Base,          # %O ancestor version

    [Parameter(Mandatory, ParameterSetName = 'MergeDriver')]
    [string]$Ours,          # %A current-branch version; result written here

    [Parameter(Mandatory, ParameterSetName = 'MergeDriver')]
    [string]$Theirs,        # %B other-branch version

    [Parameter(ParameterSetName = 'MergeDriver')]
    [int]$MarkerSize = 7,   # %L conflict-marker width

    [Parameter(ParameterSetName = 'MergeDriver')]
    [string]$FilePath = '', # %P repo-relative path (informational only)

    # ── Standalone / pipeline mode ────────────────────────────────────────────
    [Parameter(ParameterSetName = 'Standalone')]
    [string]$RepoRoot = (Get-Location).Path
)


if ($MyInvocation.InvocationName -eq '.') {
    return
}

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

# ─── Parsing ─────────────────────────────────────────────────────────────────

function Read-LabelEntries {
    [OutputType([System.Collections.Generic.List[pscustomobject]])]
    param([string]$Path)

    $entries   = [System.Collections.Generic.List[pscustomobject]]::new()
    $lastEntry = $null

    foreach ($line in (Get-Content -LiteralPath $Path -Encoding UTF8)) {
        if ($line -match '^ ;') {
            # Comment line – belongs to the previous label definition
            if ($null -ne $lastEntry) {
                $lastEntry.Comment = $line
            }
        }
        elseif ($line -match '^([^=]+)=(.*)$') {
            $entry = [pscustomobject]@{
                Comment = $null
                LabelId = $Matches[1]
                Value   = $Matches[2]
            }
            $entries.Add($entry)
            $lastEntry = $entry
        }
        else {
            # Blank or unrecognised line – reset context
            $lastEntry = $null
        }
    }

    return $entries
}

function Get-EntryMap {
    [OutputType([hashtable])]
    param([System.Collections.Generic.List[pscustomobject]]$Entries)

    $map = [hashtable]::new([System.StringComparer]::OrdinalIgnoreCase)
    foreach ($e in $Entries) { $map[$e.LabelId] = $e }
    return $map
}

# ─── Serialising ─────────────────────────────────────────────────────────────

function Format-LabelFile {
    [OutputType([string])]
    param($Entries)

    $lines = [System.Collections.Generic.List[string]]::new()

    foreach ($e in $Entries) {
        if ($e.PSObject.Properties['IsConflict'] -and $e.IsConflict) {
            foreach ($cl in $e.ConflictLines) { $lines.Add($cl) }
            if (![string]::IsNullOrEmpty($e.Comment)) { $lines.Add($e.Comment) }
        }
        else {
            $lines.Add("$($e.LabelId)=$($e.Value)")
            if (![string]::IsNullOrEmpty($e.Comment)) { $lines.Add($e.Comment) }
        }
    }

    # Join with LF; end with a single trailing newline
    return ($lines -join "`n") + "`n"
}

function Save-LabelFile {
    param(
        [string]$Path,
        $Entries
    )

    $text = Format-LabelFile -Entries $Entries
    [System.IO.File]::WriteAllText($Path, $text, [System.Text.UTF8Encoding]::new($false))
}

# ─── Sorting ─────────────────────────────────────────────────────────────────

function Sort-LabelEntries {
    [OutputType([System.Collections.Generic.List[pscustomobject]])]
    param([System.Collections.Generic.List[pscustomobject]]$Entries)

    $sorted = [System.Collections.Generic.List[pscustomobject]]::new()
    $sorted.AddRange([pscustomobject[]]($Entries | Sort-Object -Property LabelId))
    return $sorted
}

# ─── Three-way merge ─────────────────────────────────────────────────────────

# Builds a conflict-marker entry (no actual label value; ConflictLines contains
# the full block to be written verbatim). Either $OursEntry or $TheirsEntry
# may be $null to represent a deletion on that side.
function New-ConflictEntry {
    param(
        [string]$Id,
        [string]$BaseComment,          # may be $null
        [pscustomobject]$OursEntry,    # $null → ours deleted the label
        [pscustomobject]$TheirsEntry,  # $null → theirs deleted the label
        [string]$Lt,
        [string]$Sep,
        [string]$Gt
    )

    $cl = [System.Collections.Generic.List[string]]::new()
    $cl.Add("$Lt ours")
    if ($null -ne $OursEntry) {
        $cl.Add("$Id=$($OursEntry.Value)")
        if (![string]::IsNullOrEmpty($OursEntry.Comment)) { $cl.Add($OursEntry.Comment) }
    }
    $cl.Add($Sep)
    if ($null -ne $TheirsEntry) {
        $cl.Add("$Id=$($TheirsEntry.Value)")
        if (![string]::IsNullOrEmpty($TheirsEntry.Comment)) { $cl.Add($TheirsEntry.Comment) }
    }
    $cl.Add("$Gt theirs")

    return [pscustomobject]@{
        Comment       = $BaseComment
        LabelId       = $Id
        Value         = ''
        IsConflict    = $true
        ConflictLines = $cl
    }
}

function Invoke-LabelMerge {
    param(
        [System.Collections.Generic.List[pscustomobject]]$BaseList,
        [System.Collections.Generic.List[pscustomobject]]$OursList,
        [System.Collections.Generic.List[pscustomobject]]$TheirsList,
        [int]$MarkerSize
    )

    $bMap = Get-EntryMap $BaseList
    $oMap = Get-EntryMap $OursList
    $tMap = Get-EntryMap $TheirsList

    # Union of all label IDs (order here doesn't matter; we sort at the end)
    $allIds = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
    foreach ($e in $BaseList)   { [void]$allIds.Add($e.LabelId) }
    foreach ($e in $OursList)   { [void]$allIds.Add($e.LabelId) }
    foreach ($e in $TheirsList) { [void]$allIds.Add($e.LabelId) }

    $merged      = [System.Collections.Generic.List[pscustomobject]]::new()
    $conflictIds = [System.Collections.Generic.List[string]]::new()

    $lt  = '<' * $MarkerSize
    $sep = '=' * $MarkerSize
    $gt  = '>' * $MarkerSize

    foreach ($id in $allIds) {
        $inB = $bMap.ContainsKey($id)
        $inO = $oMap.ContainsKey($id)
        $inT = $tMap.ContainsKey($id)

        # ── Not in base: newly added ──────────────────────────────────────────
        if (-not $inB) {
            if ($inO -and -not $inT) { $merged.Add($oMap[$id]); continue }
            if (-not $inO -and $inT) { $merged.Add($tMap[$id]); continue }
            # Added by both
            if ($oMap[$id].Value -eq $tMap[$id].Value) {
                $merged.Add($oMap[$id])
            }
            else {
                $conflictIds.Add($id)
                $merged.Add((New-ConflictEntry $id $null $oMap[$id] $tMap[$id] $lt $sep $gt))
            }
            continue
        }

        # ── In base: check for deletions ─────────────────────────────────────
        if (-not $inO -and -not $inT) {
            # Deleted by both → drop
            continue
        }

        if (-not $inO) {
            # Deleted by ours; theirs is present
            if ($tMap[$id].Value -eq $bMap[$id].Value) {
                # theirs unchanged → accept our deletion
            }
            else {
                # theirs modified it → conflict
                $conflictIds.Add($id)
                $merged.Add((New-ConflictEntry $id $bMap[$id].Comment $null $tMap[$id] $lt $sep $gt))
            }
            continue
        }

        if (-not $inT) {
            # Deleted by theirs; ours is present
            if ($oMap[$id].Value -eq $bMap[$id].Value) {
                # ours unchanged → accept their deletion
            }
            else {
                # ours modified it → conflict
                $conflictIds.Add($id)
                $merged.Add((New-ConflictEntry $id $bMap[$id].Comment $oMap[$id] $null $lt $sep $gt))
            }
            continue
        }

        # ── Present in all three: standard 3-way merge ───────────────────────
        $oChanged = $oMap[$id].Value -ne $bMap[$id].Value
        $tChanged = $tMap[$id].Value -ne $bMap[$id].Value

        if (-not $oChanged -and -not $tChanged) {
            $merged.Add($bMap[$id])
        }
        elseif ($oChanged -and -not $tChanged) {
            $merged.Add($oMap[$id])
        }
        elseif (-not $oChanged -and $tChanged) {
            $merged.Add($tMap[$id])
        }
        elseif ($oMap[$id].Value -eq $tMap[$id].Value) {
            # Both changed to the same value
            $merged.Add($oMap[$id])
        }
        else {
            # True conflict: both changed to different values
            $conflictIds.Add($id)
            $merged.Add((New-ConflictEntry $id $bMap[$id].Comment $oMap[$id] $tMap[$id] $lt $sep $gt))
        }
    }

    return @{
        Entries     = Sort-LabelEntries -Entries $merged
        ConflictIds = $conflictIds
    }
}

# ─── Entry point ─────────────────────────────────────────────────────────────

if ($PSCmdlet.ParameterSetName -eq 'MergeDriver') {

    $displayPath = if ($FilePath) { $FilePath } else { $Ours }
    Write-Host "Merging label file: $displayPath"

    $result = Invoke-LabelMerge `
        -BaseList   (Read-LabelEntries -Path $Base) `
        -OursList   (Read-LabelEntries -Path $Ours) `
        -TheirsList (Read-LabelEntries -Path $Theirs) `
        -MarkerSize $MarkerSize

    Save-LabelFile -Path $Ours -Entries $result.Entries

    if ($result.ConflictIds.Count -gt 0) {
        Write-Warning "Merge conflicts in '$displayPath' for label(s): $($result.ConflictIds -join ', ')"
        exit 1
    }

    exit 0
}

# ── Standalone / pipeline mode ────────────────────────────────────────────────

$labelFiles = @(Get-ChildItem -Path $RepoRoot -Filter '*.label.txt' -Recurse -File |
    Where-Object { $_.FullName -replace '\\', '/' -match '/AxLabelFile/LabelResources/[^/]+/' })

if ($labelFiles.Count -eq 0) {
    Write-Host 'No label files found matching **/AxLabelFile/LabelResources/*/*.label.txt'
    exit 0
}

$changedCount = 0

foreach ($file in $labelFiles) {
    $entries = Read-LabelEntries -Path $file.FullName
    $sorted  = Sort-LabelEntries -Entries $entries
    $before  = Format-LabelFile  -Entries $entries
    $after   = Format-LabelFile  -Entries $sorted

    if ($before -ne $after) {
        Save-LabelFile -Path $file.FullName -Entries $sorted
        Write-Host "Sorted: $($file.FullName)"
        $changedCount++
    }
    else {
        Write-Host "OK: $($file.FullName)"
    }
}

Write-Host ''
Write-Host "Done. $changedCount file(s) updated."

# SIG # Begin signature block
# MIIzNwYJKoZIhvcNAQcCoIIzKDCCMyQCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAsrL9LmimjuW9K
# dWyHQ+J64XaAyrcOoeR2SoAHyklAyqCCGzQwggXMMIIDtKADAgECAhBUmNLR1FsZ
# lUgTecgRwIeZMA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNVBAYTAlVTMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jvc29mdCBJZGVu
# dGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAy
# MDAeFw0yMDA0MTYxODM2MTZaFw00NTA0MTYxODQ0NDBaMHcxCzAJBgNVBAYTAlVT
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jv
# c29mdCBJZGVudGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRo
# b3JpdHkgMjAyMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALORKgeD
# Bmf9np3gx8C3pOZCBH8Ppttf+9Va10Wg+3cL8IDzpm1aTXlT2KCGhFdFIMeiVPvH
# or+Kx24186IVxC9O40qFlkkN/76Z2BT2vCcH7kKbK/ULkgbk/WkTZaiRcvKYhOuD
# PQ7k13ESSCHLDe32R0m3m/nJxxe2hE//uKya13NnSYXjhr03QNAlhtTetcJtYmrV
# qXi8LW9J+eVsFBT9FMfTZRY33stuvF4pjf1imxUs1gXmuYkyM6Nix9fWUmcIxC70
# ViueC4fM7Ke0pqrrBc0ZV6U6CwQnHJFnni1iLS8evtrAIMsEGcoz+4m+mOJyoHI1
# vnnhnINv5G0Xb5DzPQCGdTiO0OBJmrvb0/gwytVXiGhNctO/bX9x2P29Da6SZEi3
# W295JrXNm5UhhNHvDzI9e1eM80UHTHzgXhgONXaLbZ7LNnSrBfjgc10yVpRnlyUK
# xjU9lJfnwUSLgP3B+PR0GeUw9gb7IVc+BhyLaxWGJ0l7gpPKWeh1R+g/OPTHU3mg
# trTiXFHvvV84wRPmeAyVWi7FQFkozA8kwOy6CXcjmTimthzax7ogttc32H83rwjj
# O3HbbnMbfZlysOSGM1l0tRYAe1BtxoYT2v3EOYI9JACaYNq6lMAFUSw0rFCZE4e7
# swWAsk0wAly4JoNdtGNz764jlU9gKL431VulAgMBAAGjVDBSMA4GA1UdDwEB/wQE
# AwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIftJqhSobyhmYBAcnz1AQ
# T2ioojAQBgkrBgEEAYI3FQEEAwIBADANBgkqhkiG9w0BAQwFAAOCAgEAr2rd5hnn
# LZRDGU7L6VCVZKUDkQKL4jaAOxWiUsIWGbZqWl10QzD0m/9gdAmxIR6QFm3FJI9c
# Zohj9E/MffISTEAQiwGf2qnIrvKVG8+dBetJPnSgaFvlVixlHIJ+U9pW2UYXeZJF
# xBA2CFIpF8svpvJ+1Gkkih6PsHMNzBxKq7Kq7aeRYwFkIqgyuH4yKLNncy2RtNwx
# AQv3Rwqm8ddK7VZgxCwIo3tAsLx0J1KH1r6I3TeKiW5niB31yV2g/rarOoDXGpc8
# FzYiQR6sTdWD5jw4vU8w6VSp07YEwzJ2YbuwGMUrGLPAgNW3lbBeUU0i/OxYqujY
# lLSlLu2S3ucYfCFX3VVj979tzR/SpncocMfiWzpbCNJbTsgAlrPhgzavhgplXHT2
# 6ux6anSg8Evu75SjrFDyh+3XOjCDyft9V77l4/hByuVkrrOj7FjshZrM77nq81YY
# uVxzmq/FdxeDWds3GhhyVKVB0rYjdaNDmuV3fJZ5t0GNv+zcgKCf0Xd1WF81E+Al
# GmcLfc4l+gcK5GEh2NQc5QfGNpn0ltDGFf5Ozdeui53bFv0ExpK91IjmqaOqu/dk
# ODtfzAzQNb50GQOmxapMomE2gj4d8yu8l13bS3g7LfU772Aj6PXsCyM2la+YZr9T
# 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggaSMIIEeqADAgECAhMzAAHCNlwV
# oThYUayrAAAAAcI2MA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ
# RCBWZXJpZmllZCBDUyBBT0MgQ0EgMDQwHhcNMjYwNjA2MTgxMDQxWhcNMjYwNjA5
# MTgxMDQxWjBVMQswCQYDVQQGEwJTSTESMBAGA1UEBxMJTGp1YmxqYW5hMRgwFgYD
# VQQKEw9CRS10ZXJuYSBkLm8uby4xGDAWBgNVBAMTD0JFLXRlcm5hIGQuby5vLjCC
# AaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALaWg1OTtYVfHq18hH1jA6C8
# R3M5z670BLVLEXT0ejKLyVZWwaYKstssBVS2I5A6w4C5Q5GK9FZtb/g6DN3kASZY
# VrzbWWoWM1/ics495BNzE81FrsaQgnNvL8ysA+R4Qk/sdPYxMkOPxuWZ2Bfy0Cks
# 10qXNrV4xrXEYFXwoKkcSg27PiYGTPXKWh7mPqtEVq1Ey9trVX//3zlWUe3v79Sf
# H1Ytpz83Gf8cuw8SFJz7Od+pu8P1ECO+e9KiLouVaGRZrn5QHybNsNTpr/KaIiB7
# ESAkEGY8JgOaeP+Cs9NpcLE+qnn3cEGnf2P3E+TxdBBWGN/SFSiAupMC5vtzZRL+
# XtyvKah+NUK1eGKhAhe8OjFihBD7FzZzXY10kG84OtCUiGT1FeC/gNQgdGLQ0efK
# eJhMnAqewLw73XCVSwa1p6CUP0QOjkgrTXxJW55/XIIhnvQTTVdrzGxTRSAG0JDm
# eh2yf2pZegU5zRqUcpexXPfWQ5uhv7gGj3xJk5FgnwIDAQABo4IB1DCCAdAwDAYD
# VR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwOwYDVR0lBDQwMgYKKwYBBAGCN2EB
# AAYIKwYBBQUHAwMGGisGAQQBgjdhpOaoI4H67850gfzolDeutrtWMB0GA1UdDgQW
# BBQvDlUAdUQbfggmQNOEmp55qsjIYjAfBgNVHSMEGDAWgBRrJUHe+2t8/RiACi1/
# j3ZdqnM9uDBnBgNVHR8EYDBeMFygWqBYhlZodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ1MlMjBB
# T0MlMjBDQSUyMDA0LmNybDB0BggrBgEFBQcBAQRoMGYwZAYIKwYBBQUHMAKGWGh0
# dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIw
# SUQlMjBWZXJpZmllZCUyMENTJTIwQU9DJTIwQ0ElMjAwNC5jcnQwVAYDVR0gBE0w
# SzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNv
# bS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTANBgkqhkiG9w0BAQwFAAOCAgEA
# sxG0x+S2zzCLtdYefomtd5lAzPlumZYDlRSYF4PgZpqhddLlg2YgUTinhzvaNWWf
# ujJ7FUwypNJxlfLDGlECYAa2RjdLi7NgISTP48lNhKbtexaymXC6GT8Epzd1tYXK
# jNpl2j8s1e6Kv7ubprTv5+bC5V9IjHTFseTXqEQjyR6RCx1Y7bRReWa01OE9XjIj
# Zw8Vmufz5YjQKrBMI+X/MwKzXwPoZxcauAxAjXbxodWwUgetIeXo0jVao2ZdFFtd
# c/+aWMDbZataXvWpBlyQR55/r9hwJfqQE2SXEU7v+6trXnGl+jtIyoBP8Bsd/HQm
# Fgiixlb+a5jk8SXH7Hl/YySGfZYjLpB/Z3vOesB3Dgs6hqLFtwrMZ1HhK66znZS0
# IV93RWDf8PZ+cE9G29gXm6MBPdllosgzM3MYTLmvJXxZIB3lODZY/nmzKFFItsUb
# yV5R/7M6tWeJhNHpvSTzQ+e6aCkn4UBvFKph5B/n+DwS5dMkRKd13qEMpgXnm/GX
# fF2vKJD7FDjSlDa0psqZfDui2G4O6Ip+EwesIhNSswjNOdmBSkF6eOPkuIXexMI6
# LoR4O/Rcz8U25EpD8WXYapPs4MbnB5RJWJBTKki5kNJ/JNrV1oFzml3jlDMzVHWN
# cBxS/zoQVQQTxHgnHnknynthBYs/Z6MWlrfyZKFAizgwggcoMIIFEKADAgECAhMz
# AAAAFjGSjZICZXuaAAAAAAAWMA0GCSqGSIb3DQEBDAUAMGMxCzAJBgNVBAYTAlVT
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xNDAyBgNVBAMTK01pY3Jv
# c29mdCBJRCBWZXJpZmllZCBDb2RlIFNpZ25pbmcgUENBIDIwMjEwHhcNMjYwMzI2
# MTgxMTI5WhcNMzEwMzI2MTgxMTI5WjBaMQswCQYDVQQGEwJVUzEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMSswKQYDVQQDEyJNaWNyb3NvZnQgSUQgVmVy
# aWZpZWQgQ1MgQU9DIENBIDA0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
# AgEAylX6yNvoCTDP9G0OTlSjXbzgEsy21FDL17n/lZe2BrqHz2mR1aN4DBxeYp0/
# hjEqSHHyGfarV1NVBuvK8vLzW0LTi+DZt9In16aiNfgcogFiztWE9Fp8xu1zzrqE
# 3nlrDWb+RZo8QrEXgWb8s8swsl2W7tREHycVkx+Hm1MLQIlva6jH/Xg4/8GIYhHz
# bXiVd2RXomw9s7Qh6/SYRXXfe125wh4EKEyKnNNl+cZUSrVBgWvvjrRwQY4if7sA
# Z805KruBY6WY0Hiba5nWvrq9Qk9o35ViAf8qZ+7u1fbb1vcCWyWLfx9hLSdBjjVs
# SWe0xLvI1j4p3Tjt5czz+1Lc0v5lQ1feB7nFmpbZrK2us0hvAaBCfOyDPEEm+735
# vzuNRYWJFL/PViI+REtjuJMcojEn3veQjIrwrmK0T9oSr8e3oDzK1oAwwZMTC4Ky
# mTvYUTVDJvL5N8OW/UqIBzsiVYcchZvGhV3yMYKgxeEtIOG4W4Z85Y5kpQi5bpjG
# XFxRg46RdrTaALt1RhRmLR7U0jVSr2aYAd2+Mp2qA5Gz3/loOOdt47eFZ3mrAYGY
# QtbK2SNjQpwgQX4Iy6tOKahCgFhKIcltitvSkpJB77eVWhNWnN2LfqMojszEue7V
# 8EAySxry4PzlxTtFTb3Mw53XyH12BMQf2m9j7jEsHeVSATsCAwEAAaOCAdwwggHY
# MA4GA1UdDwEB/wQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUayVB
# 3vtrfP0YgAotf492XapzPbgwVAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUH
# AgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0
# b3J5Lmh0bTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTASBgNVHRMBAf8ECDAG
# AQH/AgEAMB8GA1UdIwQYMBaAFNlBKbAPD2Ns72nX9c0pnqRIajDmMHAGA1UdHwRp
# MGcwZaBjoGGGX2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01p
# Y3Jvc29mdCUyMElEJTIwVmVyaWZpZWQlMjBDb2RlJTIwU2lnbmluZyUyMFBDQSUy
# MDIwMjEuY3JsMH0GCCsGAQUFBwEBBHEwbzBtBggrBgEFBQcwAoZhaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBJRCUyMFZl
# cmlmaWVkJTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDIxLmNydDANBgkqhkiG
# 9w0BAQwFAAOCAgEABtVQXlR01UQZY5XGQ9yIjMcD8jI0MizWhJ1buZjg5toUQSXx
# /BrASwE5qxwHPBeO45pOQp6VD4iILgm8OmfylY+A7KIqttvDUizC3sBXxjK4u7sD
# RiyEguXHKfL1HQAwxCLEtnRPkCPTsJA6b917lA+3foQIHC1XDDpdQLHxGbbGXp4R
# r0mFK5vxbi6tAahBi/RlzOXPh6PavKPlZ/0vhlkDdsvoJETtebNJCNOZ1Kav3Tg+
# K4va4FbOrYqRHdGGahoA/gmTYmmVqw0zkGzT53HdhfajrFGttJomK7qE+T8CQGiP
# kEIkxNmSXjCTpDqc4U1IKlTGcGYnRFGSgqrnWnkANPFsJ5EDHysh82lPI+PFC3FO
# IVMLzLL+30rqznvRgHUUAj7xfFnEiuaAx3vFVSTOLb+iigpvdR6i8fSWpgYESOkd
# kn2N57tuhBs57tKwoP++vc/MVpuD1XAtmWi+lZSlahadTbDfGKjMn+bfm2xlW9PZ
# 6BSnCRv1MMhpcUZkAZX3gVEMef8rZc2c7BJ4ayRfX0wH43vI9znV+ZRJ3j0xUC0Z
# b82RQalF5yHkCr93x0IwvZtn6P2dNQyCP6qd3fC4RlVFtAQhtOH0cByTR/Iqqghv
# 6qHzL/pMptgMQQ5x8zYEYy+tCThYgYIrq7y4WEDYQfeSlqIxQOrIUJ4IJDEwggee
# MIIFhqADAgECAhMzAAAAB4ejNKN7pY4cAAAAAAAHMA0GCSqGSIb3DQEBDAUAMHcx
# CzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBG
# BgNVBAMTP01pY3Jvc29mdCBJZGVudGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0
# aWZpY2F0ZSBBdXRob3JpdHkgMjAyMDAeFw0yMTA0MDEyMDA1MjBaFw0zNjA0MDEy
# MDE1MjBaMGMxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y
# YXRpb24xNDAyBgNVBAMTK01pY3Jvc29mdCBJRCBWZXJpZmllZCBDb2RlIFNpZ25p
# bmcgUENBIDIwMjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCy8MCv
# GYgo4t1UekxJbGkIVQm0Uv96SvjB6yUo92cXdylN65Xy96q2YpWCiTas7QPTkGnK
# 9QMKDXB2ygS27EAIQZyAd+M8X+dmw6SDtzSZXyGkxP8a8Hi6EO9Zcwh5A+wOALNQ
# bNO+iLvpgOnEM7GGB/wm5dYnMEOguua1OFfTUITVMIK8faxkP/4fPdEPCXYyy8NJ
# 1fmskNhW5HduNqPZB/NkWbB9xxMqowAeWvPgHtpzyD3PLGVOmRO4ka0WcsEZqyg6
# efk3JiV/TEX39uNVGjgbODZhzspHvKFNU2K5MYfmHh4H1qObU4JKEjKGsqqA6Rzi
# ybPqhvE74fEp4n1tiY9/ootdU0vPxRp4BGjQFq28nzawuvaCqUUF2PWxh+o5/TRC
# b/cHhcYU8Mr8fTiS15kRmwFFzdVPZ3+JV3s5MulIf3II5FXeghlAH9CvicPhhP+V
# aSFW3Da/azROdEm5sv+EUwhBrzqtxoYyE2wmuHKws00x4GGIx7NTWznOm6x/niqV
# i7a/mxnnMvQq8EMse0vwX2CfqM7Le/smbRtsEeOtbnJBbtLfoAsC3TdAOnBbUkbU
# fG78VRclsE7YDDBUbgWt75lDk53yi7C3n0WkHFU4EZ83i83abd9nHWCqfnYa9qIH
# PqjOiuAgSOf4+FRcguEBXlD9mAInS7b6V0UaNwIDAQABo4ICNTCCAjEwDgYDVR0P
# AQH/BAQDAgGGMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTZQSmwDw9jbO9p
# 1/XNKZ6kSGow5jBUBgNVHSAETTBLMEkGBFUdIAAwQTA/BggrBgEFBQcCARYzaHR0
# cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRt
# MBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMBAf8wHwYD
# VR0jBBgwFoAUyH7SaoUqG8oZmAQHJ89QEE9oqKIwgYQGA1UdHwR9MHsweaB3oHWG
# c2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
# MElkZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIwUm9vdCUyMENlcnRpZmljYXRlJTIw
# QXV0aG9yaXR5JTIwMjAyMC5jcmwwgcMGCCsGAQUFBwEBBIG2MIGzMIGBBggrBgEF
# BQcwAoZ1aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNy
# b3NvZnQlMjBJZGVudGl0eSUyMFZlcmlmaWNhdGlvbiUyMFJvb3QlMjBDZXJ0aWZp
# Y2F0ZSUyMEF1dGhvcml0eSUyMDIwMjAuY3J0MC0GCCsGAQUFBzABhiFodHRwOi8v
# b25lb2NzcC5taWNyb3NvZnQuY29tL29jc3AwDQYJKoZIhvcNAQEMBQADggIBAH8l
# Kp7+1Kvq3WYK21cjTLpebJDjW4ZbOX3HD5ZiG84vjsFXT0OB+eb+1TiJ55ns0BHl
# uC6itMI2vnwc5wDW1ywdCq3TAmx0KWy7xulAP179qX6VSBNQkRXzReFyjvF2BGt6
# FvKFR/imR4CEESMAG8hSkPYso+GjlngM8JPn/ROUrTaeU/BRu/1RFESFVgK2wMz7
# fU4VTd8NXwGZBe/mFPZG6tWwkdmA/jLbp0kNUX7elxu2+HtHo0QO5gdiKF+YTYd1
# BGrmNG8sTURvn09jAhIUJfYNotn7OlThtfQjXqe0qrimgY4Vpoq2MgDW9ESUi1o4
# pzC1zTgIGtdJ/IvY6nqa80jFOTg5qzAiRNdsUvzVkoYP7bi4wLCj+ks2GftUct+f
# GUxXMdBUv5sdr0qFPLPB0b8vq516slCfRwaktAxK1S40MCvFbbAXXpAZnU20FaAo
# Dwqq/jwzwd8Wo2J83r7O3onQbDO9TyDStgaBNlHzMMQgl95nHBYMelLEHkUnVVVT
# UsgC0Huj09duNfMaJ9ogxhPNThgq3i8w3DAGZ61AMeF0C1M+mU5eucj1Ijod5O2M
# MPeJQ3/vKBtqGZg4eTtUHt/BPjN74SsJsyHqAdXVS5c+ItyKWg3Eforhox9k3Wgt
# WTpgV4gkSiS4+A09roSdOI4vrRw+p+fL4WrxSK5nMYIXWTCCF1UCAQEwcTBaMQsw
# CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSswKQYD
# VQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ1MgQU9DIENBIDA0AhMzAAHCNlwV
# oThYUayrAAAAAcI2MA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAI
# oAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB
# CzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIOyNiSCn8E6eFXY4708a
# +hy4HCcTPvnGAZqJQreEx5YZMA0GCSqGSIb3DQEBAQUABIIBgBhPfIHxpSUNwFWW
# 6ZbV/+Nn7xcUzZMr2W0bdsN300rkmAapwK0vh01iTpwy1mDszSqJmgitvrG5oWxu
# bOcO48LA0mG+V4XW8c9K0ouD5vNil5XLRUTa5LSUCV1J6pj57D9Wq8x1yvAb0b9E
# sJKxmlijVKX+aGAwmmbsSKdtDe6r1wRQPmBMvqEskrl6buDnk78+2Y1t5agbeaan
# twg7Ur+mBsJ7TiEO6wScs7VtjrnEgCI15MTzkovoVPtcpghYhDrUP731lfR7whWv
# r7qc7wiyoxFrPGHYb1aHAChvHSYBun5g9pQlfsBs+sZxbBiXa3ronHn8eSbF65ue
# WhV2/9oAE6UZ9bLqNIcFSPzSu48i7b9VPaZO5dPE9xwBMV/cex74u+lMvDrDJxom
# bPbQSdwnKbsxWvkIlVpFYi9dK7W3KRZpCz2k7j8R/oA4jo2C/kyCDXVIyG3a/72y
# QiRNZMDiVXuMKY2UVwHT+GENv/7Wn8uS5yHP1inDowpYaZbxPqGCFLIwghSuBgor
# BgEEAYI3AwMBMYIUnjCCFJoGCSqGSIb3DQEHAqCCFIswghSHAgEDMQ8wDQYJYIZI
# AWUDBAIBBQAwggFqBgsqhkiG9w0BCRABBKCCAVkEggFVMIIBUQIBAQYKKwYBBAGE
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCCn6FI24XhC7lySHsKTJ8ZIqTo7exkXrfoD
# ilGHTGPKPwIGahmQDwA9GBMyMDI2MDYwNzIyMjcxNi45NTNaMASAAgH0oIHppIHm
# MIHjMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQL
# EyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsT
# Hm5TaGllbGQgVFNTIEVTTjo3QTFBLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9z
# b2Z0IFB1YmxpYyBSU0EgVGltZSBTdGFtcGluZyBBdXRob3JpdHmggg8pMIIHgjCC
# BWqgAwIBAgITMwAAAAXlzw//Zi7JhwAAAAAABTANBgkqhkiG9w0BAQwFADB3MQsw
# CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMUgwRgYD
# VQQDEz9NaWNyb3NvZnQgSWRlbnRpdHkgVmVyaWZpY2F0aW9uIFJvb3QgQ2VydGlm
# aWNhdGUgQXV0aG9yaXR5IDIwMjAwHhcNMjAxMTE5MjAzMjMxWhcNMzUxMTE5MjA0
# MjMxWjBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcg
# Q0EgMjAyMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJ5851Jj/eDF
# nwV9Y7UGIqMcHtfnlzPREwW9ZUZHd5HBXXBvf7KrQ5cMSqFSHGqg2/qJhYqOQxwu
# EQXG8kB41wsDJP5d0zmLYKAY8Zxv3lYkuLDsfMuIEqvGYOPURAH+Ybl4SJEESnt0
# MbPEoKdNihwM5xGv0rGofJ1qOYSTNcc55EbBT7uq3wx3mXhtVmtcCEr5ZKTkKKE1
# CxZvNPWdGWJUPC6e4uRfWHIhZcgCsJ+sozf5EeH5KrlFnxpjKKTavwfFP6XaGZGW
# UG8TZaiTogRoAlqcevbiqioUz1Yt4FRK53P6ovnUfANjIgM9JDdJ4e0qiDRm5sOT
# iEQtBLGd9Vhd1MadxoGcHrRCsS5rO9yhv2fjJHrmlQ0EIXmp4DhDBieKUGR+eZ4C
# NE3ctW4uvSDQVeSp9h1SaPV8UWEfyTxgGjOsRpeexIveR1MPTVf7gt8hY64XNPO6
# iyUGsEgt8c2PxF87E+CO7A28TpjNq5eLiiunhKbq0XbjkNoU5JhtYUrlmAbpxRjb
# 9tSreDdtACpm3rkpxp7AQndnI0Shu/fk1/rE3oWsDqMX3jjv40e8KN5YsJBnczyW
# B4JyeeFMW3JBfdeAKhzohFe8U5w9WuvcP1E8cIxLoKSDzCCBOu0hWdjzKNu8Y5Sw
# B1lt5dQhABYyzR3dxEO/T1K/BVF3rV69AgMBAAGjggIbMIICFzAOBgNVHQ8BAf8E
# BAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFGtpKDo1L0hjQM972K9J
# 6T7ZPdshMFQGA1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUFBwIBFjNodHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYD
# VR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTIftJqhSobyhmYBAcnz1AQT2ioojCB
# hAYDVR0fBH0wezB5oHegdYZzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w
# cy9jcmwvTWljcm9zb2Z0JTIwSWRlbnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290
# JTIwQ2VydGlmaWNhdGUlMjBBdXRob3JpdHklMjAyMDIwLmNybDCBlAYIKwYBBQUH
# AQEEgYcwgYQwgYEGCCsGAQUFBzAChnVodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20v
# cGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMElkZW50aXR5JTIwVmVyaWZpY2F0aW9u
# JTIwUm9vdCUyMENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAyMC5jcnQwDQYJ
# KoZIhvcNAQEMBQADggIBAF+Idsd+bbVaFXXnTHho+k7h2ESZJRWluLE0Oa/pO+4g
# e/XEizXvhs0Y7+KVYyb4nHlugBesnFqBGEdC2IWmtKMyS1OWIviwpnK3aL5Jedwz
# beBF7POyg6IGG/XhhJ3UqWeWTO+Czb1c2NP5zyEh89F72u9UIw+IfvM9lzDmc2O2
# END7MPnrcjWdQnrLn1Ntday7JSyrDvBdmgbNnCKNZPmhzoa8PccOiQljjTW6GePe
# 5sGFuRHzdFt8y+bN2neF7Zu8hTO1I64XNGqst8S+w+RUdie8fXC1jKu3m9KGIqF4
# aldrYBamyh3g4nJPj/LR2CBaLyD+2BuGZCVmoNR/dSpRCxlot0i79dKOChmoONqb
# MI8m04uLaEHAv4qwKHQ1vBzbV/nG89LDKbRSSvijmwJwxRxLLpMQ/u4xXxFfR4f/
# gksSkbJp7oqLwliDm/h+w0aJ/U5ccnYhYb7vPKNMN+SZDWycU5ODIRfyoGl59BsX
# R/HpRGtiJquOYGmvA/pk5vC1lcnbeMrcWD/26ozePQ/TWfNXKBOmkFpvPE8CH+Ee
# GGWzqTCjdAsno2jzTeNSxlx3glDGJgcdz5D/AAxw9Sdgq/+rY7jjgs7X6fqPTXPm
# aCAJKVHAP19oEjJIBwD1LyHbaEgBxFCogYSOiUIr0Xqcr1nJfiWG2GwYe6ZoAF1b
# MIIHnzCCBYegAwIBAgITMwAAAFtKtY1BMm3cdAAAAAAAWzANBgkqhkiG9w0BAQwF
# ADBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
# MTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0Eg
# MjAyMDAeFw0yNjAxMDgxODU5MDVaFw0yNzAxMDcxODU5MDVaMIHjMQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQg
# SXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNT
# IEVTTjo3QTFBLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0IFB1YmxpYyBS
# U0EgVGltZSBTdGFtcGluZyBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4IC
# DwAwggIKAoICAQCQVMwW255Q13ntAdCg+RuP+O+bYRcn3LQsrhEk1kF75S4uFsf7
# XdqlHXquInXnoOlVoYjh37t8CVeE1BkkbaofQnK9QZogSr/YrhaYB8iAbuUMd/Gb
# McJRXl1UvmaiSSp10WwzUHXGEqAv+nNIUCfzx+dAwUQ0JD11cMhYsy60R/QJayXl
# IOwSnk9t837UvPyjiS7xBGxzheqUjmN2Vaa2VFm1o1sEU5qB2kPxPL61rSzchCfm
# 9PPVVtSJK2t7eBkweVm8twi9Sts2JwMQSL2n7CjBco/Trlx3EzyjA6BUjHmphvTC
# jjG+rqBtT43Zw4LCz+hDjEUs6yy+4xA9ZmwfUUnfX4bcvh0K+r2YLAZ+qFMvmE6T
# VS7JMHbVDPNlmAJD87ZTrdwIi9Ksle/1N4/7qt7xzIzzNMNN+NDOezXotIOAQnDL
# dHW6qHPdVYAm9/9+rB0ADaJ7Z9RzhdqC5PNfdEEUuN4rB1a2vB/LH+fhpaiGLGIg
# il9OB2Yjs2VvNup1SOnfvvJck3lpqY/dFGvbj2yYVY8BN6IerTuddMkqpkjEixDd
# O6dyG3txOgQG9sPd61s29uvnaUrYWyheJAKaH6gbFj1+DBLRykjn7T5lUwkOO7YI
# a1bh4mvY2Ph7I9NZuCluFrZJlZty+oTGRAjGuLIzMQF8/m1/wCYVk3uk2QIDAQAB
# o4IByzCCAccwHQYDVR0OBBYEFO/y6lJVlmIVyXV8IGCseG/Br9K2MB8GA1UdIwQY
# MBaAFGtpKDo1L0hjQM972K9J6T7ZPdshMGwGA1UdHwRlMGMwYaBfoF2GW2h0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMFB1Ymxp
# YyUyMFJTQSUyMFRpbWVzdGFtcGluZyUyMENBJTIwMjAyMC5jcmwweQYIKwYBBQUH
# AQEEbTBrMGkGCCsGAQUFBzAChl1odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtp
# b3BzL2NlcnRzL01pY3Jvc29mdCUyMFB1YmxpYyUyMFJTQSUyMFRpbWVzdGFtcGlu
# ZyUyMENBJTIwMjAyMC5jcnQwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggr
# BgEFBQcDCDAOBgNVHQ8BAf8EBAMCB4AwZgYDVR0gBF8wXTBRBgwrBgEEAYI3TIN9
# AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w
# cy9Eb2NzL1JlcG9zaXRvcnkuaHRtMAgGBmeBDAEEAjANBgkqhkiG9w0BAQwFAAOC
# AgEAAB/s3flyoeDsV2DFhZrYIpVwEBnLTowlAdcP7gYgvzl3B9yGuP123VISsxW2
# ok2yBOr2GSndaeLu5yji5GsMpgDFcrjuy0peqyyrbWSMi4Vo0ytM1zs9LuMS6vfm
# 0bQRCibwOrA+ZycB9SDus9WIs8riEaGpTAp261IsX1sUJ+EwJje7fbpPl9hVE4RG
# t3sM0cIbRvscGgGyzJMUZkduCZ313dVcSqPdPpu1s7qL/elLoMecGXXsIiCJtWVk
# 4+JQiR7qeu/S3Dmu7QMSTIqVWkpbUB/X5vUzinM5X8bVrgXC1OHbmX6sILCC7B+z
# zJHF9c8EM0A9MgLT4Z2M/SjRtduW1/oopTntUvER6r9m2waTKWqOJHFL0COnTICk
# bxZptXi24UjTkKZQzExg9bTVXTRpCPeo1Lvra6FI1jDIuOk0HwQB8bQ06UYSLv/O
# 7wFUPGekR4RcXrM+BHeSU4WiEEQMuhnDvyZPkMw86GdGq0SJCLBie62YDlQI8fXL
# X8PJR/UX43MAd8HRgWDTDVSakKVGotk2nXX+aV802RByKixBed0qwYyHiJ6EKz+1
# OVZV4jELMXsC3SDawBNpdk0dygYpG/kUEcoG06fI49sogtDQlMBvivp3YJTeUTG1
# 4xVumimufV6vm/F8yvwyvgCbYDqR4Cb/EK5OtgPrcDlSzqYxggPUMIID0AIBATB4
# MGExCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# MjAwBgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAy
# MDIwAhMzAAAAW0q1jUEybdx0AAAAAABbMA0GCWCGSAFlAwQCAQUAoIIBLTAaBgkq
# hkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIOA5/ozaOFT+
# HkF83xgCjn55lphM8XacPdfKIu3KJKSAMIHdBgsqhkiG9w0BCRACLzGBzTCByjCB
# xzCBoAQgLzEDVV2dG9McZRsPF/9yBMmzm7k+muVtXetQlvnBg+8wfDBlpGMwYTEL
# MAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAG
# A1UEAxMpTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjAC
# EzMAAABbSrWNQTJt3HQAAAAAAFswIgQgUOIbvRhoi8iqb7OyLJsJ7r6DNPeIhcru
# Ih0Xfp8GGGgwDQYJKoZIhvcNAQELBQAEggIAjx349WAC+lR2oo0PZsQH90RKNs1L
# dRCtqVwpWjKcI31bGBC/pUxKdzmE5oK+4uLuaggfn48+RK/clYeAMPG52De7ttWa
# cbb81gLT0jzwbkeAq+mYihOpPFIg74G5TLnZ9hQZNk9Wq5ZRaAHON+Pf8XoLbKnd
# oFGnXhdRE8MDNCsHJN6Sy44H4ohwMGoeAduQz2w+8bbB/d9Nu5xpwidK+xfdL9Om
# OZaR3psAl21aU3BbeBORRbQ1lulP9L0A4lZb45n4ZjBLfi9an67q4DqR6VVuCJvz
# 3F032D8UzAkDQvDjDTAbwmLn8FX7/dMEvXcpABSswGL9U9hKNvu0rAOD/t6RdA18
# dZGTcwCf8ZPitN0+2S9bqLQtvzfPJLWLnreJn/Rj9Tj6qWpb6DuvPr2RyHU/mWgf
# 5oAbRns69N+99d1myi9O33cEglhXXoUOvV38VUlsBw9WYsa1BCsLrebJOwJZZb50
# tAnU2hFY++1hPH1vUIp657lMkiznN7/U5jXIuD0keFI9XguDFCQ11v3YY1bRckpG
# fWne7MFOU4BBoWAmyg0Rktni2ib7y1HtkK/WTZ+P06fKcoA2NYawKU2QI9pHVkaX
# fAHifhth5YJ7zSywdjeWE5WGStJPNk4Bg73xMApy5Q5D3Dt45bdF2lSb9czm1bgh
# px+XWHPXnppzekw=
# SIG # End signature block