Migrate GSM Tests from SCOM to Azure Application

Global Service Monitor (GSM) is a cloud service that provides a simplified way to monitor the availability of web-based applications from multiple locations around the world. GSM tests can be performed from 16 different locations around the world.

GSM supports the following two types of monitoring:

  • Web Application Availability Monitoring
  • Visual Web Tests monitoring (test is defined as webtest file)

Important: GSM is retiring in favor of Application Insights in November 2018.

Application Insights offer two types of tests, very similar to GSM:

  • A URL Ping test which will send out web requests to a site to see if it is responsive. This test can be created within the Azure portal.
  • A Multi-Step web test which is created using Visual Studio Ultimate or Enterprise.

Besides these, there are many other additional features which are offered by Application Insights that can help to diagnose application performance issues in depth https://docs.microsoft.com/en-us/azure/application-insights/app-insights-monitor-web-app-availability

Migrate your tests from Global Service Monitor to Application Insights

The System Center team has developed a Migration tool which will migrate all your Ping Tests and Web Tests from GSM to Azure Application Insights. This tool will also create corresponding alerts in Application Insights, like what you had configured in GSM for your tests.

Important: The following sections provide information on how to migrate the GSM tests to Application Insights, also few notes and points to consider while migrating.

Prerequisites

  • Azure Subscription: Subscription Name is displayed in Azure portal under Subscriptions.
  • ResourceGroupName refers to the resource group in Azure where all the tests will be migrated to. If you do not have a Resource group created in Azure, this script will create a Resource Group with the name provided in the parameters.
  • ResourceLocation refers to location of Resource group metadata in Azure.
  • Azure PowerShell

Other considerations

Understand the following details/do the actions applicable in case you are attempting to migrate the tests under specific scenarios as mentioned below:

Scenario

Notes

You are trying to migrate more than 800 tests

AI limits these. Learn more about the limits.

The resource group can hold only 800 web tests and a component can only hold 100 tests. The migration tool creates a new resource group and migrates the remaining tests to this new resource group. This new resource group will be named as ""<RESOURCE_GROUP_NAME1>" and so on.

You do not wish to run the script from the SCOM server

Install SCOM Powershell on the computer, from where you want to run the script, and provide the SCOM server name in the PowerShell.

You wish to do a logical grouping of tests

The customer can run the tool and move everything on https://resources.azure.com .

There is an option to moveResources under -resourceGroups à DTSLogCleaner.

Run the migration tool

Important: To avoid duplicate tests in Application Insights, ensure you run the script only once.

  • Save the script/tool from Download Center to a local folder on your machine, where you want to run the tool.
  • Run the following PowerShell script:
  • ".\MigrateGSMToAI.ps1 -SubscriptionName "<AZURE_SUBSCRIPTION_NAME>" -AzureResourceGroupName "<RESOURCE_GROUP_NAME>" -ResourceLocation "<RESOURCE_LOCATION>"
  • Tests which fail to migrate, will be logged in log file along with TestInstance IDs.
  • To migrate these tests, please fix the error and rerun the tool along with FailedInstanceIDs as below
  • .\MigrateGSMToAI.ps1 -subscriptionName "<AZURE_SUBSCRIPTION_NAME>" -resourceGroupName "<RESOURCE_GROUP_NAME>" -resourceLocation "<RESOURCE_LOCATION>" -failedMultiStepTestsInstanceId "<FailedMultiStepTestsInstanceId>" -failedPingTestsInstanceId "<FailedPingTestsInstanceId>"

Logging from the tool:

  • The script writes in a log file for the tests for which migration was attempted. The script logs suitable messages for both – the tests which were successfully migrated and those which failed to migrate.
  • The log file is created under the same folder where the script file was copied.
  • Tests that fail migration are logged in a log file along with TestInstance IDs.

Important: During migration if there is any issue with Application Insights and all the tests are not yet migrated then please follow these steps:

  • If only few tests are migrated, then try to delete these tests from https://resources.azure.com . Otherwise you could delete the Resource group if it is brand new and does not contain any other resources other than the newly created availability tests
  • If most of the tests are migrated to AI, then use the log file to retrieve instance IDs of failed tests. Fix errors and rerun the tool as described above.

GSM tests location in Azure portal

Once you have successfully migrated all your GSM tests to Application Insights, verify these tests in the Azure Application Insights.

  • In the Azure portal, open the ResourceGroup that was provided in the script.
  • Under this resource group, you will find the tests which are migrated from GSM.

Note: Once all the tests are migrated to Application Insights, the test summary displays the test results in some time.

Sample Ping test: Application Insights

Click the green/red dot to find the result summary,

Alerts configuration for SCOM tests

In Application insights, URL ping tests are configured to monitor HTTP response. Http Status code 200 indicates success that a normal web page has been returned. All the GSM availability tests report success/failure based on this criterion after they are migrated to Application Insights. The failures can be sent through an email or setup a webhook which would be called when an alert is raised.

Note: The migration tool with create Alerts for your GSM tests in Application Insights. See highlighted is enabled.

Application insights provides the description and status of alerts under

Home-> Resource groups -> <ResourceGroupName>- Activity Log in Azure Portal.

Features not supported in Application Insights

There are few functionalities available in GSM but not available in Application Insights.

You cannot monitor the following scenarios in AI:

  • GSM allows Performance monitoring for a website based on the following metrics, However Application Insight does not have a mapping to automatically collect these performance metrics for websites. You would only see the Response Time for tests; the other Performance metrics on the list will not be monitored.

  • GSM allows you to enable Alerts based on HTTP Status Code. For HTTP status code 200, you will see success for others, it will be a failure.
  • GSM allows you to create Alerts on content match. Application Insights only support "Content must contain" parameter.

MigrateGSMToAI.ps1

  <#
.SYNOPSIS
    .
.DESCRIPTION
    The script will migrate all the GSM tests to Application Insights.
.PARAMETER Path
    The path to the .
.PARAMETER LiteralPath
    Specifies a path to one or more locations. Unlike Path, the value of 
    LiteralPath is used exactly as it is typed. No characters are interpreted 
    as wildcards. If the path includes escape characters, enclose it in single
    quotation marks. Single quotation marks tell Windows PowerShell not to 
    interpret any characters as escape sequences.
.EXAMPLE
    C:\PS> .\MigrateGSMToAI.ps1 -SubscriptionName MyAzureSubscription -AzureResourceGroupName MyResourceGroupName -ResourceLocation "East US" -SCOMMSComputerName "MySCOMComputer"
#>
 Param(
##############  The Azure subscription Name.
	[Parameter(Mandatory=$true)]
	[string]$SubscriptionName,
	
##############  The name of the resource group in azure portal, if you do not have the resource group created in azure, the script will create it.
	[Parameter(Mandatory=$true)]
	[string]$AzureResourceGroupName,
	
##############  The name of the Applications Insight's component, you can provide the parameter, by default it will be take SCOM's Management Group name and all tests will be created under this component.   
    [Parameter(Mandatory=$false)]
	[string]$AIcomponentName,
	
##############  Resource location for the Azure Resource group.
	[Parameter(Mandatory=$true)]
	[string]$ResourceLocation,

##############  Computer Name for SCOM Management Server machine. Provide the parameter if you are using a remote machine to connect to the Management Server or leave blank.
    [Parameter(Mandatory=$false)]
    [string]$SCOMMSComputerName,

##############  Provide the Instance IDs of Ping tests we failed to migrate.
    [Parameter(Mandatory=$false)]
    [String[]]$FailedPingTestsInstanceIds,

##############  Provide the Instance IDs of MultiStep tests we failed to migrate.
    [Parameter(Mandatory=$false)]
    [String[]]$FailedMultiStepTestsInstanceIds
	) #end param

