Framework/Listeners/RemoteReports/AIOrgTelemetry.ps1
Set-StrictMode -Version Latest class AIOrgTelemetry: ListenerBase { [Microsoft.ApplicationInsights.TelemetryClient] $TelemetryClient; hidden AIOrgTelemetry() { $this.TelemetryClient = [Microsoft.ApplicationInsights.TelemetryClient]::new() } hidden static [AIOrgTelemetry] $Instance = $null; static [AIOrgTelemetry] GetInstance() { if ( $null -eq [AIOrgTelemetry]::Instance -or $null -eq [AIOrgTelemetry]::Instance.TelemetryClient) { [AIOrgTelemetry]::Instance = [AIOrgTelemetry]::new(); } return [AIOrgTelemetry]::Instance } [void] RegisterEvents() { $this.UnregisterEvents(); $this.RegisterEvent([AzSKRootEvent]::GenerateRunIdentifier, { $currentInstance = [AIOrgTelemetry]::GetInstance(); try { $runIdentifier = [AzSKRootEventArgument] ($Event.SourceArgs | Select-Object -First 1) $currentInstance.SetRunIdentifier($runIdentifier); } catch { $currentInstance.PublishException($_); } }); $this.RegisterEvent([SVTEvent]::EvaluationCompleted, { $currentInstance = [AIOrgTelemetry]::GetInstance(); try { if(![RemoteReportHelper]::IsAIOrgTelemetryEnabled()) { return; }; $invocationContext = [System.Management.Automation.InvocationInfo] $currentInstance.InvocationContext $SVTEventContexts = [SVTEventContext[]] $Event.SourceArgs $featureGroup = [RemoteReportHelper]::GetFeatureGroup($SVTEventContexts) if($featureGroup -eq [FeatureGroup]::Subscription){ $currentInstance.PushSubscriptionScanResults($SVTEventContexts) }elseif($featureGroup -eq [FeatureGroup]::Service){ $currentInstance.PushServiceScanResults($SVTEventContexts) }else{ } } catch { $currentInstance.PublishException($_); } }); $this.RegisterEvent([AzSKGenericEvent]::Exception, { $currentInstance = [AIOrgTelemetry]::GetInstance(); try { if(![RemoteReportHelper]::IsAIOrgTelemetryEnabled()) { return; }; [System.Management.Automation.ErrorRecord] $er = ($Event.SourceArgs | Select-Object -First 1) [AIOrgTelemetryHelper]::TrackException($er, $currentInstance.InvocationContext) } catch { # Handling error while registration of Exception event. # No need to break execution } }); $this.RegisterEvent([AzSKRootEvent]::CommandError, { $currentInstance = [AIOrgTelemetry]::GetInstance(); try { if(![RemoteReportHelper]::IsAIOrgTelemetryEnabled()) { return; }; [System.Management.Automation.ErrorRecord] $er = $Event.SourceArgs.ExceptionMessage [AIOrgTelemetryHelper]::TrackException($er, $currentInstance.InvocationContext) } catch { # Handling error while registration of CommandError event at AzSKRoot. # No need to break execution } }); $this.RegisterEvent([SVTEvent]::CommandError, { $currentInstance = [AIOrgTelemetry]::GetInstance(); try { if(![RemoteReportHelper]::IsAIOrgTelemetryEnabled()) { return; }; [System.Management.Automation.ErrorRecord] $er = $Event.SourceArgs.ExceptionMessage [AIOrgTelemetryHelper]::TrackException($er, $currentInstance.InvocationContext) } catch { # Handling error while registration of CommandError event at SVT. # No need to break execution } }); $this.RegisterEvent([SVTEvent]::EvaluationError, { $currentInstance = [AIOrgTelemetry]::GetInstance(); try { if(![RemoteReportHelper]::IsAIOrgTelemetryEnabled()) { return; }; [System.Management.Automation.ErrorRecord] $er = $Event.SourceArgs.ExceptionMessage [AIOrgTelemetryHelper]::TrackException($er, $currentInstance.InvocationContext) } catch { # Handling error while registration of EvaluationError event at SVT. # No need to break execution } }); $this.RegisterEvent([SVTEvent]::ControlError, { $currentInstance = [AIOrgTelemetry]::GetInstance(); try { if(![RemoteReportHelper]::IsAIOrgTelemetryEnabled()) { return; }; [System.Management.Automation.ErrorRecord] $er = $Event.SourceArgs.ExceptionMessage [AIOrgTelemetryHelper]::TrackException($er, $currentInstance.InvocationContext) } catch { # Handling error while registration of ControlError event at SVT. # No need to break execution } }); } hidden [void] PushSubscriptionScanResults([SVTEventContext[]] $SVTEventContexts) { $SVTEventContextFirst = $SVTEventContexts[0] $baseProperties = @{ "RunIdentifier" = $this.RunIdentifier; [TelemetryKeys]::FeatureGroup = [FeatureGroup]::Subscription; "ScanKind" = [RemoteReportHelper]::GetSubscriptionScanKind( $this.InvocationContext.MyCommand.Name, $this.InvocationContext.BoundParameters); "SubscriptionMetadata" = [JsonHelper]::ConvertToJsonCustomCompressed($SVTEventContextFirst.SubscriptionContext.SubscriptionMetadata); } $this.PushControlResults($SVTEventContexts, $baseProperties) } hidden [void] PushServiceScanResults([SVTEventContext[]] $SVTEventContexts) { $SVTEventContextFirst = $SVTEventContexts[0] # PartialScanIdentifier for each control scanned event to get idea about all resources scanned for a subscription in case of partial run $PartialScanIdentifier = "" # try catch for cases if partial scan is not applicable try{ $PartialScanIdentifier = $SVTEventContextFirst.PartialSCanIdentifier } catch{ $PartialScanIdentifier = "" } $baseProperties = @{ "RunIdentifier" = $this.RunIdentifier; [TelemetryKeys]::FeatureGroup = [FeatureGroup]::Service; "ScanKind" = [RemoteReportHelper]::GetServiceScanKind( $this.InvocationContext.MyCommand.Name, $this.InvocationContext.BoundParameters); "Feature" = $SVTEventContextFirst.FeatureName; "ResourceGroup" = $SVTEventContextFirst.ResourceContext.ResourceGroupName; "ResourceName" = $SVTEventContextFirst.ResourceContext.ResourceName; "ResourceId" = $SVTEventContextFirst.ResourceContext.ResourceId; "ResourceMetadata" = [JsonHelper]::ConvertToJsonCustomCompressed($SVTEventContextFirst.ResourceContext.ResourceMetadata); "PartialScanIdentifier" = $PartialScanIdentifier } $this.PushControlResults($SVTEventContexts, $baseProperties) } hidden [void] PushControlResults([SVTEventContext[]] $SVTEventContexts, [hashtable] $BaseProperties){ $telemetryEvents = [System.Collections.ArrayList]::new() foreach($context in $SVTEventContexts){ $propertiesCollection = $this.AttachControlProperties($BaseProperties, $context) foreach($properties in $propertiesCollection){ $telemetryEvent = "" | Select-Object Name, Properties, Metrics $telemetryEvent.Name = "Control Scanned" $telemetryEvent.Properties = $properties $telemetryEvent = [AIOrgTelemetry]::SetCommonProperties($telemetryEvent); $telemetryEvents.Add($telemetryEvent) | Out-Null } } [AIOrgTelemetryHelper]::TrackEvents($telemetryEvents); } hidden [hashtable[]] AttachControlProperties([hashtable] $BaseProperties, [SVTEventContext] $context){ if($null -eq $context) {return ([hashtable[]]([System.Collections.ArrayList]::new()))} $properties = @{} if ($null -ne $BaseProperties) { $properties = $BaseProperties.Clone() } $propertiesArray = [System.Collections.ArrayList]::new() $properties.Add("ControlIntId", $context.ControlItem.Id); $properties.Add("ControlId", $context.ControlItem.ControlID); $properties.Add("ControlSeverity", $context.ControlItem.ControlSeverity); $properties.Add("IsBaselineControl", $context.ControlItem.IsBaselineControl) #add PreviewBaselineFlag $properties.Add("IsPreviewBaselineControl", $context.ControlItem.IsPreviewBaselineControl) if (!$context.ControlItem.Enabled) { $properties.Add("VerificationResult", [VerificationResult]::Disabled) $properties.Add("AttestationStatus", [AttestationStatus]::None) $propertiesArray.Add($properties) | Out-Null }else{ $results = $context.ControlResults if($results.Count -eq 1){ $properties.Add("HasAttestationWritePermissions", $results[0].CurrentSessionContext.Permissions.HasAttestationWritePermissions) $properties.Add("HasAttestationReadPermissions", $results[0].CurrentSessionContext.Permissions.HasAttestationReadPermissions) $properties.Add("ActualVerificationResult", $results[0].ActualVerificationResult) $properties.Add("AttestationStatus", $results[0].AttestationStatus) $properties.Add("VerificationResult", $results[0].VerificationResult) $properties.Add("HasRequiredAccess", $results[0].CurrentSessionContext.Permissions.HasRequiredAccess) $properties.Add("TimeTakenInMs", $results[0].TimeTakenInMs) $properties.Add("ScanStartDateTime", $results[0].ScanStartDateTime) $properties.Add("ScanEndDateTime", $results[0].ScanEndDateTime) if($null -ne $context.ResourceContext){ if($context.ResourceContext.ResourceName -eq $results[0].ChildResourceName -or [string]::IsNullOrWhiteSpace($results[0].ChildResourceName)){ $properties.Add("IsNestedResource", 'No') $properties.Add("NestedResourceName", "NA") }else{ $properties.Add("IsNestedResource", 'Yes') $properties.Add("NestedResourceName", $results[0].ChildResourceName) } } if(($null -ne $results[0].StateManagement) -and ($null -ne $results[0].StateManagement.AttestedStateData)) { $properties.Add("AttestedBy", $results[0].StateManagement.AttestedStateData.AttestedBy) $properties.Add("Justification", $results[0].StateManagement.AttestedStateData.Justification) $properties.Add("AttestedState", [JsonHelper]::ConvertToJsonCustomCompressed($results[0].StateManagement.AttestedStateData.DataObject)) $properties.Add("AttestedDate", ($results[0].StateManagement.AttestedStateData.AttestedDate).Tostring("yyyy_MM_dd_hh_mm")) $properties.Add("ExpiryDate", ([DateTime]$results[0].StateManagement.AttestedStateData.ExpiryDate).Tostring("yyyy_MM_dd_hh_mm")) } if(($null -ne $results[0].StateManagement) -and ($null -ne $results[0].StateManagement.CurrentStateData)) { $properties.Add("CurrentState", [JsonHelper]::ConvertToJsonCustomCompressed($results[0].StateManagement.CurrentStateData.DataObject)) } $propertiesArray.Add($properties) | Out-Null }elseif($results.Count -gt 1){ $properties.Add("IsNestedResource", 'Yes') foreach($result in $results){ $propertiesIn = $properties.Clone() $propertiesIn.Add("ActualVerificationResult", $result.ActualVerificationResult) $propertiesIn.Add("AttestationStatus", $result.AttestationStatus) $propertiesIn.Add("VerificationResult", $result.VerificationResult) $propertiesIn.Add("NestedResourceName", $result.ChildResourceName) $propertiesIn.Add("HasRequiredAccess", $result.CurrentSessionContext.Permissions.HasRequiredAccess) if(($null -ne $result.StateManagement) -and ($null -ne $result.StateManagement.AttestedStateData)) { $propertiesIn.Add("AttestedBy", $result.StateManagement.AttestedStateData.AttestedBy) $propertiesIn.Add("Justification", $result.StateManagement.AttestedStateData.Justification) $propertiesIn.Add("AttestedState", [JsonHelper]::ConvertToJsonCustomCompressed($result.StateManagement.AttestedStateData.DataObject)) $propertiesIn.Add("AttestedDate", ($result.StateManagement.AttestedStateData.AttestedDate).Tostring("yyyy_MM_dd_hh_mm")) $propertiesIn.Add("ExpiryDate", ([DateTime]$result.StateManagement.AttestedStateData.ExpiryDate).Tostring("yyyy_MM_dd_hh_mm")) } if(($null -ne $result.StateManagement) -and ($null -ne $result.StateManagement.CurrentStateData)) { $propertiesIn.Add("CurrentState", [JsonHelper]::ConvertToJsonCustomCompressed($result.StateManagement.CurrentStateData.DataObject)) } $propertiesArray.Add($propertiesIn) | Out-Null } } } $returnObj = [hashtable[]] $propertiesArray return $returnObj; } static [psobject] SetCommonProperties([psobject] $telemetryEvent) { try { $NA = "NA"; try { $telemetryEvent.properties.Add("ScanSource", [RemoteReportHelper]::GetScanSource()); } catch { # Eat the current exception which typically happens when the property already exist in the object and try to add the same property again # No need to break execution } try { $module = Get-Module 'AzSK*' | Select-Object -First 1 $telemetryEvent.properties.Add("ScannerModuleName", $module.Name); $telemetryEvent.properties.Add("ScannerVersion", $module.Version.ToString()); $telemetryEvent.properties.Add("OrgVersion", [ConfigurationManager]::GetAzSKConfigData().GetLatestAzSKVersion($module.Name).ToString()); $telemetryEvent.properties.Add("PolicyOrgName", [ConfigurationManager]::GetAzSKConfigData().PolicyOrgName) $AzSKLatestVersion= [ConfigurationManager]::GetAzSKConfigData().GetAzSKLatestPSGalleryVersion($module.Name) $telemetryEvent.properties.Add("LatestVersion", $AzSKLatestVersion); } catch { # Eat the current exception which typically happens when the property already exist in the object and try to add the same property again # No need to break execution } try { $azureContext = [ContextHelper]::GetCurrentContext() try { $telemetryEvent.properties.Add([TelemetryKeys]::SubscriptionId, $azureContext.Subscription.Id) } catch { # Eat the current exception which typically happens when the property already exist in the object and try to add the same property again # No need to break execution } try { $telemetryEvent.properties.Add([TelemetryKeys]::SubscriptionName, $azureContext.Subscription.Name) } catch { # Eat the current exception which typically happens when the property already exist in the object and try to add the same property again # No need to break execution } try { $telemetryEvent.properties.Add("AzureEnv", $azureContext.Environment.Name) } catch { # Eat the current exception which typically happens when the property already exist in the object and try to add the same property again # No need to break execution } try { $telemetryEvent.properties.Add("TenantId", $azureContext.Tenant.Id) } catch { # Eat the current exception which typically happens when the property already exist in the object and try to add the same property again # No need to break execution } try { $telemetryEvent.properties.Add("AccountId", $azureContext.Account.Id) } catch { # Eat the current exception which typically happens when the property already exist in the object and try to add the same property again # No need to break execution } try { if ($telemetryEvent.Properties.ContainsKey("RunIdentifier")) { $actualRunId = $telemetryEvent.Properties["RunIdentifier"] if ($telemetryEvent.Properties.ContainsKey("UniqueRunIdentifier")) { $telemetryEvent.Properties["UniqueRunIdentifier"] = [RemoteReportHelper]::Mask($azureContext.Account.Id + '##' + $actualRunId.ToString()) } else { $telemetryEvent.properties.Add("UniqueRunIdentifier", [RemoteReportHelper]::Mask($azureContext.Account.Id + '##' + $actualRunId.ToString())) } } } catch { # Eat the current exception which typically happens when the property already exist in the object and try to add the same property again # No need to break execution } try { $telemetryEvent.properties.Add("AccountType", $azureContext.Account.Type); } catch { # Eat the current exception which typically happens when the property already exist in the object and try to add the same property again # No need to break execution } } catch { # Eat the current exception which typically happens when the property already exist in the object and try to add the same property again # No need to break execution } } catch { # Eat the current exception which typically happens when the property already exist in the object and try to add the same property again # No need to break execution } return $telemetryEvent; } } # SIG # Begin signature block # MIIjpQYJKoZIhvcNAQcCoIIjljCCI5ICAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDzCxr9uMoAvCFM # ffQWPD4CdjsUOHVcpyFH2MH7NAlXdaCCDYUwggYDMIID66ADAgECAhMzAAABiK9S # 1rmSbej5AAAAAAGIMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ4WhcNMjEwMzAzMTgzOTQ4WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQCSCNryE+Cewy2m4t/a74wZ7C9YTwv1PyC4BvM/kSWPNs8n0RTe+FvYfU+E9uf0 # t7nYlAzHjK+plif2BhD+NgdhIUQ8sVwWO39tjvQRHjP2//vSvIfmmkRoML1Ihnjs # 9kQiZQzYRDYYRp9xSQYmRwQjk5hl8/U7RgOiQDitVHaU7BT1MI92lfZRuIIDDYBd # vXtbclYJMVOwqZtv0O9zQCret6R+fRSGaDNfEEpcILL+D7RV3M4uaJE4Ta6KAOdv # V+MVaJp1YXFTZPKtpjHO6d9pHQPZiG7NdC6QbnRGmsa48uNQrb6AfmLKDI1Lp31W # MogTaX5tZf+CZT9PSuvjOCLNAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUj9RJL9zNrPcL10RZdMQIXZN7MG8w # VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh # dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzQ1ODM4NjAfBgNVHSMEGDAW # gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw # MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx # XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB # ACnXo8hjp7FeT+H6iQlV3CcGnkSbFvIpKYafgzYCFo3UHY1VHYJVb5jHEO8oG26Q # qBELmak6MTI+ra3WKMTGhE1sEIlowTcp4IAs8a5wpCh6Vf4Z/bAtIppP3p3gXk2X # 8UXTc+WxjQYsDkFiSzo/OBa5hkdW1g4EpO43l9mjToBdqEPtIXsZ7Hi1/6y4gK0P # mMiwG8LMpSn0n/oSHGjrUNBgHJPxgs63Slf58QGBznuXiRaXmfTUDdrvhRocdxIM # i8nXQwWACMiQzJSRzBP5S2wUq7nMAqjaTbeXhJqD2SFVHdUYlKruvtPSwbnqSRWT # GI8s4FEXt+TL3w5JnwVZmZkUFoioQDMMjFyaKurdJ6pnzbr1h6QW0R97fWc8xEIz # LIOiU2rjwWAtlQqFO8KNiykjYGyEf5LyAJKAO+rJd9fsYR+VBauIEQoYmjnUbTXM # SY2Lf5KMluWlDOGVh8q6XjmBccpaT+8tCfxpaVYPi1ncnwTwaPQvVq8RjWDRB7Pa # 8ruHgj2HJFi69+hcq7mWx5nTUtzzFa7RSZfE5a1a5AuBmGNRr7f8cNfa01+tiWjV # Kk1a+gJUBSP0sIxecFbVSXTZ7bqeal45XSDIisZBkWb+83TbXdTGMDSUFKTAdtC+ # r35GfsN8QVy59Hb5ZYzAXczhgRmk7NyE6jD0Ym5TKiW5MIIHejCCBWKgAwIBAgIK # 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/Xmfwb1tbWrJUnMTDXpQzTGCFXYwghVyAgEBMIGVMH4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p # Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAGIr1LWuZJt6PkAAAAA # AYgwDQYJYIZIAWUDBAIBBQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIKCN # KbqCR6n7uaSvPxUfIn8m5eo3GmnYsAVvCcfx8yj8MEQGCisGAQQBgjcCAQwxNjA0 # oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEcgBpodHRwczovL3d3dy5taWNyb3NvZnQu # Y29tIDANBgkqhkiG9w0BAQEFAASCAQAT3TRpx1cYN4u60C2T5it/1LDWF7HTwr5T # D0m2B2HrnhPemCnnmJAgE0ZsekEqtA6eeyxOzSUx2ceYehp2E/NiRFqf96cnVK7K # i/INX+tVdHnO9XK5WcWQ2T0gRvHJQLrvrcf1PF4sdbU9QPPAOGWTs9KlLkK8OuFn # Bbx6PGhBGHVz8SCFbMuvQW7vg/8cdq60scmIB8wQxJs4GinOhaZYvYKmWJINfSbB # YvV7NbZJkwVjrhr5u7cDUCPyBPgnlutohRbE2zXif4pZvS7jgHKwAtz19SOFWlvW # 9SrX/2GL5NcVElMZ06RYme8z+730dEQJiChr5VXkOJfbSO2ztJ9soYIS/jCCEvoG # CisGAQQBgjcDAwExghLqMIIS5gYJKoZIhvcNAQcCoIIS1zCCEtMCAQMxDzANBglg # hkgBZQMEAgEFADCCAVkGCyqGSIb3DQEJEAEEoIIBSASCAUQwggFAAgEBBgorBgEE # AYRZCgMBMDEwDQYJYIZIAWUDBAIBBQAEIJ7kDjbbXc8Ra/wLW9KJl8RdjuQxUSOq # wkdxTfzx+FmiAgZfvGeecjcYEzIwMjEwMTE1MTEwNzQ4Ljg1MVowBIACAfSggdik # gdUwgdIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNV # BAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEmMCQGA1UE # CxMdVGhhbGVzIFRTUyBFU046RTA0MS00QkVFLUZBN0UxJTAjBgNVBAMTHE1pY3Jv # c29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wggg5NMIIE+TCCA+GgAwIBAgITMwAAATdB # j0PnWltvpwAAAAABNzANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFt # cCBQQ0EgMjAxMDAeFw0yMDEwMTUxNzI4MTRaFw0yMjAxMTIxNzI4MTRaMIHSMQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNy # b3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxl # cyBUU1MgRVNOOkUwNDEtNEJFRS1GQTdFMSUwIwYDVQQDExxNaWNyb3NvZnQgVGlt # ZS1TdGFtcCBTZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA # xBHuadElm3G5tikhTzjSDB0+9sXmUhUyDVRj0Y4vz9rZ9sykNobL5/6At5zOkeB2 # bl9IXvVdyS/ZJNZT373knzrQ347z30Mmw7++VU/CE+4x4w9kb5bqQHfSzbJQt6Km # WsuMmJLzg4R5MeJs5MY5YdPLxoMoDRcTi//KoMFR0KzS1/324D2/4KkHD1Xt+s0x # Y0DICUOK1RbmJCKEgBP1/GDZjuZQBS9Di89yTnvLJV+Lr1QtriH4EqmRoAdmV3zJ # 0GJsr5vhGPmKfOPCRSk7Q8igX7goFnCLzpYcfHGCqoR/mw95gfQpwymVwxZB0PkG # MrQw+LKVPa/FHP4C4KO+QQIDAQABo4IBGzCCARcwHQYDVR0OBBYEFA1gsHMM+udg # Y7rEne66OyzxlE9lMB8GA1UdIwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYG # A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3Js # L3Byb2R1Y3RzL01pY1RpbVN0YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcB # AQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kv # Y2VydHMvTWljVGltU3RhUENBXzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAw # EwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggEBAJ32U9d90RVu # AUb9NsnXBG1K42qjhU+jHvwBdbipIcX4Wg7dH5ZduQZj3gWgKADZ5z+TehX7GnBb # i265VI7xDRsFe2CjkTm4JIoisdKwYBDruS+YRRBG4B1ERuWi54XGwx+lSA+iQNrI # i6Jm0CL/MfQLvwsqPJSGP69OEHCyaExos486+X3JTuGV11CBl/BO7r8UHbx/rE6f # ZrlZZYabIF6aeahvTL14LvZLV/bMzYSODsbjHHsTm9QaGm1ijhagCdbkAqr8+7HA # gYEar8XPlzxUhVI4ShVB5ZGd9gZ2yBkwxdA0oFc745TdOPrbP79vd0ePqgvJDH5t # kOhTRNI55XQwggZxMIIEWaADAgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUA # MIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQD # EylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0x # MDA3MDEyMTM2NTVaFw0yNTA3MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w # IFBDQSAyMDEwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcR # ijog7PwTl/X6f2mUa3RUENWlCgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9B # GxqVHc4JE458YTBZsTBED/FgiIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HN # vyRgMlhgRvJYR4YyhB50YWeRX4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScd # JGcSchohiq9LZIlQYrFd/XcfPfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u # 5ZrKsajyeioKMfDaTgaRtogINeh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJ # RF1eFpwBBU8iTQIDAQABo4IB5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0O # BBYEFNVjOlyKMZDzQ3t8RhvFM2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIA # QwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2 # VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwu # bWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEw # LTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYt # MjMuY3J0MIGgBgNVHSABAf8EgZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEF # BQcCARYxaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZh # dWx0Lmh0bTBABggrBgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMA # eQBfAFMAdABhAHQAZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aI # UQ3ixuCYP4FxAz2do6Ehb7Prpsz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ie # JeP5vO1rVFcIK1GCRBL7uVOMzPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMiv # v3/Gf/I3fVo/HPKZeUqRUgCvOA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOl # lo9ZKby2/QThcJ8ySif9Va8v/rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbi # OewZSnFjnXshbcOco6I8+n99lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4 # tYCbIjggtSXlZOz39L9+Y1klD3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ # 732D8OE7cQnfXXSYIghh2rBQHm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293 # qYHLpwmsObvsxsvYgrRyzR30uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAz # LhIp9cAvVCch98isTtoouLGp25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZ # ii8bxyGvWbWu3EQ8l1Bx16HSxVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gF # Lu8NoFA12u8JJxzVs341Hgi62jbb01+P3nSISRKhggLXMIICQAIBATCCAQChgdik # gdUwgdIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNV # BAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEmMCQGA1UE # CxMdVGhhbGVzIFRTUyBFU046RTA0MS00QkVFLUZBN0UxJTAjBgNVBAMTHE1pY3Jv # c29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoBATAHBgUrDgMCGgMVAOq7qDk4iVz8 # ITuZbUFrAG7ecxqcoIGDMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw # MTAwDQYJKoZIhvcNAQEFBQACBQDjq3ObMCIYDzIwMjEwMTE1MDk1MTIzWhgPMjAy # MTAxMTYwOTUxMjNaMHcwPQYKKwYBBAGEWQoEATEvMC0wCgIFAOOrc5sCAQAwCgIB # AAICGMcCAf8wBwIBAAICEecwCgIFAOOsxRsCAQAwNgYKKwYBBAGEWQoEAjEoMCYw # DAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0B # AQUFAAOBgQBwcZX6Y3gvj3dxoaJ4MGIDQFkLEVc3qcEbmLh+YmCZ6oIfLVThQmEt # yoT6MiUBkLr0K5OpNSH3zQYBGAL0Gj8LtNjidfgMDOd2PUuI5AS8IFjl6qpzqiyA # RkpXB2dV2HzM5cE8NGjOCf7r8G7h8rGxD55L2l0zkGyUBlHQY+A9JDGCAw0wggMJ # AgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAk # BgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABN0GPQ+da # W2+nAAAAAAE3MA0GCWCGSAFlAwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZI # hvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIBSQpBkX6/Xi37syL680ikNoSJsEVvnl # LFijPE2dqjRbMIH6BgsqhkiG9w0BCRACLzGB6jCB5zCB5DCBvQQgHVl+r8CeBJ0i # yX/aGZD2YbQ7gk+U7N7BQiTDKAYSHBAwgZgwgYCkfjB8MQswCQYDVQQGEwJVUzET # MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV # TWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1T # dGFtcCBQQ0EgMjAxMAITMwAAATdBj0PnWltvpwAAAAABNzAiBCCk3QRV8oW5Wm1C # kpNrH4nYV065c5hrucA0+kZbUZrFvTANBgkqhkiG9w0BAQsFAASCAQCJ2WtmZn5E # 9FGkN3xVyHpM9CVSm3fUyiL+lRiA43P/OQYYZIh/SyABE43pG9k8fSaHAgvukt6I # dSeT6DMWi6u/GfsRwdA2k0YP3Ue5ZeMKYjDE/59Ecf1MkFQV4RZVQ3q7gz7YzI7+ # YeP3xICdm4QAJTAbgDusqtgYTRNO3vK6EJJuws+QvGsxkMDxarkELkdmSJW1caqF # Ann5mdMMt5Z9LROMZtU2TSMfi2cEcewWBo/eFflSmoqwoABtyGFeLqmb63vIXgi7 # Grfu3D+QpjYQrLGF6hLVICcSylLZ5vR8JSkR/x3dhO8lO9Gc602doU5xWOD98Od3 # PHBgSDamhYP3 # SIG # End signature block |