Framework/Managers/PartialScanManager.ps1

Set-StrictMode -Version Latest

class PartialScanManager : EventBase
{
    hidden [string] $OrgName = $null;
    hidden [string] $ProjectName = $null;
    hidden [PSObject] $ScanPendingForResources = $null;
    hidden [string] $ResourceScanTrackerFileName=$null;
    hidden [PartialScanResourceMap] $ResourceScanTrackerObj = $null
    [PSObject] $ControlSettings;
    hidden [ActiveStatus] $ActiveStatus = [ActiveStatus]::NotStarted;
    hidden [string] $CAScanProgressSnapshotsContainerName = [Constants]::CAScanProgressSnapshotsContainerName
    hidden [string] $AzSKTempStatePath = (Join-Path $([Constants]::AzSKAppFolderPath) "TempState" | Join-Path -ChildPath "PartialScanData");
    hidden [bool] $StoreResTrackerLocally = $false;
    hidden [string] $ScanSource = $null;
    hidden [bool] $IsRTFAlreadyAvailable = $false;
    hidden [bool] $IsDurableStorageFound = $false;
    hidden [string] $MasterFilePath;
    $StorageContext = $null;
    $ControlStateBlob = $null;
    hidden static $IsCsvUpdatedAtCheckpoint = $false; 
    hidden static $CollatedSummaryCount = @(); # Matrix of counts for severity and control status
    hidden static $CollatedBugSummaryCount = @(); # Matrix of counts for severity and Bug status
    hidden static $ControlResultsWithBugSummary = @();
    hidden static $ControlResultsWithSARIFSummary= @();
    hidden static $ControlResultsWithClosedBugSummary= @();
    hidden static $duplicateClosedBugCount=0;
  hidden [string] $SummaryMarkerText = "------";
  hidden [string] $BackupControlStatePath = (Join-Path $([Constants]::AzSKAppFolderPath) "TempState" | Join-Path -ChildPath "BackupControlState");
    hidden [string] $BackupControlStateFilePath;
    hidden [PSObject] $StateOfControlsToBeFixed = $null;
    hidden [bool] $IsControlStateBackupFetched = $false;


    hidden static [PartialScanManager] $Instance = $null;
    
    static [PartialScanManager] GetInstance([PSObject] $StorageAccount, [string] $OrganizationName)
    {
        if ( $null -eq  [PartialScanManager]::Instance)
        {
            [PartialScanManager]::Instance = [PartialScanManager]::new($OrganizationName);
        }
        [PartialScanManager]::Instance.OrgName = $OrganizationName;
        return [PartialScanManager]::Instance
    }

    static [PartialScanManager] GetInstance()
    {
        if ( $null -eq  [PartialScanManager]::Instance)
        {
            [PartialScanManager]::Instance = [PartialScanManager]::new();
        }
        return [PartialScanManager]::Instance
    }
    static [void] ClearInstance()
    {
       [PartialScanManager]::Instance = $null
       [PartialScanManager]::IsCsvUpdatedAtCheckpoint = $false
    }
    PartialScanManager([string] $OrganizationName)
    {
        $this.ControlSettings = [ConfigurationManager]::LoadServerConfigFile("ControlSettings.json");
        $this.OrgName = $OrganizationName;
        if ([string]::isnullorwhitespace($this.ResourceScanTrackerFileName))
        {
           if([ConfigurationManager]::GetAzSKSettings().IsCentralScanModeOn)
           {
                $this.ResourceScanTrackerFileName = Join-Path $OrganizationName $([Constants]::ResourceScanTrackerCMBlobName)
           }
           else
           {
                $this.ResourceScanTrackerFileName = Join-Path $OrganizationName $([Constants]::ResourceScanTrackerBlobName)
           }
        }        
        $this.GetResourceScanTrackerObject();
    }

    PartialScanManager()
    {
        $this.ControlSettings = [ConfigurationManager]::LoadServerConfigFile("ControlSettings.json");
        if ([string]::isnullorwhitespace($this.ResourceScanTrackerFileName))
        {
            $this.ResourceScanTrackerFileName =  [Constants]::ResourceScanTrackerBlobName
        }
        $this.GetResourceScanTrackerObject();
    }

     hidden [void] GetResourceTrackerFile($orgName, $isControlFixCmd)
    {
        $this.ScanSource = [AzSKSettings]::GetInstance().GetScanSource();
        $this.OrgName = $orgName

        #Validating the configuration of storing resource tracker file
        if($null -ne $this.ControlSettings.PartialScan)
        {
            $this.StoreResTrackerLocally = [Bool]::Parse($this.ControlSettings.PartialScan.StoreResourceTrackerLocally);
        }

        #Use local Resource Tracker files for partial scanning
        if ($this.StoreResTrackerLocally -and ($this.ScanSource -ne "CA" -and $this.ScanSource -ne "CICD") )
        {
            if($null -eq $this.ScanPendingForResources)
            {
                if($isControlFixCmd)
                {
                    $this.ResourceScanTrackerFileName = "ControlFix"+ $this.ResourceScanTrackerFileName
                }
                if(![string]::isnullorwhitespace($this.OrgName)){
                    if(Test-Path (Join-Path (Join-Path $this.AzSKTempStatePath $this.OrgName) $this.ResourceScanTrackerFileName))    
                    {
                        $this.ScanPendingForResources = Get-Content (Join-Path (Join-Path $this.AzSKTempStatePath $this.OrgName) $this.ResourceScanTrackerFileName) -Raw
                    }
                    $this.MasterFilePath = (Join-Path (Join-Path $this.AzSKTempStatePath $this.OrgName) $this.ResourceScanTrackerFileName)
                }
                else {
                    $this.MasterFilePath = (Join-Path $this.AzSKTempStatePath $this.ResourceScanTrackerFileName)
                }
            }
        }

        if ($this.ScanSource -eq "CA") # use storage in ADOScannerRG in case of CA scan
        {
            $this.MasterFilePath = (Join-Path (Join-Path $this.AzSKTempStatePath $this.OrgName) $this.ResourceScanTrackerFileName)

            try {
                #Validate if Storage is found
                $keys = Get-AzStorageAccountKey -ResourceGroupName $env:StorageRG -Name $env:StorageName
                $this.StorageContext = New-AzStorageContext -StorageAccountName $env:StorageName -StorageAccountKey $keys[0].Value -Protocol Https
                $containerObject = Get-AzStorageContainer -Context $this.StorageContext -Name $this.CAScanProgressSnapshotsContainerName -ErrorAction SilentlyContinue
                    
                #If checkpoint container is found then get ResourceTracker.json (if exists)
                if($null -ne $containerObject)
                {
                    $this.ControlStateBlob = Get-AzStorageBlob -Container $this.CAScanProgressSnapshotsContainerName -Context $this.StorageContext -Blob (Join-Path $this.OrgName.ToLower() $this.ResourceScanTrackerFileName) -ErrorAction SilentlyContinue

                    #If controlStateBlob is null then it will get created when we first write the resource tracker file to storage
                    #If its not null this means Resource tracker file has been found in storage and will be used to continue pending scan
                    if ($null -ne $this.ControlStateBlob)
                    {
                        if ($null -ne $this.MasterFilePath)
                        {
                            if (-not (Test-Path $this.MasterFilePath))
                            {
                                $filePath = $this.MasterFilePath.Replace($this.ResourceScanTrackerFileName, "")
                                New-Item -ItemType Directory -Path $filePath
                                New-Item -Path $filePath -Name $this.ResourceScanTrackerFileName -ItemType "file" 
                            }
                            #Copy existing RTF locally to handle any non ascii characters as ICloudBlob.DownloadText() was inserting non ascii charcaters
                            Get-AzStorageBlobContent -CloudBlob $this.ControlStateBlob.ICloudBlob -Context $this.StorageContext -Destination $this.MasterFilePath -Force                
                            $this.ScanPendingForResources  = Get-ChildItem -Path $this.MasterFilePath -Force | Get-Content | ConvertFrom-Json
                            #Delete the local RTF file
                            Remove-Item -Path (Join-Path (Join-Path $this.AzSKTempStatePath $this.OrgName) $this.ResourceScanTrackerFileName)
                        }
                        $this.IsRTFAlreadyAvailable = $true
                    }
                    else {
                        $this.IsRTFAlreadyAvailable = $false
                    }
                    $this.IsDurableStorageFound = $true
                }
                #If checkpoint container is not found then create new
                else {
                    $containerObject = New-AzStorageContainer -Name $this.CAScanProgressSnapshotsContainerName -Context $this.StorageContext -ErrorAction SilentlyContinue
                    if ($null -ne $containerObject )
                    {
                        $this.IsDurableStorageFound = $true
                    }
                    else 
                    {                        
                        $this.PublishCustomMessage("Could not find/create partial scan container in storage.", [MessageType]::Warning)
                    }
                }
            }
            catch {                
                $this.PublishCustomMessage("Exception when trying to find/create partial scan container: $_.", [MessageType]::Warning)
                #Eat exception
            }

        }
        
        elseif ($this.ScanSource -eq "CICD") # use extension storage in case of CICD partial scan
        {
                if(![string]::isnullorwhitespace($this.OrgName))
                {
                    $rmContext = [ContextHelper]::GetCurrentContext();
                    $user = "";
                    $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$rmContext.AccessToken)))
                    $uri= "";