##############  Log the progress of Migration.
function LogMessage([string]$message, [string]$logFileName, [int]$logLevel, [string]$testNameForLog)
{
	$levelText = ""
	If ( $logLevel -eq $ERROR )
	{
		$levelText = "[ERROR]"
		$newLogFileName = $logFileName.Replace($testNameForLog, ($testNameForLog + "-Failed"))
        Move-Item -Path $logFileName -Destination $newLogFileName -Force
		$logFileName = $newLogFileName
	} 
	ElseIf ( $logLevel -eq $FATALERROR )
	{
		$levelText = "[FATALERROR]"
		Write-Host "The script has ended abruptly, Please see the logs @ :- $migrationLogFileName" -ForegroundColor Red
	}
	ElseIf ( $logLevel -eq $DUPERROR )
	{
		$levelText = "[DUPLICATE TEST]"
	}
    Else
    {
        $levelText = "[INFO]"
    }
	$messageToBelogged = $($levelText + " : " + $message)
	$messageToBelogged | Out-File -Append -filepath $logFileName -Force
}

############## Check prerequisites
function Check-Prerequisites
{
	If ( -not (Get-Module OperationsManager ) ) 
	{
		Import-Module OperationsManager
	}

	If ( -not (Get-Module OperationsManager ) ) 
	{
		LogMessage "OperationsManager Powershell module not found." $migrationLogFileName $FATALERROR
		exit
	}

	If ( -not ( Get-Module AzureRm.Profile ) ) 
	{
		Import-Module AzureRm.Profile
	}

	If ( -not (Get-Module AzureRm.Profile ) ) 
	{
		LogMessage "AzureRm.Profile Powershell module not found." $migrationLogFileName $FATALERROR
		exit
	}
}

##############  Interactive login to connect to the Azure account.
function Login-ToAzure
{
	$azureConnection = $null
	Try	
	{
		$azureConnection = Connect-AzureRmAccount
	} 
	Catch	
	{
		LogMessage "Please verify the login credentials. Unable to login to the azure portal." $migrationLogFileName $FATALERROR
		exit
	}

	If ($azureConnection -eq $null)
	{
		LogMessage "Please verify the login credentials. Unable to login to the azure portal." $migrationLogFileName $FATALERROR
		exit
	}
}

##############  Function creates the resource group if already not present on azure.
function Create-ResourceGroup()
{
	$resourceGroupFromAzure = $null
	$IsResourceGroupFoundToBeUsed = $false
	$IsResourceGroupToBeCreated = $false
	While ( -Not $IsResourceGroupFoundToBeUsed )
	{
		Try 
		{
			LogMessage "Verifying if the resource group with Name:- $script:resourceGroupName and location:- $ResourceLocation already exists." $migrationLogFileName $INFORMATION
			$resourceGroupFromAzure = Get-AzureRmResource -ResourceGroupName $script:resourceGroupName -ResourceType "microsoft.insights/components" -ApiVersion 2014-04-01
			If ( $resourceGroupFromAzure -ne $null )
			{
				If ( $( $resourceGroupFromAzure | Group-Object ResourceType).Count -ge 8 )
				{
					$resourceGroupSuffix ++
					$script:resourceGroupName = $( $AzureResourceGroupName + $resourceGroupSuffix)
					continue
				}
			}
			Else
			{
				$resourceGroupFromAzure = Get-AzureRmResource -ResourceId /subscriptions/$subscriptionID/resourceGroups/$script:resourceGroupName -ApiVersion 2014-04-01
				If ( $resourceGroupFromAzure -ne $null )
				{
					LogMessage "Resource group with Name:- $script:resourceGroupName and location:- $resourceLocation already exists." $migrationLogFileName $INFORMATION
					$IsResourceGroupFoundToBeUsed = $true
				}
				Else
				{
					LogMessage "The azure resource group:- $script:resourceGroupName does not exist. Will try to create the resource group." $migrationLogFileName $INFORMATION
					$IsResourceGroupToBeCreated = $true
				}
			}
		} 
		Catch 
		{
			LogMessage "The azure resource group:- $script:resourceGroupName does not exist. Will try to create the resource group." $migrationLogFileName $INFORMATION
			$IsResourceGroupToBeCreated = $true
		}
		$IsResourceGroupFoundToBeUsed = $true
	}
	
	If ( $IsResourceGroupToBeCreated )
	{
		LogMessage "Creating resource group with Name:- $script:resourceGroupName and location:- $ResourceLocation." $migrationLogFileName $INFORMATION
		Try	
		{
			New-AzureRmResourceGroup -Location $ResourceLocation -Name $script:resourceGroupName
		} 
		Catch	
		{
			LogMessage "Unable to create the resource group with Name:- $script:resourceGroupName and location:- $ResourceLocation. Please verify if you have the correct privileges to create the resource group." $migrationLogFileName $FATALERROR
			exit
		}
	} 
	Else 
	{
		LogMessage "Resource group with Name:- $script:resourceGroupName and location:- $ResourceLocation already exists." $migrationLogFileName $INFORMATION
		return
	}
	
	LogMessage "Created Resource group with Name:- $script:resourceGroupName and location:- $ResourceLocation." $migrationLogFileName $INFORMATION
}

##############  Function for creating component in Application Insights.
function Create-Component( $componentName )
{
	$kindOfComponent = "web"
	$componentJSON = ""
    
	$componentJSONObject = New-Object -TypeName PSObject

    Add-Member -InputObject $componentJSONObject -MemberType NoteProperty -Name name -Value $componentName
    Add-Member -InputObject $componentJSONObject -MemberType NoteProperty -Name location -Value $ResourceLocation
    Add-Member -InputObject $componentJSONObject -MemberType NoteProperty -Name kind -Value $kindOfComponent

    $componentPropertiesObject = New-Object -TypeName PSObject
    Add-Member -InputObject $componentPropertiesObject -MemberType NoteProperty -Name Application_Type -Value "web"
    Add-Member -InputObject $componentPropertiesObject -MemberType NoteProperty -Name ApplicationId -Value $componentName
    Add-Member -InputObject $componentPropertiesObject -MemberType NoteProperty -Name Flow_Type -Value "Bluefield"
    Add-Member -InputObject $componentPropertiesObject -MemberType NoteProperty -Name Request_Source -Value "rest"

    Add-Member -InputObject $componentJSONObject -MemberType NoteProperty -Name properties -Value $componentPropertiesObject

	$componentJSON = $componentJSONObject | ConvertTo-Json
	
	LogMessage $( "Component JSON:- " + $componentJSON ) $migrationLogFileName $INFORMATION
	
	LogMessage "Creating Component with Name:- $componentName." $migrationLogFileName $INFORMATION
	Try	
	{
		New-AzureRmResource -ResourceName $componentName -Location $ResourceLocation -PropertyObject $componentJSON -ResourceGroupName $script:resourceGroupName -ResourceType microsoft.insights/components -ApiVersion 2015-05-01 -Force
	} 
	Catch	
	{
		LogMessage "Unable to create Component with Name:- $componentName." $migrationLogFileName $FATALERROR
		exit
	}
	
	LogMessage $( "Created Component Name:- " + $componentName + " in Resource group :- " + $script:resourceGroupName ) $migrationLogFileName $INFORMATION
}

