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 # MII2lQYJKoZIhvcNAQcCoII2hjCCNoICAQExDzANBglghkgBZQMEAgEFADB5Bgor # 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 # 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggaSMIIEeqADAgECAhMzAAHdaaaY # 6eAQYJsSAAAAAd1pMA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ # RCBWZXJpZmllZCBDUyBBT0MgQ0EgMDMwHhcNMjYwNjA4MTgxMjEzWhcNMjYwNjEx # MTgxMjEzWjBVMQswCQYDVQQGEwJTSTESMBAGA1UEBxMJTGp1YmxqYW5hMRgwFgYD # VQQKEw9CRS10ZXJuYSBkLm8uby4xGDAWBgNVBAMTD0JFLXRlcm5hIGQuby5vLjCC # AaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAJS9/C6Mi/J2DjnLKo8x/yTo # mfR3mrPDVEa0YSY95IWMnIT8UhSk9PIl/iwLef759Z4mOPOtOT4D93Yln/wdBxwP # 2qIDF4u4/H3oIA8qHCm7E1a6KMt4xMhm+Fyhwj3Q7bZUOy9LjthNdjR/AJd8xgb6 # eP4iLgAA/j0RusS03WxkO4T41JbfY/h/ldoZv0nVD7iCN75mZsQgH+cqncSOKX7h # y+2JluyJ22ZFn4QGcbEmg8biWjl3Ox4TKXaJlw2F0ZewBdtSfbuvf3yhiJ9OSk0c # X9gBKwduhXyBHK/3YxkWOgEA5rJq7yx3512a+JRTIY4kPiQweLzyCWmaQylyr6S3 # OLRC/IevT4ggnoGqPiPN9P2DsqNaGrejIkZ9qM4d+Y5WEA2tYvGpyKWtQ//soo01 # Hdju7cVb/PMf47mR+4MGRKdiq+PRqOSPiSju+tMQBSaxMc1yxcec0e1mdanowyiu # V/eCl/4Hcpnl7u/woJS/5YhQrrvCeFp2faaISWuaqwIDAQABo4IB1DCCAdAwDAYD # VR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwOwYDVR0lBDQwMgYKKwYBBAGCN2EB # AAYIKwYBBQUHAwMGGisGAQQBgjdhpOaoI4H67850gfzolDeutrtWMB0GA1UdDgQW # BBRwvc4GA2pbi0KnqmADaclVziwBADAfBgNVHSMEGDAWgBSkQwx/dlqlhec+jSgP # DBeiRWlwxjBnBgNVHR8EYDBeMFygWqBYhlZodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ1MlMjBB # T0MlMjBDQSUyMDAzLmNybDB0BggrBgEFBQcBAQRoMGYwZAYIKwYBBQUHMAKGWGh0 # dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIw # SUQlMjBWZXJpZmllZCUyMENTJTIwQU9DJTIwQ0ElMjAwMy5jcnQwVAYDVR0gBE0w # SzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNv # bS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTANBgkqhkiG9w0BAQwFAAOCAgEA # IOBnoHIENsGe0KoxEFinohJ0YK/l4/Gf/8dGA7dNOWOCdYPHpmdmYFkA9G1bPPoF # jjGHHIjleggIQt2MPXwoU2Jk0mTHPA+j+mmQgKxLF+n/sAjtlETbKOldNPSHLyep # PIzFlLWzHlwb/ytd4nv1x6qqkkhQkNGdaRtxgmXtlqvaJUGY0uAh414Bt2AFTzB5 # yLR0VRRTYDzGE3WA9nM91UghYcSbpseOeCmAzWr3k0MHFU87G9ECTk1vY346jII4 # uXeEyf+tmYVPsfFMw0lpAjqjl23SuxiC8oj89CkJ1CDh9268lCFvoVm3gN8oda4s # 8IS7W0+2w5o4Y7gAElZ1vg5BSK2sb0xXHeze07Udi+Tg7Kx5zZ9Vk00hSzkxZy9L # uWF5KKyodUCc2eCESqR2moXwZCva8mIsW3yM3HyAgLE2VLVMOZ+kBmVEQsK50l/+ # mgFIMmYZBGJDA3l86rQGlJk5x67UzJYvve6a5K6bBgHkVkPD3IkMOvBjqEPrTbLO # Nx2sF/zVW4TdZOYEMsHgsdNyzD7vSSCAXwDTMFPWbB8+zbE7QB9v7AXa0Myszp4n # qXwp0RZOuWceG6jtpVTBtEXISSilknjYUBIWxIs2bixNh0nCo32lIgmFjfpcN1xU # IS3Cwo3z2SUiIlgjfOGsKk0/0Cp9P6S9AA6dOVwS4gQwggcoMIIFEKADAgECAhMz # 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+fL4WrxSK5nMYIatzCCGrMCAQEwcTBaMQsw # CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSswKQYD # VQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ1MgQU9DIENBIDAzAhMzAAHdaaaY # 6eAQYJsSAAAAAd1pMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAI # oAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB # CzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIOHvyJBHEKkSCCJ/L9vV # S99gCUW5SzkWuBHsaXdjRk//MA0GCSqGSIb3DQEBAQUABIIBgDQN+KtbznY7slah # E5f+xUF8UybFsT/LNbUBAL+sxUuvAeAT7hrd5lpwVzHPTuaj+dVpiwdQ7+XkXtAW # hvt23a3AgKt5lWoMvNJbXD/sYwnki9VQPM+gQf/50HuUkoM5wEagp0z86FiJpaE4 # xULQwixLl1f+NtxBXopHYvTPvrtg3pRmJFhm4OYQoQwHC/SI3MSOqTCOkiArQKUT # qkU2zVnpO4gSdWgzw9UTBWEzaqe5xSuU5rDPCd5BzOBXOOnaLjgBymN/XWtenscw # pZCDWEHnH83IF6ZdefZSKhfW7ipVssYd7L1kqJOEncoWAALC8VUe7K3PmaUPWIbf # X5Rd00sCAkKRMEQsFEY9XRUNTrW0QZjv/Fss21WKUo0+LsQH6ys8bTHFTggDFsQl # hkpxqNFyTt3qOTZ7+BPKTS59o5SV7bLPhK/lZrqOgH/C5rdahJlx68KsZ1QUo/n9 # bNuXj+wgBOMTOeDMcDd3eOLtstKYc2izhN54qZHriHNdhsrzO6GCGBAwghgMBgor # BgEEAYI3AwMBMYIX/DCCF/gGCSqGSIb3DQEHAqCCF+kwghflAgEDMQ8wDQYJYIZI # AWUDBAIBBQAwggFhBgsqhkiG9w0BCRABBKCCAVAEggFMMIIBSAIBAQYKKwYBBAGE # WQoDATAxMA0GCWCGSAFlAwQCAQUABCAcwB5f7IcB7hXAHFiIzW78OJT5hWAZ6I5k # NNc6qazjoAIGahxW5PxNGBIyMDI2MDYwOTIyMTYzOS43NlowBIACAfSggeGkgd4w # gdsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsT # HE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQg # VFNTIEVTTjpBNTAwLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0IFB1Ymxp # YyBSU0EgVGltZSBTdGFtcGluZyBBdXRob3JpdHmggg8hMIIHgjCCBWqgAwIBAgIT # MwAAAAXlzw//Zi7JhwAAAAAABTANBgkqhkiG9w0BAQwFADB3MQswCQYDVQQGEwJV # UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMUgwRgYDVQQDEz9NaWNy # b3NvZnQgSWRlbnRpdHkgVmVyaWZpY2F0aW9uIFJvb3QgQ2VydGlmaWNhdGUgQXV0 # aG9yaXR5IDIwMjAwHhcNMjAxMTE5MjAzMjMxWhcNMzUxMTE5MjA0MjMxWjBhMQsw # CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYD # VQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDCC # AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJ5851Jj/eDFnwV9Y7UGIqMc # HtfnlzPREwW9ZUZHd5HBXXBvf7KrQ5cMSqFSHGqg2/qJhYqOQxwuEQXG8kB41wsD # JP5d0zmLYKAY8Zxv3lYkuLDsfMuIEqvGYOPURAH+Ybl4SJEESnt0MbPEoKdNihwM # 5xGv0rGofJ1qOYSTNcc55EbBT7uq3wx3mXhtVmtcCEr5ZKTkKKE1CxZvNPWdGWJU # PC6e4uRfWHIhZcgCsJ+sozf5EeH5KrlFnxpjKKTavwfFP6XaGZGWUG8TZaiTogRo # AlqcevbiqioUz1Yt4FRK53P6ovnUfANjIgM9JDdJ4e0qiDRm5sOTiEQtBLGd9Vhd # 1MadxoGcHrRCsS5rO9yhv2fjJHrmlQ0EIXmp4DhDBieKUGR+eZ4CNE3ctW4uvSDQ # VeSp9h1SaPV8UWEfyTxgGjOsRpeexIveR1MPTVf7gt8hY64XNPO6iyUGsEgt8c2P # xF87E+CO7A28TpjNq5eLiiunhKbq0XbjkNoU5JhtYUrlmAbpxRjb9tSreDdtACpm # 3rkpxp7AQndnI0Shu/fk1/rE3oWsDqMX3jjv40e8KN5YsJBnczyWB4JyeeFMW3JB # fdeAKhzohFe8U5w9WuvcP1E8cIxLoKSDzCCBOu0hWdjzKNu8Y5SwB1lt5dQhABYy # zR3dxEO/T1K/BVF3rV69AgMBAAGjggIbMIICFzAOBgNVHQ8BAf8EBAMCAYYwEAYJ # KwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFGtpKDo1L0hjQM972K9J6T7ZPdshMFQG # A1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jv # c29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYI # KwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwDwYDVR0TAQH/BAUw # AwEB/zAfBgNVHSMEGDAWgBTIftJqhSobyhmYBAcnz1AQT2ioojCBhAYDVR0fBH0w # ezB5oHegdYZzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWlj # cm9zb2Z0JTIwSWRlbnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290JTIwQ2VydGlm # aWNhdGUlMjBBdXRob3JpdHklMjAyMDIwLmNybDCBlAYIKwYBBQUHAQEEgYcwgYQw # gYEGCCsGAQUFBzAChnVodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2Nl # cnRzL01pY3Jvc29mdCUyMElkZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIwUm9vdCUy # MENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAyMC5jcnQwDQYJKoZIhvcNAQEM # BQADggIBAF+Idsd+bbVaFXXnTHho+k7h2ESZJRWluLE0Oa/pO+4ge/XEizXvhs0Y # 7+KVYyb4nHlugBesnFqBGEdC2IWmtKMyS1OWIviwpnK3aL5JedwzbeBF7POyg6IG # G/XhhJ3UqWeWTO+Czb1c2NP5zyEh89F72u9UIw+IfvM9lzDmc2O2END7MPnrcjWd # QnrLn1Ntday7JSyrDvBdmgbNnCKNZPmhzoa8PccOiQljjTW6GePe5sGFuRHzdFt8 # y+bN2neF7Zu8hTO1I64XNGqst8S+w+RUdie8fXC1jKu3m9KGIqF4aldrYBamyh3g # 4nJPj/LR2CBaLyD+2BuGZCVmoNR/dSpRCxlot0i79dKOChmoONqbMI8m04uLaEHA # v4qwKHQ1vBzbV/nG89LDKbRSSvijmwJwxRxLLpMQ/u4xXxFfR4f/gksSkbJp7oqL # wliDm/h+w0aJ/U5ccnYhYb7vPKNMN+SZDWycU5ODIRfyoGl59BsXR/HpRGtiJquO # YGmvA/pk5vC1lcnbeMrcWD/26ozePQ/TWfNXKBOmkFpvPE8CH+EeGGWzqTCjdAsn # o2jzTeNSxlx3glDGJgcdz5D/AAxw9Sdgq/+rY7jjgs7X6fqPTXPmaCAJKVHAP19o # EjJIBwD1LyHbaEgBxFCogYSOiUIr0Xqcr1nJfiWG2GwYe6ZoAF1bMIIHlzCCBX+g # AwIBAgITMwAAAFZ+j51YCI7pYAAAAAAAVjANBgkqhkiG9w0BAQwFADBhMQswCQYD # VQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQD # EylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDAeFw0y # NTEwMjMyMDQ2NTFaFw0yNjEwMjIyMDQ2NTFaMIHbMQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBP # cGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046QTUwMC0wNUUwLUQ5 # NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWUgU3RhbXBpbmcg # QXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtKWfm/ul # 027/d8Rlb8Mn/g0QUvvLqY2Vsy3tI8U2tFSspTZomZOD3BHT8LkR+RrhMJgb1VjA # KFNysaK9cLSXifPGSIBrPCgs9P4y24lrJEmrV6Q5z4BmqMhIPrZhEvZnWpCS4HO7 # jYSei/nxmC7/1Er+l5Lg3PmSxb8d2IVcARxSw1B4mxB6XI0nkel9wa1dYb2wfGpo # fraFmxZOxT9eNht4LH0RBSVueba6ZNpjS/0gtfm7qiIiyP6p6PRzTTbMnVqsHnV/ # d/rW0zHx+Q+QNZ5wUqKmTZJB9hU853+2pX5rDfK32uNY9/WBOAmzbqgpEdQkbiMa # vUMyUDShmycIvgHdQnS207sTj8M+kJL3tOdahPuPqMwsaCCgdfwwQx0O9TKe7FSv # bAEYs1AnldCl/KHGZCOVvUNqjyL10JLe0/+GD9/ynqXGWFpXOjaunvZ/cKROhjN4 # M5e6xx0b2miqcPii4/ii2ZheKallJET7CKlpFShs3wyg6F/fojQxQvPnbWD4Nyx6 # lhjWjwmoLcx6w1FSCtavLCly33BLRSlTU4qKUxaa8d7YN7Eqpn9XO0SY0umOvKFX # rWH7rxl+9iaicitdnTTksAnRjvekdKT3lg7lRMfmfZU8vXNiN0UYJzT9EjqjRm0u # N/h0oXxPhNfPYqeFbyPXGGxzaYUz6zx3qTcCAwEAAaOCAcswggHHMB0GA1UdDgQW # BBS+tjPyu6tZ/h5GsyLvyz1H+FNIWjAfBgNVHSMEGDAWgBRraSg6NS9IY0DPe9iv # Sek+2T3bITBsBgNVHR8EZTBjMGGgX6BdhltodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBQdWJsaWMlMjBSU0ElMjBUaW1lc3Rh # bXBpbmclMjBDQSUyMDIwMjAuY3JsMHkGCCsGAQUFBwEBBG0wazBpBggrBgEFBQcw # AoZdaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3Nv # ZnQlMjBQdWJsaWMlMjBSU0ElMjBUaW1lc3RhbXBpbmclMjBDQSUyMDIwMjAuY3J0 # MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/ # BAQDAgeAMGYGA1UdIARfMF0wUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEW # M2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5 # Lmh0bTAIBgZngQwBBAIwDQYJKoZIhvcNAQEMBQADggIBAA4DqAXEsO26j/La7Fgn # /Qifit8xuZekqZ57+Ye+sH/hRTbEEjGYrZgsqwR/lUUfKCFpbZF8msaZPQJOR4YY # UEU8XyjLrn8Y1jCSmoxh9l7tWiSoc/JFBw356JAmzGGxeBA2EWSxRuTr1AuZe6nY # aN8/wtFkiHcs8gMadxXBs6DxVhyu5YnhLPQkfumKm3lFftwE7pieV7f1lskmlgsC # 6AeSGCzGPZUgCvcH5Tv/Qe9z7bIImSD3SuzhOIwaP+eKQTYf67TifyJKkWQSdGfT # A6Kcu41k8LB6oPK+MLk1jbxxK5wPqLSL62xjK04SBXHEJSEnsFt0zxWkxP/lgej1 # DxqUnmrYEdkxvzKSHIAqFWSZul/5hI+vJxvFPhsNQBEk4cSulDkJQpcdVi/gmf/m # HFOYhDBjsa15s4L+2sBil3XV/T8RiR66Q8xYvTLRWxd2dVsrOoCwnsU4WIeiC0Ji # nCv1WLHEh7Qyzr9RSr4kKJLWdpNYLhgjkojTmEkAjFO774t3xB7enbvIF0GOsV19 # xnCUzq9EGKyt0gMuaphKlNjJ+aTpjWMZDGo+GOKsnp93Hmftml0Syp3F9+M3y+y6 # WJGUZoIZJq227jDjjEndtpUrh9BdPdVIfVJD/Au81Rzh05UHAivorQ3Os8PELHIg # iOd9TWzbdgmGzcILt/ddVQERMYIHQzCCBz8CAQEweDBhMQswCQYDVQQGEwJVUzEe # MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3Nv # ZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMAITMwAAAFZ+j51YCI7p # YAAAAAAAVjANBglghkgBZQMEAgEFAKCCBJwwEQYLKoZIhvcNAQkQAg8xAgUAMBoG # CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwNjA5 # MjIxNjM5WjAvBgkqhkiG9w0BCQQxIgQgLWzfQOYu0rGMtInkBJWgAeWKnzwsBGj2 # 92xQaQA3G8QwgbkGCyqGSIb3DQEJEAIvMYGpMIGmMIGjMIGgBCC2DDMlTaTj8JV3 # iTg5Xnpe4CSH60143Z+X9o5NBgMMqDB8MGWkYzBhMQswCQYDVQQGEwJVUzEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQg # UHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMAITMwAAAFZ+j51YCI7pYAAA # AAAAVjCCA14GCyqGSIb3DQEJEAISMYIDTTCCA0mhggNFMIIDQTCCAikCAQEwggEJ # oYHhpIHeMIHbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUw # IwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5u # U2hpZWxkIFRTUyBFU046QTUwMC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jvc29m # dCBQdWJsaWMgUlNBIFRpbWUgU3RhbXBpbmcgQXV0aG9yaXR5oiMKAQEwBwYFKw4D # AhoDFQD/c/cpFSqQWYBeXggyRJ2ZbvYEEaBnMGWkYzBhMQswCQYDVQQGEwJVUzEe # MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3Nv # ZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDANBgkqhkiG9w0BAQsF # AAIFAO3SstowIhgPMjAyNjA2MDkxNTQyMThaGA8yMDI2MDYxMDE1NDIxOFowdDA6 # BgorBgEEAYRZCgQBMSwwKjAKAgUA7dKy2gIBADAHAgEAAgIT0TAHAgEAAgISgTAK # AgUA7dQEWgIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB # AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQCXAXMX1U7tFncE # b62A4vxpOiXij4M1aegoWk/Q43cIgsAGy5yuwHvhF92H7+vZDZP4VVG353vXw0fJ # kDBq9+WVwr3t7mXPg/Cnn1QVm7ZqmkQGlNJvRzcoEWZYYJeu8bl0goZb9QI4Px9h # FyDJfXBTy/ZWlBQrP1JeFDFls6CSGExzDqD6rtKVG4CD7UmwwV1tLO5tCCNhKtbB # seoue5wglEwcJxmWGmPVWbNnQZyIUsQWHaMmpS73GeYg+07BxrjwEcXMDmb3sGWf # N+GFIltTGuCvGjmm/j43DywFxDKd1C/D5Rwur+NXCxqYOIsGQI4RDieLIxVWe5mk # Zvd5ou72MA0GCSqGSIb3DQEBAQUABIICABwf7vqgDBxxO6lk2qEERgpeAmH2hsY9 # lmVifj/QD4be2K+Zcf9oWU6AByNkcy7v7R4WpWC05qdQYceQnlveZu5VlThyXlbr # hJRjhnPIDQkJDMLyQmr02k1MjfVZ7VLPvd9tz7bkRAfJoJUiGZPYODGuLiMB57H4 # 70x5wgjraBJmxDQqL0Jl2yHtxgLzHbhPIrSkM2DI6MSOwBtHBJlVVZ9mdgXZSDSm # wmT1jnV6t+NKjnkUCvy6/uzPLheE/jDPIOnv1UIDmhWSO1WfL0kP0YuT/n4ZrNjq # dEJL4TbvNWzDaEvZWoWaxJiSA4RyiKSr6c9lL+a5wzMCQiRNifNzt/HQImR9HRNH # f9Dx2/n2A3NE8CREgpgCopHOQcGL7yvNNv2QDpBHOorEIhjn3C/G1i70Z0TC3jPZ # cwDGk4n/QMWzTaz3wKmCrySqWL59lwGFAhfY+AAba9o4wJ/Ski0EcjWD3JOorLRm # tzOiCUxYXMxX5FPWfcaJK/+xCfPXVQ7BX3dHHAkaOb58IQXkaDQ98yz7lJJIfp7P # zBo/3ujFuinJR+0z8IH2kccSeSOixlhM6vIg4wB+Srxt4U8C9SJEEH1GuqJ/4Wv3 # ezA9KkRKh6reXP0HCw21HwBbsKE17Edj/uMWzLPtP1rvr5NfORL3s2y+5EAIrT9m # ZyCUhRH1SGo+ # SIG # End signature block |