                    if (Test-Path env:partialScanURI)
                    {
                        #Uri is created in cicd task based on jobid
                        $uri = $env:partialScanURI
                    }
                    else {
                        $uri = [Constants]::StorageUri -f $this.OrgName, $this.OrgName, "ResourceTrackerFile"
                    }

                    try {
                        $webRequestResult = Invoke-RestMethod -Uri $uri -Method Get -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}
                        $this.ScanPendingForResources = $webRequestResult.value | ConvertFrom-Json
                        $this.IsRTFAlreadyAvailable = $true;
                    }
                    catch
                    {
                        $this.ScanPendingForResources = $null
                        $this.IsRTFAlreadyAvailable = $false;
                    }    
                }
        }
        
    }

    #Update resource status in ResourceMapTable object
    [void] UpdateResourceStatus([string] $resourceId, [ScanState] $state)
    {
        $resourceValues = @();
        #$this.GetResourceScanTrackerObject();
        if($this.IsListAvailableAndActive())
        {
            $resourceValue = $this.ResourceScanTrackerObj.ResourceMapTable | Where-Object { $_.Id -eq $resourceId};
            if($null -ne $resourceValue)
            {
                $resourceValue.ModifiedDate = [DateTime]::UtcNow;
                $resourceValue.State = $state;
            }
            else
            {
                $resourceValue = [PartialScanResource]@{
                    Id = $resourceId;
                    State = $state;
                    ScanRetryCount = 1;
                    CreatedDate = [DateTime]::UtcNow;
                    ModifiedDate = [DateTime]::UtcNow;
                }
                $this.ResourceScanTrackerObj.ResourceMapTable +=$resourceValue;
            }
        }
    }

    [void] UpdateResourceScanRetryCount([string] $resourceId)
    {
        $resourceValues = @();
        if($this.IsListAvailableAndActive())
        {
            $resourceValue = $this.ResourceScanTrackerObj.ResourceMapTable | Where-Object { $_.Id -eq $resourceId};
            if($null -ne $resourceValue)
            {
                $resourceValue.ModifiedDate = [DateTime]::UtcNow;
                $resourceValue.ScanRetryCount = $resourceValue.ScanRetryCount + 1;
                if($resourceValue.ScanRetryCount -ge [Constants]::PartialScanMaxRetryCount)
                {
                    $resourceValue.State = [ScanState]::ERR
                }
            }
            else
            {
                #do nothing
            }
        }
    }

    # Method to remove obsolete Resource Tracker file
    [void] RemovePartialScanData()
    {
        if ($this.ScanSource -eq "CICD")
        {
            if($null -ne $this.ResourceScanTrackerObj)
            {
                $rmContext = [ContextHelper]::GetCurrentContext();
                $user = "";
                $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$rmContext.AccessToken)))
                $uri ="";

                if (Test-Path env:partialScanURI)
                    {
                        #Uri is created by cicd task based on jobid
                        $uri = $env:partialScanURI
                    }
                else {
                    $uri = [Constants]::StorageUri -f $this.OrgName, $this.OrgName, "ResourceTrackerFile"
                }
                
                try {
                    if ($this.ResourceScanTrackerObj.ResourceMapTable -ne $null){
                        $webRequestResult = Invoke-WebRequest -Uri $uri -Method Delete -ContentType "application/json" -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo) } 
                        $this.ResourceScanTrackerObj = $null
                    }
                }
                catch {
                    #do nothing
                }
            }
        }
        elseif ($this.ScanSource -eq "CA" -and $this.IsDurableStorageFound) {
            #Move resource tracker file to archive folder
            if($null -ne $this.ControlStateBlob)
            {
                $archiveName = "Checkpoint_" +(Get-Date).ToUniversalTime().ToString("yyyyMMddHHmmss") + ".json";
                #Store final RTF file locally and then upload to archive folder
                [JsonHelper]::ConvertToJsonCustom($this.ResourceScanTrackerObj) | Out-File $this.MasterFilePath -Force

                Set-AzStorageBlobContent -File $this.MasterFilePath -Container $this.CAScanProgressSnapshotsContainerName -Blob (Join-Path $this.OrgName.ToLower() (Join-Path "Archive" $archiveName)) -BlobType Block -Context $this.StorageContext -Force
                Remove-AzStorageBlob -CloudBlob $this.ControlStateBlob.ICloudBlob -Force -Context $this.StorageContext

                #Delete local RTF file
                if (Test-Path (Join-Path $this.AzSKTempStatePath $this.OrgName))
                {
                    Remove-Item -Path (Join-Path $this.AzSKTempStatePath $this.OrgName) -Recurse
                }
            }    
        }

        #Use local Resource Tracker files for partial scanning
        elseif ($this.StoreResTrackerLocally) {
            if($null -ne $this.ResourceScanTrackerObj)
            {
                if(![string]::isnullorwhitespace($this.OrgName)){
                    if(Test-Path (Join-Path $this.AzSKTempStatePath $this.OrgName))
                    {
                        Remove-Item -Path (Join-Path (Join-Path $this.AzSKTempStatePath $this.OrgName) $this.ResourceScanTrackerFileName)
                        
                        <#Create archive folder if not exists
                        if(-not (Test-Path (Join-Path (Join-Path $this.AzSKTempStatePath $this.OrgName) "archive")))
                        {
                            New-Item -ItemType Directory -Path (Join-Path (Join-Path $this.AzSKTempStatePath $this.OrgName) "archive")
                        }
                        $timestamp =(Get-Date -format "yyMMddHHmmss")
                        Move-Item -Path (Join-Path (Join-Path $this.AzSKTempStatePath $this.OrgName) $this.ResourceScanTrackerFileName) -Destination (Join-Path (Join-Path (Join-Path $this.AzSKTempStatePath $this.OrgName) "archive")"Checkpoint_$($timestamp)")
                        #>

                    }
                }
                $this.ResourceScanTrackerObj = $null
            }
        }
    }

    #Method to fetch all applicable resources as per input command (including those with "COMP" status in ResourceTracker file)
    [void] CreateResourceMasterList([PSObject] $resourceIds)
    {
        if(($resourceIds | Measure-Object).Count -gt 0)
        {
            [System.Collections.Generic.List[PartialScanResource]] $resourceIdMap = @();
            $progressCount=1
            $resourceIds | ForEach-Object {            
                $resourceValue = [PartialScanResource]@{
                    Id = $_.ResourceId;
                    State = [ScanState]::INIT;
                    ScanRetryCount = 0;
                    CreatedDate = [DateTime]::UtcNow;
                    ModifiedDate = [DateTime]::UtcNow;
                    Name=$_.ResourceName;
                    ProjectName = $_.ResourceGroupName
                    #ResourceDetails=$_.ResourceDetails
                    
                }

                #We dont need to store project name if -dnrr not given or the resource is not release/agentpool
                if($PSCmdlet.MyInvocation.BoundParameters['DoNotRefetchResources']){ 
                    if($_.ResourceType -ne "ADO.Release" -and $_.ResourceType -ne "ADO.AgentPool"){
                        $resourceValue = $resourceValue | Select-Object -Property * -ExcludeProperty ProjectName                        
                    }
                }
                else {
                    $resourceValue = $resourceValue | Select-Object -Property * -ExcludeProperty ProjectName
                }
                
                #$resourceIdMap.Add($hashId,$resourceValue);
                $resourceIdMap.Add([PartialScanResource] $resourceValue)
                if ($progressCount%100 -eq 0) {                
                    Write-Progress -Activity "Tracking $($progressCount) of $($resourceIds.Count) untracked resources " -Status "Progress: " -PercentComplete ($progressCount / $resourceIds.Count * 100)
                }
                $progressCount++;
            }
            Write-Progress -Activity "Tracked all resources" -Status "Ready" -Completed
            $masterControlBlob = [PartialScanResourceMap]@{
                Id = [DateTime]::UtcNow.ToString("yyyyMMdd_HHmmss");
                CreatedDate = [DateTime]::UtcNow;
                ResourceMapTable = $resourceIdMap;
            }

            if ($this.ScanPendingForResources -ne $null -and $this.ScanSource -eq "CICD"){

                if([Helpers]::CheckMember($this.ScanPendingForResources.ResourceMapTable,"value"))
                {
                    $this.ResourceScanTrackerObj = [PartialScanResourceMap]@{
                        Id = $this.ScanPendingForResources.Id;
                        CreatedDate = $this.ScanPendingForResources.CreatedDate;
                        ResourceMapTable = $this.ScanPendingForResources.ResourceMapTable.value;
                    }
                }
                else{
                    $this.ResourceScanTrackerObj = [PartialScanResourceMap]@{
                        Id = $this.ScanPendingForResources.Id;
                        CreatedDate = $this.ScanPendingForResources.CreatedDate;
                        ResourceMapTable = $this.ScanPendingForResources.ResourceMapTable;
                    }
                }
            }
            else{
                $this.ResourceScanTrackerObj = $masterControlBlob;
            }

            if ($this.ScanSource -eq "CICD" -or $this.ScanSource -eq "CA")
            {
                $this.WriteToDurableStorage();
            }
            else {
                $this.WriteToResourceTrackerFile();
            }

            $this.ActiveStatus = [ActiveStatus]::Yes;
        }
    }

    [void] WriteToResourceTrackerFile()
    {
        if ($this.StoreResTrackerLocally) 
        {
            if($null -ne $this.ResourceScanTrackerObj)
            {
                if(![string]::isnullorwhitespace($this.OrgName)){
                    if(-not (Test-Path (Join-Path $this.AzSKTempStatePath $this.OrgName)))
                    {
                        New-Item -ItemType Directory -Path (Join-Path $this.AzSKTempStatePath $this.OrgName) -ErrorAction Stop | Out-Null
                    }    
                }
                else{
                    if(-not (Test-Path "$this.AzSKTempStatePath"))
                    {
                        New-Item -ItemType Directory -Path "$this.AzSKTempStatePath" -ErrorAction Stop | Out-Null
                    }
                }                
                $this.PublishCustomMessage("Updating resource tracker file", [MessageType]::Warning)
                [JsonHelper]::ConvertToJsonCustom($this.ResourceScanTrackerObj) | Out-File $this.MasterFilePath -Force                
                $this.PublishCustomMessage("Resource tracker file updated", [MessageType]::Warning)
                
            }
        }
    }

    [void] WriteToDurableStorage()
    {
        if ($this.ScanSource -eq "CICD")
        {
            if($null -ne $this.ResourceScanTrackerObj)
            {
                if(![string]::isnullorwhitespace($this.OrgName))
                {
                    $rmContext = [ContextHelper]::GetCurrentContext();
                    $user = "";
                    $uri = "";
                    $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$rmContext.AccessToken)))
                    $scanObject = $this.ResourceScanTrackerObj | ConvertTo-Json
                    $body = "";

                    if (Test-Path env:partialScanURI)
                    {
                        $uri = $env:partialScanURI
                        $JobId ="";
                        $JobId = $uri.Replace('?','/').Split('/')[$JobId.Length -2]
                        if ($this.IsRTFAlreadyAvailable -eq $true){
                            $body = @{"id" = $Jobid; "__etag"=-1; "value"= $scanObject;} | ConvertTo-Json
                        }
                        else{
                            $body = @{"id" = $Jobid; "value"= $scanObject;} | ConvertTo-Json
                        }
                    }
                    else {
                        $uri = [Constants]::StorageUri -f $this.OrgName, $this.OrgName, "ResourceTrackerFile"
                        if ($this.IsRTFAlreadyAvailable -eq $true){
                            $body = @{"id" = "ResourceTrackerFile";"__etag"=-1; "value"= $scanObject;} | ConvertTo-Json
                        }
                        else{
                            $body = @{"id" = "ResourceTrackerFile"; "value"= $scanObject;} | ConvertTo-Json
                        }
                    }

                    try {
                        $webRequestResult = Invoke-WebRequest -Uri $uri -Method Put -ContentType "application/json" -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo) } -Body $body 
                        $this.IsRTFAlreadyAvailable = $true;
                    }
                    catch
                    {                        
                        $this.PublishCustomMessage("Could not update resource tracker file.", [MessageType]::Warning);
                    }        
                }
            }
        }
        elseif ($this.ScanSource -eq "CA" -and $this.IsDurableStorageFound) 
        {
            if ($this.IsRTFAlreadyAvailable) # Copy RTF from memory
            {
                $this.ControlStateBlob.ICloudBlob.UploadText([JsonHelper]::ConvertToJsonCustom($this.ResourceScanTrackerObj) )
            }
            else { # If file is not available in storage then upload it from local for the first instance
                if ($null -ne $this.MasterFilePath -and -not (Test-Path $this.MasterFilePath))
                {
                    # Create directory and resource tracker file
                    $filePath = $this.MasterFilePath.Replace($this.ResourceScanTrackerFileName, "")
                    if (-not (Test-Path $filePath))
                    {
                        New-Item -ItemType Directory -Path $filePath
                    }
                    New-Item -Path $filePath -Name $this.ResourceScanTrackerFileName -ItemType "file" 
                }
                [JsonHelper]::ConvertToJsonCustom($this.ResourceScanTrackerObj) | Out-File $this.MasterFilePath -Force
                Set-AzStorageBlobContent -File $this.MasterFilePath -Container $this.CAScanProgressSnapshotsContainerName -Blob (Join-Path $this.OrgName.ToLower() $this.ResourceScanTrackerFileName) -BlobType Block -Context $this.StorageContext -Force
                $this.ControlStateBlob = Get-AzStorageBlob -Container $this.CAScanProgressSnapshotsContainerName -Context $this.StorageContext -Blob (Join-Path $this.OrgName.ToLower() $this.ResourceScanTrackerFileName) -ErrorAction SilentlyContinue
                $this.IsRTFAlreadyAvailable = $true
            }
        }
    }

    #Method to fetch ResourceTrackerFile as an object
    hidden [void] GetResourceScanTrackerObject()
    {
        try
        {
            if($null -eq $this.ScanPendingForResources)
            {
                return;
            }
            if ($this.ScanSource -eq "CICD") # use extension storage in case of CICD partial scan
            {
                if(![string]::isnullorwhitespace($this.ScanPendingForResources))
                {
                    if([Helpers]::CheckMember($this.ScanPendingForResources.ResourceMapTable,"value"))
                    {
                        $this.ResourceScanTrackerObj = [PartialScanResourceMap]@{
                            Id = $this.ScanPendingForResources.Id;
                            CreatedDate = $this.ScanPendingForResources.CreatedDate;
                            ResourceMapTable = $this.ScanPendingForResources.ResourceMapTable.value;
                        }
                    }
                    else{
                        $this.ResourceScanTrackerObj = [PartialScanResourceMap]@{
                            Id = $this.ScanPendingForResources.Id;
                            CreatedDate = $this.ScanPendingForResources.CreatedDate;
                            ResourceMapTable = $this.ScanPendingForResources.ResourceMapTable;
                        }
                    }
                }
            }
            elseif ($this.ScanSource -eq "CA")
            {
                if(![string]::isnullorwhitespace($this.ScanPendingForResources))
                {
                    $this.ResourceScanTrackerObj = $this.ScanPendingForResources
                }
            }
            elseif ($this.StoreResTrackerLocally) 
            {
                if(![string]::isnullorwhitespace($this.OrgName)){
                    if(-not (Test-Path (Join-Path $this.AzSKTempStatePath $this.OrgName)))
                    {
                        New-Item -ItemType Directory -Path (Join-Path $this.AzSKTempStatePath $this.OrgName) -ErrorAction Stop | Out-Null
                    }
                }
                else{
                    if(-not (Test-Path "$this.AzSKTempStatePath"))
                    {
                        New-Item -ItemType Directory -Path "$this.AzSKTempStatePath" -ErrorAction Stop | Out-Null
                    }
                }
                $this.ResourceScanTrackerObj = Get-content $this.MasterFilePath | ConvertFrom-Json
            }
        }
        catch{
            $this.ResourceScanTrackerObj = $null
            $this.ScanPendingForResources = $null
            $this.PublishCustomMessage("RTF not found", [MessageType]::Warning);            
        }
    }

    #Sending $isControlFixCmd as true in case set-azskadosecuritystatus command is used in order to store RTF in separate folder, so that it does not interfere with GADS command
    [ActiveStatus] IsPartialScanInProgress($orgName, $isControlFixCmd) 
    {
        $this.GetResourceTrackerFile($orgName, $isControlFixCmd);
        if($null -ne $this.ControlSettings.PartialScan)
        {
            $resourceTrackerFileValidforDays = [Int32]::Parse($this.ControlSettings.PartialScan.ResourceTrackerValidforDays);
            $this.GetResourceScanTrackerObject();
            if($null -eq $this.ResourceScanTrackerObj)
            {
                return $this.ActiveStatus = [ActiveStatus]::No;
            }
            $shouldStopScanning = ($this.ResourceScanTrackerObj.ResourceMapTable | Where-Object {$_.State -notin ([ScanState]::COMP,[ScanState]::ERR)} |  Measure-Object).Count -eq 0
            if($this.ResourceScanTrackerObj.CreatedDate.AddDays($resourceTrackerFileValidforDays) -lt [DateTime]::UtcNow -or $shouldStopScanning)
            {
                $this.RemovePartialScanData();
                $this.ScanPendingForResources = $null;
                return $this.ActiveStatus = [ActiveStatus]::No;
            }
            return $this.ActiveStatus = [ActiveStatus]::Yes
        }
        else
        {
            $this.ScanPendingForResources = $null;
            return $this.ActiveStatus = [ActiveStatus]::No;
        }
    }

    [PSObject] GetNonScannedResources()
    {
        #[System.Collections.Generic.List[PartialScanResource]] $nonScannedResources = @();
        $nonScannedResources = @()
        $this.GetResourceScanTrackerObject();
        if($this.IsListAvailableAndActive())
        {
            

            $nonScannedResources +=[PartialScanResource[]] $this.ResourceScanTrackerObj.ResourceMapTable | Where-Object {$_.State -eq [ScanState]::INIT}
            return [PartialScanResource[]] $nonScannedResources;
        }
        return $null;
    }

    [PSObject] GetAllListedResources()
    {
        #[System.Collections.Generic.List[PartialScanResource]] $nonScannedResources = @();
        $nonScannedResources = @()
        $this.GetResourceScanTrackerObject();
        if($this.IsListAvailableAndActive())
        {
            $nonScannedResources +=[PartialScanResource[]]  $this.ResourceScanTrackerObj.ResourceMapTable
            return [PartialScanResource[]] $nonScannedResources;
        }
        return $null;
    }

    [Bool] IsListAvailableAndActive()
    {
        if($null -ne $this.ResourceScanTrackerObj -and $this.ActiveStatus -eq [ActiveStatus]::Yes -and $null -ne $this.ResourceScanTrackerObj.ResourceMapTable)
        {
            return $true
        }
        else
        {
            return $false
        }
    }

    # Collect control results summary data and append to it at every checkpoint. Any changes in this method should be synced with WritePSConsole.ps1 PrintSummaryData method
    [void] CollateSummaryData($event)
    {
        $summary = @($event | select-object @{Name="VerificationResult"; Expression = {$_.ControlResults.VerificationResult}},@{Name="ControlSeverity"; Expression = {$_.ControlItem.ControlSeverity}})

        if(($summary | Measure-Object).Count -ne 0)
        {

            $severities = @();
            $severities += $summary | Select-Object -Property ControlSeverity | Select-Object -ExpandProperty ControlSeverity -Unique;

            $verificationResults = @();
            $verificationResults += $summary | Select-Object -Property VerificationResult | Select-Object -ExpandProperty VerificationResult -Unique;

            if($severities.Count -ne 0)
            {
                # Create summary matrix
                $totalText = "Total";
                $MarkerText = "MarkerText";
                $rows = @();
                $rows += $severities;
                $rows += $MarkerText;
                $rows += $totalText;
                $rows += $MarkerText;

                #Execute below block only once (when first resource is scanned)
                if([PartialScanManager]::CollatedSummaryCount.Count -eq 0)
                {
                    $rows | ForEach-Object {
                        $result = [PSObject]::new();
                        Add-Member -InputObject $result -Name "Summary" -MemberType NoteProperty -Value $_.ToString()
                        Add-Member -InputObject $result -Name $totalText -MemberType NoteProperty -Value 0

                        #Get all possible verificationResults initially
                        [Enum]::GetNames([VerificationResult]) | 
                        ForEach-Object {
                            Add-Member -InputObject $result -Name $_.ToString() -MemberType NoteProperty -Value 0
                        };
                        [PartialScanManager]::CollatedSummaryCount += $result;
                    };
                }

                $totalRow = [PartialScanManager]::CollatedSummaryCount | Where-Object { $_.Summary -eq $totalText } | Select-Object -First 1;

                $summary | Group-Object -Property ControlSeverity | ForEach-Object {
                    $item = $_;
                    $summaryItem = [PartialScanManager]::CollatedSummaryCount | Where-Object { $_.Summary -eq $item.Name } | Select-Object -First 1;
                    if($summaryItem)
                    {
                        $summaryItem.Total += $_.Count;
                        if($totalRow)
                        {
                            $totalRow.Total += $_.Count
                        }
                        $item.Group | Group-Object -Property VerificationResult | ForEach-Object {
                            $propName = $_.Name;
                            $summaryItem.$propName += $_.Count;
                            if($totalRow)
                            {
                                $totalRow.$propName += $_.Count
                            }
                        };
                    }
                };
                $markerRows = [PartialScanManager]::CollatedSummaryCount | Where-Object { $_.Summary -eq $MarkerText } 
                $markerRows | ForEach-Object { 
                    $markerRow = $_
                    Get-Member -InputObject $markerRow -MemberType NoteProperty | ForEach-Object {
                            $propName = $_.Name;
                            $markerRow.$propName = $this.SummaryMarkerText;                
                        }
                    };
            }
        }
    }

    # Collect Bug summary data and append to it at every checkpoint. Any changes in this method should be synced with WritePSConsole.ps1 PrintBugSummaryData method
    [void] CollateBugSummaryData($event){
        #gather all control results that have failed/verify as their control result
        #obtain their control severities
        $event | ForEach-Object {
            $item = $_
            if ($item -and $item.ControlResults -and ($item.ControlResults[0].VerificationResult -eq "Failed" -or $item.ControlResults[0].VerificationResult -eq "Verify"))
            {
                $item
                $item.ControlResults[0].Messages | ForEach-Object{
                    if($_.Message -eq "New Bug" -or $_.Message -eq "Active Bug" -or $_.Message -eq "Resolved Bug"){
                    [PartialScanManager]::CollatedBugSummaryCount += [PSCustomObject]@{
                        BugStatus=$_.Message
                        ControlSeverity = $item.ControlItem.ControlSeverity;
                        
                    };
                }
                };
                #Collecting control results where bug has been found (new/active/resolved). This is used to generate BugSummary at the end of scan
                [PartialScanManager]::ControlResultsWithBugSummary += $item
            }
        };

    }
            # Collect Closed Bugs summary data and append to it at every checkpoint. Any changes in this method should be synced with WritePSConsole.ps1 PrintBugSummaryData method
    [void] CollateClosedBugSummaryData($event){
        #gather all control results that have passed as their control result
        #obtain their control severities
        $TotalWorkItemCount=0;
        $TotalControlsClosedCount=0;
        $event | ForEach-Object {
            $item = $_
            if ($item -and $item.ControlResults)
            {
                $TotalControlsClosedCount+=1;
                # If two bugs are logged against same resource and control in different project, message will contain closed bug twice with different urls
                $item.ControlResults[0].Messages | ForEach-Object{
                    if($_.Message -eq "Closed Bug"){
                        # CollatedBugSummaryCount is used for PS Console summary printing
                        [PartialScanManager]::CollatedBugSummaryCount += [PSCustomObject]@{
                            BugStatus=$_.Message
                            ControlSeverity = $item.ControlItem.ControlSeverity;
                        };
                        $TotalWorkItemCount+=1
                    }
                };
                #Collecting control results where closed bug has been found. This is used to generate BugSummary at the end of scan
                [PartialScanManager]::ControlResultsWithClosedBugSummary += $item
            }
        };
        [PartialScanManager]::duplicateClosedBugCount+=($TotalWorkItemCount-$TotalControlsClosedCount)

    }

    # Write to csv and append to it at every checkpoint. Any changes in this method should be synced with WriteSummaryFile.ps1 WriteToCSV method
    [void] WriteToCSV([SVTEventContext[]] $arguments, $FilePath)
    {
        if ([string]::IsNullOrEmpty($FilePath)) {
            return;
        }
        [CsvOutputItem[]] $csvItems = @();
        $anyAttestedControls = $null -ne ($arguments | 
            Where-Object { 
                $null -ne ($_.ControlResults | Where-Object { $_.AttestationStatus -ne [AttestationStatus]::None } | Select-Object -First 1) 
            } | Select-Object -First 1);

        $arguments | ForEach-Object {
            $item = $_
            if ($item -and $item.ControlResults) {
                

                $item.ControlResults | ForEach-Object{
                    $csvItem = [CsvOutputItem]@{
                        ControlID = $item.ControlItem.ControlID;
                        ControlSeverity = $item.ControlItem.ControlSeverity;
                        Description = $item.ControlItem.Description;
                        FeatureName = $item.FeatureName;
                        Recommendation = $item.ControlItem.Recommendation;    
                        Rationale = $item.ControlItem.Rationale;
                        AdditionalInfo = $_.AdditionalInfoInCSV
                    };
                    if($_.VerificationResult -ne [VerificationResult]::NotScanned)
                    {
                        $csvItem.Status = $_.VerificationResult.ToString();
                    }
                    
                    if($item.ControlItem.IsBaselineControl)
                    {
                        $csvItem.IsBaselineControl = "Yes";
                    }
                    else
                    {
                        $csvItem.IsBaselineControl = "No";
                    }

                    if($anyAttestedControls)
                    {
                        $csvItem.ActualStatus = $_.ActualVerificationResult.ToString();
                    }

                    if($item.IsResource())
                    {
                        $csvItem.ResourceName = $item.ResourceContext.ResourceName;
                        $csvItem.ResourceGroupName = $item.ResourceContext.ResourceGroupName;
                        try {
                            if($item.ResourceContext.ResourceDetails -ne $null -and ([Helpers]::CheckMember($item.ResourceContext.ResourceDetails,"ResourceLink")))
                            {
                                $csvItem.ResourceLink = $item.ResourceContext.ResourceDetails.ResourceLink;                            
                            }
                        }
                        catch {
                            $_
                        }
                        $csvItem.ResourceId = $item.ResourceContext.ResourceId;
                        $csvItem.DetailedLogFile = "/$([Helpers]::SanitizeFolderName($item.ResourceContext.ResourceGroupName))/$($item.FeatureName).LOG";

                        
                    }
                    else
                    {
                        $csvItem.ResourceId = $item.OrganizationContext.scope;
                        $csvItem.DetailedLogFile = "/$([Helpers]::SanitizeFolderName($item.OrganizationContext.OrganizationName))/$($item.FeatureName).LOG"
                        
                    }

                    if($_.AttestationStatus -ne [AttestationStatus]::None)
                    {
                        $csvItem.AttestedSubStatus = $_.AttestationStatus.ToString();
                        if($null -ne $_.StateManagement -and $null -ne $_.StateManagement.AttestedStateData)
                        {
                            $csvItem.AttesterJustification = $_.StateManagement.AttestedStateData.Justification
                            $csvItem.AttestedBy =  $_.StateManagement.AttestedStateData.AttestedBy
                            if(![string]::IsNullOrWhiteSpace($_.StateManagement.AttestedStateData.ExpiryDate))
                            {
                                $csvItem.AttestationExpiryDate =  $_.StateManagement.AttestedStateData.ExpiryDate
                            }
                            if(![string]::IsNullOrWhiteSpace($_.StateManagement.AttestedStateData.AttestedDate))
                            {
                                $csvItem.AttestedOn=  $_.StateManagement.AttestedStateData.AttestedDate
                            }
                        }
                    }
                    <#if($_.IsControlInGrace -eq $true)
                    {
                        $csvItem.IsControlInGrace = "Yes"
                    }
                    else
                    {
                        $csvItem.IsControlInGrace = "No"
                    }#>
                    
                    $csvItems += $csvItem;
                }                                
            }
        } 

        if ($csvItems.Count -gt 0) {
            # Remove Null properties
            $nonNullProps = @();
            $nonNullProps = [CsvOutputItem].GetMembers() | Where-Object { $_.MemberType -eq [System.Reflection.MemberTypes]::Property }| Select-object -Property Name
            
            ($csvItems | Select-Object -Property $nonNullProps.Name -ExcludeProperty SupportsAutoFix,ChildResourceName,IsPreviewBaselineControl,UserComments ) | Group-Object -Property FeatureName | Foreach-Object {$_.Group | Export-Csv -Path $FilePath -append -NoTypeInformation}
            [PartialScanManager]::IsCsvUpdatedAtCheckpoint = $true
        }
    }
    [void]     CollateSARIFData($event)
    {
        $event | ForEach-Object {
            $item = $_
            if ($item -and $item.ControlResults -and ($item.ControlResults[0].VerificationResult -eq "Failed" -or $item.ControlResults[0].VerificationResult -eq "Verify"))
            {
                #Collecting Failed and verify controls
                [PartialScanManager]::ControlResultsWithSARIFSummary += $item
            }
        };
    }
    
    
    [void] FetchControlStateBackup($InternalId)
    {
        $this.BackupControlStateFilePath = (Join-Path $this.BackupControlStatePath $this.OrgName)
        if($InternalId -match "Organization")
        {
            if(-not (Test-Path $this.BackupControlStateFilePath))
            {
                New-Item -ItemType Directory -Path $this.BackupControlStateFilePath -ErrorAction Stop | Out-Null
            }
            else {
                $this.StateOfControlsToBeFixed += Get-Content (Join-Path $this.BackupControlStateFilePath "$InternalId + '.Json'") -Raw | ConvertFrom-Json
            }
        }
        else {
            # validate org level folder exists
            if(-not (Test-Path $this.BackupControlStateFilePath))
            {
                New-Item -ItemType Directory -Path $this.BackupControlStateFilePath -ErrorAction Stop | Out-Null
            }

            $this.BackupControlStateFilePath = (Join-Path $this.BackupControlStateFilePath $this.ProjectName)
            if(-not (Test-Path $this.BackupControlStateFilePath))
            {
                New-Item -ItemType Directory -Path $this.BackupControlStateFilePath -ErrorAction Stop | Out-Null
            }
            else {
                $this.StateOfControlsToBeFixed += Get-Content (Join-Path $this.BackupControlStateFilePath "$($InternalId + '.Json')") -Raw | ConvertFrom-Json
            }
        }
        $this.IsControlStateBackupFetched = $true
    }


    [void] WriteControlFixDataObject($results)
    {
        if ($this.ScanSource -eq "SDL" -or $this.ScanSource -eq "")
        {
            $scannedby = [ContextHelper]::GetCurrentSessionUser();
            $date = [DateTime]::UtcNow;
            $applicableControls = @()
            $controlsDataObject = @();
            if (($results | measure-object).Count -gt 0) {
                if ($results[0].FeatureName -eq "Project") {
                    $controlsDataObject = @($results  | Where-Object {$_.ControlItem.Tags -contains 'AutomatedFix' -and ($_.ControlResults.VerificationResult -eq 'Failed' -or $_.ControlResults.VerificationResult -eq 'Verify') -and $null -ne $_.ControlResults.BackupControlState} `
                    | Select-Object @{Name="ProjectName"; Expression={$_.ResourceContext.ResourceName}}, @{Name="ResourceName"; Expression={$_.ResourceContext.ResourceName}}, @{Name="ResourceId"; Expression={$_.ResourceContext.ResourceId}}, @{Name="InternalId"; Expression={$_.ControlItem.id}}, @{Name="DataObject"; Expression={$_.ControlResults.BackupControlState}}); 
                }
                else {
                    $controlsDataObject = @($results  | Where-Object {$_.ControlItem.Tags -contains 'AutomatedFix' -and ($_.ControlResults.VerificationResult -eq 'Failed' -or $_.ControlResults.VerificationResult -eq 'Verify') -and $null -ne $_.ControlResults.BackupControlState} `
                    | Select-Object @{Name="ProjectName"; Expression={$_.ResourceContext.ResourceGroupName}}, @{Name="ResourceName"; Expression={$_.ResourceContext.ResourceName}}, @{Name="ResourceId"; Expression={$_.ResourceContext.ResourceId}}, @{Name="InternalId"; Expression={$_.ControlItem.id}}, @{Name="DataObject"; Expression={$_.ControlResults.BackupControlState}}); 
                }
            }
            if($null -ne $controlsDataObject -and $controlsDataObject.Count -gt 0)
        {
                $controlsDataObject | Add-Member -NotePropertyName ScannedBy -NotePropertyValue $scannedBy 
                $controlsDataObject | Add-Member -NotePropertyName Date -NotePropertyValue $date  

                if(-not $this.IsControlStateBackupFetched)  
                {
                    $this.ProjectName = ($controlsDataObject | Select-Object -Property ProjectName -Unique).ProjectName
                    $this.ProjectName = $this.ProjectName.Trim()
                    $this.FetchControlStateBackup($controlsDataObject[0].InternalId);
                }

                $controlsDataObject = @($controlsDataObject)

                if($controlsDataObject.Count -gt 0)
                {
                    $fileName =  $controlsDataObject[0].InternalId + ".json"

                    if($null -ne $this.StateOfControlsToBeFixed)
                    {
                        $existingDataObj = $this.StateOfControlsToBeFixed | where-Object {$_.ResourceId -in $controlsDataObject.ResourceId}
                        if (($existingDataObj | Measure-Object).Count -gt 0)
                        {
                            $this.StateOfControlsToBeFixed = @($this.StateOfControlsToBeFixed | where-Object {$_ -notin $existingDataObj})
                        }
                    }

                    $applicableControls += $controlsDataObject |  select-object -property Date,ResourceId,ResourceName,DataObject,ScannedBy
                    $this.StateOfControlsToBeFixed += $applicableControls
                    [JsonHelper]::ConvertToJsonCustom($this.StateOfControlsToBeFixed) | Out-File (Join-Path $this.BackupControlStateFilePath $fileName) -Force
                }
            }        
             
                                    
            
        }
    }
}

