functions/MergeDrivers/Merge-D365LabelFile.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/MergeDrivers/Merge-D365LabelFile.ps1 -Base %O -Ours %A -Theirs %B -MarkerSize %L -FilePath %P" Alternatively, install the D365GitOps module and run: Register-D365LabelFileMergeDriver .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/MergeDrivers/Merge-D365LabelFile.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 # MII2mQYJKoZIhvcNAQcCoII2ijCCNoYCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBwBd5NXIsoD7jZ # hBdBfG0R3YdUcRM8PMq/xHRB1srfdaCCGzQwggXMMIIDtKADAgECAhBUmNLR1FsZ # 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 # 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggaSMIIEeqADAgECAhMzAAHu9TZJ # AXLIgeNaAAAAAe71MA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ # RCBWZXJpZmllZCBDUyBBT0MgQ0EgMDMwHhcNMjYwNjEwMTgxNDMyWhcNMjYwNjEz # MTgxNDMyWjBVMQswCQYDVQQGEwJTSTESMBAGA1UEBxMJTGp1YmxqYW5hMRgwFgYD # VQQKEw9CRS10ZXJuYSBkLm8uby4xGDAWBgNVBAMTD0JFLXRlcm5hIGQuby5vLjCC # AaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALwaIKqmCEITt4bpy6OMZOo3 # 9/b6lN6E67xLbwzzFJ717FN0v5u22v8lGrR+gS42rK38bAzdDtv86y/rDq/4WHnO # y2FPEFDNSfxReib8W+UJuZFdTkCTlMFlz0gaesSMXK0kS13HrJBHAZ7r/84L8yZB # ntRGXP2JWKhZ48h0AYUKlfggFMr3PQyOCJQKHBK53B3ZDbFoMeCurNeX8VYjMulP # 1DWvCg2HtGwVLcbkHysZi8z7xK+TW4Zl1W1EjMmOb7u+wYQsBh94eAnUv5hp3Vss # 2zm/c4o0bz5Nz37PHrYqmaEYVsUwcu2WpSje5xCvvonia0st+jz0+KBBKyrctNoS # PUB06KxqrxEGvZg+SBgXsmh4fuC2I7LYKbajX4JzlzHDOAcTsMLryl3TlgyjAIR7 # skzlkTwy5jnmxvuidk30AdH6as7S1uI2/Lq2z99CTAzaKOG8DN0UyvBKMwLmx/vF # xWs7OnF1FDugRVcTrLbeH7c7oYnKqYO5eIFVbjhpQQIDAQABo4IB1DCCAdAwDAYD # VR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwOwYDVR0lBDQwMgYKKwYBBAGCN2EB # AAYIKwYBBQUHAwMGGisGAQQBgjdhpOaoI4H67850gfzolDeutrtWMB0GA1UdDgQW # BBSORAcvu9iCNkIHpzlgvfEIMKVdgjAfBgNVHSMEGDAWgBSkQwx/dlqlhec+jSgP # DBeiRWlwxjBnBgNVHR8EYDBeMFygWqBYhlZodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ1MlMjBB # T0MlMjBDQSUyMDAzLmNybDB0BggrBgEFBQcBAQRoMGYwZAYIKwYBBQUHMAKGWGh0 # dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIw # SUQlMjBWZXJpZmllZCUyMENTJTIwQU9DJTIwQ0ElMjAwMy5jcnQwVAYDVR0gBE0w # SzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNv # bS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTANBgkqhkiG9w0BAQwFAAOCAgEA # fl8NZOZWwetiZqJkIGDn4l7ctL03OD1Ra3EDB0sn129okZb3g5KsYlqpuA6AhfHK # mNT4p7prAc10H1kO1RIWoyL15N/rBGDbz/yYC6+gZl52Ve43Zj0gxg75vfis4fzz # Bj6wubfZlDBC93csGnVzxSdr/FtLrf0mNCcKMPAl+UpmcdnTJ9p0N3h+bYWjZrXU # dOU2x1C0g0KbwB+L+3cfNbe92UKY7fkPqvJTnv42QOfeOGpZNZVr3wyDMcrrpG5G # vw5t54q3Cnwqt2NyTyL141YJ2tEnc+b+n9qndXaf7LLWGg7PoD5s6ABraoH2R6aW # LN4cP5kIQPHK6KV5j5dJZEQPM43hOYu9mQzj8cz8nX1wJRBANH46qJdSi4ZLDfHS # WQ5jAQMkyp+DY0R5AuRg5l8Ey5ARGGPbBhJECSiyHMuglyuWWW9Vic5bgj+zAD7B # vJSlBGfukk1EfvM7LzBBUABzOsLWhVDR7T6av1PvYNfc6cJGG+ZlA9oW+s/9TOo4 # iZa7Rscry8NZjkGl2DHejb6R7P9PgfoSbCNtNv771QpblbbVcv9wRjoKOot/Adxc # w0RqPJtkf01K1lHH7ZFzpDbO1pLCS3KDY8aDm4saoTHsPXoeSmCw6LizNw/c6Zv4 # gQxtnjLrquDzBJHyAIBrDbT21A3O9lZiJfDXR6ryXSowggcoMIIFEKADAgECAhMz # AAAAGA3rkVWpigCYAAAAAAAYMA0GCSqGSIb3DQEBDAUAMGMxCzAJBgNVBAYTAlVT # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xNDAyBgNVBAMTK01pY3Jv # c29mdCBJRCBWZXJpZmllZCBDb2RlIFNpZ25pbmcgUENBIDIwMjEwHhcNMjYwMzI2 # MTgxMTMyWhcNMzEwMzI2MTgxMTMyWjBaMQswCQYDVQQGEwJVUzEeMBwGA1UEChMV # TWljcm9zb2Z0IENvcnBvcmF0aW9uMSswKQYDVQQDEyJNaWNyb3NvZnQgSUQgVmVy # aWZpZWQgQ1MgQU9DIENBIDAzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC # AgEAyIDaYDRWoon9lVnlj+SOj5xV8Sf5Qd+3yUeeRgr0exi2QTJAYo24ilcIKQSN # 8TOZ3+POM5x/6p3Cfjgqust44J0FvkfGXe1Puy45a5nLJGpc0kNIITMRKZwVvPxx # 7NlfGSc0JOhz/kg7G77C+y3ZR/3jtpeJpJ4QwcK9Gf0Peuk7xLYeW/JAsY9b6ole # GDbYSxkamUfbtnyv8gTFrvN6ejuLqNhHYPvoBHsOSC+7555yhapkof0fbzyct1hd # WHGXsAFMfLF2TVJ8d2YVYOfZdi6YrT4sMxOhTKiLKmhL1XtzM7hXdmv7lg2R+lWw # 8lIkSu/JiINQ0GAPcwxMsgRXDSPp8VUs4Jby+ruz0bjaoHFd7H+hC8cPPcrEDP2e # EdYURVl0acjliigCrXwR05NFJzYj3MZizDGLPI3lIzonX1T40yK8v1FcJ8MXZZCv # OXGXwRDGGfwwTTsHaJj+OfWNZ/IsypG4bGvqeJcPnEFcQEwRcfYIEe/R4a8k+xw5 # qTy75CbwWeMFuAlt9lE9kjMg3tvJyDlN5voXx5VXinCwUHMpuVaEQ4yHAlSO7qoB # ltjzTBNHH3ovMwsAsuhwrLLCVhUu3oP2GxYZwEyXMlnzK5DbgGzHzDfDaYPHK0uo # 1VaMMg9Bhuc3YIvrkFXEiv+t/JgNcRGCt6ZyKEIDtPbrgwcCAwEAAaOCAdwwggHY # MA4GA1UdDwEB/wQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUpEMM # f3ZapYXnPo0oDwwXokVpcMYwVAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUH # AgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0 # b3J5Lmh0bTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTASBgNVHRMBAf8ECDAG # AQH/AgEAMB8GA1UdIwQYMBaAFNlBKbAPD2Ns72nX9c0pnqRIajDmMHAGA1UdHwRp # MGcwZaBjoGGGX2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01p # Y3Jvc29mdCUyMElEJTIwVmVyaWZpZWQlMjBDb2RlJTIwU2lnbmluZyUyMFBDQSUy # MDIwMjEuY3JsMH0GCCsGAQUFBwEBBHEwbzBtBggrBgEFBQcwAoZhaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBJRCUyMFZl # cmlmaWVkJTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDIxLmNydDANBgkqhkiG # 9w0BAQwFAAOCAgEAcccgVvl+poXUYksA/TzDFnBlAJ8ef0FMJzb2XRRhF/uA0QyK # /VgoeAvO8B7cPpYNQ97sytdA7LT19CxSwRQAt71jGF+CJl8KC4aEdMZTfJlHaKyd # 24J6QiVriNed9WdawsD7lK0pAcXziBg5N6dhAm9x6P8R4uT0UkfzlK1rkB8F4mlz # E7l7tyES3s8FZGaRZjcGEQ+e0fTcdhf8jO7czmNB4dIRgmmBCt/P+ha0tEl2nV1s # g1An5+VzhgAkY1Apx8fiUFBtH+Ehw/om5aQCNIJfmR51ZnV18R02Xk2tAmAiIRcS # j9vdtrNIOsy5nolddy1lJrbf1Be061l6TItv9FDZ4mg6B+65zxkVecVV/Ll8uLGY # ouGrMM6jzO2O/ps3K2p6mfBI2ZOYIy4UNwNrGWqa5TrvAmkZsn3CIlR+81X4AL5v # NTFlxc4gH+5su0Dr58hBTxnXavDEnz7X0csP1Kt7h+iqaGiTSHz2B+n3HmUoud0W # rdQPYKxMat0To4YUqU3HIbgSLQDDVT8aCjW1Jvokf1915C/vVkIIp48h3voVy3JW # PLwBlxQ9aeND6jCKQGLJhCQRSlvXX+P/9TeaEA6/xWPSASZf6Ekve/Yua7U+zWc/ # Sr2K2gj0QRrNEAsvrFr4EGtHKDO9ECVS3lcJksVDv9KHdMPUK8u20i68RqAwggee # 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+fL4WrxSK5nMYIauzCCGrcCAQEwcTBaMQsw # CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSswKQYD # VQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ1MgQU9DIENBIDAzAhMzAAHu9TZJ # AXLIgeNaAAAAAe71MA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAI # oAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB # CzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIOHvyJBHEKkSCCJ/L9vV # S99gCUW5SzkWuBHsaXdjRk//MA0GCSqGSIb3DQEBAQUABIIBgADkyp+JQxa18JDP # q4mcZ5wS8NiuIWQzL9jZUoekuUjx5A4RdpG4YHJ5BGB2R2WZjgZrdpLIu8gRr0Ou # 9txxYjnogm5Q1nJSqGLUMut3twZlRPGnVPd6eiRrUfLrxH5Z/d7Dja6ND6zWi/+n # 3OkEKYKExySvedeDPQQIO84X7svu76BO64Ur/xtw3svtLPdQvfIQijK9XWl02MUq # FTwH1CGE/W7lgFlLuqoj6S94BNycZS0f4dnw/RpQRmT/KGLBTYRpIYrS1qWQDTBE # XD4HjcCrKjXhkYRfNhcLFM8DPyjdjJwRCXtXOSnpqAQB0u/m977bYWtMwR0u0ehf # VmdiXVa8CBmxMpQedbfPd001YEK578g0qj7AJb9ObfZA9P+jUzl0z948Fzb/BogI # 3B00ClFMP8OFpu2q54WMFgNUHSOltpWdR/iUdiBuKozyHxrSxkXyfSkAj3tknS8r # IMihxRMDfZB6g8xXzmJUJ1oNgcJbfcZk+KzuhCq1a2jN/LRrwqGCGBQwghgQBgor # BgEEAYI3AwMBMYIYADCCF/wGCSqGSIb3DQEHAqCCF+0wghfpAgEDMQ8wDQYJYIZI # AWUDBAIBBQAwggFiBgsqhkiG9w0BCRABBKCCAVEEggFNMIIBSQIBAQYKKwYBBAGE # WQoDATAxMA0GCWCGSAFlAwQCAQUABCDfWBUw1z4Fg6VjSHtqEJw8YOEx6bFHK/Zc # oirON3AG/QIGahdmJ+kHGBMyMDI2MDYxMjEzMjQyOC40OTNaMASAAgH0oIHhpIHe # MIHbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQL # ExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxk # IFRTUyBFU046N0EwMC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJs # aWMgUlNBIFRpbWUgU3RhbXBpbmcgQXV0aG9yaXR5oIIPITCCB4IwggVqoAMCAQIC # EzMAAAAF5c8P/2YuyYcAAAAAAAUwDQYJKoZIhvcNAQEMBQAwdzELMAkGA1UEBhMC # VVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjFIMEYGA1UEAxM/TWlj # cm9zb2Z0IElkZW50aXR5IFZlcmlmaWNhdGlvbiBSb290IENlcnRpZmljYXRlIEF1 # dGhvcml0eSAyMDIwMB4XDTIwMTExOTIwMzIzMVoXDTM1MTExOTIwNDIzMVowYTEL # MAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAG # A1UEAxMpTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjAw # ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCefOdSY/3gxZ8FfWO1BiKj # HB7X55cz0RMFvWVGR3eRwV1wb3+yq0OXDEqhUhxqoNv6iYWKjkMcLhEFxvJAeNcL # AyT+XdM5i2CgGPGcb95WJLiw7HzLiBKrxmDj1EQB/mG5eEiRBEp7dDGzxKCnTYoc # DOcRr9KxqHydajmEkzXHOeRGwU+7qt8Md5l4bVZrXAhK+WSk5CihNQsWbzT1nRli # VDwunuLkX1hyIWXIArCfrKM3+RHh+Sq5RZ8aYyik2r8HxT+l2hmRllBvE2Wok6IE # aAJanHr24qoqFM9WLeBUSudz+qL51HwDYyIDPSQ3SeHtKog0ZubDk4hELQSxnfVY # XdTGncaBnB60QrEuazvcob9n4yR65pUNBCF5qeA4QwYnilBkfnmeAjRN3LVuLr0g # 0FXkqfYdUmj1fFFhH8k8YBozrEaXnsSL3kdTD01X+4LfIWOuFzTzuoslBrBILfHN # j8RfOxPgjuwNvE6YzauXi4orp4Sm6tF245DaFOSYbWFK5ZgG6cUY2/bUq3g3bQAq # Zt65KcaewEJ3ZyNEobv35Nf6xN6FrA6jF9447+NHvCjeWLCQZ3M8lgeCcnnhTFty # QX3XgCoc6IRXvFOcPVrr3D9RPHCMS6Ckg8wggTrtIVnY8yjbvGOUsAdZbeXUIQAW # Ms0d3cRDv09SvwVRd61evQIDAQABo4ICGzCCAhcwDgYDVR0PAQH/BAQDAgGGMBAG # CSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRraSg6NS9IY0DPe9ivSek+2T3bITBU # BgNVHSAETTBLMEkGBFUdIAAwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNy # b3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMBMGA1UdJQQMMAoG # CCsGAQUFBwMIMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQF # MAMBAf8wHwYDVR0jBBgwFoAUyH7SaoUqG8oZmAQHJ89QEE9oqKIwgYQGA1UdHwR9 # MHsweaB3oHWGc2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01p # Y3Jvc29mdCUyMElkZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIwUm9vdCUyMENlcnRp # ZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAyMC5jcmwwgZQGCCsGAQUFBwEBBIGHMIGE # MIGBBggrBgEFBQcwAoZ1aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j # ZXJ0cy9NaWNyb3NvZnQlMjBJZGVudGl0eSUyMFZlcmlmaWNhdGlvbiUyMFJvb3Ql # MjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMjAuY3J0MA0GCSqGSIb3DQEB # DAUAA4ICAQBfiHbHfm21WhV150x4aPpO4dhEmSUVpbixNDmv6TvuIHv1xIs174bN # GO/ilWMm+Jx5boAXrJxagRhHQtiFprSjMktTliL4sKZyt2i+SXncM23gRezzsoOi # Bhv14YSd1Klnlkzvgs29XNjT+c8hIfPRe9rvVCMPiH7zPZcw5nNjthDQ+zD563I1 # nUJ6y59TbXWsuyUsqw7wXZoGzZwijWT5oc6GvD3HDokJY401uhnj3ubBhbkR83Rb # fMvmzdp3he2bvIUztSOuFzRqrLfEvsPkVHYnvH1wtYyrt5vShiKheGpXa2AWpsod # 4OJyT4/y0dggWi8g/tgbhmQlZqDUf3UqUQsZaLdIu/XSjgoZqDjamzCPJtOLi2hB # wL+KsCh0Nbwc21f5xvPSwym0Ukr4o5sCcMUcSy6TEP7uMV8RX0eH/4JLEpGyae6K # i8JYg5v4fsNGif1OXHJ2IWG+7zyjTDfkmQ1snFOTgyEX8qBpefQbF0fx6URrYiar # jmBprwP6ZObwtZXJ23jK3Fg/9uqM3j0P01nzVygTppBabzxPAh/hHhhls6kwo3QL # J6No803jUsZcd4JQxiYHHc+Q/wAMcPUnYKv/q2O444LO1+n6j01z5mggCSlRwD9f # aBIySAcA9S8h22hIAcRQqIGEjolCK9F6nK9ZyX4lhthsGHumaABdWzCCB5cwggV/ # oAMCAQICEzMAAABYZc3rP6HX/NIAAAAAAFgwDQYJKoZIhvcNAQEMBQAwYTELMAkG # A1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UE # AxMpTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjAwHhcN # MjUxMDIzMjA0NjU1WhcNMjYxMDIyMjA0NjU1WjCB2zELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2Eg # T3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjdBMDAtMDVFMC1E # OTQ3MTUwMwYDVQQDEyxNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lIFN0YW1waW5n # IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJ14NKR2 # kOz1QJZZ/h2WayRXC6Cm3pIVtci/kDQVIBRVLI2SCmqqjeKCCbCTN6bNKyTUju53 # QjUbmQ19loLq9wJO+3l65aAV6mZjumVV3gzUQi5XVuANPzX48ye115HRIY6/NYIV # xKUe8wvsG2jTfrD0scywGQXomwxT+18LOcF9GbSLDdWtvl6uW71qd5ETMrcLJE47 # p0YHi2S/7Qadt+yVXUTxQEPY2ESqQqlAaP79cYwS0Qldz2pSo5xn29zDeFO41cqo # nxR0oXJ1uQhEUaAZlGurMoA8xUq/Ht4Pd0zzSxVIr1BNBpi321+XHg9RrdRXGesf # yS1QE85OfgVh2zMcCSFZFT06kkjI0OikynXJ6t6R9HOABSaf4Jb3KatFPX82SIyR # hr3aYrIZUZe+0ULVIUo8R7wp9ywv8akEMDh0kA7BoejV9g9EX7EshLUwAcgGnvts # NRwckw03JpUzSxLkC3go9YDQXSFo9FjmMg7Y40P/Ik1mOnstb2/ah5YyI+R4CJ3U # +T/TGJNlYNnu4SlGTQTWwP4bIAbLqGfiF/PVr4xDfWmxfdUuDiVbop5irCzvzC25 # 5e4pLg9HTeqANGHsMg0J3LNdrDPRzrbu9kAP02ZXn71vK/cbTFwGKEJXBo7JPFuF # HO3H6lamyD43aHPGcQcy3F3Fcj+KeXMi8L5DAgMBAAGjggHLMIIBxzAdBgNVHQ4E # FgQUco1NxXq+FcVyfoYz3ESZ8Z0SCbAwHwYDVR0jBBgwFoAUa2koOjUvSGNAz3vY # r0npPtk92yEwbAYDVR0fBGUwYzBhoF+gXYZbaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwUHVibGljJTIwUlNBJTIwVGltZXN0 # YW1waW5nJTIwQ0ElMjAyMDIwLmNybDB5BggrBgEFBQcBAQRtMGswaQYIKwYBBQUH # MAKGXWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9z # b2Z0JTIwUHVibGljJTIwUlNBJTIwVGltZXN0YW1waW5nJTIwQ0ElMjAyMDIwLmNy # dDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB # /wQEAwIHgDBmBgNVHSAEXzBdMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9y # eS5odG0wCAYGZ4EMAQQCMA0GCSqGSIb3DQEBDAUAA4ICAQB768SIlRdYh3F78ayU # wg/HjrWz1Gyvcfi8+9ImHoYfhtFKDjHDH9OEA+rUD03meR4RhE5HJ9K2gyeTaX20 # QbihB99a8W2Sve6NdikQzSdzbuHj2lCKR/03Fs/Dy1TghAssEsWxIBBttJMsnRnO # OnOfdbV86X5CQ3JI6GK8qWnq3XkC0UB/S2qE2GX3QMzKPg8tDtQ8xSZBeWJ7JgDP # Jbfa9TbV3RY3WxTAm1eXWruuJldtrNfOgPFJovpdt/flHtHGyUCMpFoSJYYVocUI # KJLKh8+5KdhhWQAHskk5iDkDlslzgPCQPEyEicp9yQzoErb+fNz91dEEgC0+iVww # ltuhVdtPFRiTM5L9Ettojk2Sf6Gpk6ZPEcw/KFk/KX23tav5P28T4l2EW86bPemu # WDpKO59FXaOtQziYS/5oZNNWN+PIKur4Rv1U3HRh4dawpMDjNOQd+QGWavQLT6X0 # cyYp6x88xkcfq+nw93HGDDzDF/zcHdoq866Yde9n0HEn9XzML8CIZnx+BliSfpn9 # RwOrl6ADlQcnJILl75Y/ID4u09hEukVPPkLLH6kzUySo7AYXlilr9luBElXp9i+5 # Qs+4u/RYQPtJKdMlyZ2MHc1ktKL0yDVCyDZs1cjHElJuVrlX/GGd93ALndjqa+jd # fkbi2Q2rw744noZSOXR/hhMuejGCB0YwggdCAgEBMHgwYTELMAkGA1UEBhMCVVMx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9z # b2Z0IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjACEzMAAABYZc3rP6HX # /NIAAAAAAFgwDQYJYIZIAWUDBAIBBQCgggSfMBEGCyqGSIb3DQEJEAIPMQIFADAa # BgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTI2MDYx # MjEzMjQyOFowLwYJKoZIhvcNAQkEMSIEINIYtoQIvMS1+AW0j8XXuJcjH6rNRW+v # eLQ8beM5niizMIG5BgsqhkiG9w0BCRACLzGBqTCBpjCBozCBoAQgxSJUu7IH0PsA # KNXFm1s/ljevVQXbOfIW62p/dfWi6HEwfDBlpGMwYTELMAkGA1UEBhMCVVMxHjAc # BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0 # IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjACEzMAAABYZc3rP6HX/NIA # AAAAAFgwggNhBgsqhkiG9w0BCRACEjGCA1AwggNMoYIDSDCCA0QwggIsAgEBMIIB # CaGB4aSB3jCB2zELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO # BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEl # MCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMe # blNoaWVsZCBUU1MgRVNOOjdBMDAtMDVFMC1EOTQ3MTUwMwYDVQQDEyxNaWNyb3Nv # ZnQgUHVibGljIFJTQSBUaW1lIFN0YW1waW5nIEF1dGhvcml0eaIjCgEBMAcGBSsO # AwIaAxUAnWR5G9unq3BdjutrwnWVH1ErxFygZzBlpGMwYTELMAkGA1UEBhMCVVMx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9z # b2Z0IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjAwDQYJKoZIhvcNAQEL # BQACBQDt1lPRMCIYDzIwMjYwNjEyMDk0NTUzWhgPMjAyNjA2MTMwOTQ1NTNaMHcw # PQYKKwYBBAGEWQoEATEvMC0wCgIFAO3WU9ECAQAwCgIBAAICGV0CAf8wBwIBAAIC # EyQwCgIFAO3XpVECAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAK # MAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQsFAAOCAQEAb8+XvQvT # oxMtI9+znfpjfHrnI/eX/oDLlPDd3UD2VT0boxHBd8k5gppv/Owmrbr4zdKZ7tUh # nJs7AUgpBcXdqsWe/DiKeZGmyA8qNMAYJo2wMVyUBa+JLA4RvcohR3OQzN5OkKM1 # e7+Pd665cNeXZ1qkgHRqdJwD2n4G8VbN12U/R6Hf1kPrLFlw7yuRLudrTymWQcs8 # y37u9IAQh3KumInsj8t0n9k5jk93Ts5KOL4v07U84iAVRpdKxbfYDQjlDTS7onA1 # GVOoaRf2w7fO23qdnQWl4UVIRdhV/pA8w+EEl0mxu1wXyUfcOAPhYWlwKFrOLDNf # +u0SmvEOOvWPNzANBgkqhkiG9w0BAQEFAASCAgAOXLzGhY9jtEZM0JBHDAFM8P4/ # 0A5/cxNKrLu+ls8DKchNdRY165baEcnsEl6+UG8FQl6wxWYy59ncqDeenpoVBV3+ # chGhF7t9LTNvuMICsi6ZEGGh4TGulZvXUI9uD+Yf5/FPExmJaC7V8brCkldiOr5i # DBMN6rjMd6CoQ0l4ErjP7yaTfz4fGrdwUNq0102duk+KgEZJJJ7XmGzF4VYAkJzU # BzFzO1rR7+DGxNw75hcJ/evLd4KVKZ4g4ngynEkIGAjbox1W5wEzQrIxHF7Qa7M9 # gG6p2IMjhR8rYhSYQYGYUXu2rD5TquABJ6LYt5KoB6HgK+gBmW9k5sPmDi/bBySn # CE7b73cBKzkpn5N/WTYY2B4gb3CEDIyrtohPrfjqhzOAKFl9Qy+2xImGMYmEIn7H # UD364B/om7Y5X1dKMNpbkaNRHggb+7CJrBq+r/xG9tHiSgC9xyxYP/PRJptbHZpO # mWFBxsoF6yaxpkmBfERvcZxaFm7gTRzpwKM8D/+PhCC+HeAEx8gzAb/V8oOkrkd6 # lcXa2RW7fB44iZSnwTspx6dCm1flOH7NfW6aHfr6ka+Gwef9XWUh9T8TtfmnrNvl # wG08Q8z8ut7aAlxxCBGxvx7lZRTIEFih8a3cXBst2RKHQ05/47HgUtsrD9P9Uqip # Jia4Cl3jDorQKbuYnA== # SIG # End signature block |