##############  Function to validate the resource location provided by the user as the parameter ResourceLocation
function ValidateResourceLocation()
{
    $azureLocations = $(Get-AzureRmLocation).DisplayName
    If ( -Not $azureLocations.Contains($ResourceLocation) )
    {
        LogMessage $("Please provide a valid resource location. Here are the valid locations "+$azureLocations) $migrationLogFileName $FATALERROR
		exit
    }
}

##############  Function for formating GeoLocations to REST API consumable format.
function Format-GeoLocations ( $testLocations )
{
    $webTestGeoLocations = @{}, @{}
    Foreach ( $location in $testLocations ) 
    {
        Switch ( $location )
        {

            "emea-nl-ams-edge"  { $location = "emea-nl-ams-azr" }
            "us-ca-lax-edge"    { $location = "us-ca-sjc-azr" }
            "apac-sg-sin-edge"  { $location = "apac-sg-sin-azr" }
            "us-tx-sn1-edge"    { $location = "us-tx-sn1-azr" }
            "us-il-ch1-edge"    { $location = "us-il-ch1-azr" }
            "emea-gb-lts-edge"  { $location = "emea-gb-db3-azr" }
            "emea-gb-lts-edge"  { $location = "emea-gb-db3-azr" }
            "us-nj-ewr-edge"    { $location = "us-va-ash-azr" }
            "apac-tw-tpa-edge"  { $location = "apac-hk-hkn-azr" }

        }

        $webTestGeoLocations += @{Id = $location}
	}
	
    return $webTestGeoLocations | Select-Object -Skip 2
}

##############  Common Function for Ping and Multistep test to create JSON.
function Build-TestJSON ( $scomTest, $completeWebTestName, $componentName, $webTestGeoLocations, $webTestXML, $webTestKind, $frequency, $timeout, $testInstanceID)
{
	$testID = $completeWebTestName + "-" + $componentName
    $testLogFileName = $( $testLogFilePath + $completeWebTestName + ".txt" )
    "" | Out-File -filepath $testLogFileName -Force
    LogMessage $( "Building JSON for Test NAME:- " + $completeWebTestName ) $testLogFileName $INFORMATION
	LogMessage $( "SCOM Instance ID :- " + $testInstanceID ) $testLogFileName $INFORMATION
	Write-Host "Building JSON for Test NAME:- " $completeWebTestName -ForegroundColor Green
	############# Convert SCOM GSM test frequency into Applications Insights UI supported values (5, 10, 15) minutes
    $newFrequency = [int][Math]::Ceiling($frequency/60) *60
    If ( $newFrequency -gt 900 )
    {
        $newFrequency = 900
    }
    If ( $frequency -ne $newFrequency )
    {
        Write-Host "The Test frequency is changed from :-"$frequency "to :-"$newFrequency -ForegroundColor Yellow
        LogMessage $( "The Test frequency is changed from :-" + $frequency + " to :- "+ $newFrequency) $testLogFileName $INFORMATION
    }

	############# Convert SCOM GSM test timeout into Applications Insights UI supported values (30, 60, 90, 120) seconds
    If ( $webTestKind -eq "ping" )
    {
        $newTimeout = [int][Math]::Ceiling($timeout/30) *30
        If ( $newTimeout -gt 120 )
        {
            $newTimeout = 120
        }
        If ( $timeout -ne $newTimeout )
        {
            Write-Host "The Test Time out is changed from :-"$timeout "to :-"$newTimeout -ForegroundColor Yellow
            LogMessage $( "The Test Time out is changed from :-" + $timeout + " to :- "+ $newTimeout) $testLogFileName $INFORMATION
        }
    }
    
	$enabled = $true
	$retryEnabled = $true

	$propertiesObject = New-Object -TypeName PSObject
    $configurationObject = New-Object -TypeName PSObject

    Add-Member -InputObject $configurationObject -MemberType NoteProperty -Name WebTest -Value $webTestXML

    Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name SyntheticMonitorId -Value $testID
    Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Name -Value $completeWebTestName
	Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Description -Value ("$webTestKind web test for " + $completeWebTestName)
	Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Enabled -Value $enabled
	Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Frequency -Value $newFrequency
	Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Timeout -Value $newTimeout
    Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Kind -Value $webTestKind
	Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name RetryEnabled -Value $retryEnabled
    Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Locations -Value @( $webTestGeoLocations )
    Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Configuration -Value $configurationObject

    return $propertiesObject
}

##############  Function for Building MultiStepTest JSON.
function Build-MultiStepTest( $FailedMultiStepTestsInstanceIds )
{
	$multiTestJSON = ""
    $multiStepTestsForRequest = @()
    $numberOfTestsInComponent = 0
    $componentSuffix = 1
	
	$allGeoLocations = Get-SCOMClass -Name "Microsoft.SystemCenter.Omonline.OutsideIn.OutsideInPop" | Get-SCOMClassInstance

    If ( $FailedMultiStepTestsInstanceIds.count -eq 0)
    {
	    $multiStepTests = Get-SCOMClass -DisplayName "Visual Studio Web Test Container" | Get-SCOMClassInstance
	}
    Else
    {
        $multiStepTests = Get-SCOMClassInstance -Id $FailedMultiStepTestsInstanceIds
		$componentSuffix = $( $( Get-AzureRmResource -ResourceGroupName $script:resourceGroupName -ResourceType "microsoft.insights/components" -ApiVersion 2014-04-01 ) | Group-Object ResourceType).Count
		$componentSuffix ++
    }

	Foreach ( $multiStepTest in $multiStepTests ) 
	{
        $multiStepTestID = $multiStepTest.Id
        If ( $numberOfTestsInComponent -eq 0 )
        {
            ##############  Invoke Create Component using New-AzureRmResource. More info -- https://docs.microsoft.com/en-us/powershell/module/azurerm.resources/new-azurermresource?view=azurermps-6.5.0
            $componentName = $("MultiStep-" + $AIcomponentName + $componentSuffix)
            $componentSuffix++
        }

		[xml]$testLocationsXML = $multiStepTest.'[Microsoft.SystemCenter.Omonline.OutsideIn.VSWebTest.VSWebTestContainer].Locations'.Value
		$testLocationsIDs = $testLocationsXML.Locations.Location.managementActionPointId

		$testLocations = $allGeoLocations | Select-Object -Property Id, Name | Where-Object {$_.Id -in $testLocationsIDs}
        $webTestGeoLocations = Format-GeoLocations $testLocations.Name

		## Case where test is configured to run on internal agent.
		If ( $webTestGeoLocations -eq $null )
        {
            continue;
        }
		$NumOfLocMultiTest = $webTestGeoLocations.Count
        If ( $NumOfLocMultiTest -ge 3 )
        {
            $NumOfLocMultiTest = 3;
        }
		
		[xml]$testConfigXML = $multiStepTest.'[Microsoft.SystemCenter.Omonline.OutsideIn.VSWebTest.VSWebTestContainer].VSDeclarativeTestConfigs'.Value
        $webTestXML = $testConfigXML.VSWebTestConfigs.VSWebTestElement.content
		$multiTestFrequency = $multiStepTest.'[Microsoft.SystemCenter.Omonline.OutsideIn.VSWebTest.VSWebTestContainer].IntervalInSeconds'.Value
		
		## Case where test name is a duplicate
		If ( $allTests.Contains($multiStepTest.DisplayName) )
		{
            $testLogFileName = $( $testLogFilePath + "MultiStep-DuplicateTest.txt" )
			LogMessage $( "Cannot migrate test, as there is already a multistep test with name :- " + $multiStepTest.DisplayName + ". Please rename the test to migrate." ) $testLogFileName $DUPERROR
            LogMessage $( "Information to find the SCOM Instance ID :- " + $multiStepTestID + " with name :- " + $multiStepTest.DisplayName ) $testLogFileName $DUPERROR
			Write-Host "Cannot migrate test, as there is already a multistep test with name :- " $multiStepTest.DisplayName ". Please rename the test to migrate." -ForegroundColor Red
			continue
		}
		Else 
		{
			$allTests.Add($multiStepTest.DisplayName)
            $numberOfTestsInComponent++
            If ( $numberOfTestsInComponent -ge $componentLimit )
            {
                $numberOfTestsInComponent = 0
            }
		}
        
        $multiStepTestProperty = Build-TestJSON $multiStepTest $multiStepTest.DisplayName $componentName $webTestGeoLocations $webTestXML "multistep" $multiTestFrequency 120 $multiStepTestID

        $multiStepTestForRequest = New-Object -TypeName PSObject
        Add-Member -InputObject $multiStepTestForRequest -MemberType NoteProperty -Name NAME -Value $multiStepTest.DisplayName
        Add-Member -InputObject $multiStepTestForRequest -MemberType NoteProperty -Name ID -Value $multiStepTestID
        Add-Member -InputObject $multiStepTestForRequest -MemberType NoteProperty -Name PROPERTY -Value $multiStepTestProperty
        Add-Member -InputObject $multiStepTestForRequest -MemberType NoteProperty -Name COMPONENT -Value $componentName
        Add-Member -InputObject $multiStepTestForRequest -MemberType NoteProperty -Name NUMOFLOC -Value $NumOfLocMultiTest

        $multiStepTestsForRequest += $multiStepTestForRequest
	}
	
	return $multiStepTestsForRequest
}