# SIG # Begin signature block
# MIIoKgYJKoZIhvcNAQcCoIIoGzCCKBcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAy3lzkth8SP/7L
# 8pN6F9nfHdsP27vJIAHV8gLpaUoTMKCCDXYwggX0MIID3KADAgECAhMzAAADrzBA
# DkyjTQVBAAAAAAOvMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjMxMTE2MTkwOTAwWhcNMjQxMTE0MTkwOTAwWjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDOS8s1ra6f0YGtg0OhEaQa/t3Q+q1MEHhWJhqQVuO5amYXQpy8MDPNoJYk+FWA
# hePP5LxwcSge5aen+f5Q6WNPd6EDxGzotvVpNi5ve0H97S3F7C/axDfKxyNh21MG
# 0W8Sb0vxi/vorcLHOL9i+t2D6yvvDzLlEefUCbQV/zGCBjXGlYJcUj6RAzXyeNAN
# xSpKXAGd7Fh+ocGHPPphcD9LQTOJgG7Y7aYztHqBLJiQQ4eAgZNU4ac6+8LnEGAL
# go1ydC5BJEuJQjYKbNTy959HrKSu7LO3Ws0w8jw6pYdC1IMpdTkk2puTgY2PDNzB
# tLM4evG7FYer3WX+8t1UMYNTAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQURxxxNPIEPGSO8kqz+bgCAQWGXsEw
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwMTgyNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAISxFt/zR2frTFPB45Yd
# mhZpB2nNJoOoi+qlgcTlnO4QwlYN1w/vYwbDy/oFJolD5r6FMJd0RGcgEM8q9TgQ
# 2OC7gQEmhweVJ7yuKJlQBH7P7Pg5RiqgV3cSonJ+OM4kFHbP3gPLiyzssSQdRuPY
# 1mIWoGg9i7Y4ZC8ST7WhpSyc0pns2XsUe1XsIjaUcGu7zd7gg97eCUiLRdVklPmp
# XobH9CEAWakRUGNICYN2AgjhRTC4j3KJfqMkU04R6Toyh4/Toswm1uoDcGr5laYn
# TfcX3u5WnJqJLhuPe8Uj9kGAOcyo0O1mNwDa+LhFEzB6CB32+wfJMumfr6degvLT
# e8x55urQLeTjimBQgS49BSUkhFN7ois3cZyNpnrMca5AZaC7pLI72vuqSsSlLalG
# OcZmPHZGYJqZ0BacN274OZ80Q8B11iNokns9Od348bMb5Z4fihxaBWebl8kWEi2O
# PvQImOAeq3nt7UWJBzJYLAGEpfasaA3ZQgIcEXdD+uwo6ymMzDY6UamFOfYqYWXk
# ntxDGu7ngD2ugKUuccYKJJRiiz+LAUcj90BVcSHRLQop9N8zoALr/1sJuwPrVAtx
# HNEgSW+AKBqIxYWM4Ev32l6agSUAezLMbq5f3d8x9qzT031jMDT+sUAoCw0M5wVt
# CUQcqINPuYjbS1WgJyZIiEkBMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
# /Xmfwb1tbWrJUnMTDXpQzTGCGgowghoGAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAAOvMEAOTKNNBUEAAAAAA68wDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIGT1zsyPq62vQ7V5shwchnD2
# yWbO7qhSD7CnQ1Dml0FjMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEApGd55pVToFRTJDomAuSqDaBLEzkpIrPIIejHXhkHRW6Y7jGD3wiMoToP
# GONn0yoj7gLPBf5IEfCCgSrocEcKwi+dGu+XAvZXoCTqdsvjkGZ/SOFMbZ2e1Wtj
# 37S2ZiJ+sHcNICGvKSlrpNgRabznl12zShF98Y9d2BzvkjN0WOT6IJ8dSJEplllW
# jP+KbcVePU5RkWemjU45uqxxCP/l6dM4fTOWEfN+LuCrYT7IEm2b64Ud2x5mD39v
# Ef84Xw5QCBFlOO8sL33VqmF9AmB0whvNfHnmECvyYKlipstcamqrEzvvvC/nW3uD
# j88DpSoPF+ZtmaDsZNUjRx1pf93r1aGCF5QwgheQBgorBgEEAYI3AwMBMYIXgDCC
# F3wGCSqGSIb3DQEHAqCCF20wghdpAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCB0azXYjpCFG3qsOkZnsXJ+vaRaIk02xZoUalB8IKFCLAIGZeensqz3
# GBMyMDI0MDMxMjA2NTU1Ny41OTVaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046REMwMC0w
# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
# ghHqMIIHIDCCBQigAwIBAgITMwAAAehQsIDPK3KZTQABAAAB6DANBgkqhkiG9w0B
# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMzEyMDYxODQ1
# MjJaFw0yNTAzMDUxODQ1MjJaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046REMwMC0wNUUwLUQ5NDcxJTAjBgNV
# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQDhQXdE0WzXG7wzeC9SGdH6eVwdGlF6YgpU7weOFBkp
# W9yuEmJSDE1ADBx/0DTuRBaplSD8CR1QqyQmxRDD/CdvDyeZFAcZ6l2+nlMssmZy
# C8TPt1GTWAUt3GXUU6g0F0tIrFNLgofCjOvm3G0j482VutKS4wZT6bNVnBVsChr2
# AjmVbGDN/6Qs/EqakL5cwpGel1te7UO13dUwaPjOy0Wi1qYNmR8i7T1luj2JdFdf
# ZhMPyqyq/NDnZuONSbj8FM5xKBoar12ragC8/1CXaL1OMXBwGaRoJTYtksi9njuq
# 4wDkcAwitCZ5BtQ2NqPZ0lLiQB7O10Bm9zpHWn9x1/HmdAn4koMWKUDwH5sd/zDu
# 4vi887FWxm54kkWNvk8FeQ7ZZ0Q5gqGKW4g6revV2IdAxBobWdorqwvzqL70Wdsg
# DU/P5c0L8vYIskUJZedCGHM2hHIsNRyw9EFoSolDM+yCedkz69787s8nIp55icLf
# DoKw5hak5G6MWF6d71tcNzV9+v9RQKMa6Uwfyquredd5sqXWCXv++hek4A15WybI
# c6ufT0ilazKYZvDvoaswgjP0SeLW7mvmcw0FELzF1/uWaXElLHOXIlieKF2i/YzQ
# 6U50K9dbhnMaDcJSsG0hXLRTy/LQbsOD0hw7FuK0nmzotSx/5fo9g7fCzoFjk3tD
# EwIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFPo5W8o980kMfRVQba6T34HwelLaMB8G
# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQCWfcJm2rwXtPi74km6PKAkni9+BWotq+Qt
# DGgeT5F3ro7PsIUNKRkUytuGqI8thL3Jcrb03x6DOppYJEA+pb6o2qPjFddO1TLq
# vSXrYm+OgCLL+7+3FmRmfkRu8rHvprab0O19wDbukgO8I5Oi1RegMJl8t5k/UtE0
# Wb3zAlOHnCjLGSzP/Do3ptwhXokk02IvD7SZEBbPboGbtw4LCHsT2pFakpGOBh+I
# SUMXBf835CuVNfddwxmyGvNSzyEyEk5h1Vh7tpwP7z7rJ+HsiP4sdqBjj6Avopuf
# 4rxUAfrEbV6aj8twFs7WVHNiIgrHNna/55kyrAG9Yt19CPvkUwxYK0uZvPl2WC39
# nfc0jOTjivC7s/IUozE4tfy3JNkyQ1cNtvZftiX3j5Dt+eLOeuGDjvhJvYMIEkpk
# V68XLNH7+ZBfYa+PmfRYaoFFHCJKEoRSZ3PbDJPBiEhZ9yuxMddoMMQ19Tkyftot
# 6Ez0XhSmwjYBq39DvBFWhlyDGBhrU3GteDWiVd9YGSB2WnxuFMy5fbAK6o8PWz8Q
# RMiptXHK3HDBr2wWWEcrrgcTuHZIJTqepNoYlx9VRFvj/vCXaAFcmkW1nk7VE+ow
# aXr5RJjryDq9ubkyDq1mdrF/geaRALXcNZbfNXIkhXzXA6a8CiamcQW/DgmLJpiV
# QNriZYCHIDCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNN
# MIICNQIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOkRDMDAtMDVFMC1EOTQ3MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQCM
# JG4vg0juMOVn2BuKACUvP80FuqCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA6ZoPDzAiGA8yMDI0MDMxMTIzMTUy
# N1oYDzIwMjQwMzEyMjMxNTI3WjB0MDoGCisGAQQBhFkKBAExLDAqMAoCBQDpmg8P
# AgEAMAcCAQACAhyKMAcCAQACAhPKMAoCBQDpm2CPAgEAMDYGCisGAQQBhFkKBAIx
# KDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZI
# hvcNAQELBQADggEBAA7+z2yiE9B3PKe3Wxy3vZ/sMQEXpxM2Iucn4l0EFecxWbn5
# JUEI6dR3IgOEvrOxJl4aZg7mTX6rQGt+wvi+tv9Q59FTSSKRWSwpJqYcxg9a42xo
# rBTuBLI2wt5tYw7gF5DHNzHWTqjpp1qWxAancEHo9dv/hcQTL231cqG1aAwJICB6
# lOMqnhqRSeqDMCHBuaAVMlNMRxoHNGg7HGIgX17sKrFyiTRzkRsifbEtXl6pNZbB
# nhcxo0uHrv34h6hEikoiIKLMxm/JAP0XdeVvGmVDbuQNnOTmQ0sj4ldU4pXjEew0
# QdRN1guqhUJyIpYHq55VZmU6vZVaD34UN1zN+sgxggQNMIIECQIBATCBkzB8MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy
# b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAehQsIDPK3KZTQABAAAB6DAN
# BglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8G
# CSqGSIb3DQEJBDEiBCA+CV0XwIg8sexLfSIs9AXsAW5ouDrYuWyBqebUM6th0DCB
# +gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EICrS2sTVAoQggkHR59pNqige0xfJ
# T2J3U8W1Sc8H+OsdMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
# MTACEzMAAAHoULCAzytymU0AAQAAAegwIgQghO0MR8z3bNUSwt4VURmbDQkFhI/w
# K492g5UX2eLs2/0wDQYJKoZIhvcNAQELBQAEggIA2hLpeVSIFnk1HYk8TB9UhJtS
# e3dRh+6p1m8ulFrRI5/scGy+L6FqPEcZK2bJ2IVHJMN/TWF5jj92CH+zKl6YsbiC
# CEiAq5jMe4lkDV8pej+H4yGumEah64gnan8IC68PAa7zUcCc30twCW8uTOSYxPuu
# RpwKum4sY/2QhZmwhr3gfvcIv0vlVqHK7UKaTxd2LvPc9CHCMXL49aXQ9KUbAJ5I
# 5KILGBnzsA0jg0Dlwyj+zBqRGCBvukI2Er1x2CWDlfZts8Iu/S0g1qEETTs2BEMm
# RLQk7lBMhwEcbAYe2JjuIzE4l0nJNSqXTgFZt0IZKmcAAEpUXUfyPnSIQhfOGSv9
# etS0sJAD8T6hE+sTt/wnIJp7Arl19rX9tWYxJaSMhzhQth9hjTDbsl9Ujw0TKFhY
# 4dE8C0wlbEyGc9AMq6l9QgpgAzGqJxDYLTbWLZdlDlemCDx7EoMQ0m/AbQHN1QkC
# RaASQuo0lyHtTlqRXZQXhm97AIf72fTnhWFYPjO8v4wBQm/6358M3K3ZeLVgGY4p
# xRFFpn7sjlYDO+MnVt+LX3jmhxRNncZ9yZly9Egaz0fRsVQSyrTceo+j89eXbYW4
# UHm0m7S+OLDrzxG3/pPtE369GvnwDUcbrG/TMX1fvG2bOy8sxhYXFNsk61e0HAxt
# ++ym1ZeF3ZbuA+86c4M=
# SIG # End signature block