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 # MII2mAYJKoZIhvcNAQcCoII2iTCCNoUCAQExDzANBglghkgBZQMEAgEFADB5Bgor # 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 # 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggaSMIIEeqADAgECAhMzAAHN2pPd # RvtxAVSpAAAAAc3aMA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ # RCBWZXJpZmllZCBDUyBBT0MgQ0EgMDQwHhcNMjYwNjA3MTgxMTExWhcNMjYwNjEw # MTgxMTExWjBVMQswCQYDVQQGEwJTSTESMBAGA1UEBxMJTGp1YmxqYW5hMRgwFgYD # VQQKEw9CRS10ZXJuYSBkLm8uby4xGDAWBgNVBAMTD0JFLXRlcm5hIGQuby5vLjCC # AaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAIuek4u1xxt98HTW6+qLZbQN # s+tNW5N3QbpBfcBdMIcxChf0d0EI+cFASigGOgAEtE8tMwM/vE3Fu7hm1Vxt7m8a # 32mQFKxDQuSiZ0p6KdcLO7otoBfIpzUZGyjtFnqcue2nssTF38Z4PwbpZE7daahS # bVNtJqxeZiCJoxqF9vFFt4Sls0nFVrtzXkW82HrNuHzv+y9qGwmbMD2hhGd15jLO # YUsQoAWpuB/Qf+N7W3cJZwF9wZe946lOK50c2GZzEI/6yDPHsK6PbuAh6+GupLdB # gEPk6+4ikYD2AmgodGW7iU3O2fUP1pxxLYyqep+gKYPF5NvTlJTZcEdThOt8eJgk # Sg4j+MzFwl/7DaiuIJvQCeLauXGBqrsjn1/6KmxUKEBUuSImzHy1mMB0aQCqtfOe # 8De/gYCLRoPFnuhn42di2b+/FVOylHRGfjH0ote+XjXa22ihgUuYkl79gIFKI6Wx # zSzeOLid2Hq0CeQvIYYWoAV/oWnXhDjcfCPL4mw9FwIDAQABo4IB1DCCAdAwDAYD # VR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwOwYDVR0lBDQwMgYKKwYBBAGCN2EB # AAYIKwYBBQUHAwMGGisGAQQBgjdhpOaoI4H67850gfzolDeutrtWMB0GA1UdDgQW # BBQFyT8vKd7egKqCrAZDR3KVZHQ9WzAfBgNVHSMEGDAWgBRrJUHe+2t8/RiACi1/ # j3ZdqnM9uDBnBgNVHR8EYDBeMFygWqBYhlZodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ1MlMjBB # T0MlMjBDQSUyMDA0LmNybDB0BggrBgEFBQcBAQRoMGYwZAYIKwYBBQUHMAKGWGh0 # dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIw # SUQlMjBWZXJpZmllZCUyMENTJTIwQU9DJTIwQ0ElMjAwNC5jcnQwVAYDVR0gBE0w # SzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNv # bS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTANBgkqhkiG9w0BAQwFAAOCAgEA # nWo4TL4COzXcN0g2Roy9HuhXIcYwow4IYihK5OzzjiWmfxaoLylVGfrJoWuiWaH5 # 4RZIkxRmisk1eFPr8ls95NRxAwd2w5+tGslTnzqFl1Fi2u2JXwpHvjY7AwO+Svyi # mAp3B+AimN6dJiV0CAgDFUZiHgEvYUwZO37QE7v9p0pa44bHEXoXPImoIFEowNTb # Ro/sXyNgp9bjbpEbdcCv6z11KpHZGWW637gsZ9lEIY9qoWML81FnQOy8umHKzDt3 # wcK5Urd7B8K5zMX4mUdoxZbm/PNfr2EvMKmuagSANekb6oIp5llHC3UoTwEBlrDt # frUIf2KvUAREDeGS2GGiQbflyy483C8FZZ44ore25q/9+C4xlSKzJU/Tw4021T1c # yULVgQge5CLlvGQ+dFJe0ClXClpL6MOlUWTwRjTmyqmzaFSQavL8kSNvpsw8tE68 # Z3DBL0j5Pz+DHS8888BAtbCfNlm85bvYaNTNbV3ieC2il7k7yDHhIhRAj2E4halT # W3hEGGsS4txGdQbUEvS80Kf3ERgRkKfD5whP06Gx18SwWxd1v1DsDO3yL5gjN9d2 # hxNPxP60c0SdxmPBTsPZZoOOKF+wps7N6jL8FKBjbV6AojUVdwkIg+/hxpQKXqUw # ouPaqMLANxBmDs491R11/5p/NUHddT9F4bHQXLGq/ywwggcoMIIFEKADAgECAhMz # 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+fL4WrxSK5nMYIaujCCGrYCAQEwcTBaMQsw # CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSswKQYD # VQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ1MgQU9DIENBIDA0AhMzAAHN2pPd # RvtxAVSpAAAAAc3aMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAI # oAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB # CzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIOyNiSCn8E6eFXY4708a # +hy4HCcTPvnGAZqJQreEx5YZMA0GCSqGSIb3DQEBAQUABIIBgFlCWve0zziqHyDO # UpSiATCcj7Ca4taJl/O7QL/8VtRV/fNzvYqTp37fkmoPerCJUkMLp87W9f8NSNFa # MN62tzwufWK6/I3qRYVqusD8iHxH/lUdWZiIZaIvkLd3Do0cwYjDzmb2SzhWx8Lm # YwDGig+B/nlO6adyPtd1GPU1Q847yExAdUz9koezujb8uX1N9/PYff7hkhdlyZ6+ # Medh09a0v62VxQxd7B1tOryqYFKNPB/7B0Ih+B+2baZZuCNakLKi89ZCBEnvv+pu # myJgPUZauCL4squA1Ekvofw5AWDu1er2FmanQfxZuo4RUl3+Z1bbu9Qbf/Wae656 # 4ao63i0i0jxRBjoz7OVRWaXpfYFz8L5Pe6tBv5/Q9xg//1wg0wY5cddLR3ANO03U # h3NiLwIVIMiR+sjag719VJnSU6NcbKbor7u7PPyD3NZVZ4B1nwa7H/pjjFaLPymt # hSGvnVC6oX3809oQ0rFsi+VsByFOekdIptcSg/lTjF2iL2bn/6GCGBMwghgPBgor # BgEEAYI3AwMBMYIX/zCCF/sGCSqGSIb3DQEHAqCCF+wwghfoAgEDMQ8wDQYJYIZI # AWUDBAIBBQAwggFhBgsqhkiG9w0BCRABBKCCAVAEggFMMIIBSAIBAQYKKwYBBAGE # WQoDATAxMA0GCWCGSAFlAwQCAQUABCCnJTE/Uq/9HQAYrUyrYX4uDT3dlx+jboNf # pHQzcIfM3AIGaeiBYshgGBIyMDI2MDYwODIxNTkxOS41MlowBIACAfSggeGkgd4w # gdsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsT # HE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQg # VFNTIEVTTjo3RDAwLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0IFB1Ymxp # 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 # AwIBAgITMwAAAFXZ3WkmKPn44gAAAAAAVTANBgkqhkiG9w0BAQwFADBhMQswCQYD # VQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQD # EylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDAeFw0y # NTEwMjMyMDQ2NDlaFw0yNjEwMjIyMDQ2NDlaMIHbMQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBP # cGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046N0QwMC0wNUUwLUQ5 # NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWUgU3RhbXBpbmcg # QXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvbkfkh5Z # SLP0MCUWafaw/KZoVZu9iQx8r5JwhZvdrUi86UjCCFQONjQanrIxGF9hRGIZLQZ5 # 0gHrLC+4fpUEJff5t04VwByWC2/bWOuk6NmaTh9JpPZDcGzNR95QlryjfEjtl+gx # j12zNPEdADPplVfzt8cYRWFBx/Fbfch08k6P9p7jX2q1jFPbUxWYJ+xOyGC1aKhD # GY5b+8wL39v6qC0HFIx/v3y+bep+aEXooK8VoeWK+szfaFjXo8YTcvQ8UL4szu9H # FTuZNv6vvoJ7Ju+o5aTj51sph+0+FXW38TlL/rDBd5ia79jskLtOeHbDjkbljilw # zegcxv9i49F05ZrS/5ELZCCY1VaqO7EOLKVaxxdAO5oy1vb0Bx0ZRVX1mxFjYzay # 2EC051k6yGJHm58y1oe2IKRa/SM1+BTGse6vHNi5Q2d5ZnoR9AOAUDDwJIIqRI4r # Zz2MSinh11WrXTG9urF2uoyd5Ve+8hxes9ABeP2PYQKlXYTAxvdaeanDTQ/vwmnM # +yTcWzrVm84Z38XVFw4G7p/ZNZ2nscvv6uru2AevXcyV1t8ha7iWmhhgTWBNBrVi # uDlc3iPvOz2SVPbPeqhyY/NXwNZCAgc2H5pOztu6MwQxDIjte3XM/FkKBxHofS2a # bNT/0HG+xZtFqUJDaxgbJa6lN1zh7spjuQ8CAwEAAaOCAcswggHHMB0GA1UdDgQW # BBRWBF8QbdwIA/DIv6nJFsrB16xltjAfBgNVHSMEGDAWgBRraSg6NS9IY0DPe9iv # Sek+2T3bITBsBgNVHR8EZTBjMGGgX6BdhltodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBQdWJsaWMlMjBSU0ElMjBUaW1lc3Rh # bXBpbmclMjBDQSUyMDIwMjAuY3JsMHkGCCsGAQUFBwEBBG0wazBpBggrBgEFBQcw # AoZdaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3Nv # ZnQlMjBQdWJsaWMlMjBSU0ElMjBUaW1lc3RhbXBpbmclMjBDQSUyMDIwMjAuY3J0 # MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/ # BAQDAgeAMGYGA1UdIARfMF0wUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEW # M2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5 # Lmh0bTAIBgZngQwBBAIwDQYJKoZIhvcNAQEMBQADggIBAFIe4ZJUe9qUKcWeWypc # hB58fXE/ZIWv2D5XP5/k/tB7LCN9BvmNSVKZ3VeclQM978wfEvuvdMQSUv6Y20bo # IM8DK1K1IU9cP21MG0ExiHxaqjrikf2qbfrXIip4Ef3v2bNYKQxCxN3Sczp1SX0H # 7uqK2L5OhfDEiXf15iou5hh+EPaaqp49czNQpJDOR/vfJghUc/qcslDPhoCZpZx8 # b2ODvywGQNXwqlbsmCS24uGmEkQ3UH5JUeN6c91yasVchS78riMrm6R9ZpAiO5pf # NKMGU2MLm1A3pp098DcbFTAc95Hh6Qvkh//28F/Xe2bMFb6DL7Sw0ZO95v0gv0ZT # yJfxS/LCxfraeEII9FSFOKAMEp1zNFSs2ue0GGjBt9yEEMUwvxq9ExFz0aZzYm8i # vJfffpIVDnX/+rVRTYcxIkQyFYslIhYlWF9SjCw5r49qakjMRNh8W9O7aaoolSVZ # leQZjGt0K8JzMlyp6hp2lbW6XqRx2cOHbbxJDxmENzohGUziI13lI2g2Bf5qibfC # 4bKNRpJo9lbE8HUbY0qJiE8u3SU8eDQaySPXOEhJjxRCQwwOvejYmBG5P7CckQNB # Snnl12+FKRKgPoj0Mv+z5OMhj9z2MtpbnHLAkep0odQClEyyCG/uR5tK5rW6mZH5 # Oq56UWS0NI6NV1JGS7Jri6jFMYIHRjCCB0ICAQEweDBhMQswCQYDVQQGEwJVUzEe # MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3Nv # ZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMAITMwAAAFXZ3WkmKPn4 # 4gAAAAAAVTANBglghkgBZQMEAgEFAKCCBJ8wEQYLKoZIhvcNAQkQAg8xAgUAMBoG # CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwNjA4 # MjE1OTE5WjAvBgkqhkiG9w0BCQQxIgQg0Oho7UJ49uGEezLmliZi5y+kWH/8k22j # jArplEXQ6zgwgbkGCyqGSIb3DQEJEAIvMYGpMIGmMIGjMIGgBCDYuTyXZIZiu799 # /v4PaqsmeSzBxh0rqkYq7sYYavj+zTB8MGWkYzBhMQswCQYDVQQGEwJVUzEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQg # UHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMAITMwAAAFXZ3WkmKPn44gAA # AAAAVTCCA2EGCyqGSIb3DQEJEAISMYIDUDCCA0yhggNIMIIDRDCCAiwCAQEwggEJ # oYHhpIHeMIHbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUw # IwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5u # U2hpZWxkIFRTUyBFU046N0QwMC0wNUUwLUQ5NDcxNTAzBgNVBAMTLE1pY3Jvc29m # dCBQdWJsaWMgUlNBIFRpbWUgU3RhbXBpbmcgQXV0aG9yaXR5oiMKAQEwBwYFKw4D # AhoDFQAdO1QBgmW/tuBZV5EGjhfsV4cN6qBnMGWkYzBhMQswCQYDVQQGEwJVUzEe # MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3Nv # ZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAyMDANBgkqhkiG9w0BAQsF # AAIFAO3RnrAwIhgPMjAyNjA2MDgyMDA0MDBaGA8yMDI2MDYwOTIwMDQwMFowdzA9 # BgorBgEEAYRZCgQBMS8wLTAKAgUA7dGesAIBADAKAgEAAgIlfgIB/zAHAgEAAgIS # 7jAKAgUA7dLwMAIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAow # CAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQCzYFu1OKeW # truFntZYwSLwXXgAeoHisrkZSAybHqH3rdZHm4QL1tixFSUbiXoCp04AkGavurm5 # wAd/BPL0wu/lvu/o7So2TyLPs1q4GZsH2DAdj9R5WFWvfb4op5seb5KZewIIZ+X2 # TH7enD/4DV/GRe3il+P5iO+qRQQS1o6y3Sz4mukzNJkSf37Obw6bdJx736SxwlO3 # eUyXuan9eORkq42906TT7BfFuQ6VYaVeLRanRbj3OaWxjxTZjlpx8OJSMkPEg489 # pu+Gb4Exh0lORS+m/WXYo2sxcHRkoVjblZdzNwSjvOwmaOFNbx4d5rMCY9NgBT5P # VkWkM0T+D8YAMA0GCSqGSIb3DQEBAQUABIICAAXwWTHq/HIuXMY4/CXOe5Ro0lbe # P1enj33RxmZyKIzvn6Ce4BVH02KJBgDOePV1Q9EMtwuGjT9CT+g/uyeW3inBG5yS # AeCJVxrDa5/2xiJ/ofjhFH615KmID9TJorb8cFEG9CWq9aJpso6/c+0QqpqBp26L # pN0iHmrIAtuL3b0ji/Xz26zOMtqWbpeKKwoMJhijJ/Jk2qRc5NKIdFqe/mJI0xOe # TRV9jFA6Z9SwTix4snlqRSLEK8aJdJiov3tT8Vwf4HZWThmF8BfGgN8w25oi6/FO # 0x8F1GwMYrojF/3WAKFm4vZct4+d0CenyU9CpTUabLOW8Vs5y5J5/oiqw24Arl7t # KTsvgUXaA1WOZh4wpXEOrcr3ZqZPBFEaGhxiA8u9d90Jjx8JbCOnK8OApOdulioK # vlkGjewtkQgkAaInpdXRItZ6PFlKw/TJzTz/uLAojK5gDkuO3BUHRXQx4pv+jyH+ # ydzoZitbGmDjriP45ZfkGDwordoFg9UGlg48Qdm7j8RXcA64VwXio8LBh6Fh+cnr # 86Od8ujtUiS6Qs4BOOZgbwttfe3YDJ/VaJhUAaflrijI6RRDr567xjzyIKivlVGD # urSQTJe0ZGiecy0T7hoqpZs1BGM1Qzt14YqcgpvAF2y8V/voFyMkyMb2DPgIddjR # +3JTQp/wV2UQoKZi # SIG # End signature block |