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