scripts/commit-bug-review.ps1
|
#!/usr/bin/env pwsh param( [int]$MaxIterations = 148, [ValidateSet('claude', 'copilot', 'codex')] [string]$Type = 'copilot', [string]$Model = 'gpt-5.4', [ValidateSet('low', 'medium', 'high', 'max', 'xhigh')] [string]$Effort = 'max', [switch]$DryRun ) $ErrorActionPreference = 'Stop' if (Get-Variable -Name PSNativeCommandUseErrorActionPreference -ErrorAction SilentlyContinue) { $PSNativeCommandUseErrorActionPreference = $false } $RepoRoot = Split-Path $PSScriptRoot -Parent $TrackerPath = Join-Path $RepoRoot "docs\trackers\features\commit-bug-review-TRACKER.md" $PromptPath = Join-Path $RepoRoot "scripts\commit-bug-review-prompt.md" # Resolve engine binary if ($Type -eq 'copilot') { # Try common Copilot CLI locations on Windows $candidatePaths = @( "copilot", "gh copilot", "$env:LOCALAPPDATA\Programs\copilot\copilot.exe", "/home/vscode/.local/bin/copilot" ) $EngineBin = "copilot" foreach ($candidate in $candidatePaths) { if (Get-Command $candidate -ErrorAction SilentlyContinue) { $EngineBin = $candidate break } } Write-Host "Using Copilot CLI: $EngineBin" -ForegroundColor DarkGray } elseif ($Type -eq 'codex') { $EngineBin = "codex" } else { $EngineBin = "claude" } function Get-PendingCount { $tracker = Get-Content $TrackerPath -Raw return ([regex]::Matches($tracker, '\| PENDING \|')).Count } function Get-CompletedCount { $tracker = Get-Content $TrackerPath -Raw $done = ([regex]::Matches($tracker, '\| DONE \|')).Count $needsWork = ([regex]::Matches($tracker, '\| NEEDS_WORK \|')).Count $blocked = ([regex]::Matches($tracker, '\| BLOCKED \|')).Count return $done + $needsWork + $blocked } function Invoke-Iteration { param([int]$Iteration) Write-Host "" Write-Host ("=" * 50) -ForegroundColor Yellow Write-Host " Iteration $Iteration of $MaxIterations ($Type / $Model)" -ForegroundColor Yellow Write-Host ("=" * 50) -ForegroundColor Yellow $prompt = Get-Content $PromptPath -Raw if ($Type -eq 'copilot') { $copilotEffort = if ($Effort -eq 'max') { 'xhigh' } else { $Effort } $engineArgs = @( '-p', $prompt '--model', $Model '--allow-all' '--reasoning-effort', $copilotEffort ) if ($DryRun) { Write-Host " [DRY RUN] Would run: $EngineBin $($engineArgs -join ' ')" -ForegroundColor DarkGray return $true } & $EngineBin @engineArgs | ForEach-Object { $line = "$PSItem" if ($line -and $line -notmatch '^\s*$') { Write-Host " $line" -ForegroundColor White } } } elseif ($Type -eq 'codex') { $codexEffort = if ($Effort -eq 'max') { 'xhigh' } else { $Effort } $engineArgs = @( 'exec' '--model', $Model '--config', "model_reasoning_effort=`"$codexEffort`"" '--dangerously-bypass-approvals-and-sandbox' '-' ) if ($DryRun) { Write-Host " [DRY RUN] Would run: codex exec --model $Model --config model_reasoning_effort=`"$codexEffort`" --dangerously-bypass-approvals-and-sandbox - < prompt" -ForegroundColor DarkGray return $true } $prompt | & $EngineBin @engineArgs } else { $sessionId = [guid]::NewGuid().ToString() $engineArgs = @( '--dangerously-skip-permissions' '--session-id', $sessionId '--no-session-persistence' '--model', $Model '--effort', $Effort '--verbose' '--output-format', 'stream-json' '-p', $prompt ) if ($DryRun) { Write-Host " [DRY RUN] Would run: claude $($engineArgs -join ' ')" -ForegroundColor DarkGray return $true } # Stream and parse JSON - show tool use with file details & $EngineBin @engineArgs | ForEach-Object { $line = $PSItem try { $obj = $line | ConvertFrom-Json -ErrorAction Stop switch ($obj.type) { 'assistant' { if ($obj.message.content) { foreach ($content in $obj.message.content) { switch ($content.type) { 'tool_use' { $toolName = $content.name $detail = "" if ($content.input) { switch ($toolName) { 'Read' { $detail = Split-Path $content.input.file_path -Leaf } 'Write' { $detail = Split-Path $content.input.file_path -Leaf } 'Edit' { $detail = Split-Path $content.input.file_path -Leaf } 'Glob' { $detail = $content.input.pattern -replace '.*/',''} 'Grep' { $detail = $content.input.pattern.Substring(0, [Math]::Min(30, $content.input.pattern.Length)) } 'Bash' { $detail = ($content.input.command -split '\n')[0].Substring(0, [Math]::Min(40, ($content.input.command -split '\n')[0].Length)) } } } if ($detail) { Write-Host " 🔧 $toolName " -ForegroundColor DarkCyan -NoNewline Write-Host $detail -ForegroundColor DarkGray } else { Write-Host " 🔧 $toolName" -ForegroundColor DarkCyan } } 'text' { if ($content.text) { Write-Host $content.text -ForegroundColor White } } } } } } 'result' { $duration = [math]::Round($obj.duration_ms / 1000, 1) $cost = [math]::Round($obj.total_cost_usd, 4) Write-Host "" Write-Host "✓ Completed in ${duration}s (`$$cost)" -ForegroundColor Green } } } catch { if ($line -and $line -notmatch '^\s*$') { Write-Host $line -ForegroundColor DarkGray } } } } return $LASTEXITCODE -eq 0 } # Main loop $total = 135 # 138 commits minus 3 pre-marked version bumps Write-Host "Ralph Wiggum: commit-bug-review ($Type, $Model, effort=$Effort)" -ForegroundColor Cyan Write-Host "Tracker: $TrackerPath" -ForegroundColor DarkGray Write-Host "Prompt: $PromptPath" -ForegroundColor DarkGray Write-Host "" $iteration = 0 $stalledCount = 0 $maxStalled = 3 while ($iteration -lt $MaxIterations) { $iteration++ $pending = Get-PendingCount $completed = Get-CompletedCount $completedBefore = $completed $percent = [math]::Min(100, [math]::Round(($completed / $total) * 100)) $barFilled = [math]::Min(20, [math]::Floor($percent / 5)) $barEmpty = [math]::Max(0, 20 - $barFilled) Write-Host "[$(('=' * $barFilled))$(('-' * $barEmpty))] $percent% ($completed/$total)" -ForegroundColor Cyan if ($pending -eq 0) { Write-Host "All items completed!" -ForegroundColor Green break } if (-not (Invoke-Iteration -Iteration $iteration)) { Write-Host "Iteration failed. Stopping." -ForegroundColor Red exit 1 } if ($DryRun) { Write-Host "Dry run complete. Tracker was not modified." -ForegroundColor DarkGray break } # Zero-trust: verify the iteration actually progressed $completedAfter = Get-CompletedCount if ($completedAfter -le $completedBefore) { $stalledCount++ Write-Host "⚠️ No progress detected (stalled $stalledCount/$maxStalled)" -ForegroundColor Yellow Write-Host " Before: $completedBefore completed, $pending pending" -ForegroundColor Yellow Write-Host " After: $completedAfter completed" -ForegroundColor Yellow if ($stalledCount -ge $maxStalled) { Write-Host "✗ Stalled $maxStalled times in a row. AI is claiming done without finishing." -ForegroundColor Red Write-Host " Check the tracker for items marked DONE that shouldn't be." -ForegroundColor Red exit 1 } } else { $stalledCount = 0 Write-Host "✓ Progress: $completedBefore → $completedAfter completed" -ForegroundColor Green } Start-Sleep -Seconds 2 } Write-Host "Done. Completed: $(Get-CompletedCount) / $total" -ForegroundColor Green # SIG # Begin signature block # MIItZAYJKoZIhvcNAQcCoIItVTCCLVECAQMxDTALBglghkgBZQMEAgEwewYKKwYB # BAGCNwIBBKBtBGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA79zbEIs8pRuI8 # 6ehxAk1VZFuQZU7tv4LliESmkcyhO6CCFWUwggaTMIIEe6ADAgECAhMzAAETuC/6 # W6KVT30LAAAAARO4MA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ # RCBWZXJpZmllZCBDUyBBT0MgQ0EgMDQwHhcNMjYwNTE2MDI0NzA4WhcNMjYwNTE5 # MDI0NzA4WjBXMQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExDzANBgNV # BAcTBlZpZW5uYTERMA8GA1UEChMIZGJhdG9vbHMxETAPBgNVBAMTCGRiYXRvb2xz # MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAi0CmhZOKS+I8l6jOfDPy # 09NiQe+pHwccTKxFgHS3fq5TELNtpPb7MZoAUKjlA/umZg8w0zDtYupFRoNwxDJd # Mxaxu0EWseEccYpEYdjRugEeyvMaOpn2oo8rLQygdMFXr1A/qq4lZUZKusqeGEQF # 1sYdYtUmDufCqKVUFbdrvPJMH5X8yItjYWPcI8u4HVZPDmOmKUdnB/uWwoK63e85 # CQrrfVOyNOhRUbk+c3nVJovl1dQ74XvXlf6QizI6aj9XpLDWp1CqcCemhrVDh/gU # +K/ZJUekWb02u/ifZfcm3N5fFH8qg8/D7wrw8jROSsCp7dxqaWORCNqR1Rmj4Udf # ocgsLAUw1JTZGdrJbGj0p9IP4XJMUlELTSQ2NwBaRchOhmusbdPXVmtHbintVUq0 # 8xm26IacbhgXbPr9dcyckBIpbxkXqWf9Ckwqhi+CGfNFqpIHefThmD+N8y+Zj06G # G6hwzwaP7qxzjB9lq5mJP1zRKf3AJ1s3NbUG4LbvzEnvAgMBAAGjggHTMIIBzzAM # BgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDA6BgNVHSUEMzAxBgorBgEEAYI3 # YQEABggrBgEFBQcDAwYZKwYBBAGCN2H5+cEspPS4DoOuxLIcm56wGDAdBgNVHQ4E # FgQUK60uP2XKiAHCh4ob85+cb/VysEAwHwYDVR0jBBgwFoAUayVB3vtrfP0YgAot # f492XapzPbgwZwYDVR0fBGAwXjBcoFqgWIZWaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwSUQlMjBWZXJpZmllZCUyMENTJTIw # QU9DJTIwQ0ElMjAwNC5jcmwwdAYIKwYBBQUHAQEEaDBmMGQGCCsGAQUFBzAChlho # dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUy # MElEJTIwVmVyaWZpZWQlMjBDUyUyMEFPQyUyMENBJTIwMDQuY3J0MFQGA1UdIARN # MEswSQYEVR0gADBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wDQYJKoZIhvcNAQEMBQADggIB # AJNbVP6F8rmpLtPR1BQbzpOqD/0jdgfECBbtzTjT/etuIiZCUYmwSeZXZIAVAxln # P8d8ikNhiDJTyCr8D6KzhgzKsOsMG4IpmeEm00uo4R9NueT5AJjATBTh5/1Jj41s # pFRxqzwjX2byKxPCtP9cBUGGhnfLD4RGITFeJ/L9/7TpdZvPxqRtfqt6KN0hqCFh # JOEd3jadqH4zUEJDaNQ/FH49Wn73mgoXA6QMdYwC1diUHXrdXQb56kmhJD0a48QQ # eaeOi1hH8ZPOfb1V0m7ILvFJvYu7vwECoUqA7FkskaT1ZGffPZg7n9CoXMw2vsfQ # FFvntvcVfQYQM6VANwOCbhyK68elzS9qx2V606Fg1gfk1YOb8Cl9nt2y11l6pCQy # Yum+Fb/4sHRcQc5QB45OpIoNni86PZ51aKObBbWceyt7qyT15YdsIJ5OTg1aLRxT # RW+dQugdj1tDHGBjWVOWh3aOJkjBEpDtNrivfiz0bX+Clvf5zVtcjj0RJDuuNa4i # UxoKe1yFpUKeEqzCP2VYtOzMFn2Dq1n4VMD8axr1J3KjIcIVqHbFkMmDw0OFk2dg # y8NJPibU3nspC1fbKUss2JNt3WUGqRnFe10bdRPFHRSI1bZgI4NwPQLKBIpzphhA # YODAJuaJFk1d0OEJv5V3u1lF/xBwPuhGyojp9o2sb9F2MIIHKDCCBRCgAwIBAgIT # MwAAABYxko2SAmV7mgAAAAAAFjANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQGEwJV # UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTQwMgYDVQQDEytNaWNy # b3NvZnQgSUQgVmVyaWZpZWQgQ29kZSBTaWduaW5nIFBDQSAyMDIxMB4XDTI2MDMy # NjE4MTEyOVoXDTMxMDMyNjE4MTEyOVowWjELMAkGA1UEBhMCVVMxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjErMCkGA1UEAxMiTWljcm9zb2Z0IElEIFZl # cmlmaWVkIENTIEFPQyBDQSAwNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBAMpV+sjb6Akwz/RtDk5Uo1284BLMttRQy9e5/5WXtga6h89pkdWjeAwcXmKd # P4YxKkhx8hn2q1dTVQbryvLy81tC04vg2bfSJ9emojX4HKIBYs7VhPRafMbtc866 # hN55aw1m/kWaPEKxF4Fm/LPLMLJdlu7URB8nFZMfh5tTC0CJb2uox/14OP/BiGIR # 8214lXdkV6JsPbO0Iev0mEV133tducIeBChMipzTZfnGVEq1QYFr7460cEGOIn+7 # AGfNOSq7gWOlmNB4m2uZ1r66vUJPaN+VYgH/Kmfu7tX229b3Alsli38fYS0nQY41 # bElntMS7yNY+Kd047eXM8/tS3NL+ZUNX3ge5xZqW2aytrrNIbwGgQnzsgzxBJvu9 # +b87jUWFiRS/z1YiPkRLY7iTHKIxJ973kIyK8K5itE/aEq/Ht6A8ytaAMMGTEwuC # spk72FE1Qyby+TfDlv1KiAc7IlWHHIWbxoVd8jGCoMXhLSDhuFuGfOWOZKUIuW6Y # xlxcUYOOkXa02gC7dUYUZi0e1NI1Uq9mmAHdvjKdqgORs9/5aDjnbeO3hWd5qwGB # mELWytkjY0KcIEF+CMurTimoQoBYSiHJbYrb0pKSQe+3lVoTVpzdi36jKI7MxLnu # 1fBAMksa8uD85cU7RU29zMOd18h9dgTEH9pvY+4xLB3lUgE7AgMBAAGjggHcMIIB # 2DAOBgNVHQ8BAf8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFGsl # Qd77a3z9GIAKLX+Pdl2qcz24MFQGA1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUF # BwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3Np # dG9yeS5odG0wGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwEgYDVR0TAQH/BAgw # BgEB/wIBADAfBgNVHSMEGDAWgBTZQSmwDw9jbO9p1/XNKZ6kSGow5jBwBgNVHR8E # aTBnMGWgY6Bhhl9odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9N # aWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ29kZSUyMFNpZ25pbmclMjBQQ0El # MjAyMDIxLmNybDB9BggrBgEFBQcBAQRxMG8wbQYIKwYBBQUHMAKGYWh0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwSUQlMjBW # ZXJpZmllZCUyMENvZGUlMjBTaWduaW5nJTIwUENBJTIwMjAyMS5jcnQwDQYJKoZI # hvcNAQEMBQADggIBAAbVUF5UdNVEGWOVxkPciIzHA/IyNDIs1oSdW7mY4ObaFEEl # 8fwawEsBOascBzwXjuOaTkKelQ+IiC4JvDpn8pWPgOyiKrbbw1Iswt7AV8YyuLu7 # A0YshILlxyny9R0AMMQixLZ0T5Aj07CQOm/de5QPt36ECBwtVww6XUCx8Rm2xl6e # Ea9JhSub8W4urQGoQYv0Zczlz4ej2ryj5Wf9L4ZZA3bL6CRE7XmzSQjTmdSmr904 # PiuL2uBWzq2KkR3RhmoaAP4Jk2JplasNM5Bs0+dx3YX2o6xRrbSaJiu6hPk/AkBo # j5BCJMTZkl4wk6Q6nOFNSCpUxnBmJ0RRkoKq51p5ADTxbCeRAx8rIfNpTyPjxQtx # TiFTC8yy/t9K6s570YB1FAI+8XxZxIrmgMd7xVUkzi2/oooKb3UeovH0lqYGBEjp # HZJ9jee7boQbOe7SsKD/vr3PzFabg9VwLZlovpWUpWoWnU2w3xiozJ/m35tsZVvT # 2egUpwkb9TDIaXFGZAGV94FRDHn/K2XNnOwSeGskX19MB+N7yPc51fmUSd49MVAt # GW/NkUGpRech5Aq/d8dCML2bZ+j9nTUMgj+qnd3wuEZVRbQEIbTh9HAck0fyKqoI # b+qh8y/6TKbYDEEOcfM2BGMvrQk4WIGCK6u8uFhA2EH3kpaiMUDqyFCeCCQxMIIH # njCCBYagAwIBAgITMwAAAAeHozSje6WOHAAAAAAABzANBgkqhkiG9w0BAQwFADB3 # MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMUgw # RgYDVQQDEz9NaWNyb3NvZnQgSWRlbnRpdHkgVmVyaWZpY2F0aW9uIFJvb3QgQ2Vy # dGlmaWNhdGUgQXV0aG9yaXR5IDIwMjAwHhcNMjEwNDAxMjAwNTIwWhcNMzYwNDAx # MjAxNTIwWjBjMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv # cmF0aW9uMTQwMgYDVQQDEytNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ29kZSBTaWdu # aW5nIFBDQSAyMDIxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsvDA # rxmIKOLdVHpMSWxpCFUJtFL/ekr4weslKPdnF3cpTeuV8veqtmKVgok2rO0D05Bp # yvUDCg1wdsoEtuxACEGcgHfjPF/nZsOkg7c0mV8hpMT/GvB4uhDvWXMIeQPsDgCz # UGzTvoi76YDpxDOxhgf8JuXWJzBDoLrmtThX01CE1TCCvH2sZD/+Hz3RDwl2MsvD # SdX5rJDYVuR3bjaj2QfzZFmwfccTKqMAHlrz4B7ac8g9zyxlTpkTuJGtFnLBGaso # Onn5NyYlf0xF9/bjVRo4Gzg2Yc7KR7yhTVNiuTGH5h4eB9ajm1OCShIyhrKqgOkc # 4smz6obxO+HxKeJ9bYmPf6KLXVNLz8UaeARo0BatvJ82sLr2gqlFBdj1sYfqOf00 # Qm/3B4XGFPDK/H04kteZEZsBRc3VT2d/iVd7OTLpSH9yCORV3oIZQB/Qr4nD4YT/ # lWkhVtw2v2s0TnRJubL/hFMIQa86rcaGMhNsJrhysLNNMeBhiMezU1s5zpusf54q # lYu2v5sZ5zL0KvBDLHtL8F9gn6jOy3v7Jm0bbBHjrW5yQW7S36ALAt03QDpwW1JG # 1Hxu/FUXJbBO2AwwVG4Fre+ZQ5Od8ouwt59FpBxVOBGfN4vN2m3fZx1gqn52Gvai # Bz6ozorgIEjn+PhUXILhAV5Q/ZgCJ0u2+ldFGjcCAwEAAaOCAjUwggIxMA4GA1Ud # DwEB/wQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU2UEpsA8PY2zv # adf1zSmepEhqMOYwVAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0 # dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0 # bTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAPBgNVHRMBAf8EBTADAQH/MB8G # A1UdIwQYMBaAFMh+0mqFKhvKGZgEByfPUBBPaKiiMIGEBgNVHR8EfTB7MHmgd6B1 # hnNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQl # MjBJZGVudGl0eSUyMFZlcmlmaWNhdGlvbiUyMFJvb3QlMjBDZXJ0aWZpY2F0ZSUy # MEF1dGhvcml0eSUyMDIwMjAuY3JsMIHDBggrBgEFBQcBAQSBtjCBszCBgQYIKwYB # BQUHMAKGdWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWlj # cm9zb2Z0JTIwSWRlbnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290JTIwQ2VydGlm # aWNhdGUlMjBBdXRob3JpdHklMjAyMDIwLmNydDAtBggrBgEFBQcwAYYhaHR0cDov # L29uZW9jc3AubWljcm9zb2Z0LmNvbS9vY3NwMA0GCSqGSIb3DQEBDAUAA4ICAQB/ # JSqe/tSr6t1mCttXI0y6XmyQ41uGWzl9xw+WYhvOL47BV09Dgfnm/tU4ieeZ7NAR # 5bguorTCNr58HOcA1tcsHQqt0wJsdClsu8bpQD9e/al+lUgTUJEV80Xhco7xdgRr # ehbyhUf4pkeAhBEjABvIUpD2LKPho5Z4DPCT5/0TlK02nlPwUbv9URREhVYCtsDM # +31OFU3fDV8BmQXv5hT2RurVsJHZgP4y26dJDVF+3pcbtvh7R6NEDuYHYihfmE2H # dQRq5jRvLE1Eb59PYwISFCX2DaLZ+zpU4bX0I16ntKq4poGOFaaKtjIA1vRElIta # OKcwtc04CBrXSfyL2Op6mvNIxTk4OaswIkTXbFL81ZKGD+24uMCwo/pLNhn7VHLf # nxlMVzHQVL+bHa9KhTyzwdG/L6uderJQn0cGpLQMStUuNDArxW2wF16QGZ1NtBWg # KA8Kqv48M8HfFqNifN6+zt6J0GwzvU8g0rYGgTZR8zDEIJfeZxwWDHpSxB5FJ1VV # U1LIAtB7o9PXbjXzGifaIMYTzU4YKt4vMNwwBmetQDHhdAtTPplOXrnI9SI6HeTt # jDD3iUN/7ygbahmYOHk7VB7fwT4ze+ErCbMh6gHV1UuXPiLciloNxH6K4aMfZN1o # LVk6YFeIJEokuPgNPa6EnTiOL60cPqfny+Fq8UiuZzGCF1UwghdRAgEBMHEwWjEL # MAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjErMCkG # A1UEAxMiTWljcm9zb2Z0IElEIFZlcmlmaWVkIENTIEFPQyBDQSAwNAITMwABE7gv # +luilU99CwAAAAETuDALBglghkgBZQMEAgGgfDAQBgorBgEEAYI3AgEMMQIwADAZ # BgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYB # BAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgO0Fz07AhorzFbqfJ6dLxEZIsbdp+71Kj # fWtOid43wv4wCwYJKoZIhvcNAQEBBIIBgCMmU7LHsg6kdOHYxLlYsSVGhaOlRP25 # uhOUlAcmYemaQKejx8tOfiQf5qNZ7m3MGx8TUafiP8DX1+tqn9J1zPRnrFPerT4K # vcfWgJb+QHizqIZIDAIWkvFkscqQOHFrwcKkqPX2braY2BvS8dgSTM3Nhkzy45ki # xmVpt8Vh/1YOxDJbJ1QdYzx3wLLTdPHqZ0fJPj5FVCqNcukSbYIk+kRKv7phhmyq # MZUH3Q0djBm6SiXfwoLdBDBAhq001CMPRmCRa8rVFrmeV77Y3ByWvC8sIuxL+B5N # gruAQTez+lZcKJ2jOyGGWbHzlE4nsGr1unead8OenXGz37aJNf8PRnD34QhKuLzE # LB6LK16Dc/ME/8yO4tb9U/529Nmj7qQrYn0P4DDZ0R67w/f5Svln+fANsOsT0AcE # R7CLRO8CfLiIhHAfqq8nG6RrKHVcmQCDdnDXDD5iifqAy5/GL8zI1S7R3EyrA05x # 6p30ozlPt4DEKMBCSP/d9GBBum4G6/aRNqGCFLswghS3BgorBgEEAYI3AwMBMYIU # pzCCFKMGCSqGSIb3DQEHAqCCFJQwghSQAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFz # BgsqhkiG9w0BCRABBKCCAWIEggFeMIIBWgIBAQYKKwYBBAGEWQoDATAxMA0GCWCG # SAFlAwQCAQUABCBBNXOLfsP2ppAJrUDCXzZzZMivdXsuu3OfRZSt4UTNIgIGafSH # ByCLGBIyMDI2MDUxNzAxMTIwMy42N1owBIACAfQCCH747mRa04BLoIHppIHmMIHj # MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk # bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRN # aWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5T # aGllbGQgVFNTIEVTTjo0OTFBLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0 # IFB1YmxpYyBSU0EgVGltZSBTdGFtcGluZyBBdXRob3JpdHmggg8pMIIHgjCCBWqg # AwIBAgITMwAAAAXlzw//Zi7JhwAAAAAABTANBgkqhkiG9w0BAQwFADB3MQswCQYD # VQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMUgwRgYDVQQD # Ez9NaWNyb3NvZnQgSWRlbnRpdHkgVmVyaWZpY2F0aW9uIFJvb3QgQ2VydGlmaWNh # dGUgQXV0aG9yaXR5IDIwMjAwHhcNMjAxMTE5MjAzMjMxWhcNMzUxMTE5MjA0MjMx # WjBhMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u # MTIwMAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0Eg # MjAyMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJ5851Jj/eDFnwV9 # Y7UGIqMcHtfnlzPREwW9ZUZHd5HBXXBvf7KrQ5cMSqFSHGqg2/qJhYqOQxwuEQXG # 8kB41wsDJP5d0zmLYKAY8Zxv3lYkuLDsfMuIEqvGYOPURAH+Ybl4SJEESnt0MbPE # oKdNihwM5xGv0rGofJ1qOYSTNcc55EbBT7uq3wx3mXhtVmtcCEr5ZKTkKKE1CxZv # NPWdGWJUPC6e4uRfWHIhZcgCsJ+sozf5EeH5KrlFnxpjKKTavwfFP6XaGZGWUG8T # ZaiTogRoAlqcevbiqioUz1Yt4FRK53P6ovnUfANjIgM9JDdJ4e0qiDRm5sOTiEQt # BLGd9Vhd1MadxoGcHrRCsS5rO9yhv2fjJHrmlQ0EIXmp4DhDBieKUGR+eZ4CNE3c # tW4uvSDQVeSp9h1SaPV8UWEfyTxgGjOsRpeexIveR1MPTVf7gt8hY64XNPO6iyUG # sEgt8c2PxF87E+CO7A28TpjNq5eLiiunhKbq0XbjkNoU5JhtYUrlmAbpxRjb9tSr # eDdtACpm3rkpxp7AQndnI0Shu/fk1/rE3oWsDqMX3jjv40e8KN5YsJBnczyWB4Jy # eeFMW3JBfdeAKhzohFe8U5w9WuvcP1E8cIxLoKSDzCCBOu0hWdjzKNu8Y5SwB1lt # 5dQhABYyzR3dxEO/T1K/BVF3rV69AgMBAAGjggIbMIICFzAOBgNVHQ8BAf8EBAMC # AYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFGtpKDo1L0hjQM972K9J6T7Z # PdshMFQGA1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0l # BAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwDwYDVR0T # AQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTIftJqhSobyhmYBAcnz1AQT2ioojCBhAYD # VR0fBH0wezB5oHegdYZzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j # cmwvTWljcm9zb2Z0JTIwSWRlbnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290JTIw # Q2VydGlmaWNhdGUlMjBBdXRob3JpdHklMjAyMDIwLmNybDCBlAYIKwYBBQUHAQEE # gYcwgYQwgYEGCCsGAQUFBzAChnVodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtp # b3BzL2NlcnRzL01pY3Jvc29mdCUyMElkZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIw # Um9vdCUyMENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAyMC5jcnQwDQYJKoZI # hvcNAQEMBQADggIBAF+Idsd+bbVaFXXnTHho+k7h2ESZJRWluLE0Oa/pO+4ge/XE # izXvhs0Y7+KVYyb4nHlugBesnFqBGEdC2IWmtKMyS1OWIviwpnK3aL5JedwzbeBF # 7POyg6IGG/XhhJ3UqWeWTO+Czb1c2NP5zyEh89F72u9UIw+IfvM9lzDmc2O2END7 # MPnrcjWdQnrLn1Ntday7JSyrDvBdmgbNnCKNZPmhzoa8PccOiQljjTW6GePe5sGF # uRHzdFt8y+bN2neF7Zu8hTO1I64XNGqst8S+w+RUdie8fXC1jKu3m9KGIqF4aldr # YBamyh3g4nJPj/LR2CBaLyD+2BuGZCVmoNR/dSpRCxlot0i79dKOChmoONqbMI8m # 04uLaEHAv4qwKHQ1vBzbV/nG89LDKbRSSvijmwJwxRxLLpMQ/u4xXxFfR4f/gksS # kbJp7oqLwliDm/h+w0aJ/U5ccnYhYb7vPKNMN+SZDWycU5ODIRfyoGl59BsXR/Hp # RGtiJquOYGmvA/pk5vC1lcnbeMrcWD/26ozePQ/TWfNXKBOmkFpvPE8CH+EeGGWz # qTCjdAsno2jzTeNSxlx3glDGJgcdz5D/AAxw9Sdgq/+rY7jjgs7X6fqPTXPmaCAJ # KVHAP19oEjJIBwD1LyHbaEgBxFCogYSOiUIr0Xqcr1nJfiWG2GwYe6ZoAF1bMIIH # nzCCBYegAwIBAgITMwAAAFr2DWeMhe3dCAAAAAAAWjANBgkqhkiG9w0BAQwFADBh # MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIw # MAYDVQQDEylNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lc3RhbXBpbmcgQ0EgMjAy # MDAeFw0yNjAxMDgxODU5MDNaFw0yNzAxMDcxODU5MDNaMIHjMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl # bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT # Tjo0OTFBLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0IFB1YmxpYyBSU0Eg # VGltZSBTdGFtcGluZyBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw # ggIKAoICAQDv9DtHlo4FG/a5x3EC0XX1jzeB/vdWt2J5Wj+OhNZuLg/iSsenLFjE # rV+/X8SyVAKhyakFhNfVJTTIUvYxAd9nQCeMrlrB8lLjPnaYYw8+BOY5eIGBmRJm # jqyrzbfiqpRWssoP6E4NwZS0buGgavOuvAOapR3H7Loeg3UqhSA9YsSRWcx62RRt # YhgRu1NQZ9jjSw6O428F+azHD3bkwFMP3OzN1oUsUAbmaUIs/EUBiiKginyMYEJC # nc6QqVNElkDhPw4E12893NeSjEQnZBpS9s2/pZ7kleLLHkJt6n5WYmXJC8p9sSSP # GVw5KviIPm/67DzyHyPHYttvFrytY+uyV6cnlQmklDvRK85S506540JHl1UCKe98 # blQVa5r6E3/7+GuzJ65riksiF3ObyVBxBgd+OfjvKJhbdcPG/l4PQ/TyiEagzxL+ # x0ZNAvmL8bvBbxyb0qHEiGSvr/xZihToqWJ6T++sgJiTZ8oXrnEoToJPEIlOd1Ep # //gMjG+8VvdOYGZ8jam9vR3lXUNe+aQxyRhM/AsecIh3lZYhs+YQAbnBQ8pUfc9y # 0k5gevt2biMXhvQWUuOj+gDT5Llbg+ZvMIHOxiy84O9wrAxdPbpLfFH/HU3DAV96 # 6Pu/5PTOl7fFjxuyC/b/+A78jGNN7ZG/WPUYuh1mr10T2EQlHj7KTwIDAQABo4IB # yzCCAccwHQYDVR0OBBYEFI5jskOrcDHD9WW0crScSOH515nCMB8GA1UdIwQYMBaA # FGtpKDo1L0hjQM972K9J6T7ZPdshMGwGA1UdHwRlMGMwYaBfoF2GW2h0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMFB1YmxpYyUy # MFJTQSUyMFRpbWVzdGFtcGluZyUyMENBJTIwMjAyMC5jcmwweQYIKwYBBQUHAQEE # bTBrMGkGCCsGAQUFBzAChl1odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz # L2NlcnRzL01pY3Jvc29mdCUyMFB1YmxpYyUyMFJTQSUyMFRpbWVzdGFtcGluZyUy # MENBJTIwMjAyMC5jcnQwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEF # BQcDCDAOBgNVHQ8BAf8EBAMCB4AwZgYDVR0gBF8wXTBRBgwrBgEEAYI3TIN9AQEw # QTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9E # b2NzL1JlcG9zaXRvcnkuaHRtMAgGBmeBDAEEAjANBgkqhkiG9w0BAQwFAAOCAgEA # gJTPK/rd4SG9odZQ0wMfomJEJcRblO0DjXsiBSAWdvcbxpfKXoSsRKw8yJ4jqSF/ # 3pblAMECqGiNM8LigHUdJq0h1wp4jKCzZKOVvua+7FzWpil+0DFdwXxjl94IvalX # 8clHuwB126kPCgUBzWApzRbUEB4AEa5WIbcgCqJeXLTNAgHP8t6GO20zLFSb5wOb # uw1Vj3l6Ek9ihDA3iwbyWKtCCWesjKQzli2eFD/Nm5LMkoSAf13WsIqyBi3bHrna # 8kcVTJN9d5gHIxkW+ffiLbbeqLVb2EFqh/jxq01MxHHs/GkLjt7pqDWYyrhaF+Vb # Dz/4EmbHvqK4Rt832ZPSA8hNw31Ba4b5L+h9LYoytQ9LiBocDAVkpvZLUOqHlPmr # q2RcdzCPizg5x7G0RWQMtdbjL8CqvmTQtUnuLSDNbvaYlgIZ0z6IeplCyopBzlYR # 2jved7ZMwwrY7LHuRlCjsfcoPZ6hyljIJzg6etv7jz8wv8gxCEq1wnFO1Ae7QE69 # 81jRHbTOHdNPYl1iOnVf0nXCCF+OK6aC8gi8Pp148afn2P3coCzu1HUkGlWlBVY9 # ytp1crroz7KbeS7p3ORb7mD6pov8/JAEppsG4hfltD9FE1hWgvODFn1NoejA4ObN # KMZnTRSu+o1698GX3UqFexQin6uRnXhqMuVMA0MDAtAxggPUMIID0AIBATB4MGEx # CzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAw # BgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIw # AhMzAAAAWvYNZ4yF7d0IAAAAAABaMA0GCWCGSAFlAwQCAQUAoIIBLTAaBgkqhkiG # 9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIMFgtBq/PWDDaXHm # 7f7F8R6n+ponBlAM8ZoHM9T1gqsKMIHdBgsqhkiG9w0BCRACLzGBzTCByjCBxzCB # oAQgYrlkQIvqfej0bAbd08Ft4zaM4D0EvkHKNQlZvzWlNEMwfDBlpGMwYTELMAkG # A1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UE # AxMpTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjACEzMA # AABa9g1njIXt3QgAAAAAAFowIgQgKQwCtB9cB75lcSb2HP5OSTznFZ4fMbLJpwWo # Ouq4ri8wDQYJKoZIhvcNAQELBQAEggIAq9ooI5+8ZVhPjAAq13rpUGUcHPDfy0yK # dHgt/tMflvF8eWt223dWtOsOZMuXZzUika96QCZddAtwbWNs7+4ci51pIpQmpS17 # saxirr0MFeFvAXs85hyPGQit8w9QSNiY8OJAAigvUqpocL6mXi58g8pEovFNAIeN # EcDhBcDCXw6rzc7XxVJlzsMQC+1bzgTTvD26duZ9Cig3ol20ShQbuP5I7kSqRkVp # 6aU+omJ8y1ikB7IbfZMGHxPw9bIMGEjjxPGUSVN/+upVQo16ifFCEulANy3IdP6e # JhfJ2vcNpi3LMqDD9kRBloiy2ysu6In0XG5XcaQ0HKbN07twDITWDbp3ErCGrRwa # 5rt1mvJL3Hwd9x3pw0fWHZ/UI/vYCRWrcQNUNN+SOpcwwnUVGIZsIDZs2OITit1U # h6iNxU3nRbwvuJtauMtNpMFKT8O1QjlOAfEkTSSRkUbW+GPF2sQv/l9x77imDDBw # dbhPBJ3crJC+LBYnNFmO9OHNEC5RL7lWmtj4/ufWKx+bPuNFzkDjRz7wyygKX8Kq # 1csCMFkPRGMlhXB3bIa6MWExWtqe2s1mA+H3zWlnRm244ZNlibGy448aTP8mgJNV # /pVQbUx5oQIr1qp387hnudL3TvIcFPb1vNWWwZSYuZwgWAFVlp6gpk4yf9Csq1xg # zXvZk3phv28= # SIG # End signature block |