internal/Write-AppInsightsException.ps1
<# .SYNOPSIS Write Exception to Application Insights. .EXAMPLE PS C:\>Write-AppInsightsEvent $exception Write Exception to Application Insights. .INPUTS System.Exception #> function Write-AppInsightsException { [CmdletBinding()] [Alias('Write-AIException')] param ( # Exceptions [Parameter(Mandatory = $true, ParameterSetName = 'Exception', Position = 1)] [Exception[]] $Exception, # ErrorRecords [Parameter(Mandatory = $true, ParameterSetName = 'ErrorRecord', Position = 1)] [System.Management.Automation.ErrorRecord[]] $ErrorRecord, # Severity Level [Parameter(Mandatory = $false)] [ValidateSet('Verbose', 'Information', 'Warning', 'Error', 'Critical')] [string] $SeverityLevel, # Custom Properties [Parameter(Mandatory = $false)] [hashtable] $Properties, # Custom Ordered Properties. An ordered dictionary can be defined as: [ordered]@{ first = '1'; second = '2' } [Parameter(Mandatory = $false)] [System.Collections.Specialized.OrderedDictionary] $OrderedProperties, # Include process processor and memory usage statistics. [Parameter(Mandatory = $false)] [switch] $IncludeProcessStatistics, # Instrumentation Key [Parameter(Mandatory = $false)] [string] $InstrumentationKey = $script:ModuleConfig.'ai.instrumentationKey', # Ingestion Endpoint [Parameter(Mandatory = $false)] [string] $IngestionEndpoint = $script:ModuleConfig.'ai.ingestionEndpoint' ) begin { ## Return Immediately when Telemetry is Disabled if ($script:ModuleConfig.'ai.disabled') { return } ## Application Insights Exception Helper Functions # https://github.com/microsoft/ApplicationInsights-dotnet/blob/81288f26921df1e8e713d31e7e9c2187ac9e6590/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/ExceptionConverter.cs#L9 Set-Variable MaxParsedStackLength -Value 32768 -Option Constant <# .SYNOPSIS Convert Exceptions Tree to ExceptionDetails .LINK https://github.com/microsoft/ApplicationInsights-dotnet/blob/81288f26921df1e8e713d31e7e9c2187ac9e6590/BASE/src/Microsoft.ApplicationInsights/DataContracts/ExceptionTelemetry.cs#L386 #> function ConvertExceptionTree ([Exception] $exception, [hashtable] $parentExceptionDetails, [System.Collections.Generic.List[hashtable]] $exceptions) { if ($null -eq $exception) { $exception = New-Object Exception -ArgumentList 'n/a' } [hashtable] $exceptionDetails = ConvertToExceptionDetails $exception $parentExceptionDetails ## For upper level exception see if Message was provided and do not use exceptiom.message in that case #if ($null -eq $parentExceptionDetails -and ![string]::IsNullOrWhiteSpace($this.Message)) { # $exceptionDetails.message = $this.Message #} $exceptions.Add($exceptionDetails) [AggregateException] $aggregate = $exception -as [AggregateException] if ($null -ne $aggregate) { foreach ($inner in $aggregate.InnerExceptions) { ConvertExceptionTree $inner $exceptionDetails $exceptions } } elseif ($null -ne $exception.InnerException) { ConvertExceptionTree $exception.InnerException $exceptionDetails $exceptions } } <# .SYNOPSIS Converts a Exception to a Microsoft.ApplicationInsights.Extensibility.Implementation.TelemetryTypes.ExceptionDetails. .LINK https://github.com/microsoft/ApplicationInsights-dotnet/blob/81288f26921df1e8e713d31e7e9c2187ac9e6590/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/ExceptionConverter.cs#L14 #> function ConvertToExceptionDetails ([Exception]$exception, [hashtable]$parentExceptionDetails) { [hashtable] $exceptionDetails = CreateWithoutStackInfo $exception $parentExceptionDetails $stack = New-Object System.Diagnostics.StackTrace -ArgumentList $Exception, $true $frames = $stack.GetFrames() $sanitizedTuple = SanitizeStackFrame $frames $exceptionDetails['parsedStack'] = $sanitizedTuple[0] $exceptionDetails['hasFullStack'] = $sanitizedTuple[1] return $exceptionDetails } <# .SYNOPSIS Creates a new instance of ExceptionDetails from a Exception and a parent ExceptionDetails. .LINK https://github.com/microsoft/ApplicationInsights-dotnet/blob/81288f26921df1e8e713d31e7e9c2187ac9e6590/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/External/ExceptionDetailsImplementation.cs#L13 #> function CreateWithoutStackInfo ([Exception]$exception, [hashtable]$parentExceptionDetails) { if ($null -eq $exception) { throw (New-Object ArgumentNullException -ArgumentList $exception.GetType().Name) } [hashtable] $exceptionDetails = [ordered]@{ id = $exception.GetHashCode() typeName = $exception.GetType().FullName message = $exception.Message } if ($null -ne $parentExceptionDetails) { $exceptionDetails.outerId = $parentExceptionDetails.id } return $exceptionDetails } <# .SYNOPSIS Sanitizing stack to 32k while selecting the initial and end stack trace. .LINK https://github.com/microsoft/ApplicationInsights-dotnet/blob/81288f26921df1e8e713d31e7e9c2187ac9e6590/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/ExceptionConverter.cs#L93 #> function SanitizeStackFrame ([System.Diagnostics.StackFrame[]]$inputList) { [System.Collections.Generic.List[hashtable]] $orderedStackTrace = New-Object System.Collections.Generic.List[hashtable] [bool] $hasFullStack = $true if ($null -ne $inputList -and $inputList.Count -gt 0) { [int] $currentParsedStackLength = 0 for ($level = 0; $level -lt $inputList.Count; $level++) { ## Skip middle part of the stack [int] $current = if ($level % 2 -eq 0) { ($inputList.Count - 1 - ($level / 2)) } else { ($level / 2) } [hashtable] $convertedStackFrame = GetStackFrame $inputList[$current] $current $currentParsedStackLength += GetStackFrameLength $convertedStackFrame if ($currentParsedStackLength -gt $MaxParsedStackLength) { $hasFullStack = $false break } $orderedStackTrace.Insert($orderedStackTrace.Count / 2, $convertedStackFrame) } } return $orderedStackTrace, $hasFullStack } <# .SYNOPSIS Converts a System.Diagnostics.StackFrame to a Microsoft.ApplicationInsights.Extensibility.Implementation.TelemetryTypes.StackFrame. .LINK https://github.com/microsoft/ApplicationInsights-dotnet/blob/81288f26921df1e8e713d31e7e9c2187ac9e6590/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/ExceptionConverter.cs#L36 #> function GetStackFrame ([System.Diagnostics.StackFrame]$stackFrame, [int]$frameId) { [hashtable] $convertedStackFrame = [ordered]@{ level = $frameId } $methodInfo = $stackFrame.GetMethod() [string] $fullName = $null [string] $assemblyName = $null if ($null -eq $methodInfo) { $fullName = "unknown" $assemblyName = "unknown" } else { $assemblyName = $methodInfo.Module.Assembly.FullName if ($null -ne $methodInfo.DeclaringType) { $fullName = $methodInfo.DeclaringType.FullName + "." + $methodInfo.Name } else { $fullName = $methodInfo.Name } } $convertedStackFrame['method'] = $fullName $convertedStackFrame['assembly'] = $assemblyName $convertedStackFrame['fileName'] = $stackFrame.GetFileName() ## 0 means it is unavailable [int] $line = $stackFrame.GetFileLineNumber() if ($line -ne 0) { $convertedStackFrame['line'] = $line } return $convertedStackFrame } <# .SYNOPSIS Gets the stack frame length for only the strings in the stack frame. .LINK https://github.com/microsoft/ApplicationInsights-dotnet/blob/81288f26921df1e8e713d31e7e9c2187ac9e6590/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/ExceptionConverter.cs#L82 #> function GetStackFrameLength ([hashtable]$stackFrame) { [int] $stackFrameLength = if ($null -eq $stackFrame.method) { 0 } else { $stackFrame.method.Length } $stackFrameLength += if ($null -eq $stackFrame.assembly) { 0 } else { $stackFrame.assembly.Length } $stackFrameLength += if ($null -eq $stackFrame.fileName) { 0 } else { $stackFrame.fileName.Length } return $stackFrameLength } } process { ## Return Immediately when Telemetry is Disabled if ($script:ModuleConfig.'ai.disabled') { return } switch ($PSCmdlet.ParameterSetName) { 'Exception' { $InputObjects = $Exception break } 'ErrorRecord' { $InputObjects = $ErrorRecord break } } foreach ($InputObject in $InputObjects) { ## Get New Telemetry Entry $AppInsightsTelemetry = New-AppInsightsTelemetry 'AppExceptions' -InstrumentationKey $InstrumentationKey ## Determine ErrorRecord from Exception input [Exception] $InputException = $null if ($InputObject -is [System.Management.Automation.ErrorRecord]) { $InputException = $InputObject.Exception $AppInsightsTelemetry.data.baseData['properties']['ScriptStackTrace'] = $InputObject.ScriptStackTrace.Replace($MyInvocation.MyCommand.Module.ModuleBase,'') } elseif ($InputObject -is [System.Management.Automation.ErrorRecord]) { $InputException = $InputObject } if ($InputException) { ## Get Exception Details [System.Collections.Generic.List[hashtable]] $exceptions = New-Object System.Collections.Generic.List[hashtable] ConvertExceptionTree $InputException $null $exceptions $AppInsightsTelemetry.data.baseData['exceptions'] = $exceptions } ## Update Telemetry Data if ($SeverityLevel) { $AppInsightsTelemetry.data.baseData['severityLevel'] = $SeverityLevel } if ($IncludeProcessStatistics) { $PsProcess = Get-Process -PID $PID $AppInsightsTelemetry.data.baseData['properties']['TotalProcessorTime'] = $PsProcess.TotalProcessorTime.ToString() $AppInsightsTelemetry.data.baseData['properties']['VirtualMemorySize'] = Format-NumberWithUnit $PsProcess.VM 'B' $AppInsightsTelemetry.data.baseData['properties']['WorkingSetMemorySize'] = Format-NumberWithUnit $PsProcess.WS 'B' $AppInsightsTelemetry.data.baseData['properties']['PagedMemorySize'] = Format-NumberWithUnit $PsProcess.PM 'B' $AppInsightsTelemetry.data.baseData['properties']['NonpagedMemorySize'] = Format-NumberWithUnit $PsProcess.NPM 'B' $AppInsightsTelemetry.data.baseData['properties']['PeakVirtualMemorySize'] = Format-NumberWithUnit $PsProcess.PeakVirtualMemorySize64 'B' $AppInsightsTelemetry.data.baseData['properties']['PeakWorkingSetMemorySize'] = Format-NumberWithUnit $PsProcess.PeakWorkingSet64 'B' $AppInsightsTelemetry.data.baseData['properties']['PeakPagedMemorySize'] = Format-NumberWithUnit $PsProcess.PeakPagedMemorySize64 'B' $AppInsightsTelemetry.data.baseData['properties']['TotalProcessorTimeInSeconds'] = $PsProcess.CPU $AppInsightsTelemetry.data.baseData['properties']['VirtualMemoryInBytes'] = $PsProcess.VM $AppInsightsTelemetry.data.baseData['properties']['WorkingSetMemoryInBytes'] = $PsProcess.WS $AppInsightsTelemetry.data.baseData['properties']['PagedMemoryInBytes'] = $PsProcess.PM $AppInsightsTelemetry.data.baseData['properties']['NonpagedMemoryInBytes'] = $PsProcess.NPM $AppInsightsTelemetry.data.baseData['properties']['PeakVirtualMemoryInBytes'] = $PsProcess.PeakVirtualMemorySize64 $AppInsightsTelemetry.data.baseData['properties']['PeakWorkingSetMemoryInBytes'] = $PsProcess.PeakWorkingSet64 $AppInsightsTelemetry.data.baseData['properties']['PeakPagedMemoryInBytes'] = $PsProcess.PeakPagedMemorySize64 } if ($OrderedProperties) { $AppInsightsTelemetry.data.baseData['properties'] += $OrderedProperties } if ($Properties) { $AppInsightsTelemetry.data.baseData['properties'] += $Properties } ## Write Data to Application Insights Write-Debug (([PSCustomObject]$AppInsightsTelemetry) | ConvertTo-Json -Depth 6) try { $result = Invoke-RestMethod -UseBasicParsing -Method Post -Uri $IngestionEndpoint -ContentType 'application/json' -Body ($AppInsightsTelemetry | ConvertTo-Json -Depth 6 -Compress) -Verbose:$false -ErrorAction SilentlyContinue } catch {} } } } # SIG # Begin signature block # MIInogYJKoZIhvcNAQcCoIInkzCCJ48CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDF2J5js01OOz6S # ohgVP2gcMAo7rLwC3cKsPwRXJk56vaCCDYUwggYDMIID66ADAgECAhMzAAACzfNk # v/jUTF1RAAAAAALNMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjIwNTEyMjA0NjAyWhcNMjMwNTExMjA0NjAyWjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDrIzsY62MmKrzergm7Ucnu+DuSHdgzRZVCIGi9CalFrhwtiK+3FIDzlOYbs/zz # HwuLC3hir55wVgHoaC4liQwQ60wVyR17EZPa4BQ28C5ARlxqftdp3H8RrXWbVyvQ # aUnBQVZM73XDyGV1oUPZGHGWtgdqtBUd60VjnFPICSf8pnFiit6hvSxH5IVWI0iO # nfqdXYoPWUtVUMmVqW1yBX0NtbQlSHIU6hlPvo9/uqKvkjFUFA2LbC9AWQbJmH+1 # uM0l4nDSKfCqccvdI5l3zjEk9yUSUmh1IQhDFn+5SL2JmnCF0jZEZ4f5HE7ykDP+ # oiA3Q+fhKCseg+0aEHi+DRPZAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU0WymH4CP7s1+yQktEwbcLQuR9Zww # VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh # dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzQ3MDUzMDAfBgNVHSMEGDAW # gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw # MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx # XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB # AE7LSuuNObCBWYuttxJAgilXJ92GpyV/fTiyXHZ/9LbzXs/MfKnPwRydlmA2ak0r # GWLDFh89zAWHFI8t9JLwpd/VRoVE3+WyzTIskdbBnHbf1yjo/+0tpHlnroFJdcDS # MIsH+T7z3ClY+6WnjSTetpg1Y/pLOLXZpZjYeXQiFwo9G5lzUcSd8YVQNPQAGICl # 2JRSaCNlzAdIFCF5PNKoXbJtEqDcPZ8oDrM9KdO7TqUE5VqeBe6DggY1sZYnQD+/ # LWlz5D0wCriNgGQ/TWWexMwwnEqlIwfkIcNFxo0QND/6Ya9DTAUykk2SKGSPt0kL # tHxNEn2GJvcNtfohVY/b0tuyF05eXE3cdtYZbeGoU1xQixPZAlTdtLmeFNly82uB # VbybAZ4Ut18F//UrugVQ9UUdK1uYmc+2SdRQQCccKwXGOuYgZ1ULW2u5PyfWxzo4 # BR++53OB/tZXQpz4OkgBZeqs9YaYLFfKRlQHVtmQghFHzB5v/WFonxDVlvPxy2go # a0u9Z+ZlIpvooZRvm6OtXxdAjMBcWBAsnBRr/Oj5s356EDdf2l/sLwLFYE61t+ME # iNYdy0pXL6gN3DxTVf2qjJxXFkFfjjTisndudHsguEMk8mEtnvwo9fOSKT6oRHhM # 9sZ4HTg/TTMjUljmN3mBYWAWI5ExdC1inuog0xrKmOWVMIIHejCCBWKgAwIBAgIK # YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm # aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw # OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD # VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG # 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la # UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc # 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D # dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+ # lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk # kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6 # A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd # X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL # 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd # sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3 # T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS # 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI # bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL # BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD # uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv # c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF # BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h # cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA # YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn # 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7 # v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b # pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/ # KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy # CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp # mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi # hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb # BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS # oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL # gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX # cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCGXMwghlvAgEBMIGVMH4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p # Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAALN82S/+NRMXVEAAAAA # As0wDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIHxt # NjXKYcz8fx5yxDhJm5DF3Xnri59meOPyLQ6oJ3jvMEIGCisGAQQBgjcCAQwxNDAy # oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20wDQYJKoZIhvcNAQEBBQAEggEAUoNOqp5SI1wlkte//5+gZY1omhRnxVF10JB3 # F6PidPSJMIUWj9bY0u/x4vOgb09khxVIy3XylnTqTOvmSVRp3imBhFP1ug0cGo8J # vcT8uLtyhUQ+zGhxg+kv29wB0pXfjr8e4BILUkX3XIpZr0ODFVL/zAHQDPPUoi/u # INiDbZStx6OD+GpuycAGyj3etS1ManQNmc/UrQC5n1A/69Fe31xDntNVzLvssvW6 # yT/GBE59j87U9+f7NaDTM5x0j/MzndFZcLuHXhiKJwqu2dPx8H8Shnvxqe9N5H2x # iFttsswxNdNVsDcKUiIwTdDCUoi8VaOFACJFhknVZnG7GRYOEaGCFv0wghb5Bgor # BgEEAYI3AwMBMYIW6TCCFuUGCSqGSIb3DQEHAqCCFtYwghbSAgEDMQ8wDQYJYIZI # AWUDBAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGE # WQoDATAxMA0GCWCGSAFlAwQCAQUABCATyBeqPpW//E4u3C6n83aJge5s82TFQmXQ # TjkBi7J9UwIGYxFjXkqjGBMyMDIyMDkwNjIxNDAyNy4zNTVaMASAAgH0oIHQpIHN # MIHKMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQL # ExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMSYwJAYDVQQLEx1UaGFsZXMg # VFNTIEVTTjpBRTJDLUUzMkItMUFGQzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt # U3RhbXAgU2VydmljZaCCEVQwggcMMIIE9KADAgECAhMzAAABlklbYuEv3fdPAAEA # AAGWMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw # MB4XDTIxMTIwMjE5MDUxM1oXDTIzMDIyODE5MDUxM1owgcoxCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVy # aWNhIE9wZXJhdGlvbnMxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOkFFMkMtRTMy # Qi0xQUZDMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIC # IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0h9sEAtvrf48wOoy+i2TIQzS # RtJ79XFKnvh+DBishIEWVMKdWLB5dSExsovCva5D0SiigItJU/ING9RiIqZFnPKg # rRN8Im8aDUeJgsq74BLF7rZ28SNaG8fHDH2tl4HIRv1wRmXBbRndFEL15MVGL6JH # xtU8gTKpyGb0Ni7XJho/OpWj0TbkaHZBDO1VVDtqDEhyW2kzY9W9pAAvLKpcrR9c # 5n60KUwN62TshJssE+Nw0X7DZV5pDSjIluwWnzZx2SxhxmnKYphOHaAzLq98oh/6 # ggsdjzuKSKpAOlixkjfMoWGr3EGURVbbJf8fyIri9H8TxqUJkXPOJuNcmrp3L3jY # f+f9eDKrGe7oGNYsfH5DmICQZS7LPJsj4WjAOqnBAf0VlqnAn4cgETYwnJgTRjV3 # jICsmf/nt2wjpV5lng7VSQy5jrcxAwS5pINv3rad0/YTl/i6HWMHQZGNp6AgxMz1 # lWvN+AJpCb0espxHgRo+qLlon6V8WqGwXWrG9Pq//XmK/k9NMqyxZ9eq601C51c5 # Fu5S8l1hKLrL82J7pdxzwkKKEEuC2NRwSk8k0n7Rl+emYDs+0ZPnrL23K/jYy7wQ # cu13qJoJLsNRf1K7u5WfQEfhEG6YNqbwh0mqzEEB239Rlz4ZQ0x8JHrJEYs+Yz40 # 69Vs/3/vQmceaL7UxdECAwEAAaOCATYwggEyMB0GA1UdDgQWBBTS3wjZLC5lrSBh # LImLhCqa0c10sjAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNV # HR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2Ny # bC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYI # KwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAy # MDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0G # CSqGSIb3DQEBCwUAA4ICAQCvYAsQuCFW2ClUARz+c7SXP5H4Erm3C+YU0XlRNbsE # lSqfdkn3fyCLxYBkHMFZQGXPA7mzoU7IZUdn0hXyuvrFM6DDrn/SLShe5t+PPkqW # eOeYiEw8k4BI6l4U5k07wX8hBwOoMRxs1aOe/JNkLHO6krl5j6/GZHrkTRzTsRUU # Jp1FpnUzixiZWyavc0x/imG5yWdrSuccE9ndoq7Qbu1Pxa7swsUm5zNNMunaWGXD # FAnS7s8RxJ1/P3qTtZ0Ja6VE6SeoHpdj7/hPuKJLXV/M89GNFn8HUDmVW5+YK/8D # y7yKHHiiSd+ugAN+pW3PA6OYek0ryW1QKzbrW4P9SXAk+U5faXjBJoitW98+ZERW # X387VHvaTWJ4Yo5BmkJ0U27Aal2ggi5j1PYuDxB3DsofM+7ebc4zgJ0GF4u6DQW0 # V4rc/F2zytl2rDQfUGlPtNUymUZVbWJbFqw64je8QsAnMeG1J8ohxjYlea3iLAzG # wime4dbMSyEHoObVvzIN0d9BJ84xVeXKvET176GhY/PS6RTJZiW5PPihZh88F3Je # cEvhlct/FbpQPt+mhDOBQAyqjI1tdBQlBFVX85xWd1JRnUkuxqshXqFwcxKr8GiF # sb9AV7y7TT30fmMTs3gmnojFQt3MdD5Q3M/gBf1TdlhyiPNXTgJhP6iyZHfxKZi2 # czCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZIhvcNAQEL # BQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNV # BAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4X # DTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3Rh # bXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDk4aZM # 57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25PhdgM/9cT8dm # 95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPFdvWGUNzB # RMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6GnszrYBb # fowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBpDco2LXCO # Mcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50ZuyjLVwIYw # XE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3EXzTdEonW # /aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0lBw0gg/w # EPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1qGFphAXPK # Z6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ+QuJYfM2 # BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PAPBXbGjfH # CBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkwEgYJKwYB # BAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxGNSnPEP8v # BO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARVMFMwUQYM # KwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0 # LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAKBggrBgEF # BQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD # VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBW # BgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny # bC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUH # AQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtp # L2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG9w0BAQsF # AAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0xM7U518Jx # Nj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmCVgADsAW+ # iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449xvNo32X2 # pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wMnosZiefw # C2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDSPeZKPmY7 # T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2dY3RILLFO # Ry3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxnGSgkujhL # mm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+CrvsQWY9af3L # wUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokLjzbaukz5 # m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL6Xu/OHBE # 0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggLLMIICNAIB # ATCB+KGB0KSBzTCByjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEmMCQGA1UE # CxMdVGhhbGVzIFRTUyBFU046QUUyQy1FMzJCLTFBRkMxJTAjBgNVBAMTHE1pY3Jv # c29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoBATAHBgUrDgMCGgMVAND6JppVWWnb # irQx4Ic7QWQ35lb+oIGDMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw # MTAwDQYJKoZIhvcNAQEFBQACBQDmwdBRMCIYDzIwMjIwOTA2MjE1NzM3WhgPMjAy # MjA5MDcyMTU3MzdaMHQwOgYKKwYBBAGEWQoEATEsMCowCgIFAObB0FECAQAwBwIB # AAICCX0wBwIBAAICEdEwCgIFAObDIdECAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYK # KwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQUF # AAOBgQA8HJydZKNp+voJvcorEM3EWyNS61awFXD5sUEXTXu8AzGAvhbrS+VxvJnj # 6Kcw8PLae9pI6Sa6cLi2C4oukawJ50tY0Kb8yAWMu+UTGlINNkBkCnfs6joRFh4a # +a7fyPQC2/XYKexZ4l7xUlhKxvzFRFfCZRd70j8ABcOB/tr51DGCBA0wggQJAgEB # MIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV # BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABlklbYuEv3fdP # AAEAAAGWMA0GCWCGSAFlAwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcN # AQkQAQQwLwYJKoZIhvcNAQkEMSIEIAOQ4b/VhzROui0CtXYbLUXnCmuVVHL3hSgD # IU3Hrs7PMIH6BgsqhkiG9w0BCRACLzGB6jCB5zCB5DCBvQQgdgTWAvgdNdOSdkcu # gn52dCQPCX5WUEOrC6RyNy2yvZAwgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFt # cCBQQ0EgMjAxMAITMwAAAZZJW2LhL933TwABAAABljAiBCBVbVBuBL7VxMi6fefr # N4++XJIDCfhu0J83C2EpuIit/DANBgkqhkiG9w0BAQsFAASCAgA2kIWGNboeyZ3u # A13uqThwmXYhhaqZzctH8WLVLocnIFWNh+WT7InHe0IABnD51tZwcMRk7ZbMWS3I # J0VrvEx1a0ufwaM7+w746ZQ4jY6d8+y/c1vUN4jw+PI1+oZZkoDoNe25rflkh+52 # TTNYDqXLgHCQi2kiva5Hwmes1x19YY519oHAmTzugqM7CJgRk5I7fqhjGGK2hn4W # aS/S0DMiZn9+YJ/3+g2C9NCxF2Uq84rAlvmpzX5zCV9PXym7DSi8DG1qHyqfErHl # rDeHohIxoX6l/dlbQnksFSfPIZKmtPMjrMwl7kaw8YV7zJrNVi67LRHBtOaFPvRn # jeDb8Ho3HFerrghIUoVu5kE0zgl2iaecDXalYjPKuOPYJOk5F9uhij1k6A/myW5a # MqUJvTXoiw6F9lCO/QKfMpusdyOWkQe78eIDLm1URKKUP5MRAt4Ptsnk9RKsrH+M # tD/cXB+wYAH8BkT5MLvMhL/LVBsZh01URrLa8VFWYMc+OEaubdeDJhWiUZIHVtzS # j3OeCIgXGY5smgGNBoYCpvNb2guwAsOWAjSoTAeTbSllUOYuexut7kQ9qQSfQvoU # au0cNIA8/cD/Kn+Hmf0MT5PB8Kqm9HDHui0jLiZm/zb0yK3jh6hFwTTFN/WW/02J # GP+d0JYcDsSLMtWHZKysbVR20eaoAg== # SIG # End signature block |