Framework/BugLog/AutoBugLog.ps1
Set-StrictMode -Version Latest class AutoBugLog { hidden [ControlStateExtension] $ControlStateExt; hidden [SubscriptionContext] $SubscriptionContext; hidden [InvocationInfo] $InvocationContext; hidden [PSObject] $ControlSettings; hidden [SVTEventContext[]] $ControlResults; hidden [bool] $isBugLogCustomFlow = $false; hidden [bool] $ShowBugsInS360 = $false; AutoBugLog([SubscriptionContext] $subscriptionContext, [InvocationInfo] $invocationContext, [SVTEventContext[]] $ControlResults, [ControlStateExtension] $ControlStateExt) { $this.SubscriptionContext = $subscriptionContext; $this.InvocationContext = $invocationContext; $this.ControlResults = $ControlResults; $this.ControlSettings = [ConfigurationManager]::LoadServerConfigFile("ControlSettings.json"); $this.ControlStateExt = $ControlStateExt #flag to check if pluggable bug logging interface (service tree) if ([Helpers]::CheckMember($this.ControlSettings.BugLogging, "BugAssigneeAndPathCustomFlow", $null)) { $this.isBugLogCustomFlow = $this.ControlSettings.BugLogging.BugAssigneeAndPathCustomFlow; } } static [string] ComputeHashX([string] $dataToHash) { return [Helpers]::ComputeHashShort($dataToHash, [Constants]::AutoBugLogTagLen) } #main function where bug logging takes place hidden [void] LogBugInADO([SVTEventContext[]] $ControlResults, [string] $BugLogParameterValue) { #check if user has permissions to log bug for the current resource if (($ControlResults.ControlResults.VerificationResult -contains "Failed" -or $ControlResults.ControlResults.VerificationResult -contains "Verify") -and $this.CheckPermsForBugLog($ControlResults[0])) { #retrieve the project name for the current resource $ProjectName = $this.GetProjectForBugLog($ControlResults[0]) #check if the area and iteration path are valid if ([BugLogPathManager]::CheckIfPathIsValid($this.SubscriptionContext.SubscriptionName,$ProjectName,$this.InvocationContext, $this.ControlSettings.BugLogging.BugLogAreaPath, $this.ControlSettings.BugLogging.BugLogIterationPath, $this.isBugLogCustomFlow)) { #Obtain the assignee for the current resource, will be same for all the control failures for this particular resource $metaProviderObj = [BugMetaInfoProvider]::new(); $AssignedTo = $metaProviderObj.GetAssignee($ControlResults[0], $this.ControlSettings.BugLogging) $serviceId = $metaProviderObj.ServiceId #Set ShowBugsInS360 if customebuglog is enabled and sericeid not null and ShowBugsInS360 enabled in policy if ($this.isBugLogCustomFlow -and (-not [string]::IsNullOrEmpty($serviceId)) -and ([Helpers]::CheckMember($this.ControlSettings.BugLogging, "ShowBugsInS360") -and $this.ControlSettings.BugLogging.ShowBugsInS360) ) { $this.ShowBugsInS360 = $true; } else { $this.ShowBugsInS360 = $false; } #Obtain area and iteration paths $AreaPath = [BugLogPathManager]::GetAreaPath() $IterationPath = [BugLogPathManager]::GetIterationPath() $BugLoggingProject = [BugLogPathManager]::GetBugLoggingProject() #This project should be used to check if current bug exists or not #this falg is added to restrict 'Determining bug logging' message should print only once $printLogBugMsg = $true; #Loop through all the control results for the current resource $ControlResults | ForEach-Object { $control = $_; #filter controls on basis of whether they are baseline or not depending on the value given in autobuglog flag $LogControlFlag=$false if ($BugLogParameterValue -eq "All") { $LogControlFlag = $true } elseif ($BugLogParameterValue -eq "BaselineControls") { $LogControlFlag = $this.CheckBaselineControl($control.ControlItem.ControlID) } else { $LogControlFlag = $this.CheckPreviewBaselineControl($control.ControlItem.ControlID) } if ($LogControlFlag -and ($control.ControlResults[0].VerificationResult -eq "Failed" -or $control.ControlResults[0].VerificationResult -eq "Verify") ) { #compute hash of control Id and resource Id $hash = $this.GetHashedTag($control.ControlItem.Id, $control.ResourceContext.ResourceId) #check if a bug with the computed hash exists $workItem = $this.GetWorkItemByHash($hash, $BugLoggingProject) if ($workItem[0].results.count -gt 0) { #a work item with the hash exists, find if it's state and reactivate if resolved bug $this.ManageActiveAndResolvedBugs($ProjectName, $control, $workItem, $AssignedTo) } else { if($printLogBugMsg) { Write-Host "Determining bugs to log..." -ForegroundColor Cyan } $printLogBugMsg = $false; #filling the bug template $Title = "[ADOScanner] Control failure - {0} for resource {1} {2}" $Description = "Control failure - {3} for resource {4} {5} </br></br> <b>Control Description: </b> {0} </br></br> <b> Control Result: </b> {6} </br> </br> <b> Rationale:</b> {1} </br></br> <b> Recommendation:</b> {2}" $Title = $Title.Replace("{0}", $control.ControlItem.ControlID) $Title = $Title.Replace("{1}", $control.ResourceContext.ResourceTypeName) $Title = $Title.Replace("{2}", $control.ResourceContext.ResourceName) $Description = $Description.Replace("{0}", $control.ControlItem.Description) $Description = $Description.Replace("{1}", $control.ControlItem.Rationale) $Description = $Description.Replace("{2}", $control.ControlItem.Recommendation) $Description = $Description.Replace("{3}", $control.ControlItem.ControlID) $Description = $Description.Replace("{4}", $control.ResourceContext.ResourceTypeName) $Description = $Description.Replace("{5}", $control.ResourceContext.ResourceName) $Description = $Description.Replace("{6}", $control.ControlResults[0].VerificationResult) $RunStepsForControl = " </br></br> <b>Control Scan Command:</b> Run: {0}" $RunStepsForControl = $RunStepsForControl.Replace("{0}", $this.GetControlReproStep($control)) $Description += $RunStepsForControl #check and append any detailed log and state data for the control failure if ($this.GetDetailedLogForControl($control)) { $Description += "<hr></br><b>Some other details for your reference</b> </br><hr> {7} " $log = $this.GetDetailedLogForControl($control).Replace("\", "\\") $Description = $Description.Replace("{7}", $log) } $Description = $Description.Replace("`"", "'") $Severity = $this.GetSeverity($control.ControlItem.ControlSeverity) #function to attempt bug logging $this.AddWorkItem($Title, $Description, $AssignedTo, $AreaPath, $IterationPath, $Severity, $ProjectName, $control, $hash, $serviceId) } } } } } } #function to get the security command for repro of this bug hidden [string] GetControlReproStep([SVTEventContext []] $ControlResult){ $StepsForRepro="" if ($ControlResult.FeatureName -eq "Organization") { $StepsForRepro="Get-AzSKADOSecurityStatus -OrganizationName '{0}' -ControlIds '{1}'" $StepsForRepro=$StepsForRepro.Replace("{0}",$ControlResult.ResourceContext.ResourceName) $StepsForRepro=$StepsForRepro.Replace("{1}",$ControlResult.ControlItem.ControlID) } elseif ($ControlResult.ResourceContext.ResourceTypeName -eq "Project") { $StepsForRepro="Get-AzSKADOSecurityStatus -OrganizationName '{0}' -ProjectNames '{1}' -ControlIds '{2}'" $StepsForRepro=$StepsForRepro.Replace("{0}",$ControlResult.ResourceContext.ResourceGroupName) $StepsForRepro=$StepsForRepro.Replace("{1}",$ControlResult.ResourceContext.ResourceName) $StepsForRepro=$StepsForRepro.Replace("{2}",$ControlResult.ControlItem.ControlID) } else { $StepsForRepro="Get-AzSKADOSecurityStatus -OrganizationName '{0}' -ProjectNames '{1}' -{2}Names '{3}' -ControlIds '{4}'" $StepsForRepro=$StepsForRepro.Replace("{0}",$this.SubscriptionContext.SubscriptionName) $StepsForRepro=$StepsForRepro.Replace("{1}",$ControlResult.ResourceContext.ResourceGroupName) $StepsForRepro=$StepsForRepro.Replace("{2}",$ControlResult.FeatureName) $StepsForRepro=$StepsForRepro.Replace("{3}",$ControlResult.ResourceContext.ResourceName) $StepsForRepro=$StepsForRepro.Replace("{4}",$ControlResult.ControlItem.ControlID) } return $StepsForRepro } #function to retrieve project name according to the resource hidden [string] GetProjectForBugLog([SVTEventContext[]] $ControlResult) { $ProjectName = "" #if resource is the organization, call control state extension to retreive attestation host project if ($ControlResult.FeatureName -eq "Organization") { $ProjectName = $this.ControlStateExt.GetProject() } #for all the other resource types, retrieve the project name from the control itself elseif ($ControlResult.ResourceContext.ResourceTypeName -eq "Project") { $ProjectName = $ControlResult.ResourceContext.ResourceName } else { $ProjectName = $ControlResult.ResourceContext.ResourceGroupName } return $ProjectName } #function to check if the bug can be logged for the current resource type hidden [bool] CheckPermsForBugLog([SVTEventContext[]] $ControlResult) { switch -regex ($ControlResult.FeatureName) { 'Organization' { #check if any host project can be retrieved, if not use getHostProject to return the correct behaviour output if (!($this.GetHostProject($ControlResult))) { return $false } } 'Project' { #check if user is member of PA/PCA if (!$this.ControlStateExt.GetControlStatePermission($ControlResult.FeatureName, $ControlResult.ResourceContext.ResourceName)) { Write-Host "`nAuto bug logging denied due to insufficient permissions. Make sure you are a project administrator. " -ForegroundColor Red return $false } } 'User' { #TODO: User controls dont have a project associated with them, can be rectified in future versions Write-Host "`nAuto bug logging for user control failures is currently not supported." -ForegroundColor Yellow return $false } } return $true } #function to retrive the attestation host project for organization level control failures hidden [string] GetHostProject([SVTEventContext[]] $ControlResult) { $Project = $null #check if attestationhost project has been specified along with the command if ($this.InvocationContext.BoundParameters["AttestationHostProjectName"]) { #check if the user has permission to log bug at org level if ($this.ControlStateExt.GetControlStatePermission("Organization", "")) { #user is PCA member, set the host project and return the project name $this.ControlStateExt.SetProjectInExtForOrg() $Project = $this.ControlStateExt.GetProject() return $Project } #user is not a member of PCA, invalidate the bug log else { Write-Host "Error: Could not configure host project to log bugs for organization-specific control failures.`nThis may be because you may not have correct privilege (requires 'Project Collection Administrator')." -ForegroundColor Red return $null } } else { #check if the user is a member of PCA after validating that the host project name was not provided if (!$this.ControlStateExt.GetControlStatePermission("Organization", "") ) { Write-Host "Error: Auto bug logging denied.`nThis may be because you are attempting to log bugs for areas you do not have RBAC permission to." -ForegroundColor Red return $null } else{ $Project = $this.ControlStateExt.GetProject() #user is a PCA member but the project has not been set for org control failures if (!$Project) { Write-Host "`nNo project defined to log bugs for organization-specific controls." -ForegroundColor Red Write-Host "Use the '-AttestationHostProjectName' parameter with this command to configure the project that will host bug logging details for organization level controls.`nRun 'Get-Help -Name Get-AzSKADOSecurityStatus -Full' for more info." -ForegroundColor Yellow return $null } } } return $Project } #function to check any detailed log and state data for the control failure hidden [string] GetDetailedLogForControl([SVTEventContext[]] $ControlResult) { $log = "" #retrieve the message data for control result $Messages = $ControlResult.ControlResults[0].Messages $Messages | ForEach-Object { if ($_.Message) { $log += "<b>$($_.Message)</b> </br></br>" } #check for state data if ($_.DataObject) { $log += "<hr>" #beautify state data for bug template $stateData = [Helpers]::ConvertObjectToString($_, $false) $stateData=$stateData.Replace("`"","'") $stateData = $stateData.Replace("@{", "@{</br>") $stateData = $stateData.Replace("@(", "@(</br>") $stateData = $stateData.Replace(";", ";</br>") $stateData = $stateData.Replace("},", "</br>},</br>") $stateData = $stateData.Replace(");", "</br>});</br>") $log += "$($stateData) </br></br>" } } #sanitizing input for JSON $log = $log.Replace("\", "\\") return $log } #function to retrieve the person to whom the bug will be assigned hidden [string] GetAssignee([SVTEventContext[]] $ControlResult) { $metaProviderObj = [BugMetaInfoProvider]::new(); return $metaProviderObj.GetAssignee($ControlResult, $this.ControlSettings.BugLogging); } #function to map severity of the control item hidden [string] GetSeverity([string] $ControlSeverity) { $Severity = "" switch -regex ($ControlSeverity) { 'Critical' { $Severity = "1 - Critical" } 'High' { $Severity = "2 - High" } 'Important' { $Severity = "2 - High" } 'Medium' { $Severity = "3 - Medium" } 'Moderate' { $Severity = "3 - Medium" } 'Low' { $Severity = "4 - Low" } } return $Severity } hidden [string] GetSecuritySeverity([string] $ControlSeverity) { $Severity = "" switch -regex ($ControlSeverity) { 'Critical' { $Severity = "1 - Critical" } 'High' { $Severity = "2 - Important" } 'Important' { $Severity = "2 - Important" } 'Moderate' { $Severity = "3 - Moderate" } 'Medium' { $Severity = "3 - Moderate" } 'Low' { $Severity = "4 - Low" } } return $Severity } #function to find active bugs and reactivate resolved bugs hidden [void] ManageActiveAndResolvedBugs([string]$ProjectName, [SVTEventContext[]] $control, [object] $workItem, [string] $AssignedTo) { $state = ($workItem[0].results.values[0].fields | where { $_.name -eq "State" }) $id = ($workItem[0].results.values[0].fields | where { $_.name -eq "ID" }).value #bug url that redirects user to bug logged in ADO, this is not available via the API response and thus has to be created via the ID of bug $bugUrl = "https://{0}.visualstudio.com/{1}/_workitems/edit/{2}" -f $($this.SubscriptionContext.SubscriptionName), $ProjectName , $id #TODO : whether the bug is active or resolved, we have to ensure the state of the bug remains active after this function #if a PCA assigns this to a non PCA, the control can never be fixed for org/project controls. to tackle this, reassign it to the original owner PCA #do this for both active and resolved bugs, as we need it to be assigned to the actual person who can fix this control #for other control results, we need not changed the assignee <# $url = "https://dev.azure.com/{0}/{1}/_apis/wit/workitems/{2}?api-version=5.1" -f $($this.SubscriptionContext.SubscriptionName), $ProjectName, $id $BugTemplate = [ConfigurationManager]::LoadServerConfigFile("TemplateForResolvedBug.json") $BugTemplate = $BugTemplate | ConvertTo-Json -Depth 10 $BugTemplate=$BugTemplate.Replace("{0}",$AssignedTo) $header = [WebRequestHelper]::GetAuthHeaderFromUriPatch($url) try { #TODO: shift all this as a patch request in webrequesthelper class and manage accented characters as well $responseObj = Invoke-RestMethod -Uri $url -Method Patch -ContentType "application/json-patch+json ; charset=utf-8" -Headers $header -Body $BugTemplate } catch { #if the user to whom the bug has been assigneed is not a member of org any more if ($_.ErrorDetails.Message -like '*System.AssignedTo*') { $body = $BugTemplate | ConvertFrom-Json #let it remain assigned $body[2].value = ""; $body = $body | ConvertTo-Json try { $responseObj = Invoke-RestMethod -Uri $url -Method Patch -ContentType "application/json-patch+json ; charset=utf-8" -Headers $header -Body $body $bugUrl = "https://{0}.visualstudio.com/_workitems/edit/{1}" -f $($this.SubscriptionContext.SubscriptionName), $responseObj.id } catch { Write-Host "Could not reactivate the bug" -ForegroundColor Red } } else { Write-Host "Could not reactivate the bug" -ForegroundColor Red } } #if the bug state was intially resolved, add in the state data to be referenced later if ($state.value -eq "Resolved") { $control.ControlResults.AddMessage("Resolved Bug", $bugUrl) } #if the bug state was initially active else { $control.ControlResults.AddMessage("Active Bug", $bugUrl) }#> #change the assignee for resolved bugs only if ($state.value -eq "Resolved") { $url = "https://dev.azure.com/{0}/{1}/_apis/wit/workitems/{2}?api-version=5.1" -f $($this.SubscriptionContext.SubscriptionName), $ProjectName, $id $BugTemplate = [ConfigurationManager]::LoadServerConfigFile("TemplateForResolvedBug.json") $BugTemplate = $BugTemplate | ConvertTo-Json -Depth 10 $BugTemplate=$BugTemplate.Replace("{0}",$AssignedTo) $header = [WebRequestHelper]::GetAuthHeaderFromUriPatch($url) try { #TODO: shift all this as a patch request in webrequesthelper class and manage accented characters as well $responseObj = Invoke-RestMethod -Uri $url -Method Patch -ContentType "application/json-patch+json ; charset=utf-8" -Headers $header -Body $BugTemplate $control.ControlResults.AddMessage("Resolved Bug", $bugUrl) } catch { #if the user to whom the bug has been assigneed is not a member of org any more if ($_.ErrorDetails.Message -like '*System.AssignedTo*') { $body = $BugTemplate | ConvertFrom-Json #let it remain assigned $body[2].value = ""; $body = $body | ConvertTo-Json try { $responseObj = Invoke-RestMethod -Uri $url -Method Patch -ContentType "application/json-patch+json ; charset=utf-8" -Headers $header -Body $body $control.ControlResults.AddMessage("Resolved Bug", $bugUrl) } catch { Write-Host "Could not reactivate the bug" -ForegroundColor Red } } else { Write-Host "Could not reactivate the bug" -ForegroundColor Red } } } else{ $control.ControlResults.AddMessage("Active Bug", $bugUrl) } } #function to search for existing bugs based on the hash hidden [object] GetWorkItemByHash([string] $hash, [string] $ProjectName) { $url = "https://{0}.almsearch.visualstudio.com/{1}/_apis/search/workItemQueryResults?api-version=5.1-preview" -f $($this.SubscriptionContext.SubscriptionName), $ProjectName; #TODO: validate set to allow only two values : ReactiveOldBug and CreateNewBug #check for ResolvedBugBehaviour in control settings if ($this.ControlSettings.BugLogging.ResolvedBugLogBehaviour -ne "ReactiveOldBug") { #new bug is to be logged for every resolved bug, hence search for only new/active bug $body = '{"searchText":"{0}","skipResults":0,"takeResults":25,"sortOptions":[],"summarizedHitCountsNeeded":true,"searchFilters":{"Projects":["{1}"],"Work Item Types":["Bug"],"States":["Active","New"]},"filters":[],"includeSuggestions":false}' | ConvertFrom-Json } else { #resolved bug needs to be reactivated, hence search for new/active/resolved bugs $body = '{"searchText":"{0}","skipResults":0,"takeResults":25,"sortOptions":[],"summarizedHitCountsNeeded":true,"searchFilters":{"Projects":["{1}"],"Work Item Types":["Bug"],"States":["Active","New","Resolved"]},"filters":[],"includeSuggestions":false}' | ConvertFrom-Json } #tag to be searched $body.searchText = "Tags: " + $hash $body.searchFilters.Projects = $ProjectName $response = [WebRequestHelper]:: InvokePostWebRequest($url, $body) return $response } #function to compute hash and return the tag hidden [string] GetHashedTag([string] $ControlId, [string] $ResourceId) { $hashedTag = $null $stringToHash = "{0}#{1}" #create a hash of resource id and control id $stringToHash = $stringToHash.Replace("{0}", $ResourceId) $stringToHash = $stringToHash.Replace("{1}", $ControlId) #return the bug tag $hashedTag="ADOScanID: " + [AutoBugLog]::ComputeHashX($stringToHash) return $hashedTag } hidden [void] AddWorkItem([string] $Title, [string] $Description, [string] $AssignedTo, [string] $AreaPath, [string] $IterationPath, [string]$Severity, [string]$ProjectName, [SVTEventContext[]] $control, [string] $hash, [string] $serviceId) { #logging new bugs $apiurl = 'https://dev.azure.com/{0}/{1}/_apis/wit/workitems/$bug?api-version=5.1' -f $($this.SubscriptionContext.SubscriptionName), $ProjectName; $BugTemplate = $null; $SecuritySeverity = ""; if ($this.ShowBugsInS360) { $BugTemplate = [ConfigurationManager]::LoadServerConfigFile("TemplateForNewBugS360.json") $SecuritySeverity = $this.GetSecuritySeverity($control.ControlItem.ControlSeverity) } else { $BugTemplate = [ConfigurationManager]::LoadServerConfigFile("TemplateForNewBug.json") } # Replace the field reference name for bug description if it is customized if ([Helpers]::CheckMember($this.controlsettings.BugLogging, 'BugDescriptionField') -and -not ([string]::IsNullOrEmpty($this.ControlSettings.BugLogging.BugDescriptionField))) { $BugTemplate[1].path = "/fields/"+$this.ControlSettings.BugLogging.BugDescriptionField } if ($this.InvocationContext.BoundParameters['BugDescriptionField']) { $BugTemplate[1].path = "/fields/"+$this.InvocationContext.BoundParameters['BugDescriptionField'] } $BugTemplate = $BugTemplate | ConvertTo-Json -Depth 10 $BugTemplate=$BugTemplate.Replace("{0}",$Title) $BugTemplate=$BugTemplate.Replace("{1}",$Description) $BugTemplate=$BugTemplate.Replace("{2}",$Severity) $BugTemplate=$BugTemplate.Replace("{3}",$AreaPath) $BugTemplate=$BugTemplate.Replace("{4}",$IterationPath) $BugTemplate=$BugTemplate.Replace("{5}",$hash) $BugTemplate=$BugTemplate.Replace("{6}",$AssignedTo) if ($this.ShowBugsInS360) { $BugTemplate=$BugTemplate.Replace("{7}", $this.controlsettings.BugLogging.HowFound) #ComplianceArea $BugTemplate=$BugTemplate.Replace("{8}", $this.controlsettings.BugLogging.ComplianceArea) #ServiceHierarchyId $BugTemplate=$BugTemplate.Replace("{9}", $serviceId) #ServiceHierarchyIdType $BugTemplate=$BugTemplate.Replace("{10}", $this.controlsettings.BugLogging.ServiceTreeIdType) #Severity $BugTemplate=$BugTemplate.Replace("{11}", $SecuritySeverity) } $responseObj = $null $header = [WebRequestHelper]::GetAuthHeaderFromUriPatch($apiurl) try { $responseObj = Invoke-RestMethod -Uri $apiurl -Method Post -ContentType "application/json-patch+json ; charset=utf-8" -Headers $header -Body $BugTemplate $bugUrl = "https://{0}.visualstudio.com/_workitems/edit/{1}" -f $($this.SubscriptionContext.SubscriptionName), $responseObj.id $control.ControlResults.AddMessage("New Bug", $bugUrl) } catch { #handle assignee users who are not part of org any more if ($_.ErrorDetails.Message -like '*System.AssignedTo*') { $BugTemplate = $BugTemplate | ConvertFrom-Json $BugTemplate[6].value = ""; $BugTemplate = $BugTemplate | ConvertTo-Json try { $responseObj = Invoke-RestMethod -Uri $apiurl -Method Post -ContentType "application/json-patch+json ; charset=utf-8" -Headers $header -Body $BugTemplate $bugUrl = "https://{0}.visualstudio.com/_workitems/edit/{1}" -f $($this.SubscriptionContext.SubscriptionName), $responseObj.id $control.ControlResults.AddMessage("New Bug", $bugUrl) } catch { Write-Host "Could not log the bug" -ForegroundColor Red } } #handle the case wherein due to global search area/ iteration paths from different projects passed the checkvalidpath function elseif ($_.ErrorDetails.Message -like '*Invalid Area/Iteration id*') { Write-Host "Please verify the area and iteration path. They should belong under the same project area." -ForegroundColor Red } elseif ($_.ErrorDetails.Message -like '*The current user does not have permissions to save work items under the specified area path*') { Write-Host "Could not log the bug. You do not have permissions to save work items under the area path [$($AreaPath)]." -ForegroundColor Red } else { Write-Host "Could not log the bug" -ForegroundColor Red } } } #the next two functions to check baseline and preview baseline, are duplicate controls that are present in ADOSVTBase as well. #they have been added again, due to behaviour of framework, where the file that needs to called in a certain file has to be mentioned #above the other file as it is dumped in the memory before the second file. This behaviour will effectively create a deadlock #in this case, as we have to create autobuglog object in adosvtbase, making it be declared first in framework and hence the following controls #cant be accessed here from adosvtbase. #function to check if the current control is a baseline control or not hidden [bool] CheckBaselineControl($controlId) { if (($null -ne $this.ControlSettings) -and [Helpers]::CheckMember($this.ControlSettings, "BaselineControls.ResourceTypeControlIdMappingList")) { $baselineControl = $this.ControlSettings.BaselineControls.ResourceTypeControlIdMappingList | Where-Object { $_.ControlIds -contains $controlId } if (($baselineControl | Measure-Object).Count -gt 0 ) { return $true } } if (($null -ne $this.ControlSettings) -and [Helpers]::CheckMember($this.ControlSettings, "BaselineControls.SubscriptionControlIdList")) { $baselineControl = $this.ControlSettings.BaselineControls.SubscriptionControlIdList | Where-Object { $_ -eq $controlId } if (($baselineControl | Measure-Object).Count -gt 0 ) { return $true } } return $false } #function to check if the current control is a preview baseline control or not hidden [bool] CheckPreviewBaselineControl($controlId) { if (($null -ne $this.ControlSettings) -and [Helpers]::CheckMember($this.ControlSettings, "PreviewBaselineControls.ResourceTypeControlIdMappingList")) { $PreviewBaselineControls = $this.ControlSettings.PreviewBaselineControls.ResourceTypeControlIdMappingList | Where-Object { $_.ControlIds -contains $controlId } if (($PreviewBaselineControls | Measure-Object).Count -gt 0 ) { return $true } } if (($null -ne $this.ControlSettings) -and [Helpers]::CheckMember($this.ControlSettings, "PreviewBaselineControls.SubscriptionControlIdList")) { $PreviewBaselineControls = $this.ControlSettings.PreviewBaselineControls.SubscriptionControlIdList | Where-Object { $_ -eq $controlId } if (($PreviewBaselineControls | Measure-Object).Count -gt 0 ) { return $true } } return $false } } # SIG # Begin signature block # MIIhewYJKoZIhvcNAQcCoIIhbDCCIWgCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDP9oJx/LK4GlI/ # vZy/DCsbCV/oQ374gFLwKLqfO9SReaCCC28wggTrMIID06ADAgECAhMzAAAD53EW # vSG3L5ZCAAAAAAPnMA0GCSqGSIb3DQEBCwUAMHkxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29mdCBUZXN0aW5nIFBD # QSAyMDEwMB4XDTIwMDMwNDE5NTgzOVoXDTIxMDMwMzE5NTgzOVowfDELMAkGA1UE # BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc # BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdQ29kZSBTaWdu # IFRlc3QgKERPIE5PVCBUUlVTVCkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK # AoIBAQC0dFU8yYFFisft2syLgnrgoEcOrrzraGs5owrAJ8YWyYuxhhk7UUJP0YAC # wuDAlPQMHrhnEhZsqmD7DfWGzz33gxe7hvcNpHdhItPpgXiVkh3thZrWz4jfHFGc # RMW1zyebGUJ16gN5cYWsI18Pax9tBZW1YZIef2hIQNU5Vr5QhVKZVAbaqZFqJRo+ # 51czrP44ZnofEMr3Z3HBmIS7C97kkFYS/G8JpkufIuDsTchX7dWduHhMbFIem+Zx # nT7mrsps0D5hXV3L9JPe8TFm1T0iwaFy6RWFaWPelibrTryIbWk6Qrv4Lz89WMM6 # XFxlrqQVphAmhns1+rNrr6yacRCtAgMBAAGjggFnMIIBYzATBgNVHSUEDDAKBggr # BgEFBQcDAzAdBgNVHQ4EFgQUseZoPiUpJDttlBAhnIzqzbcXsK4wUAYDVR0RBEkw # R6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNv # MRYwFAYDVQQFEw0yMzAwNzIrNDU4Mzk0MB8GA1UdIwQYMBaAFN3WR4sjFC/YOGhC # oz5tw/CQ9yzQMFMGA1UdHwRMMEowSKBGoESGQmh0dHA6Ly9jcmwubWljcm9zb2Z0 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Rlc1BDQV8yMDEwLTA3LTAxLmNybDBX # BggrBgEFBQcBAQRLMEkwRwYIKwYBBQUHMAKGO2h0dHA6Ly93d3cubWljcm9zb2Z0 # LmNvbS9wa2kvY2VydHMvTWljVGVzUENBXzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB # /wQCMAAwDQYJKoZIhvcNAQELBQADggEBAJYdTCu6GLf0F8qu4JuKidCt6hweTHFz # 012VGqDoVNN8REwov3VMjK71y8oL6wgvx29RYYqD2sKn6a/NcKUlHJjttvbXW/Az # NK4FetsfpyURFCRTS8C5hRcGZTIZfiSsJXn0N/yV/pbf/M6N4c0Q//I5f+e5lMch # 0jf6TGVLEHcXgOOH1PcS4Rd9LjAaggJG7VAOrIQaoSfgtsMn/a0CoYXeigizHb4k # sZW2nEC5JSAZ49b3Y1Pjvtr1H6xfMewXwtGCEvTq2btl8in/TV8du5cimL7VmZAa # aggJr0eFOmLCNUgGhH+Ic+sLH7G7vpkdggW9PRQ0wtQm8ofUIYhIn2swggZ8MIIE # ZKADAgECAgphEYRvAAAAAAADMA0GCSqGSIb3DQEBCwUAMIGQMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTowOAYDVQQDEzFNaWNyb3NvZnQgVGVz # dGluZyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTEwMDcwMTIx # MjMwMVoXDTI1MDcwMTIxMzMwMVoweTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEjMCEGA1UEAxMaTWljcm9zb2Z0IFRlc3RpbmcgUENBIDIwMTAw # ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBvSHVS2YGAJIwORjKy3NC # WbHvmyeo4OhVvSmw+SQfOtHow1mJ7ZG2wegzY/ZaZBniLnwMkIAFOL8cproNai/v # J5er3vbvUPOD59fDRTciPxi1wpYRto0Sg1mLJ1EGVnW5YGoTDtUmPy2WqgXMoYc/ # vk807wxMb8wE1KHmZ80KJzOf46+bb2h8vLQMczSMWoH5h/tUHMVHbOqfV7RZ/c4Z # qXd8h0KftXmUvMt2ktuWl6FfBCQ5/qGV4Z+G417ZXFbfQ5CfyRTq0fWgW6vzCATd # KK8b4qouE6AK7dKZRCr1mUT7K6RP8bthwh0t9SUnAqh475M59F51ge7S4HYMWyPv # AgMBAAGjggHsMIIB6DAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU3dZHiyMU # L9g4aEKjPm3D8JD3LNAwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0P # BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUowEEfjCIM+u5MZzK # 64V2Z/xltNEwWQYDVR0fBFIwUDBOoEygSoZIaHR0cDovL2NybC5taWNyb3NvZnQu # Y29tL3BraS9jcmwvcHJvZHVjdHMvTWljVGVzUm9vQ2VyQXV0XzIwMTAtMDYtMTcu # Y3JsMF0GCCsGAQUFBwEBBFEwTzBNBggrBgEFBQcwAoZBaHR0cDovL3d3dy5taWNy # b3NvZnQuY29tL3BraS9jZXJ0cy9NaWNUZXNSb29DZXJBdXRfMjAxMC0wNi0xNy5j # cnQwgaAGA1UdIAEB/wSBlTCBkjCBjwYJKwYBBAGCNy4DMIGBMD0GCCsGAQUFBwIB # FjFodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vUEtJL2RvY3MvQ1BTL2RlZmF1bHQu # aHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAFAAbwBsAGkAYwB5AF8A # UwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBAYQU+N90z # e1LCSGuA92ADFrbJLol+vdlYHGPT9ZLS9loEDQjuh7/rmDQ6ZXxQ5MgbKVB5VXsY # OZG1QSbzF3+YlWd8TN1y5B21BM3DSPb6r+3brl50kW2t1JqACtiLbZnmhmh5hkdJ # i8HYUfLQ7xKcP0g1CIJP9CyKil7UJv/HnMXKigTGiBaHjfVtVwG5k8roymrEirpB # DcOMVB0OZiTXxYIHDbM4v7LItZYIISdPs6+LwxwzwdroMdpj42+3dWQBumpRGQAg # qJ9i5UiBQtUM+9vLpKIRnujnWfQxbaIuIt2HRLFpHUYKGOXRlf148o+71dX3YWap # 88+ocaxkM8rkavgDNkcWSe9Dpoq8a3tS2P9BpxewDV+iSzF0JRo9UOZeciaSQDZv # rkQskxJjtdO725L6E5Fu1Ti+lGl6exRCnhPbooxCqHEGLRdiwXkrmLp+huTGAK8z # mfEt0d1JFrrDdu5kqoG3OVT2dN4JVFNpOFvCU/LNiVDCyCIcG0cSRVtDjyNckMhu # 1PcPtberjr1mcL8RkTzvonoH4pIvQk1k4IOLpdxslOj2oigApZjqCBJA3mIEZHln # wRuglg4Er74nSmL6953C0r1Vwl7T0vXnQO8izb+incAb1r6Y+45N5aVXww+PqHJB # RjvhjyBKG+1aDLVM3ixjV9P6OZkOvp4uozGCFWIwghVeAgEBMIGQMHkxCzAJBgNV # BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w # HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29m # dCBUZXN0aW5nIFBDQSAyMDEwAhMzAAAD53EWvSG3L5ZCAAAAAAPnMA0GCWCGSAFl # AwQCAQUAoIGuMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC # AQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBmiFpI8C5S0oJuy6U9 # zxEa8bA4/WST8ztc52+lek5NrTBCBgorBgEEAYI3AgEMMTQwMqAUgBIATQBpAGMA # cgBvAHMAbwBmAHShGoAYaHR0cDovL3d3dy5taWNyb3NvZnQuY29tMA0GCSqGSIb3 # DQEBAQUABIIBACv30I40n/EI01RFXfJtWJfxDgN88KaRX0kKHOT0GGeJ55WOKxS9 # NwtdXXRIXDDbyhLQRp3PjK/65dia4da93JXgivlzVNA93q35wchvOZTL+7dKcjDQ # DzG6w3VTPozcvJSut65iYak0uOKWJlqzV4obgZiM7MGvcS1epbsjB5+tHL+6NcRf # OCZ6CjEyvsxmSGk8h9L/9Wr8PEvCV7u50ZE7Na198jFJS++nKJXG8IggOxdazXde # 2twDGz9vL4hpIfCrhtnULNWU58QYhzj0n+v7AIk3iQG+neHrj5T8mqLjV2t5E+eq # Ag6A4ayi1VkreOXmhwCekHyzQeDQYpn5YFKhghLxMIIS7QYKKwYBBAGCNwMDATGC # Et0wghLZBgkqhkiG9w0BBwKgghLKMIISxgIBAzEPMA0GCWCGSAFlAwQCAQUAMIIB # VQYLKoZIhvcNAQkQAQSgggFEBIIBQDCCATwCAQEGCisGAQQBhFkKAwEwMTANBglg # hkgBZQMEAgEFAAQgCdoXam970fAeWKcPo1Is5CCkSesiQvPTso/ool4tW6gCBl+7 # 0KpETBgTMjAyMDExMjcxMTQ4NTMuMjMyWjAEgAIB9KCB1KSB0TCBzjELMAkGA1UE # BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc # BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWljcm9zb2Z0 # IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNO # OjYwQkMtRTM4My0yNjM1MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT # ZXJ2aWNloIIORDCCBPUwggPdoAMCAQICEzMAAAEm37pLIrmCggcAAAAAASYwDQYJ # KoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcNMTkx # MjE5MDExNDU5WhcNMjEwMzE3MDExNDU5WjCBzjELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWljcm9zb2Z0IE9wZXJhdGlvbnMg # UHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjYwQkMtRTM4My0y # NjM1MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIBIjAN # BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnjC+hpxO8w2VdBO18X8LHk6XdfR9 # yNQ0y+MuBOY7n5YdgkVunvbk/f6q8UoNFAdYQjVLPSAHbi6tUMiNeMGHk1U0lUxA # kja2W2/szj/ghuFklvfHNBbsuiUShlhRlqcFNS7KXL2iwKDijmOhWJPYa2bLEr4W # /mQLbSXail5p6m138Ttx4MAVEzzuGI0Kwr8ofIL7z6zCeWDiBM57LrNCqHOA2wbo # euMsG4O0Oz2LMAzBLbJZPRPnZAD2HdD4HUL2mzZ8wox74Mekb7RzrUP3hiHpxXZc # eJvhIEKfAgVkB5kTZQnio8A1JijMjw8f4TmsJPdJWpi8ei73sexe8/YjcwIDAQAB # o4IBGzCCARcwHQYDVR0OBBYEFEmrrB8XsH6YQo3RWKZfxqM0DmFBMB8GA1UdIwQY # MBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6 # Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0YVBD # QV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0 # dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENBXzIw # MTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwgw # DQYJKoZIhvcNAQELBQADggEBAECW+51o6W/0J/O/npudfjVzMXq0u0csHjqXpdRy # H6o03jlmY5MXAui3cmPBKufijJxD2pMRPVMUNh3VA0PQuJeYrP06oFdqLpLxd3IJ # ARm98vzaMgCz2nCwBDpe9X2M3Js9K1GAX+w4Az8N7J+Z6P1OD0VxHBdqeTaqDN1l # k1vwagTN7t/WitxMXRDz0hRdYiWbATBAVgXXCOfzs3hnEv1n/EDab9HXOLMXKVY/ # +alqYKdV9lkuRp8Us1Q1WZy9z72Azu9x4mzft3fJ1puTjBHo5tHfixZoummbI+Ww # jVCrku7pskJahfNi5amSgrqgR6nWAwvpJELccpVLdSxxmG0wggZxMIIEWaADAgEC # AgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0 # aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3MDEy # MTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAk # BgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkqhkiG # 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWlCgCC # hfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/FgiIRU # QwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeRX4FU # sc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/XcfPfBX # day9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogINeh4 # HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB5jCC # AeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvFM2ha # hW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNV # HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYG # A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3Js # L3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcB # AQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kv # Y2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8EgZUw # gZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5taWNy # b3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcCAjA0 # HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUAbgB0 # AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Prpsz1 # Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOMzPRg # Eop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCvOA8X # 9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v/rbl # jjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99lmqQ # eKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1klD3ou # OVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQHm+9 # 8eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30uIUB # HoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp25ay # p0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HSxVXj # ad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi62jbb # 01+P3nSISRKhggLSMIICOwIBATCB/KGB1KSB0TCBzjELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWljcm9zb2Z0IE9wZXJhdGlv # bnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjYwQkMtRTM4 # My0yNjM1MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMK # AQEwBwYFKw4DAhoDFQAKZzI5aZnESumrToHx3Lqgxnr//KCBgzCBgKR+MHwxCzAJ # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jv # c29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBBQUAAgUA42rr6jAi # GA8yMDIwMTEyNzA3MDcyMloYDzIwMjAxMTI4MDcwNzIyWjB3MD0GCisGAQQBhFkK # BAExLzAtMAoCBQDjauvqAgEAMAoCAQACAiU7AgH/MAcCAQACAhIdMAoCBQDjbD1q # AgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSCh # CjAIAgEAAgMBhqAwDQYJKoZIhvcNAQEFBQADgYEAftIvh3v+kV1QHlioLmUPKIR0 # AzC0jQLMhHzDvOhp2VKAZ1dgpTCymAajeKyatU/AgP9iJdfqFxn8MOhLBUvj2jef # +e/uq/2juqk3MBH9or7/rb0dbdp0ripG7+4f5vBJpPG4r2VeR7m/kZN3fa5jrYNc # 7XHcG0Hc7S79SqIUNgYxggMNMIIDCQIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFt # cCBQQ0EgMjAxMAITMwAAASbfuksiuYKCBwAAAAABJjANBglghkgBZQMEAgEFAKCC # AUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCAe # TLAeqit5OVKQbn3GZW1sy/jd6nA5708CI9iRw4I9lDCB+gYLKoZIhvcNAQkQAi8x # geowgecwgeQwgb0EIDb9z++evV5wDO9qk5ZnbEZ8CTOuR+kZyu8xbTsJCXUPMIGY # MIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV # BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG # A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAEm37pLIrmC # ggcAAAAAASYwIgQguagNNCaUG2eZW35NKAmr/aY71HhrTNrPz2lpA5Jbfs8wDQYJ # KoZIhvcNAQELBQAEggEAB1WI2UwOS+C3aSCn+tduZAIseis49oo2D+guOsSiLT9H # vE1CLT2jZV9V4ri25ryBDImADV0fOjeJ6IGs3hcV8CRCM1/74ePP15nnnuopJLsf # Xs+vGUtXqvJElQuK2ePXfJPzYbsg2vXdljq5gJfjV7VNhSsCIUD5/qTeSNnV9Dx7 # dxYEcIvOT0xW2e81YLltF6ynTM/RUWr4BI98xkak358AaNKIURG0ALDKBGlJsyoi # UgcgBTlLT4lNhog9NN8kucj7bGpJTMuB3dlzqeiuWQyJ1MvJyU9AQiMSBbAjTSNB # Cqm6VzbZtDpEuuWOdfzBjE6aJsQ4hyqxIfZuVE3n9g== # SIG # End signature block |