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 # 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggaSMIIEeqADAgECAhMzAAHxvjzX # QAAWrnYGAAAAAfG+MA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ # RCBWZXJpZmllZCBDUyBFT0MgQ0EgMDQwHhcNMjYwNjE0MTgxODQzWhcNMjYwNjE3 # MTgxODQzWjBVMQswCQYDVQQGEwJTSTESMBAGA1UEBxMJTGp1YmxqYW5hMRgwFgYD # VQQKEw9CRS10ZXJuYSBkLm8uby4xGDAWBgNVBAMTD0JFLXRlcm5hIGQuby5vLjCC # AaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAIpDLpP0SRhDOd8sX2jFT9zM # lZoFHWK/NfQkJZIrkG0anaOIo0AZbwvJ2oqHnWCEKGEgCBWU1QaD9iKLr6Ah+cBH # JUrfjKtU/KpH0ij3KdGCx/y0hrcRZq3j1wo+vcySXQrAYqxujmMg7qan6+GLHQ55 # fVdmccem2iEpEyw4jYseMRdMroKvAFCBksI+Dgi5nPckn8fJH4bZmUj65KWOJhn3 # n/B4i+oWyP1EOGgBfvm5jFs8BW1Z5a9eLXS8+cC0GV+9Mkn6OtT9VUJj2tMu2Jun # GLOww1V0nMteqVGt4nZ6n6QUXEcvK1nPrUK19nkZb26en1ZSlgGBwS/TR+ti9G/m # mFSOZAfkAMTxFNM0VZrdgNUwy1Ginh/+Uy0Mn8ku026GuXUWykjiCNgc7aNuNBCo # xuaibKbiyCYikDVK1C49sySqyfTN+eJ9PYXP8ve9vcoxMU4oWUvt46/PDzsifUWE # zes8L9ufzHuPKudofIMowfJSJ7U3jZTY2F0PNXdS6wIDAQABo4IB1DCCAdAwDAYD # VR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwOwYDVR0lBDQwMgYKKwYBBAGCN2EB # AAYIKwYBBQUHAwMGGisGAQQBgjdhpOaoI4H67850gfzolDeutrtWMB0GA1UdDgQW # BBQUDZ5ikhrjjetzP6/ke2d4tfTf4DAfBgNVHSMEGDAWgBSa8VR3dQyHFjdGoKze # efn0f8F46TBnBgNVHR8EYDBeMFygWqBYhlZodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ1MlMjBF # T0MlMjBDQSUyMDA0LmNybDB0BggrBgEFBQcBAQRoMGYwZAYIKwYBBQUHMAKGWGh0 # dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIw # SUQlMjBWZXJpZmllZCUyMENTJTIwRU9DJTIwQ0ElMjAwNC5jcnQwVAYDVR0gBE0w # SzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNv # bS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTANBgkqhkiG9w0BAQwFAAOCAgEA # WQa/CzxHrrk6I+nb3lG4Ug1cH7rwJhXOSArmI4jEa0iJ9Hu5DsSqjGFuuXJB9ZKW # m4pzWnu1XCduK9aVzgs4pWWN/PLJk39MoBmyP1hErYWHY9g3DMM0B/4Ue1z8OpCg # htr6lfO2DxPoMJJY2qu4cjrh4nUFpzsvBc1cQdZjQxQp3fSbg2ZxA+oKbrZsUc1R # rbxKwMdrUehb5AiBAPmgzK7pAMbN++wvnvVc3FEnYGcskorJKJSs/HmOh0G0uNDS # ZxsPgX6ddcMTPyAHAP82tStH3RgEVjLE0s98l/Z9uOuHc/JOxkUGm58ulnNdvyV1 # xBajAQoUT2ug1wPjFWojqOAvT666wSCQZYVsgaI52uArI8b8ZOLCjwIT5Ik2YTfk # WWjSF8YNuYwyglz2q95rlvL4XiwKTsePBurHzH8mnfrEw4hMCn+ZihkdloE5DYg7 # vvHHa6k9pSlNougHkdp6xqXOftBq2b082CtM+EzZNdOCnkqDX2i1n0Zx37JRSHfQ # e9uCKXF7ZxEFGeltJjiWcxzyYi5KYHr/T2yqTi/BWW0uHOPVzO1hf6/o3MSRwz2/ # 9qrnxlinoTZOeEhR14VXxQa+euAN1FNiC2m1tz3JoTDNX31OoLpdL1khGMwl8VIV # K5aGHFrqoNcgWa65tzq4d6GwnRQT7DrVkMgktOtD7BQwggcoMIIFEKADAgECAhMz # AAAAFydFCQuLh6/GAAAAAAAXMA0GCSqGSIb3DQEBDAUAMGMxCzAJBgNVBAYTAlVT # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xNDAyBgNVBAMTK01pY3Jv # c29mdCBJRCBWZXJpZmllZCBDb2RlIFNpZ25pbmcgUENBIDIwMjEwHhcNMjYwMzI2 # MTgxMTMxWhcNMzEwMzI2MTgxMTMxWjBaMQswCQYDVQQGEwJVUzEeMBwGA1UEChMV # TWljcm9zb2Z0IENvcnBvcmF0aW9uMSswKQYDVQQDEyJNaWNyb3NvZnQgSUQgVmVy # aWZpZWQgQ1MgRU9DIENBIDA0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC # AgEAgsdk/gMPZioBlcyfk6tDzJ+PRt4rSLGKW8ewpS0kRxXtURC3T3GdbCKljobE # n8ussqhGqQpRh/SXvRVwNXEIGb76UG5IPkCJ1S6/9BD61QQsKzPepW0SNj8TXgsF # xvS7MltoRuikIIp7Q5jQgaOM6QyK9++6ZVXUpYmZulAe6x8JrwZ0dNkE+rZ66lqt # oocwepUSVUxM7odDmn8yDHjJ2DNPsfr3uRDix3X4qvh14jH/SW+2Cx7WIMhyIiQO # 201i6hUixmk4e2ZW8W7C1wPdTjq6BKb+zo8xbrt7ZKQvRX5QOA6dhLquPqj5sVKn # xqfk19IC0SafTSTs8yC43Ew965BRRW8VL9ccoOmr4rxQy7aCgYTNk3dd/LphNaTT # mnGp7kmLTxyHkB5geoWhYuuGrywS8E0wJv0W4rfOtHBV0e9sKvuUIeIUpnsx6ilx # EVj6VQXvgD6yeCKnPmj3jJiJKAlmUDtth5yzRVBUl44sMiG4L5R/yyACRKk2n088 # Q2YCoZS1O86+oMLKt1jaXGECOjbsVp8Id1VQw8he6J0KirOS5e25XlTdGPFb6oBO # OaacgW78Kjf0bp+XzAgkc92mDGNJGYSjvdnj+7eMx6meW0DAIGdLRNj8/429MIsp # FBfz3KDqqpN71S4kQ2LLer3dxhDDczKVFL0HLwRuOvgjiG8CAwEAAaOCAdwwggHY # MA4GA1UdDwEB/wQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUmvFU # d3UMhxY3RqCs3nn59H/BeOkwVAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUH # AgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0 # b3J5Lmh0bTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTASBgNVHRMBAf8ECDAG # AQH/AgEAMB8GA1UdIwQYMBaAFNlBKbAPD2Ns72nX9c0pnqRIajDmMHAGA1UdHwRp # MGcwZaBjoGGGX2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01p # Y3Jvc29mdCUyMElEJTIwVmVyaWZpZWQlMjBDb2RlJTIwU2lnbmluZyUyMFBDQSUy # MDIwMjEuY3JsMH0GCCsGAQUFBwEBBHEwbzBtBggrBgEFBQcwAoZhaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBJRCUyMFZl # cmlmaWVkJTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDIxLmNydDANBgkqhkiG # 9w0BAQwFAAOCAgEAkHVaGf1NJt/JdoimmRZbMWr6baaDi8mkdWvWStk0hdZDpxSY # TA7HuipAoLL3qIhI101XOl7fOiCh5++jZOamQdAV79ojEUNoIgCZmL2XJrLaGanw # djNynecJyYVCTrRf2+h7KknpWOp4axdOs6K9ZQ5g0IsQWXCwfc0dfkSkLKNY3pDc # WLlJPh2jd5NUue6pNDv/2G5MFNJhCwltODebyAjGceU+XOzav+7i721YQnQ+39m2 # aQOFO7zpAdaKAeAGhEd6Y6CdDGneSxcoujWvafWbv4ay3jo1ORSLUuWMbKr5X18Q # E4Sde+gppGLLSkZsrUh2eyYSkX1envWX7ZPzg2/wiuKRlQFarDn+N9+20Bqzhxwk # NyLzfYJp1Lg4fCXb24XqFjx8SDdRgebFImOfOLVze8XQ/CwkrEaib0PHu2t4GVk4 # FYroEbNUFqvjdBvTY3uiR5TdQoyXoYHvh+TxpLSY2vo7hhK9D/rpEpHC+qmmcRUE # 4d0gyO9Zb1vvt25fxM3ekjvDfVHcPq3qMr0Rwsk4krKZWUEgU1SXT5qN6gqRrshx # bT6OQgZ9/xT04qiXdzPQR6KindBvSpoOnxnALxcJyzVwNpKL+9u8EZYy98qX6i+4 # gE/2J6cbpekcB0ZXDn/XQxoNUUb6/djT/wllVyG+vIHkdq71PzbH5rYxdcAwggee # 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 # VQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ1MgRU9DIENBIDA0AhMzAAHxvjzX # QAAWrnYGAAAAAfG+MA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAI # oAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB # CzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIOHvyJBHEKkSCCJ/L9vV # S99gCUW5SzkWuBHsaXdjRk//MA0GCSqGSIb3DQEBAQUABIIBgBOKrSjMRf3ipAWC # T1Zy1+XhGf7b8uxfMMrkqZiJWTPheODgpSybyJuGSqKQfcCdj6L8DOGacjyrNlDN # ZLEE0f5pBPOv8ehlLmeDl8aBLxnChHuSDtRRbrHHF1/gj6Pq+yEM1kHvI6VabrE/ # c62LC3PZVmihI/UH9ItdaHkyHXXRN/LGK695Ol0/uryytjGLX4YgoAnTxwP0VyfF # 7lxsZqN3u5qX+fJAHT5HY0P4LLpgBgrO3KrKuZhiySZclF2Waohr92FYWtEuq2qX # Ax3l2eZzaPkFsDhFE3ezTTvTKDyX/3+otRaFrjH7fgJukNwISGOtDWuk8le6F5ZI # FnUiqVF5ViHjLoLKNf3kFdw/lbQxlV3BuoG/P0jW0z4Vf9xBWkbHuSM0BO56Aehr # lEtpf2sA78UoBT+1lFy7EGwLmw9rlANwLoPc9Vqv1IElGb0OO+9CHzCcjyhJ0n5r # j+fx1+Wxt+i3AN3b8mC75DwB9gwRjOOHKHMAfztB7QjWvn7ZeqGCGBQwghgQBgor # BgEEAYI3AwMBMYIYADCCF/wGCSqGSIb3DQEHAqCCF+0wghfpAgEDMQ8wDQYJYIZI # AWUDBAIBBQAwggFiBgsqhkiG9w0BCRABBKCCAVEEggFNMIIBSQIBAQYKKwYBBAGE # WQoDATAxMA0GCWCGSAFlAwQCAQUABCABAkFUa0FKj0s90ZBbWfmC7DvzTDqjrVr0 # Nv2NY+ZnogIGaeiBbxzrGBMyMDI2MDYxNTIyMTkwOS4xNDFaMASAAgH0oIHhpIHe # MIHbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQL # ExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxk # IFRTUyBFU046N0QwMC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJs # 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/ # oAMCAQICEzMAAABV2d1pJij5+OIAAAAAAFUwDQYJKoZIhvcNAQEMBQAwYTELMAkG # A1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UE # AxMpTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjAwHhcN # MjUxMDIzMjA0NjQ5WhcNMjYxMDIyMjA0NjQ5WjCB2zELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2Eg # T3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjdEMDAtMDVFMC1E # OTQ3MTUwMwYDVQQDEyxNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lIFN0YW1waW5n # IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL25H5Ie # WUiz9DAlFmn2sPymaFWbvYkMfK+ScIWb3a1IvOlIwghUDjY0Gp6yMRhfYURiGS0G # edIB6ywvuH6VBCX3+bdOFcAclgtv21jrpOjZmk4fSaT2Q3BszUfeUJa8o3xI7Zfo # MY9dszTxHQAz6ZVX87fHGEVhQcfxW33IdPJOj/ae419qtYxT21MVmCfsTshgtWio # QxmOW/vMC9/b+qgtBxSMf798vm3qfmhF6KCvFaHlivrM32hY16PGE3L0PFC+LM7v # RxU7mTb+r76CeybvqOWk4+dbKYftPhV1t/E5S/6wwXeYmu/Y7JC7Tnh2w45G5Y4p # cM3oHMb/YuPRdOWa0v+RC2QgmNVWqjuxDiylWscXQDuaMtb29AcdGUVV9ZsRY2M2 # sthAtOdZOshiR5ufMtaHtiCkWv0jNfgUxrHurxzYuUNneWZ6EfQDgFAw8CSCKkSO # K2c9jEop4ddVq10xvbqxdrqMneVXvvIcXrPQAXj9j2ECpV2EwMb3Wnmpw00P78Jp # zPsk3Fs61ZvOGd/F1RcOBu6f2TWdp7HL7+rq7tgHr13MldbfIWu4lpoYYE1gTQa1 # Yrg5XN4j7zs9klT2z3qocmPzV8DWQgIHNh+aTs7bujMEMQyI7Xt1zPxZCgcR6H0t # mmzU/9BxvsWbRalCQ2sYGyWupTdc4e7KY7kPAgMBAAGjggHLMIIBxzAdBgNVHQ4E # FgQUVgRfEG3cCAPwyL+pyRbKwdesZbYwHwYDVR0jBBgwFoAUa2koOjUvSGNAz3vY # r0npPtk92yEwbAYDVR0fBGUwYzBhoF+gXYZbaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwUHVibGljJTIwUlNBJTIwVGltZXN0 # YW1waW5nJTIwQ0ElMjAyMDIwLmNybDB5BggrBgEFBQcBAQRtMGswaQYIKwYBBQUH # MAKGXWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9z # b2Z0JTIwUHVibGljJTIwUlNBJTIwVGltZXN0YW1waW5nJTIwQ0ElMjAyMDIwLmNy # dDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB # /wQEAwIHgDBmBgNVHSAEXzBdMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9y # eS5odG0wCAYGZ4EMAQQCMA0GCSqGSIb3DQEBDAUAA4ICAQBSHuGSVHvalCnFnlsq # XIQefH1xP2SFr9g+Vz+f5P7QeywjfQb5jUlSmd1XnJUDPe/MHxL7r3TEElL+mNtG # 6CDPAytStSFPXD9tTBtBMYh8Wqo64pH9qm361yIqeBH979mzWCkMQsTd0nM6dUl9 # B+7qiti+ToXwxIl39eYqLuYYfhD2mqqePXMzUKSQzkf73yYIVHP6nLJQz4aAmaWc # fG9jg78sBkDV8KpW7JgktuLhphJEN1B+SVHjenPdcmrFXIUu/K4jK5ukfWaQIjua # XzSjBlNjC5tQN6adPfA3GxUwHPeR4ekL5If/9vBf13tmzBW+gy+0sNGTveb9IL9G # U8iX8UvywsX62nhCCPRUhTigDBKdczRUrNrntBhowbfchBDFML8avRMRc9Gmc2Jv # IryX336SFQ51//q1UU2HMSJEMhWLJSIWJVhfUowsOa+PampIzETYfFvTu2mqKJUl # WZXkGYxrdCvCczJcqeoadpW1ul6kcdnDh228SQ8ZhDc6IRlM4iNd5SNoNgX+aom3 # wuGyjUaSaPZWxPB1G2NKiYhPLt0lPHg0Gskj1zhISY8UQkMMDr3o2JgRuT+wnJED # QUp55ddvhSkSoD6I9DL/s+TjIY/c9jLaW5xywJHqdKHUApRMsghv7kebSua1upmR # +TquelFktDSOjVdSRkuya4uoxTGCB0YwggdCAgEBMHgwYTELMAkGA1UEBhMCVVMx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9z # b2Z0IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjACEzMAAABV2d1pJij5 # +OIAAAAAAFUwDQYJYIZIAWUDBAIBBQCgggSfMBEGCyqGSIb3DQEJEAIPMQIFADAa # BgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTI2MDYx # NTIyMTkwOVowLwYJKoZIhvcNAQkEMSIEIBsvIePVOdhXqWKoFAcIN8IJIM+y6hwP # nhpApLacNZt/MIG5BgsqhkiG9w0BCRACLzGBqTCBpjCBozCBoAQg2Lk8l2SGYru/ # ff7+D2qrJnkswcYdK6pGKu7GGGr4/s0wfDBlpGMwYTELMAkGA1UEBhMCVVMxHjAc # BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0 # IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjACEzMAAABV2d1pJij5+OIA # AAAAAFUwggNhBgsqhkiG9w0BCRACEjGCA1AwggNMoYIDSDCCA0QwggIsAgEBMIIB # CaGB4aSB3jCB2zELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO # BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEl # MCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMe # blNoaWVsZCBUU1MgRVNOOjdEMDAtMDVFMC1EOTQ3MTUwMwYDVQQDEyxNaWNyb3Nv # ZnQgUHVibGljIFJTQSBUaW1lIFN0YW1waW5nIEF1dGhvcml0eaIjCgEBMAcGBSsO # AwIaAxUAHTtUAYJlv7bgWVeRBo4X7FeHDeqgZzBlpGMwYTELMAkGA1UEBhMCVVMx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9z # b2Z0IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjAwDQYJKoZIhvcNAQEL # BQACBQDt2tkwMCIYDzIwMjYwNjE1MjAwNDAwWhgPMjAyNjA2MTYyMDA0MDBaMHcw # PQYKKwYBBAGEWQoEATEvMC0wCgIFAO3a2TACAQAwCgIBAAICDhMCAf8wBwIBAAIC # E3MwCgIFAO3cKrACAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAK # MAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQsFAAOCAQEALSPNa8g5 # q/5xz99ZnHPZjBW1k333P9pHT7+rkPFsw26HdE6nXk1xjOqlOxBCeSV8WGOsg9k5 # +wWndps1lkRYeVx6+kV56Jlxul9/S6N9M6VK2fV14opZ1KXcEIfrvjHt5C8LZF7/ # KJQlRe0bAyWEBkCwSy16IOgDx9ptPTYtG/IU6r3K5FHcKGW/sfF5sNgMNE/4xUIf # CmvByx2LR8/FHqHX9/aIrsAuXlphBqbqK10KE395RukIUvMPFE0I9FSka1aTrXZg # JzEAwg/16VZO9za3qjeKkkVKvc5p1CI9bIY8kBhf/gdjFRiP+k2Yiep4A6vWrAx3 # 1iBjXRTRLM5C4jANBgkqhkiG9w0BAQEFAASCAgALjB/eQGAOfcXCjW9U3S7AJ0Zg # YQvpy1yOIjSbtH/Q5OnTNb+P2XCVK10LRNttFCmAetjebMAmoKmUYvKyVZ6e25t1 # fhGeWDpogERsLrgPFow9Z1UWMzrzDpUhhlCjYk2qVvBBTmtoW8xu5feQXrGR5dp+ # UU/ZK638kfbj+0Ct/rFNO3slZ8586Hy5oEv3y4ESKnwar1PRlZ9NfwSuJgs3b5Ed # TFYBoWOL3VVnJPcCwZkXTGQFjtqHjttLiEQZQjLQ8HEDSy3U3xAjWy6RH7hog+L2 # ILbNywwY46iFxovLZ4oqowS6Yn9JheO8TnrOgiX/cz9R4Hwk92xVyIGjj57lGOCJ # A/Xt/KOLpsuPqtbwdx9DveOwZ21ZnPGY1qgQxJg0PG50mhTxMXKC5QPzXhZUk1VT # D7r9DKAcsHAgmQoTGHgVJZ9ZLmQeWkDZYpr/v1PpuAwhoTyT47ucLQwUEhOkiEgx # zphiQsRkhyHTlaCQxdwHmhyx/Qq7c2a3pDVQGfZg8Tt374t6Y7DdSHqv3YZs/5vs # 0dpuwxIhamGLhtlcgiN1Iytga1UGAyq33K/C4lhhrW86s026PQsrpkFuXP1Va6UW # pJz0NwgRsOS6cY4NRycIjv2/Srw7v1tbgqjjn+t/58ERz6nnDbtKI5Bk1RdLLYFu # F3ePdAkiUNps6kwXsQ== # SIG # End signature block |