##############  Function for Http Headers for PingTest.
function Build-HTTPHeaders( $httpHeaders )
{
	[xml]$pingHeaders = '
' $headersFlag = $true Foreach ( $httpHeader in $httpHeaders.HttpHeader ) { If ( $headersFlag ) { $pingHeaders.Headers.Header.Name = $httpHeader.Name $pingHeaders.Headers.Header.Value = $httpHeader.Value $headersFlag = $false } Else { $pingHeader = $pingHeaders.CreateElement("Header") $pingHeader.SetAttribute("Name", $httpHeader.Name) $pingHeader.SetAttribute("Value", $httpHeader.Value) [void]$pingHeaders.Headers.AppendChild($pingHeader) } } return $pingHeaders.OuterXml } ############## Function to create StringHttpBody for Ping Test, We are assuming that the customer has provided the body in JSON format function Build-StringHttpBody( $pingTestBody, $contentType ) { return ''+$([Convert]::ToBase64String($([System.Text.Encoding]::Unicode.GetBytes($pingTestBody))))+'' } ############## Function for Building PingTest JSON. function Build-PingTest( $FailedPingTestsInstanceIds ) { $pingTestsForRequest = @() $numberOfTestsInComponent = 0 $componentSuffix = 1 $allGeoLocations = Get-SCOMClass -Name "Microsoft.SystemCenter.Omonline.OutsideIn.OutsideInPop" | Get-SCOMClassInstance If ( $FailedPingTestsInstanceIds.count -eq 0 ) { $pingTests = Get-SCOMClass -Name "Microsoft.SystemCenter.WebApplicationSolutions.SingleUrlTest" | Get-SCOMClassInstance } Else { $pingTests = Get-SCOMClassInstance -Id $FailedPingTestsInstanceIds $componentSuffix = $( $( Get-AzureRmResource -ResourceGroupName $script:resourceGroupName -ResourceType "microsoft.insights/components" -ApiVersion 2014-04-01 ) | Group-Object ResourceType).Count $componentSuffix ++ } Foreach ( $pingTest in $pingTests ) { If ( $numberOfTestsInComponent -eq 0 ) { ############## Invoke Create Component using New-AzureRmResource. More info -- https://docs.microsoft.com/en-us/powershell/module/azurerm.resources/new-azurermresource?view=azurermps-6.5.0 $componentName = $("Ping-" + $AIcomponentName + $componentSuffix) $componentSuffix++ } $pingJSON = "" $parametersValues = "" $pingTestFrequency = 0 $pingTestConfig = $null $pingTestRequest = $null $pingTestTimeOut = 0 $followRedirects = "" $httpVersion = "" $httpMethod = "" $httpHeaders = "" $pingTestHttpHeaders = "" $pingTestStringHttpBody= "" $pingTestBody = "" $pingTestForRequest = $null $pingTestId = $pingTest.Id [xml]$testLocationsXML = $pingTest.'[Microsoft.SystemCenter.WebApplicationSolutions.SingleUrlTest].Locations'.Value $testLocationsIDs = $testLocationsXML.Locations.Location.managementActionPointId $testLocations = $allGeoLocations | Select-Object -Property Id, Name | Where-Object {$_.Id -in $testLocationsIDs} $webTestGeoLocations = Format-GeoLocations $testLocations.Name ## Case where test is configured to run on internal agent. If ( $webTestGeoLocations -eq $null ) { continue; } $NumOfLocPingTest = $webTestGeoLocations.Count If ( $NumOfLocPingTest -ge 3 ) { $NumOfLocPingTest = 3; } $parametersValues = ([xml]($pingTest.'[Microsoft.SystemCenter.WebApplicationSolutions.SingleUrlTest].Parameters'.Value)).Parameters.Parameter.Value $pingTestFrequency = $pingTest.'[Microsoft.SystemCenter.WebApplicationSolutions.SingleUrlTest].IntervalInSeconds'.Value $pingTestConfig = ([xml]($pingTest.'[Microsoft.SystemCenter.WebApplicationSolutions.SingleUrlTest].TestConfig'.Value)).TestConfig $pingTestRequest = $pingTestConfig.Requests.Request $pingTestTimeOut = $pingTestConfig.TestTimeout If ( $pingTestTimeOut -eq $null ) { $pingTestTimeOut = 30 } $followRedirects = $pingTestConfig.FollowRedirects If ( $followRedirects -eq $null ) { $followRedirects = "True" } $httpVersion = $pingTestRequest.Version If ( $httpVersion -eq $null ) { $httpVersion = "1.1" } $httpMethod = $pingTestRequest.Verb If ( $httpMethod -eq $null ) { $httpMethod = "GET" } $httpHeaders = $pingTestRequest.HttpHeaders If ( $httpHeaders -ne $null ) { $pingTestHttpHeaders = Build-HTTPHeaders $httpHeaders } $pingTestBody = $pingTestRequest.Body If ( $pingTestBody -ne $null ) { [xml]$pingTestHttpHeadersXML = $pingTestHttpHeaders $contentTypeForTest = $($pingTestHttpHeadersXML.Headers.Header | Where-Object {$_.Name -eq "Content-Type"}).Value $pingTestStringHttpBody = Build-StringHttpBody $pingTestBody $contentTypeForTest } Foreach ( $parametersValue in $parametersValues ) { $pingTestURL = $parametersValue.Innertext $webTestXML = '' + $pingTestHttpHeaders + $pingTestStringHttpBody + '' $pingtestName = $( $pingTest.DisplayName + "-" + $parametersValue.displayName ) ## Case where test name is a duplicate If ( $allTests.Contains( $($pingtestName + "-" + $componentName) ) ) { $testLogFileName = $( $testLogFilePath + "Ping-DuplicateTest.txt" ) LogMessage $( "Cannot migrate Ping test, as there is already a Ping test with name :- " + $pingtestName + " in component :- " + $componentName + ". Please rename the test to migrate." ) $testLogFileName $DUPERROR LogMessage $( "Information to find the SCOM Instance ID :- " + $pingTestId + " with name :- " + $pingtestName ) $testLogFileName $DUPERROR Write-Host "Cannot migrate Ping test, as there is already a Ping test with name :- " $pingtestName " with URL :- " $pingTestURL " in component :- " $componentName " . Please rename the test to migrate" -ForegroundColor Red continue } Else { $allTests.Add( $($pingtestName + "-" + $componentName) ) $numberOfTestsInComponent++ If ( $numberOfTestsInComponent -ge $componentLimit ) { $numberOfTestsInComponent = 0 } } $pingTestProperty = Build-TestJSON $pingTest $pingtestName $componentName $webTestGeoLocations $webTestXML "ping" $pingTestFrequency $pingTestTimeOut $pingTestId $pingTestForRequest = New-Object -TypeName PSObject Add-Member -InputObject $pingTestForRequest -MemberType NoteProperty -Name NAME -Value $pingtestName Add-Member -InputObject $pingTestForRequest -MemberType NoteProperty -Name ID -Value $pingTestId Add-Member -InputObject $pingTestForRequest -MemberType NoteProperty -Name PROPERTY -Value $pingTestProperty Add-Member -InputObject $pingTestForRequest -MemberType NoteProperty -Name COMPONENT -Value $componentName Add-Member -InputObject $pingTestForRequest -MemberType NoteProperty -Name NUMOFLOC -Value $NumOfLocPingTest $pingTestsForRequest += $pingTestForRequest } } return $pingTestsForRequest } ############## Function for creating a web test in Application Insights function Create-WebTest( $webTests ) { $previousComponentName = "" Foreach ( $webTest in $webTests ) { $componentName = $webTest.COMPONENT $propertiesObject = $webtest.PROPERTY If ( $componentName -ne $previousComponentName) { $previousComponentName = $componentName Create-Component $componentName } $testLogFileName = $( $testLogFilePath + $webtest.NAME + ".txt" ) ############## REST Call to create the Web Test $webTestCompleteName = $( $webtest.NAME + "-" + $componentName) $webTestMigrated = $null $webTestAlertCreated = $null LogMessage $( "Migrating Test for NAME:- " + $webtest.NAME ) $testLogFileName $INFORMATION LogMessage $( "Component NAME:- " + $componentName ) $testLogFileName $INFORMATION LogMessage $( "Resource Group NAME:- " + $script:resourceGroupName ) $testLogFileName $INFORMATION LogMessage $( "JSON for Test :- " + $( $propertiesObject | ConvertTo-Json -Depth 5 ) ) $testLogFileName $INFORMATION Write-Host "Migrating Test for NAME:- " $webtest.NAME -ForegroundColor Green Try { $tagsObject = @{} $tagsObject.Add("hidden-link:/subscriptions/$subscriptionID/resourceGroups/$script:resourceGroupName/providers/microsoft.insights/components/$componentName", "Resource") $tagsObject.Add("hidden-link:Microsoft.Internal.IsScomWebTest", "true") New-AzureRmResource -ResourceName $webTestCompleteName -Location $ResourceLocation -PropertyObject $propertiesObject -ResourceGroupName $script:resourceGroupName -ResourceType microsoft.insights/webtests -Tag $tagsObject -ApiVersion 2015-05-01 -Force } Catch { $exceptionString = $_.Exception.Message If ( $exceptionString.contains("ResourceQuotaExceeded") ) { LogMessage $( "Creating a new Resource Group as Resource Group :- " + $script:resourceGroupName + " has exceed the quota of '800' resources." ) $migrationLogFileName $INFORMATION $resourceGroupSuffix ++ $script:resourceGroupName = $( $AzureResourceGroupName + $resourceGroupSuffix) ########### If the quota of 800 resource exceeds, we will create a new Resource group and a new Component in that resource group and re-try the test creation in new Resource group. Create-ResourceGroup Create-Component $componentName Try { $tagsObject = @{} $tagsObject.Add("hidden-link:/subscriptions/$subscriptionID/resourceGroups/$script:resourceGroupName/providers/microsoft.insights/components/$componentName", "Resource") $tagsObject.Add("hidden-link:Microsoft.Internal.IsScomWebTest", "true") New-AzureRmResource -ResourceName $webTestCompleteName -Location $ResourceLocation -PropertyObject $propertiesObject -ResourceGroupName $script:resourceGroupName -ResourceType microsoft.insights/webtests -Tag $tagsObject -ApiVersion 2015-05-01 -Force } Catch { LogMessage $( "Exception:- " + $_.Exception.Message ) $testLogFileName $INFORMATION $webtest.NAME LogMessage $( "Unable to migrate the Test with Name:- " + $webtest.NAME + " SCOM Instance ID :- " + $webtest.ID ) $testLogFileName $ERROR $webtest.NAME Write-Host "Unable to migrate the Test with Name:- " $webtest.NAME ". Please see the logs @ :- $testLogFileName" -ForegroundColor Red continue } } Else { LogMessage $( "Exception:- " + $_.Exception.Message ) $testLogFileName $INFORMATION $webtest.NAME LogMessage $( "Unable to migrate the Test with Name:- " + $webtest.NAME + " SCOM Instance ID :- " + $webtest.ID ) $testLogFileName $ERROR $webtest.NAME Write-Host "Unable to migrate the Test with Name:- " $webtest.NAME ". Please see the logs @ :- $testLogFileName" -ForegroundColor Red continue } } LogMessage $( "Verifying if the test:- " + $webtest.NAME + " got created in Application Insights." ) $testLogFileName $INFORMATION $webTestMigrated = Get-AzureRmResource -ResourceGroupName $script:resourceGroupName -ResourceType microsoft.insights/webtests -ResourceName $webTestCompleteName If ( $webTestMigrated -eq $null ) { LogMessage $( "Exception:- " + $_.Exception.Message ) $testLogFileName $INFORMATION $webtest.NAME LogMessage $( "Migration Not Successful for the Test with Name:- " + $webtest.NAME + " SCOM Instance ID :- " + $webtest.ID ) $testLogFileName $ERROR $webtest.NAME Write-Host "Migration Not Successful for the Test with Name:- " $webtest.NAME ". Please see the logs @ :- $testLogFileName" -ForegroundColor Red continue } Else { LogMessage $( "Migration Successful for the Test with Name:- " + $webtest.NAME ) $testLogFileName $INFORMATION } Try { LogMessage $( "Creating alert for test :- " + $webtest.NAME ) $migrationLogFileName $INFORMATION Create-WebTestAlert $webTestCompleteName $webTest.COMPONENT $webTest.NUMOFLOC } Catch { LogMessage $( "Exception:- " + $_.Exception.Message ) $testLogFileName $INFORMATION $webtest.NAME LogMessage $( "Unable to create alert for Name:- " + $webtest.NAME ) $testLogFileName $ERROR $webtest.NAME Write-Host "Unable to create alert for Name:- " $webtest.NAME ". Please see the logs @ :- $testLogFileName" -ForegroundColor Red continue } LogMessage $( "Verifying if the alert for test:- " + $webtest.NAME + " got created in Application Insights." ) $testLogFileName $INFORMATION $webTestAlertCreated = Get-AzureRmResource -ResourceGroupName $script:resourceGroupName -ResourceType microsoft.insights/alertrules -ResourceName $webTestCompleteName If ( $webTestAlertCreated -eq $null ) { LogMessage $( "Exception:- " + $_.Exception.Message ) $testLogFileName $INFORMATION $webtest.NAME LogMessage $( "Creation of alert Not Successful for the Test with Name:- " + $webtest.NAME ) $testLogFileName $ERROR $webtest.NAME Write-Host "Creation of alert Not Successful for the Test with Name:- " $webtest.NAME ". Please see the logs @ :- $testLogFileName" -ForegroundColor Red continue } Else { LogMessage $( "Creation of alert Successful for the Test with Name:- " + $webtest.NAME ) $testLogFileName $INFORMATION } Write-Host "Migration Successful for the Test with Name:- " $webtest.NAME -ForegroundColor Green $newTestLogFileName = $testLogFileName.Replace($webtest.NAME, ($webtest.NAME + "-Migrated")) Move-Item -Path $testLogFileName -Destination $newTestLogFileName -Force $testLogFileName = $newTestLogFileName } } ############## Function for creating Alert for a web test. function Create-WebTestAlert( $completeWebTestName, $componentName, $numberOfAlertLocations) { $tagsObject = @{} $propertiesObject = New-Object -TypeName PSObject $conditionObject = New-Object -TypeName PSObject $dataSourceObject = New-Object -TypeName PSObject $actionObject = New-Object -TypeName PSObject $tagsObject.Add("hidden-link:/subscriptions/$subscriptionID/resourceGroups/$script:resourceGroupName/providers/microsoft.insights/components/$componentName", "Resource") $tagsObject.Add("hidden-link:/subscriptions/$subscriptionID/resourceGroups/$script:resourceGroupName/providers/microsoft.insights/webtests/$completeWebTestName", "Resource") Add-Member -InputObject $dataSourceObject -MemberType NoteProperty -Name odata.type -Value "Microsoft.Azure.Management.Insights.Models.RuleMetricDataSource" Add-Member -InputObject $dataSourceObject -MemberType NoteProperty -Name MetricName -Value "GSMT_AvRaW" Add-Member -InputObject $dataSourceObject -MemberType NoteProperty -Name ResourceUri -Value "/subscriptions/$subscriptionID/resourceGroups/$script:resourceGroupName/providers/microsoft.insights/webtests/$completeWebTestName" Add-Member -InputObject $conditionObject -MemberType NoteProperty -Name odata.type -Value "Microsoft.Azure.Management.Insights.Models.LocationThresholdRuleCondition" Add-Member -InputObject $conditionObject -MemberType NoteProperty -Name DataSource -Value $dataSourceObject Add-Member -InputObject $conditionObject -MemberType NoteProperty -Name WindowSize -Value "PT5M" Add-Member -InputObject $conditionObject -MemberType NoteProperty -Name FailedLocationCount -Value $numberOfAlertLocations Add-Member -InputObject $actionObject -MemberType NoteProperty -Name odata.type -Value "Microsoft.Azure.Management.Insights.Models.RuleEmailAction" Add-Member -InputObject $actionObject -MemberType NoteProperty -Name SendToServiceOwners -Value $true Add-Member -InputObject $actionObject -MemberType NoteProperty -Name CustomEmails -Value @() Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Name -Value $completeWebTestName Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Description -Value ("Alert rule for web test " + $completeWebTestName) Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name IsEnabled -Value $true Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Condition -Value $conditionObject Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name Action -Value $actionObject Add-Member -InputObject $propertiesObject -MemberType NoteProperty -Name actions -Value @() LogMessage $( "JSON Data for the alert :- " + $( $propertiesObject | ConvertTo-Json -Depth 5 ) ) $testLogFileName $INFORMATION New-AzureRmResource -ResourceName $completeWebTestName -Location $ResourceLocation -PropertyObject $propertiesObject -ResourceGroupName $script:resourceGroupName -ResourceType microsoft.insights/alertrules -Tag $tagsObject -ApiVersion 2016-03-01 -Force } ############## START OF SCRIPT ############## clear ############## Logging variables $ERROR = 1 $FATALERROR = 2 $DUPERROR = 3 $INFORMATION = 4 $testLogFilePath = $(Get-Location).Path + "\Logs\" $migrationLogFileName = $testLogFilePath + "MigrationLog.txt" $testLogFileName = "" $allTests = New-Object 'System.Collections.Generic.List[string]' ############## Variables used in the script. $subscriptionID = "" $pingWebTests = $null $multiStepWebTests = $null $subscription = $null $componentLimit = 100 $resourceGroupSuffix = 0 $resourceGroupName = $AzureResourceGroupName $allWebTestsToMigrate = @() ############## Creating Log folder if does not exist, and delete all log files if already exists. If ( -Not (Test-Path -Path $testLogFilePath) ) { New-Item -ItemType directory -Path $testLogFilePath -ErrorAction Stop } Else { Remove-Item $testLogFilePath* -Include *.txt } "[INFO] START OF SCRIPT" | Out-File -filepath $migrationLogFileName -Force ############## Check Prerequisites. Check-Prerequisites ############## Creates a persistent connection to a management group. Try { IF ( [string]::IsNullOrEmpty($SCOMMSComputerName) ) { New-SCOMManagementGroupConnection } Else { $SCOMCredentials = Get-Credential -Message "Enter SCOM Management Server Credentials." New-SCOMManagementGroupConnection -ComputerName $SCOMMSComputerName -Credential $SCOMCredentials } } Catch { LogMessage $( "Exception:- " + $_.Exception.Message ) $migrationLogFileName $FATALERROR LogMessage "Unable to connect to SCOM. Please verify your credentials" $migrationLogFileName $FATALERROR exit } ############## If the Component Name is not provided in the script parameters, defaulting it to SCOM Management Group. If ( [string]::IsNullOrEmpty($AIcomponentName) ) { $AIcomponentName = $(Get-SCOMManagementGroup).Name } ############## Interactive Login to connect to the Azure account. Login-ToAzure ############## Interactive Login to connect to the Azure account. ValidateResourceLocation ############## Getting The Azure subscription ID from the subcription name. Try { Select-AzureRmSubscription -SubscriptionName $SubscriptionName $subscription = (Get-AzureRmContext).Subscription $subscriptionID = $subscription.Id } Catch { LogMessage $( "Exception:- " + $_.Exception.Message ) $migrationLogFileName $FATALERROR LogMessage "Unable to get the Subscription:- $SubscriptionName from the azure account. Please verify the name of the subscription." $migrationLogFileName $FATALERROR exit } ############## Creates Resource group if not present. Create-ResourceGroup ############## Get the data of the ping test from operations manager and then create the test in Application Insights If ( (( $FailedPingTestsInstanceIds.count -eq 0 ) -and ( $FailedMultiStepTestsInstanceIds.count -eq 0 )) -or ($FailedPingTestsInstanceIds.count -ne 0) ) { $pingWebTests = Build-PingTest $FailedPingTestsInstanceIds $allWebTestsToMigrate += $pingWebTests } ############## Get the data of the multi step test from operations manager and then create the test in Application Insights If ( (( $FailedPingTestsInstanceIds.count -eq 0 ) -and ( $FailedMultiStepTestsInstanceIds.count -eq 0 )) -or ($FailedMultiStepTestsInstanceIds.count -ne 0) ) { $multiStepWebTests = Build-MultiStepTest $FailedMultiStepTestsInstanceIds $allWebTestsToMigrate += $multiStepWebTests } ############## Create Ping and MultiStep Tests in Azure Application Insights. Create-WebTest $allWebTestsToMigrate ############## Logout the session. Disconnect-AzureRmAccount ############## Deletes persistent connections to management groups. Get-SCOMManagementGroupConnection |?{$_.IsActive } | Remove-SCOMManagementGroupConnection ############## All the Log files of the migrated tests. $migratedTestsLogFiles = get-childitem -Path $testLogFilePath | where-object {$_.Name -like "*-Migrated*"} If ( $migratedTestsLogFiles ) { LogMessage $( "Logs for all the tests we successfully migrated to Azure App Insights :-" + $migratedTestsLogFiles ) $migrationLogFileName $INFORMATION Write-Host "Logs for all the tests we successfully migrated to Azure App Insights :-" $migratedTestsLogFiles -ForegroundColor Green } ############## All the Log files of the failed tests. $failedTestsLogFiles = get-childitem -Path $testLogFilePath | where-object {$_.Name -like "*-Failed*"} If ( $failedTestsLogFiles ) { LogMessage $( "Logs of all the tests which are failed to migrate to Azure App Insights :-" + $failedTestsLogFiles ) $migrationLogFileName $INFORMATION Write-Host "Logs of all the tests which are failed to migrate to Azure App Insights :-" $failedTestsLogFiles -ForegroundColor Red } ############## All the Log files of the duplicate tests. $duplicateTestsLogFiles = get-childitem -Path $testLogFilePath | where-object {$_.Name -like "*-DuplicateTest*"} If ( $duplicateTestsLogFiles ) { LogMessage $( "Please refer the logs :- " + $duplicateTestsLogFiles + " to get all the tests which are duplicate, please rename them and re-migrate." ) $migrationLogFileName $INFORMATION Write-Host "Please refer the logs :- " $duplicateTestsLogFiles " to get all the tests which are duplicate, please rename them and re-migrate." -ForegroundColor Red } LogMessage "[INFO] END OF SCRIPT" $migrationLogFileName $INFORMATION ############## Please verify the web test should get created on the Application Insights. ############## END OF SCRIPT ############## # SIG # Begin signature block # MIIkmgYJKoZIhvcNAQcCoIIkizCCJIcCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD+JCbmHCRozGmo # bLxC0111LvTnQmJ9bybdN3/mwuPfOqCCDYEwggX/MIID56ADAgECAhMzAAABA14l # HJkfox64AAAAAAEDMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMTgwNzEyMjAwODQ4WhcNMTkwNzI2MjAwODQ4WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDRlHY25oarNv5p+UZ8i4hQy5Bwf7BVqSQdfjnnBZ8PrHuXss5zCvvUmyRcFrU5 # 3Rt+M2wR/Dsm85iqXVNrqsPsE7jS789Xf8xly69NLjKxVitONAeJ/mkhvT5E+94S # nYW/fHaGfXKxdpth5opkTEbOttU6jHeTd2chnLZaBl5HhvU80QnKDT3NsumhUHjR # hIjiATwi/K+WCMxdmcDt66VamJL1yEBOanOv3uN0etNfRpe84mcod5mswQ4xFo8A # DwH+S15UD8rEZT8K46NG2/YsAzoZvmgFFpzmfzS/p4eNZTkmyWPU78XdvSX+/Sj0 # NIZ5rCrVXzCRO+QUauuxygQjAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUR77Ay+GmP/1l1jjyA123r3f3QP8w # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDM3OTY1MB8GA1UdIwQYMBaAFEhu # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAn/XJ # Uw0/DSbsokTYDdGfY5YGSz8eXMUzo6TDbK8fwAG662XsnjMQD6esW9S9kGEX5zHn # wya0rPUn00iThoj+EjWRZCLRay07qCwVlCnSN5bmNf8MzsgGFhaeJLHiOfluDnjY # DBu2KWAndjQkm925l3XLATutghIWIoCJFYS7mFAgsBcmhkmvzn1FFUM0ls+BXBgs # 1JPyZ6vic8g9o838Mh5gHOmwGzD7LLsHLpaEk0UoVFzNlv2g24HYtjDKQ7HzSMCy # RhxdXnYqWJ/U7vL0+khMtWGLsIxB6aq4nZD0/2pCD7k+6Q7slPyNgLt44yOneFuy # bR/5WcF9ttE5yXnggxxgCto9sNHtNr9FB+kbNm7lPTsFA6fUpyUSj+Z2oxOzRVpD # MYLa2ISuubAfdfX2HX1RETcn6LU1hHH3V6qu+olxyZjSnlpkdr6Mw30VapHxFPTy # 2TUxuNty+rR1yIibar+YRcdmstf/zpKQdeTr5obSyBvbJ8BblW9Jb1hdaSreU0v4 # 6Mp79mwV+QMZDxGFqk+av6pX3WDG9XEg9FGomsrp0es0Rz11+iLsVT9qGTlrEOla # P470I3gwsvKmOMs1jaqYWSRAuDpnpAdfoP7YO0kT+wzh7Qttg1DO8H8+4NkI6Iwh # SkHC3uuOW+4Dwx1ubuZUNWZncnwa6lL2IsRyP64wggd6MIIFYqADAgECAgphDpDS # AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla # MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT # H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG # OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S # 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz # y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7 # 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u # M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33 # X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl # XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP # 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB # l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF # RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM # CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ # BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud # DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO # 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw # cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA # XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY # 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj # 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd # d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ # Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf # wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ # aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j # NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B # xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 # eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 # r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I # RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIWbzCCFmsCAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAQNeJRyZH6MeuAAAAAABAzAN # BglghkgBZQMEAgEFAKCB2DAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgcFbsP8Rq # TSsOVfu+s8r3OJ8ZVdTwo/Cd7Hg54yWTjugwbAYKKwYBBAGCNwIBDDFeMFygMIAu # AE0AaQBjAHIAbwBzAG8AZgB0ACAAUwB5AHMAdABlAG0AIABDAGUAbgB0AGUAcqEo # gCZodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vU3lzdGVtQ2VudGVyIDANBgkqhkiG # 9w0BAQEFAASCAQADnpFjiTloqk5V9kfRV+UsXvR7AW/NuPscz0F+o3bye8v3K7Sh # 0LH+fUE/TWL7IoP62ebbebp0lPCISiauOmkrKUM7CLNsnGE0W1d+yu4Dez467lMh # Y4xD5HiwPJxbhU5RYpoTvvqBtFIxRZQfQJVK8hTehtO9lYqTHZN+HAbxjPs3FwF5 # gLW7a0IohuP9ebPDgZV/kYzDWHptjI8iIGN1xfZK5vaKXM5CG/QHpKtNXHyjaFRi # 0xdtmtdIEPZDWpgdfF9w2lEorM2lkSSjxL8ABUsj5rR7FGF9qu4MHDqU3UNuMFHs # MRj4B1g+CpGVqHp+YVb8j/Tl2GSZvwqL/iZtoYITzzCCE8sGCisGAQQBgjcDAwEx # ghO7MIITtwYJKoZIhvcNAQcCoIITqDCCE6QCAQMxDzANBglghkgBZQMEAgEFADCC # AVgGCyqGSIb3DQEJEAEEoIIBRwSCAUMwggE/AgEBBgorBgEEAYRZCgMBMDEwDQYJ # YIZIAWUDBAIBBQAEIOp0tHy2xDS2PWFabVsBgwP6Xi0db7rmpAprihmc079ZAgZb # iBHO5a8YEzIwMTgwOTEwMTAwNDIwLjc3MVowBwIBAYACAfSggdSkgdEwgc4xCzAJ # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jv # c29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNT # IEVTTjo5OEZELUM2MUUtRTY0MTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3Rh # bXAgU2VydmljZaCCDx8wggT1MIID3aADAgECAhMzAAAAy194yyMOlJfDAAAAAADL # MA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n # dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y # YXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4X # DTE4MDgyMzIwMjYyNFoXDTE5MTEyMzIwMjYyNFowgc4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRp # b25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo5OEZELUM2 # MUUtRTY0MTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCC # ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMV4yB3v8B1BcBxtNEo/VALK # GnizA1WCEIU22DCpyy838O0VlW7D3KUomZPIU3nsx3MxaQXpai0OiVs+DPuHqdoK # tsuYCaMxeDHhodCgPWdPT9NN0hngnC07R2nDB2NhvtRBpr4V36791Pqi3CssKDdL # jBrOQUhqEn8S0VP5xldDQPfMIpqRFQdP6Ut4dvaI/Mva5e86HbawJxdGKrTdHp7L # Oae3YHX25khbhuNatqp3dDu3Do6xDE1BIa2GuUGZa4oHVNwWIWk3SZ4xZlarT3eA # i712yWyeTrjGv56Ryje8yDiBtd+1UCn67t0TwQpTa+a2ZPP2v8HyQxQegc+9ThUC # AwEAAaOCARswggEXMB0GA1UdDgQWBBQo5PLm9snRTa5uyNsqlr8xw/vZdjAfBgNV # HSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBHhkVo # dHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNUaW1T # dGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAC # hj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0YVBD # QV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUF # BwMIMA0GCSqGSIb3DQEBCwUAA4IBAQCL9GGFgwVibMsUlJfD6SUDbHKxL9pN6ZYM # g+aOTE8AyCh9oD6HcuinUjkj6afQU63TvgVRWExYJLzrQBysAh2GgbGkKIPtdV6y # QQMlJxclXpR48t1jS1VvBX0KksR5Bq/4/0e58+jXvUaU2JcUQVw3lHn9I/YtQJeu # AvnNfLENxJKE3A7FOjOAw+fEH49OGK1IBR9yhXS+r6HslFuFLfjK7DU89+Cu1zAg # 9JTCCrqlWSydWApAYh/ACInONLHHp9OZdilC42zGjB8Ro/07YqMAjPhK7Ze12lWT # hiZIFqc5fZTxCi3L2T8pQI91/Nxu4CnpIzLXUwSXUxkIpfSNsK7OMIIGcTCCBFmg # AwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3Qg # Q2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcNMjUw # NzAxMjE0NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ # MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u # MSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIwDQYJ # KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0VBDV # pQoAgoX77XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEwRA/x # YIiEVEMM1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQedGFn # kV+BVLHPk0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKxXf13 # Hz3wV3WsvYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4GkbaI # CDXoeByw6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEAAaOC # AeYwggHiMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7fEYb # xTNoWoVtVTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYw # DwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoY # xDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtp # L2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYB # BQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20v # cGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0gAQH/ # BIGVMIGSMIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYBBQUH # AgIwNB4yIB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUAbQBl # AG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOhIW+z # 66bM9TG+zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS+7lT # jMz0YBKKdsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlKkVIA # rzgPF/UveYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon/VWv # L/625Y4zu2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOiPPp/ # fZZqkHimbdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/fmNZ # JQ96LjlXdqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCIIYdqw # UB5vvfHhAN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0cs0d # 9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7aKLix # qduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQcdeh # 0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+NR4I # uto229Nfj950iEkSoYIDrTCCApUCAQEwgf6hgdSkgdEwgc4xCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVy # YXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo5OEZE # LUM2MUUtRTY0MTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vydmlj # ZaIlCgEBMAkGBSsOAwIaBQADFQC5o5PSQHbRtx8VowRRl644K9uaIaCB3jCB26SB # 2DCB1TELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT # B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UE # CxMgTWljcm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJzAlBgNVBAsTHm5D # aXBoZXIgTlRTIEVTTjo1N0Y2LUMxRTAtNTU0QzErMCkGA1UEAxMiTWljcm9zb2Z0 # IFRpbWUgU291cmNlIE1hc3RlciBDbG9jazANBgkqhkiG9w0BAQUFAAIFAN9Ad/Aw # IhgPMjAxODA5MTAxMjU2MTZaGA8yMDE4MDkxMTEyNTYxNlowdDA6BgorBgEEAYRZ # CgQBMSwwKjAKAgUA30B38AIBADAHAgEAAgIU6zAHAgEAAgIWpDAKAgUA30HJcAIB # ADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMBoAowCAIBAAIDFuNgoQow # CAIBAAIDB6EgMA0GCSqGSIb3DQEBBQUAA4IBAQCQNbEJlYUpSLy39rCmIhHOxn6L # 7dxJ+UtC0IokKI4JYm7wgV9d8tBe0iGbA1IZdR1lfnt7iPGXQDwyFvc7MA2Ndu/V # DrruUiZtLbQ87vAaxwCQ/RdJHkIoJjjOIDv9UKwkyH1MOtuuf49VX+ZYvF7tVz3S # HChsPffGG3WpN/3lL/PyGdeaCWvc4qzDTfc8PnXXHSpI8fc56h32HfsUEzHXuidT # d6iakoZkkfmqVsx9VrIDvKiPSiigU90w0W1GUheY/9VKOrrsH7Sg9JbR1bpcwABq # Y140G1cULPhK7SGF6KE333Jm5Wixzu2ePTDTfORyM3Fij/3OIV8ZPXHKtdACMYID # DTCCAwkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAADL # X3jLIw6Ul8MAAAAAAMswDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzEN # BgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgmJ7xUUlWd+g3nNKvMH81Vw+I # l6RYuBy6iZYk6Ivvo3IwgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCA2JyGq # qWCnXutz0KS9S3wuF/afS9Mu7hRHXqpg3cEdZDCBmDCBgKR+MHwxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU # aW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAAy194yyMOlJfDAAAAAADLMCIEIF94UIgv # XMNDmgF6TuOsuWjS0VkxLAmBopLCk2o1lLkYMA0GCSqGSIb3DQEBCwUABIIBAI47 # W5ne9e0dEip8s/wpGkUfLQ8LaSOCQkyHkySnrLrUFoJnBjUQKkV1CrgDHi/1F4HT # ylZsyj51qNXEaPLr/CofgP4SAMqcS7N4JirL3F6PRuCkKafOk0phbvd/LiBjF67V # 4wzKm9T19Y4X2q31MXiXBWnrNK1r1UeLpfHL+s4maMc85emWOzXJhXlcxQrtcrsI # 5Gnsuxyg2IswI+s2X2a9h3gbz2VrsRhMABc8AY9pEDqOtuz5woUAXKO8RDEqT0C6 # tY78isSqyXYLZVZ25rydOugCCbkbDN02RpEnzQ1gnPN9LPSIXhE7kK9tMCZedByr # rpxuUdgaKIm63sBo56U= # SIG # End signature block