TelemetryHelper.ps1
|
$eventIds = @{ "New-BcContainer" = "DO0001" "New-BcImage" = "DO0002" "Compile-AppInBcContainer" = "DO0003" "Publish-BcContainerApp" = "DO0004" "Run-AlCops" = "DO0005" "Run-AlValidation" = "DO0006" "Run-AlPipeline" = "DO0007" "Run-TestsInBcContainer" = "DO0008" "Sign-BcContainerApp" = "DO0009" "Publish-PerTenantExtensionApps" = "DO0010" "Install-BcAppFromAppSource" = "DO0011" "New-BcEnvironment" = "DO0012" "New-BcDatabaseExport" = "DO0013" "Remove-BcEnvironment" = "DO0014" "Download-Artifacts" = "DO0015" "New-CompanyInNavContainer" = "DO0016" "Import-TestToolkitToBcContainer" = "DO0017" "UploadImportAndApply-ConfigPackageInBcContainer" = "DO0018" "New-AppSourceSubmission" = "DO0019" "Promote-AppSourceSubmission" = "DO0020" } function FormatValue { Param( $value ) if ($value -eq $null) { "[null]" } elseif ($value -is [switch]) { $value.IsPresent } elseif ($value -is [boolean]) { $value } elseif ($value -is [SecureString]) { "[SecureString]" } elseif ($value -is [PSCredential]) { "[PSCredential]" } elseif ($value -is [string]) { if (($value -like "https:*" -or $value -like "http:*") -and ($value.Contains('?'))) { "$($value.Split('?')[0])?[parameters]" } else { "$value" } } elseif ($value -is [System.Collections.IDictionary]) { $arr = @($value.GetEnumerator() | ForEach-Object { $_ }) $str = "{" $arr | ForEach-Object { if ($_.Key -eq "RefreshToken" -or $_.Key -eq "AccessToken") { if ($_.Value) { $str += "`n $($_.Key): [token]" } else { $str += "`n $($_.Key): [null]" } } else { $str += "`n $($_.Key): $(FormatValue -value $_.Value)" } } "$str`n}" } elseif ($value -is [System.Collections.IEnumerable]) { $arr = @($value.GetEnumerator() | ForEach-Object { $_ }) if ($arr.Count -gt 1) { $str = "[" } else { $str = "" } $arr | ForEach-Object { if ($arr.Count -gt 1) { $str += "`n " } $str += "$(FormatValue -value $_)" } if ($arr.Count -gt 1) { "$str`n]" } else { $str } } else { $value } } function AddTelemetryProperty { Param( $telemetryScope, $key, $value ) if ($telemetryScope) { $value = FormatValue -value $value if ($telemetry.Debug) { Write-Host -ForegroundColor Yellow "Telemetry scope $($telemetryScope.Name), add property $key = '$value', type = $($value.GetType())" } if ($telemetryScope.properties.ContainsKey($Key)) { $telemetryScope.properties."$key" += "`n$value" } else { $telemetryScope.properties.Add($key, $value) } } } function InitTelemetryClients { Param() "Microsoft","Partner" | ForEach-Object { $clientName = "$($_)Client" $telemetryConnectionString = $bcContainerHelperConfig."$($_)TelemetryConnectionString" if ($telemetryConnectionString -and $telemetry.Assembly -ne $null) { if ($telemetry."$clientName" -eq $null -or $telemetry."$ClientName".TelemetryConfiguration.ConnectionString -ne $telemetryConnectionString) { try { $telemetryConfiguration = $telemetry.Assembly.CreateInstance('Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration') $telemetryConfiguration.Connectionstring = $telemetryConnectionString $telemetry."$clientName" = $telemetry.Assembly.CreateInstance('Microsoft.ApplicationInsights.TelemetryClient', $false, 0, $null, $telemetryConfiguration, $null, $null) } catch { $telemetry."$clientName" = $null } } } else { $telemetry."$clientName" = $null } } } function RegisterTelemetryScope { Param( [string] $telemetryScopeJson ) InitTelemetryClients $telemetryScope = $telemetryScopeJson | ConvertFrom-Json if ($telemetry.TopId -eq "") { $telemetry.TopId = $telemetryScope.CorrelationId } $scope = @{ "Name" = $telemetryScope.Name "EventId" = $telemetryScope.eventId "StartTime" = $telemetryScope.StartTime "Properties" = [Collections.Generic.Dictionary[string, string]]::new() "Parameters" = [Collections.Generic.Dictionary[string, string]]::new() "AllParameters" = [Collections.Generic.Dictionary[string, string]]::new() "CorrelationId" = $telemetryScope.CorrelationId "ParentId" = $telemetryScope.CorrelationId "TopId" = $telemetry.TopId "Emitted" = $telemetryScope.Emitted } "Properties","Parameters","AllParameters" | ForEach-Object { $prop = $_ $telemetryScope."$prop".PSObject.Properties.GetEnumerator() | ForEach-Object { $scope."$prop".Add($_.Name, $_.Value) } } $telemetry.CorrelationId = $telemetryScope.CorrelationId $scope } function InitTelemetryScope { Param( [string] $name, [string[]] $includeParameters = @(), $parameterValues = $null, [string] $eventId = "" ) InitTelemetryClients if ($telemetry.MicrosoftClient -ne $null -or $telemetry.PartnerClient -ne $null) { if ($eventId -eq "" -and ($eventIds.ContainsKey($name))) { $eventId = $eventIds[$name] } if (($eventId -ne "") -or ($telemetry.CorrelationId -eq "")) { $CorrelationId = [GUID]::NewGuid().ToString() Start-Transcript -Path (Join-Path ([System.IO.Path]::GetTempPath()) $CorrelationId) | Out-Null if ($telemetry.Debug) { Write-Host -ForegroundColor Yellow "Init telemetry scope $name" } if ($telemetry.TopId -eq "") { $telemetry.TopId = $CorrelationId } $scope = @{ "Name" = $name "EventId" = $eventId "StartTime" = [DateTime]::Now "Properties" = [Collections.Generic.Dictionary[string, string]]::new() "Parameters" = [Collections.Generic.Dictionary[string, string]]::new() "AllParameters" = [Collections.Generic.Dictionary[string, string]]::new() "CorrelationId" = $CorrelationId "ParentId" = $telemetry.CorrelationId "TopId" = $telemetry.TopId "Emitted" = $false } $telemetry.CorrelationId = $CorrelationId if ($includeParameters) { $parameterValues.GetEnumerator() | ForEach-Object { $includeParameter = $false $key = $_.key $value = FormatValue -value $_.value $scope.allParameters.Add($key, $value) $includeParameters | ForEach-Object { if ($key -like $_) { $includeParameter = $true } } if ($includeParameter) { $scope.parameters.Add($key, $value) } } } AddTelemetryProperty -telemetryScope $scope -key "eventId" -value $eventId AddTelemetryProperty -telemetryScope $scope -key "bcContainerHelperVersion" -value $BcContainerHelperVersion AddTelemetryProperty -telemetryScope $scope -key "isAdministrator" -value $isAdministrator AddTelemetryProperty -telemetryScope $scope -key "stackTrace" -value (Get-PSCallStack | % { "$($_.Command) at $($_.Location)" }) -join "`n" $scope } } } function TrackTrace { Param( $telemetryScope ) if ($telemetryScope -and !$telemetryScope.Emitted) { if ($telemetryScope.CorrelationId -eq $telemetry.CorrelationId) { if ($telemetry.Debug) { Write-Host -ForegroundColor Yellow "Emit telemetry trace, scope $($telemetryScope.Name)" } $telemetry.CorrelationId = $telemetryScope.ParentId if ($telemetry.CorrelationId -eq "") { $telemetry.TopId = "" } $telemetryScope.Emitted = $true try { Stop-Transcript | Out-Null $transcript = (@(Get-Content -Path (Join-Path ([System.IO.Path]::GetTempPath()) $telemetryScope.CorrelationId)) | select -skip 18 | select -skiplast 4 | Where-Object { -not "$_".StartsWith("::add-mask::") }) -join "`n" if ($transcript.Length -gt 32000) { $transcript = "$($transcript.SubString(0,16000))`n`n...`n`n$($transcript.SubString($transcript.Length-16000))" } Remove-Item -Path (Join-Path ([System.IO.Path]::GetTempPath()) $telemetryScope.CorrelationId) } catch { $transcript = "" } $telemetryScope.Properties.Add("duration", [DateTime]::Now.Subtract($telemetryScope.StartTime).TotalSeconds) if ($telemetry.Assembly -ne $null) { try { $printCorrelationId = $telemetry.Debug "Microsoft","Partner" | ForEach-Object { $clientName = "$($_)Client" $extendedTelemetry = $bcContainerHelperConfig.SendExtendedTelemetryToMicrosoft -or $_ -eq "Partner" if ($telemetry."$clientName") { $traceTelemetry = $telemetry.Assembly.CreateInstance('Microsoft.ApplicationInsights.DataContracts.TraceTelemetry') if ($extendedTelemetry) { $traceTelemetry.Message = "$($telemetryScope.Name)`n$transcript" $traceTelemetry.SeverityLevel = 0 $telemetryScope.allParameters.GetEnumerator() | ForEach-Object { [void]$traceTelemetry.Properties.TryAdd("parameter[$($_.Key)]", $_.Value) } } else { $traceTelemetry.Message = "$($telemetryScope.Name)" $traceTelemetry.SeverityLevel = 1 $telemetryScope.Parameters.GetEnumerator() | ForEach-Object { [void]$traceTelemetry.Properties.TryAdd("parameter[$($_.Key)]", $_.Value) } } $telemetryScope.Properties.GetEnumerator() | ForEach-Object { [void]$traceTelemetry.Properties.TryAdd($_.Key, $_.Value) } $traceTelemetry.Context.Operation.Name = $telemetryScope.Name $traceTelemetry.Context.Operation.Id = $telemetryScope.CorrelationId $traceTelemetry.Context.Operation.ParentId = $telemetryScope.ParentId $telemetry."$clientName".TrackTrace($traceTelemetry) $telemetry."$clientName".Flush() if ($extendedTelemetry) { $printCorrelationId = $true } if ($telemetry.Debug) { Write-Host "$_ telemetry emitted" } } } if ($printCorrelationId) { Write-Host "$($telemetryScope.Name) Telemetry Correlation Id: $($telemetryScope.CorrelationId)" } } catch { Write-Host -ForegroundColor Red "Error emitting telemetry." Write-Host -ForegroundColor Red "This might be caused by and old version of dotnet, you need at least dotnet 6.0." Write-Host -ForegroundColor Red "Please upgrade dotnet here: https://dotnet.microsoft.com/en-us/download/dotnet/6.0" } } } } } function TrackException { Param( $telemetryScope, $errorRecord ) TrackException -telemetryScope $telemetryScope -exception $errorRecord.Exception -scriptStackTrace $errorRecord.scriptStackTrace } function TrackException { Param( $telemetryScope, $exception, $scriptStackTrace = $null ) if ($telemetryScope -and !$telemetryScope.Emitted) { if ($telemetryScope.CorrelationId -eq $telemetry.CorrelationId) { if ($telemetry.Debug) { Write-Host -ForegroundColor Yellow "Emit telemetry exception, scope $($telemetryScope.Name)" } $telemetry.CorrelationId = $telemetryScope.ParentId if ($telemetry.CorrelationId -eq "") { $telemetry.TopId = "" } $telemetryScope.Emitted = $true try { Stop-Transcript | Out-Null $transcript = (@(Get-Content -Path (Join-Path ([System.IO.Path]::GetTempPath()) $telemetryScope.CorrelationId)) | select -skip 18 | select -skiplast 4 | Where-Object { -not "$_".StartsWith("::add-mask::") }) -join "`n" if ($transcript.Length -gt 32000) { $transcript = "$($transcript.SubString(0,16000))`n`n...`n`n$($transcript.SubString($transcript.Length-16000))" } Remove-Item -Path (Join-Path ([System.IO.Path]::GetTempPath()) $telemetryScope.CorrelationId) } catch { $transcript = "" } $telemetryScope.Properties.Add("duration", [DateTime]::Now.Subtract($telemetryScope.StartTime).TotalSeconds) if ($scriptStackTrace) { $telemetryScope.Properties.Add("errorStackTrace", $scriptStackTrace) } if ($exception) { $telemetryScope.Properties.Add("errorMessage", $exception.Message) } if ($telemetry.Assembly -ne $null) { try { "Microsoft","Partner" | ForEach-Object { $clientName = "$($_)Client" $extendedTelemetry = $bcContainerHelperConfig.SendExtendedTelemetryToMicrosoft -or $_ -eq "Partner" if ($telemetry."$clientName") { $traceTelemetry = $telemetry.Assembly.CreateInstance('Microsoft.ApplicationInsights.DataContracts.TraceTelemetry') if ($extendedTelemetry) { $traceTelemetry.Message = "$($telemetryScope.Name)`n$transcript" $traceTelemetry.SeverityLevel = 0 $telemetryScope.allParameters.GetEnumerator() | ForEach-Object { [void]$traceTelemetry.Properties.TryAdd("parameter[$($_.Key)]", $_.Value) } } else { $traceTelemetry.Message = "$($telemetryScope.Name)" $traceTelemetry.SeverityLevel = 1 $telemetryScope.Parameters.GetEnumerator() | ForEach-Object { [void]$traceTelemetry.Properties.TryAdd("parameter[$($_.Key)]", $_.Value) } } $telemetryScope.Properties.GetEnumerator() | ForEach-Object { [void]$traceTelemetry.Properties.TryAdd($_.Key, $_.Value) } $traceTelemetry.Context.Operation.Name = $telemetryScope.Name $traceTelemetry.Context.Operation.Id = $telemetryScope.CorrelationId $traceTelemetry.Context.Operation.ParentId = $telemetryScope.ParentId $telemetry."$clientName".TrackTrace($traceTelemetry) # emit exception telemetry $exceptionTelemetry = $telemetry.Assembly.CreateInstance('Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry') if ($extendedTelemetry) { $exceptionTelemetry.Message = "$($telemetryScope.Name)`n$transcript" $exceptionTelemetry.SeverityLevel = 3 $telemetryScope.allParameters.GetEnumerator() | ForEach-Object { [void]$exceptionTelemetry.Properties.TryAdd("parameter[$($_.Key)]", $_.Value) } } else { $exceptionTelemetry.Message = "$($telemetryScope.Name)" $exceptionTelemetry.SeverityLevel = 1 $telemetryScope.Parameters.GetEnumerator() | ForEach-Object { [void]$exceptionTelemetry.Properties.TryAdd("parameter[$($_.Key)]", $_.Value) } } $telemetryScope.Properties.GetEnumerator() | ForEach-Object { [void]$exceptionTelemetry.Properties.TryAdd($_.Key, $_.Value) } $exceptionTelemetry.Context.Operation.Name = $telemetryScope.Name $exceptionTelemetry.Context.Operation.Id = $telemetryScope.CorrelationId $exceptionTelemetry.Context.Operation.ParentId = $telemetryScope.ParentId $telemetry."$clientName".TrackException($exceptionTelemetry) $telemetry."$clientName".Flush() } } Write-Host "$($telemetryScope.Name) Telemetry Correlation Id: $($telemetryScope.CorrelationId)" } catch { Write-Host -ForegroundColor Red "Error emitting telemetry." Write-Host -ForegroundColor Red "This might be caused by and old version of dotnet, you need at least dotnet 6.0." Write-Host -ForegroundColor Red "Please upgrade dotnet here: https://dotnet.microsoft.com/en-us/download/dotnet/6.0" } } } } } # SIG # Begin signature block # MIIncQYJKoZIhvcNAQcCoIInYjCCJ14CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDqmeRfJdU8tpX7 # fAV4/qtHO7dCG2MF/n85/yEPWX8jLaCCDMkwggYEMIID7KADAgECAhMzAAACHPrN # xZvoL37EAAAAAAIcMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAlVTMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBD # b2RlIFNpZ25pbmcgUENBIDIwMjQwHhcNMjYwNDE2MTg1OTQxWhcNMjcwNDE1MTg1 # OTQxWjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYD # VQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IB # DwAwggEKAoIBAQDVsZfgOKmM31HPfoWOoNEiw0SlCiIxUMC0I9NMWbucKOw/e9lP # oAoehQVu6SG65V4EPzrYsnBnFPNoi4/HoOdjhz1qkrEt4I6tEcxXU6oOeY9zGveC # /3iBeuhLYxM3M/PkcUoebF+Nednm8OkdSPoDu8imViHPQq/8CQUu0WRR4rE+dMRf # rpVqfmNi2qWCX94T4MsepijGVkwE//tJg0ryAiYdHT34LSnlG/RSBZmQRGWZ5g8j # qnKjRParSqMft1gvjuUTVgtWNZfgcLFSK5Wa0myrq8OPcgTGGsRgun+tnSS+IxDT # xVsAPH1OzvPjwomguByhUe/OcvUN0D5Wmp7xAgMBAAGjggGqMIIBpjAOBgNVHQ8B # Af8EBAMCB4AwHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0O # BBYEFNoH7a2YDjOSwpkp6DHcmUS7J+0yMFQGA1UdEQRNMEukSTBHMS0wKwYDVQQL # EyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxFjAUBgNVBAUT # DTIzMDAxMis1MDc1NjkwHwYDVR0jBBgwFoAUf1k/VCHarU/vBeXmo9ctBpQSCDEw # YAYDVR0fBFkwVzBVoFOgUYZPaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w # cy9jcmwvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNy # bDBtBggrBgEFBQcBAQRhMF8wXQYIKwYBBQUHMAKGUWh0dHA6Ly93d3cubWljcm9z # b2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmcl # MjBQQ0ElMjAyMDI0LmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IC # AQAUnEqhaRXe0T3hIJjvdQErEkrA/7bByjn6t5IArODkkRjzkYwtKMc2yYj2quaN # rLutWw2YZcngKPy1b71YyDJQTy4NDRwaSh9Tw5thrk3NmcPrAHia5vtcBJ1CgtKK # 7mQbIcQ22d/N3813ayCDDFewu1+jsZmX+r/aTEqaOM4TVxVtRSkuCy8nAXKuChOK # Li/zA4XuH8iEYqIsj2YoNaeSxVmeGiERXpKdo3dDmYi0kO5w2D8VS4c3+9h6gElY # BaAAg/dYErBg27qT3vv0zRDJhJufvCNylA8S7/+8H5E/PV5cng6na9VV/w9OV3qu # uND6zdGa2EX38Glp50F9AIQk3p2xXmcvorDeM4XJ7UlWYBi6g80J1SSOQnInCYFE # msfUNn3+1AaTJKSJL83quKArTac2pKhu0Yzzzrzo6HrsRiQKzpnRBb1/dMa6P3hz # 75XbMRBctNsFhZC07WCmjExdLg2eHW5uV0TY8D5+6wozJf7vF3+WHkYPO85Z+BC6 # U4FkNbYNycZ9cE4j1tXRdyDCfml6c0HWPHjNVDObrv9lKt3qUqFpX38VCqVCyNOO # 1UcXfQiVjJw32U2WUKZjt/neJKHEBsm9kFsLuWzkQ53+qcaSaytmsCnk2gOglrlD # 5d3kKyvvAw+rzm0lT8K38P6PLxfZQHhu4W8dV7Av8N2ZmDCCBr0wggSloAMCAQIC # EzMAAAA5O7Y3Gb8GHWcAAAAAADkwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBS # b290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDExMB4XDTI0MDgwODIwNTQxOFoX # DTM2MDMyMjIyMTMwNFowVzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQ # Q0EgMjAyNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANgBnB7jOMeq # lRYHNa265v4IY9fH8TKhemHfPINe1gpLaV3dhg324WwH06LcHbpnsBukCDNitryo # 0dtS/EW6I/yEL/bLSY8hKpbfQuWusBPr9qazYcDxCW/qnjb5JsI1s8bNOg3bVATv # QVL4tcf03aTycsz8QeCdM0l/yHRObJ9QqazM1r6VPEOJ7LL+uEEb73w6QCuhs89a # 1uv1zerOYMnsneRRwCbpyW11IcggU0cRKDDq1pjVJzIbIF6+oiXXbReOsgeI8zu1 # FyQfK0fVkaya8SmVHQ/tOf23mZ4W9k0Ri22QW9p3UgSC5OUDktKxxcCmGL6tXLfO # GSWHIIV4YrTJTT6PNty5REojHJuZHArkF9VnHTERWoTjAzfI3kP+5b4alUdhgAZ7 # ttOu1bVnXfHaqPYl2rPs20ji03LOVWsh/radgE17es5hL+t6lV0eVHrVhsssROWJ # uz2MXMCt7iw7lFPG9LXKGjsmonn2gotGdHIuEg5JnJMJVmixd5LRlkmgYRZKzhxS # CwyoGIq0PhaA7Y+VPct5pCHkijcIIDm0nlkK+0KyepolcqGm0T/GYQRMhHJlGOOm # VQop36wUVUYklUy++vDWeEgEo4s7hxN6mIbf2MSIQ/iIfMZgJxC69oukMUXCrOC3 # SkE/xIkgpfl22MM1itkZ35nNXkMolU1lAgMBAAGjggFOMIIBSjAOBgNVHQ8BAf8E # BAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFH9ZP1Qh2q1P7wXl5qPX # LQaUEggxMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMB # Af8wHwYDVR0jBBgwFoAUci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBP # oE2gS4ZJaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv # TWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRSMFAw # TgYIKwYBBQUHMAKGQmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMv # TWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNydDANBgkqhkiG9w0BAQwFAAOC # AgEAFJQfOChP7onn6fLIMKrSlN1WYKwDFgAddymOUO3FrM8d7B/W/iQ6DxXsDn7D # 5W4wMwYeLystcEqfkjz4NURRgazyMu5yRzQh4LqjA4tStTcJh1opExo7nn5PuPBY # nbu0+THSuVHTe0VTTPVhily/piFrDo3axQ9P4C+Ol5yet+2gTfekICS5xS+cYfSI # vgn0JksVBVMYVI5QFu/qhnLhsEFEUzG8fvv0hjgkO+lkpV9ty6GkN4vdnd7ya6Q6 # aR9y34aiM1qmxaxBi6OUnyNl6fkuun/diTFnYDLTppOkr/mg5WSfCiDVMNCxtj4w # PKC5OmHm1DQIt/MNokbbH3UGsFP1QbzsLocuSqLCvH09Io3fDPTmscR9Y75G4qX7 # RTX8AdBPo0I6OEojf39zuFZt0qOHm65YWQE69cZM2ueE1MB05dNNgHK9gTE7zKvK # /fg8B2qjW88MT/WF5V5uvZGtqa9FSL2RazArA+rDPuf6JGYz4HpgMZHB4S6szWSK # YBv0VisCzfxgeU+dquXW9bd0auYlOB58DPcOYKdc3Se94g+xL4pcEhbB54JOgAkw # YTu/9dLeH2pDqeJZAABVDWRQCaXfO5LgyKwKCLYXpigrZYCjUSBcr+Ve8PFWMhVT # Ql0v4q8J/AUmQN5W4n101cY2L4A7GTQG1h32HHAvfQESWP0xghn+MIIZ+gIBATBu # MFcxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x # KDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMjQCEzMAAAIc # +s3Fm+gvfsQAAAAAAhwwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwG # CisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZI # hvcNAQkEMSIEIN80Bq3bn2LvR1GWduHeY3aCKmPmjB2XK/Yh6GSPte9oMEIGCisG # AQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEBBQAEggEAaEmrd1ZJnAHdmbvLc89o # Vxf7NNYyHbQCEGEPBMJq5M6LQQ4YKhehQ3njYalj+pNLbgbwJD1cmN9PV3bluOj/ # +CI0JiASSvQdsoSyuZpz4k6pZSTZE39t53QpzJ6nBxzSkKoQXrPf6ofVDtjeExkz # 4H8saYAKXXzECM+GI2fKjsu/AR3p1tF3a1Gk35r+pC3DX7GnieYTFnuMSGfk929Z # kx3CohwqT4C7WfCMO7o3Ue8jrQdH0uf3BQIxbsiDH4yGFE082EpeddMcll5NBUyF # QjkTB6CtDLlYMiVEmKC2RZaC3vg6QvfOdm4BLdf08aJghKAR9fYMG53TAo4MoBsm # F6GCF7AwghesBgorBgEEAYI3AwMBMYIXnDCCF5gGCSqGSIb3DQEHAqCCF4kwgheF # AgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsqhkiG9w0BCRABBKCCAUkEggFFMIIB # QQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUABCC4jzdEnzM4NpLRw6sH # lUk3r8u7CBeRvY7+Sj9qyhdraQIGal4a7SunGBMyMDI2MDcyMzExNTQzNi4xNDha # MASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0 # ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjozMjFBLTA1RTAtRDk0NzElMCMG # A1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCEf4wggcoMIIFEKAD # AgECAhMzAAACGqmgHQagD0OqAAEAAAIaMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNV # BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w # HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29m # dCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI1MDgxNDE4NDgyOFoXDTI2MTExMzE4 # NDgyOFowgdMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTAr # BgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUG # A1UECxMeblNoaWVsZCBUU1MgRVNOOjMyMUEtMDVFMC1EOTQ3MSUwIwYDVQQDExxN # aWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEFAAOC # Ag8AMIICCgKCAgEAmYEAwSTz79q2V3ZWzQ5Ev7RKgadQtMBy7+V3XQ8R0NL8R9mu # pxcqJQ/KPeZGJTER+9Qq/t7HOQfBbDy6e0TepvBFV/RY3w+LOPMKn0Uoh2/8IvdS # bJ8qAWRVoz2S9VrJzZpB8/f5rQcRETgX/t8N66D2JlEXv4fZQB7XzcJMXr1puhuX # bOt9RYEyN1Q3Z7YjRkhfBsRc+SD/C9F4iwZqfQgo82GG4wguIhjJU7+XMfrv4vxA # FNVg3mn1PoMWGZWio+e14+PGYPVLKlad+0IhdHK5AgPyXKkqAhEZpYhYYVEItHOO # vqrwukxVAJXMvWA3GatWkRZn33WDJVtghCW6XPLi1cDKiGE5UcXZSV4OjQIUB8vp # 2LUMRXud5I49FIBcE9nT00z8A+EekrPM+OAk07aDfwZbdmZ56j7ub5fNDLf8yIb8 # QxZ8Mr4RwWy/czBuV5rkWQQ+msjJ5AKtYZxJdnaZehUgUNArU/u36SH1eXKMQGRX # r/xeKFGI8vvv5Jl1knZ8UqEQr9PxDbis7OXp2WSMK5lLGdYVH8VownYF3sbOiRkx # 5Q5GaEyTehOQp2SfdbsJZlg0SXmHphGnoW1/gQ/5P6BgSq4PAWIZaDJj6AvLLCdb # URgR5apNQQed2zYUgUbjACA/TomA8Ll7Arrv2oZGiUO5Vdi4xxtA3BRTQTUCAwEA # AaOCAUkwggFFMB0GA1UdDgQWBBTwqyIJ3QMoPasDcGdGovbaY8IlNjAfBgNVHSME # GDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5odHRw # Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUaW1l # LVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwGCCsG # AQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01p # Y3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNVHRMB # Af8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDAN # BgkqhkiG9w0BAQsFAAOCAgEA1a72WFq7B6bJT3VOJ21nnToPJ9O/q51bw1bhPfQy # 67uy+f8x8akipzNL2k5b6mtxuPbZGpBqpBKguDwQmxVpX8cGmafeo3wGr4a8Yk6S # y09tEh/Nwwlsyq7BRrJNn6bGOB8iG4OTy+pmMUh7FejNPRgvgeo/OPytm4NNrMMg # 98UVlrZxGNOYsifpRJFg5jE/Yu6lqFa1lTm9cHuPYxWa2oEwC0sEAsTFb69iKpN0 # sO19xBZCr0h5ClU9Pgo6ekiJb7QJoDzrDoPQHwbNA87Cto7TLuphj0m9l/I70gLj # Eq53SHjuURzwpmNxdm18Qg+rlkaMC6Y2KukOfJ7oCSu9vcNGQM+inl9gsNgirZ6y # Jk9VsXEsoTtoR7fMNU6Py6ufJQGMTmq6ZCq2eIGOXWMBb79ZF6tiKTa4qami3US0 # mTY41J129XmAglVy+ujSZkHu2lHJDRHs7FjnIXZVUE5pl6yUIl23jG50fRTLQcSt # dwY/LvJUgEHCIzjvlLTqLt6JVR5bcs5aN4Dh0YPG95B9iDMZrq4rli5SnGNWev5L # LsDY1fbrK6uVpD+psvSLsNpht27QcHRsYdAMALXM+HNsz2LZ8xiOfwt6rOsVWXoi # HV86/TeMy5TZFUl7qB59INoMSJgDRladVXeT9fwOuirFIoqgjKGk3vO2bELrYMN0 # QVwwggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZAAAAAAAVMA0GCSqGSIb3DQEB # CwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYD # VQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAe # Fw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0 # YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5OGm # TOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4XYDP/XE/H # ZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTzxXb1hlDc # wUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7uhp7M62A # W36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928jaTjkY+yOSxRnOlwaQ3KNi1w # jjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3tpK56KTesy+uDRedGbsoy1cCG # MFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGaRnXNxF803RKJ # 1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fzpk03dJQcNIIP # 8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9ahhaYQFz # ymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5UPkLiWHz # NgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReTwDwV2xo3 # xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZMBIGCSsG # AQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8RjUpzxD/ # LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAEVTBTMFEG # DCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29m # dC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYIKwYB # BQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8G # A1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQw # VgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9j # cmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUF # BwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3Br # aS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcNAQEL # BQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9MTO1OdfC # cTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2LpypglYAA7AF # vonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OOPcbzaN9l # 9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8DJ6LGYnn # 8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmRsqlb30mjdAy87JGA0j3mSj5m # O0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8x1RtnWN0SCyx # TkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjcZxkoJLo4 # S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq77EFmPWn9 # y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJC4822rpM # +Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328y+l7vzhw # RNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIDWTCCAkEC # AQEwggEBoYHZpIHWMIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0 # ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjozMjFBLTA1RTAtRDk0NzElMCMG # A1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIa # AxUA8YrutmKpSrubCaAYsU4pt1Ft8DaggYMwgYCkfjB8MQswCQYDVQQGEwJVUzET # MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV # TWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1T # dGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsFAAIFAO4L5PUwIhgPMjAyNjA3MjMw # MDU1MTdaGA8yMDI2MDcyNDAwNTUxN1owdzA9BgorBgEEAYRZCgQBMS8wLTAKAgUA # 7gvk9QIBADAKAgEAAgIV9gIB/zAHAgEAAgITRjAKAgUA7g02dQIBADA2BgorBgEE # AYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYag # MA0GCSqGSIb3DQEBCwUAA4IBAQBB9hNYVFxZadHilpCjPGYY0sJJBQuX5FDPLhRU # NRvAoBDfmZZrkRMxgXHndD+Kw1BzXXG8ADSPByxrfT33CG/ymh8eH0bN9VdABY6T # LNvflz2sQObz/D3gfIJjNzQR//Lnz2orOnPveQRm/So7Y0c0Fx/o1PuScEcnf4nF # SlboeXW9Cj0ASoFdKVMn8mgpdPNIxdrliM/3pwtHwVrmrsQZD0LpkMVZd4IjWOVx # vLhfM0KpEGLhOdtrZWU7M4TAySXhUn6yGO990IgYc3ber0f9o+lxIVmohL4IYNXn # /eanwBH8zquJOJGHEBKxHdB/MIJ4wWpI0dg+vFQHYKt+GW0lMYIEDTCCBAkCAQEw # gZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT # B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UE # AxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAIaqaAdBqAPQ6oA # AQAAAhowDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0B # CRABBDAvBgkqhkiG9w0BCQQxIgQgH6OdooQ1GTyiYsTB6vmZjg2MhIGYztKGGOl/ # nchQpfUwgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCCdeiHHrbtpKcwB20do # VU89WHIOH8S7w37uaHcDmemK+zCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w # IFBDQSAyMDEwAhMzAAACGqmgHQagD0OqAAEAAAIaMCIEIHlgfm/sfsHLUPFhb1pq # N9qijIR2ObVWxnCXMTkty2e1MA0GCSqGSIb3DQEBCwUABIICAJL4edfZauI38o2e # 4IvRjawB/0kRlj9Isl6ndUfR+e+sfN0b389u/udXQ0QJZwjNk5qYU6mycVgjf3c6 # 4zJkz6Z73uWftiOEuQQj1A1Zx/aO7kRT3ilQRtf1+CZj9mJTO6aY57MJ5suUHT6N # KsdQASqDo3Qtq10i0BwJEv9RqoN3pR3Bwsz8839Q0d5751chRKwALXGl/zu/Tjzt # JjF9CSYkZtgjnBFpt1UcrvhpoMQebs4EV0ILJk5kJfEBAcMbcjUTDPsaS82hoQWK # QWPfj4xzDm6OkiQ9y+8w75aKBe+KesnEPugh5S6yNcVNoklziFI3L4KzNqi9kHA5 # pK/PH8umUD0mFl3EzKlzysAZuXskncUp1+01ThSUBrgiC+MZcOJMmdYtZRqYrBO5 # fXc5qysv50oCCK5iM4KVrUQWZLih5e9t+LIJfRPnRFazhSlwbj699MOC/UlXJ0L1 # Zto/eDRiB9D/bCGxo5KxOreMexfcOGHCbDCsEqfeoqQS+yBZr03B+loJfHq7f4pP # VtIjGjOZPnJfsYomKf8b9aivvMf9a0UzKzKBkuxcEq56JooszdsNw/CjHV/C475l # +KDyqvrLAEFFL6dBq/bXssFYQvhkLe8aMJ1KmKl2fCsoT4veBYx6jwUuW1mtw9Qm # xf6+/UNcmGuCDC60ZBUg3ZR5Zovk # SIG # End signature block |