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]::Organization){ $currentInstance.PushOrganizationScanResults($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] PushOrganizationScanResults([SVTEventContext[]] $SVTEventContexts) { $SVTEventContextFirst = $SVTEventContexts[0] $baseProperties = @{ "RunIdentifier" = $this.RunIdentifier; [TelemetryKeys]::FeatureGroup = [FeatureGroup]::Organization; "ScanKind" = [RemoteReportHelper]::GetOrganizationScanKind( $this.InvocationContext.MyCommand.Name, $this.InvocationContext.BoundParameters); "OrganizationMetadata" = [JsonHelper]::ConvertToJsonCustomCompressed($SVTEventContextFirst.OrganizationContext.OrganizationMetadata); } $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 { $organizationContext = [ContextHelper]::GetCurrentContext() try { $telemetryEvent.properties.Add([TelemetryKeys]::OrganizationId, $organizationContext.Organization.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]::OrganizationName, $organizationContext.Organization.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("ADOEnv", $organizationContext.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", $organizationContext.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", $organizationContext.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($organizationContext.Account.Id + '##' + $actualRunId.ToString()) } else { $telemetryEvent.properties.Add("UniqueRunIdentifier", [RemoteReportHelper]::Mask($organizationContext.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", $organizationContext.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 # MIIjjAYJKoZIhvcNAQcCoIIjfTCCI3kCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD9f55MdS/g3QqT # VrRD6jwwrM2oOf+4e/7GBRtndKZpSaCCDYUwggYDMIID66ADAgECAhMzAAAB4HFz # JMpcmPgZAAAAAAHgMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjAxMjE1MjEzMTQ2WhcNMjExMjAyMjEzMTQ2WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDRXpc9eiGRI/2BlmU7OMiQPTKpNlluodjT2rltPO/Gk47bH4gBShPMD4BX/4sg # NvvBun6ZOG2dxUW30myWoUJJ0iRbTAv2JFzjSpVQvPE+D5vtmdu6WlOR2ahF4leF # 5Vvk4lPg2ZFrqg5LNwT9gjwuYgmih+G2KwT8NMWusBhO649F4Ku6B6QgA+vZld5S # G2XWIdvS0pmpmn/HFrV4eYTsl9HYgjn/bPsAlfWolLlEXYTaCljK7q7bQHDBrzlR # ukyyryFpPOR9Wx1cxFJ6KBqg2jlJpzxjN3udNJPOqarnQIVgB8DUm3I5g2v5xTHK # Ovz9ucN21467cYcIxjPC4UkDAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUVBWIZHrG4UIX3uX4142l+8GsPXAw # VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh # dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzQ2MzAxMDAfBgNVHSMEGDAW # gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw # MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx # XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB # AE5msNzmYzYbNgpnhya6YsrM+CIC8CXDu10nwzZtkgQciPOOqAYmFcWJCwD5VZzs # qFwad8XIOrfCylWf4hzn09mD87yuazpuCstLSqfDLNd3740+254vEZqdGxOglAGU # ih2IiF8S0GDwucpLGzt/OLXPFr/d4MWxPuX0L+HB5lA3Y/CJE673dHGQW2DELdqt # ohtkhp+oWFn1hNDDZ3LP++HEZvA7sI/o/981Sh4kaGayOp6oEiQuGeCXyfrIC9KX # eew0UlYX/NHVDqr4ykKkqpHtzbUbuo7qovUHPbYKcRGWrrEtBS5SPLFPumqsRtzb # LgU9HqfRAN36bMsd2qynGyWBVFOM7NMs2lTCGM85Z/Fdzv/8tnYT36Cmbue+IM+6 # kS86j6Ztmx0VIFWbOvNsASPT6yrmYiecJiP6H0TrYXQK5B3jE8s53l+t61ab0Eul # 7DAxNWX3lAiUlzKs3qZYQEK1LFvgbdTXtBRnHgBdABALK3RPrieIYqPln9sAmg3/ # zJZi4C/c2cWGF6WwK/w1Nzw08pj7jaaZZVBpCeDe+y7oM26QIXxracot7zJ21/TL # 70biK36YybSUDkjhQPP/uxT0yebLNBKk7g8V98Wna2MsHWwk0sgqpkjIp02TrkVz # 26tcF2rml2THRSDrwpBa4x9c8rM8Qomiyeh2tEJnsx2LMIIHejCCBWKgAwIBAgIK # 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/Xmfwb1tbWrJUnMTDXpQzTGCFV0wghVZAgEBMIGVMH4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p # Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAHgcXMkylyY+BkAAAAA # AeAwDQYJYIZIAWUDBAIBBQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIP3+ # 2lS2X3cCtSzFLvsWrDw2DLHIxThawheEvrI5Ehd/MEQGCisGAQQBgjcCAQwxNjA0 # oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEcgBpodHRwczovL3d3dy5taWNyb3NvZnQu # Y29tIDANBgkqhkiG9w0BAQEFAASCAQAD3yTNvDOAXQidDPO8eusqQFtWedaia/YV # dqJ09Iro1zsW0AwMPxojXp+H1kowACJdxhCg3VFR0nCK9JAe5eJToekdcA5URu8u # fu2y9jXZzTkNmegPtvPhQTSREx0f6h7BPA0k/JIisXIJxoVD48LKnNUTWCpti/re # IwtaIZ1kz1wW7VBPhWIjx+cdW1cvTZFfR6SgTHpsuuBYLhdeck3kM4RJiPH+O9RE # AiUoaf6wyyBLTb3soEnkuSoJ3Gn+FXIRck1IW0G4YXQjv5RxKakHQ5WaYT0h1+Ok # KaHvtwPCKfUTcf8R/K1+wk5oZzESPh6/keI6jNwfCkMyh4XOZsFaoYIS5TCCEuEG # CisGAQQBgjcDAwExghLRMIISzQYJKoZIhvcNAQcCoIISvjCCEroCAQMxDzANBglg # hkgBZQMEAgEFADCCAVEGCyqGSIb3DQEJEAEEoIIBQASCATwwggE4AgEBBgorBgEE # AYRZCgMBMDEwDQYJYIZIAWUDBAIBBQAEILFRi8NoAat1dqn0kje9iXLQbI2ps4ax # HWoEqvtB7A4CAgZg+YUlONcYEzIwMjEwODE2MDczNzEwLjY5OFowBIACAfSggdCk # gc0wgcoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNV # BAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJjAkBgNVBAsTHVRoYWxl # cyBUU1MgRVNOOjQ5QkMtRTM3QS0yMzNDMSUwIwYDVQQDExxNaWNyb3NvZnQgVGlt # ZS1TdGFtcCBTZXJ2aWNloIIOPDCCBPEwggPZoAMCAQICEzMAAAFJgAhKuwmgMwsA # AAAAAUkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw # MTAwHhcNMjAxMTEyMTgyNTU3WhcNMjIwMjExMTgyNTU3WjCByjELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFt # ZXJpY2EgT3BlcmF0aW9uczEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046NDlCQy1F # MzdBLTIzM0MxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Uw # ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvE/uJD4XYdtp6OSoZPkol # G9p3CWcwLle1XkQMluEejNzIQMeWMsd8ZbujdfjJfWG/c3SOmZBwUAWEfVSdlCaM # ayt8gQHkKFikoD/bY1Q4y7Rfda7sCJw8CXf5wfLqzsGMvKkhtBFGOhqN/YqQm5j7 # B0c9qq128i40lrrspOm31Vel+UAqlVt1L7Jb5MGKMWmEaoQpgvLGQq9NPBDMdgVj # m1XwFFVcpeBRWWn3Vb0UCWA6tqRuFLLaOsheYCA/jw6zw3+UwITm3JmnQVMIr9HA # LgvKY2uS7lnSKiEaKRjb1oB1v0U0s8WPzkgbVpsyro+Uml2v7VreagzQzwvR+dWt # AgMBAAGjggEbMIIBFzAdBgNVHQ4EFgQUVnea8aPvuLS8NTXWT8mpc+pvJIEwHwYD # VR0jBBgwFoAU1WM6XIoxkPNDe3xGG8UzaFqFbVUwVgYDVR0fBE8wTTBLoEmgR4ZF # aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljVGlt # U3RhUENBXzIwMTAtMDctMDEuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcw # AoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNUaW1TdGFQ # Q0FfMjAxMC0wNy0wMS5jcnQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEF # BQcDCDANBgkqhkiG9w0BAQsFAAOCAQEAEN54Cz4g7OBKqc8iwqLzNdQj2OCTxKmH # +jr3Ayp+AY/1qw4d77A/4WCP8g8PdToYiC47UXC6Fd2epJ07Olen50f88rFAz49H # 5BV7XlwPjiyE1ZU0vLKHiCcB2mibalui7W0dtg4W4bIqi7UlQkhBLERS5nn+zHYQ # g/rFQUQvvJrKpx2NM0MFgv2hki4B3JkDUfFwoHxYbAAJR1UtXaH+0PG1BW5yL1DL # s451q7D/RsHGmvx1M6+RKSr3qCUicbfQEa8vaP+nKJ0T/Da5vSqpSKocfD8dwM3U # nn0tpoC+lKmqQMDbllghGs7NVhps+9xG95s7beCMr3AuUZG/E6RQaTCCBnEwggRZ # oAMCAQICCmEJgSoAAAAAAAIwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290 # IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTEwMDcwMTIxMzY1NVoXDTI1 # MDcwMTIxNDY1NVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggEiMA0G # CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpHQ28dxGKOiDs/BOX9fp/aZRrdFQQ # 1aUKAIKF++18aEssX8XD5WHCdrc+Zitb8BVTJwQxH0EbGpUdzgkTjnxhMFmxMEQP # 8WCIhFRDDNdNuDgIs0Ldk6zWczBXJoKjRQ3Q6vVHgc2/JGAyWGBG8lhHhjKEHnRh # Z5FfgVSxz5NMksHEpl3RYRNuKMYa+YaAu99h/EbBJx0kZxJyGiGKr0tkiVBisV39 # dx898Fd1rL2KQk1AUdEPnAY+Z3/1ZsADlkR+79BL/W7lmsqxqPJ6Kgox8NpOBpG2 # iAg16HgcsOmZzTznL0S6p/TcZL2kAcEgCZN4zfy8wMlEXV4WnAEFTyJNAgMBAAGj # ggHmMIIB4jAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU1WM6XIoxkPNDe3xG # G8UzaFqFbVUwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGG # MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186a # GMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3Br # aS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsG # AQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwgaAGA1UdIAEB # /wSBlTCBkjCBjwYJKwYBBAGCNy4DMIGBMD0GCCsGAQUFBwIBFjFodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vUEtJL2RvY3MvQ1BTL2RlZmF1bHQuaHRtMEAGCCsGAQUF # BwICMDQeMiAdAEwAZQBnAGEAbABfAFAAbwBsAGkAYwB5AF8AUwB0AGEAdABlAG0A # ZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQAH5ohRDeLG4Jg/gXEDPZ2joSFv # s+umzPUxvs8F4qn++ldtGTCzwsVmyWrf9efweL3HqJ4l4/m87WtUVwgrUYJEEvu5 # U4zM9GASinbMQEBBm9xcF/9c+V4XNZgkVkt070IQyK+/f8Z/8jd9Wj8c8pl5SpFS # AK84Dxf1L3mBZdmptWvkx872ynoAb0swRCQiPM/tA6WWj1kpvLb9BOFwnzJKJ/1V # ry/+tuWOM7tiX5rbV0Dp8c6ZZpCM/2pif93FSguRJuI57BlKcWOdeyFtw5yjojz6 # f32WapB4pm3S4Zz5Hfw42JT0xqUKloakvZ4argRCg7i1gJsiOCC1JeVk7Pf0v35j # WSUPei45V3aicaoGig+JFrphpxHLmtgOR5qAxdDNp9DvfYPw4TtxCd9ddJgiCGHa # sFAeb73x4QDf5zEHpJM692VHeOj4qEir995yfmFrb3epgcunCaw5u+zGy9iCtHLN # HfS4hQEegPsbiSpUObJb2sgNVZl6h3M7COaYLeqN4DMuEin1wC9UJyH3yKxO2ii4 # sanblrKnQqLJzxlBTeCG+SqaoxFmMNO7dDJL32N79ZmKLxvHIa9Zta7cRDyXUHHX # odLFVeNp3lfB0d4wwP3M5k37Db9dT+mdHhk4L7zPWAUu7w2gUDXa7wknHNWzfjUe # CLraNtvTX4/edIhJEqGCAs4wggI3AgEBMIH4oYHQpIHNMIHKMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l # cmljYSBPcGVyYXRpb25zMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo0OUJDLUUz # N0EtMjMzQzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIj # CgEBMAcGBSsOAwIaAxUAP+Wxrucu9GSImwAdD52BRGupqHeggYMwgYCkfjB8MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy # b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIFAOTET58w # IhgPMjAyMTA4MTYxMDQ0NDdaGA8yMDIxMDgxNzEwNDQ0N1owdzA9BgorBgEEAYRZ # CgQBMS8wLTAKAgUA5MRPnwIBADAKAgEAAgITAAIB/zAHAgEAAgIRQzAKAgUA5MWh # HwIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6Eg # oQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAFCd7PUH6+kXolD20GOkkJtj # YE825du6Bi4VhGi/VwiUvADWP7BgtuYllrGVFhCWsbJUaO2C6Fh4wnY3LvxzlZ8l # xmdyNxjiw2WVT6tfuPKktHpU8resH0C5RxNBPau0pr+tmVeyhFXSq4bkGaRL0nux # /EE5LukWS0L2e65dBQrYMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3Rh # bXAgUENBIDIwMTACEzMAAAFJgAhKuwmgMwsAAAAAAUkwDQYJYIZIAWUDBAIBBQCg # ggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQg # QUqpnRF6E5i9NXzcnR87EZKgTZI+w6LrnkYL0vhOcQIwgfoGCyqGSIb3DQEJEAIv # MYHqMIHnMIHkMIG9BCAolfr8WH1478zdhngQdSqc7DQL0sZx0OXG9a0fueihsjCB # mDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAk # BgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABSYAISrsJ # oDMLAAAAAAFJMCIEIAPaeiwqsk4VQF+zmAtSvpoJ0qmKmHZJzxW8ma6zHpi3MA0G # CSqGSIb3DQEBCwUABIIBAGGucj83fyGkVgNN1hr+VhARmUpkaaQtKkFlfO6rRSRg # XvB4CxIe54a92B4rDV9Zm/8v8NzcqJvOJP9m6NUFMtrfzcVQFgvSwMoI9xpfIUSr # G44e1BsROKGAePXijL986zXOgIjuHvsMjUr6omeNw+MJEGaEQkVeA2szgSjamqT4 # uW9KDlLTc5F65N79HVUROi01WyajoIX/o92qNAzA1I/IA+mtV7jbaiTutqmBWuJf # 3s4kfffAHhXN+0ughFrl4smqssnp3zQyNaFp5ah2cMIv1ytj8ARYruZlZsePb4AL # HoroQzgTSxwpveuOSo7vfTNSpqGh1qixKNkCYR+RrAw= # SIG # End signature block |