####################################################################################
####################################################################################
## ValidateAOS.ps1
## Validate AOS deployment
## Date: 09/29/2015
##
####################################################################################
####################################################################################
[CmdletBinding()]
Param(
   [Parameter(Mandatory = $true)]
   [string]$InputXml,
   [Parameter(Mandatory = $false)]
   [string]$CredentialsXml,
   [Parameter(Mandatory = $true)]
   [string]$Log
)

Import-Module "$PSScriptRoot\AosCommon.psm1" -Force -DisableNameChecking
Initialize-Log $Log

####################################################################################
## Helper Functions
####################################################################################

## Append XML Rows to Template
function Append-RowToXML
{
    [CmdletBinding()]
    Param(
       [Parameter(Mandatory = $false)]
       [string]$TestName,
       [Parameter(Mandatory = $false)]
       [string]$TestType,
       [Parameter(Mandatory = $false)]
       [string]$TestResult,
       [Parameter(Mandatory = $false)]
       [string]$RawResult,
       [Parameter(Mandatory = $false)]
       [string]$TimeStamp,
       [Parameter(Mandatory = $true)]
       [xml]$xmlTemplate
    )

    Write-Log "Getting existing rows from XML Template"
    $rows = $xmlTemplate.SelectSingleNode('CollectionResult/TabularResults/TabularData/Rows')
    Write-Log "Creating new row"
    $row = $xmlTemplate.CreateElement('ArrayOfStrings')
    $column = $xmlTemplate.CreateElement('string')#TestName
    $column.InnerText = $TestName
    $row.AppendChild($column)
    Write-Log "Adding column value: $TestName"
    $column = $xmlTemplate.CreateElement('string')#TestType
    $column.InnerText = $TestType
    $row.AppendChild($column)
    Write-Log "Adding column value: $TestType"
    $column = $xmlTemplate.CreateElement('string')#TestResult
    $column.InnerText = $TestResult
    $row.AppendChild($column)
    Write-Log "Adding column value: $TestResult"
    $column = $xmlTemplate.CreateElement('string')#RawResult
    $column.InnerText = $RawResult
    $row.AppendChild($column)
    
    $column = $xmlTemplate.CreateElement('string')#TimeStamp
    $column.InnerText = $TimeStamp
    $row.AppendChild($column)
    $rows.AppendChild($row)
    Write-Log "Adding column value: $TimeStamp"
    $xmlTemplate.CollectionResult.TabularResults.TabularData.AppendChild($rows)
    $xmlTemplate.Save($xmlTemplate)
    Write-Log "Saved rows to XML Template"
}

####################################################################################
## Validation Functions
####################################################################################

## Validate endpoint sending HTTP request to configured endpoint 
function Validate-Endpoint{ 
     [CmdletBinding()] 
    Param( 
     [Parameter(Mandatory = $true)] 
     [string]$EndPointUrl 
     ) 
 
     [bool]$result = $false 
     [string]$rawResult 
     [string]$timestamp 
 
     try{ 
         Write-Log "Connecting to '$EndPointUrl'"
         $CurrentTime = (Get-Date).ToUniversalTime() 
         $webRequest = Invoke-WebRequest -Uri $EndPointUrl -TimeoutSec (5 * 60) -UseBasicParsing 
         if($webRequest.StatusCode -eq 200){ 
             $result = $true 
             $UrlTime = [DateTime]::Parse($webRequest.Headers.Date).ToUniversalTime() 
             $rawResult = ('HttpResult: ' + $webRequest.StatusCode.ToString() + '; PingTime(ms): ' + ($CurrentTime - $UrlTime).TotalMilliseconds).ToString() 
             $timestamp = (Get-Date).ToString() 
             Write-Log "Web request returned - $rawResult"
         } 
     } 
     catch{ 
         $rawResult = $_.Exception 
         $timestamp = (Get-Date).ToString() 
         Write-Log "ERROR: $($_.Exception) CALLSTACK: $_"
     } 
 
     if($result){ 
         $returnProperties = @{ 
             Result=1; 
            RawResults=$rawResult; 
            TimeStamp=$timestamp 
         } 
     } 
     else{ 
         $returnProperties = @{ 
             Result=0; 
            RawResults=$rawResult; 
            TimeStamp=$timestamp 
         } 
     } 
     $resultObject = New-Object PsObject -Property $returnProperties 
     return $resultObject 
} 
 
## Validate install Files from a manifest file 
function Validate-Install{ 
     [CmdletBinding()] 
    Param( 
     [Parameter(Mandatory = $true)] 
     [string]$InstallPath, 
     [Parameter(Mandatory = $false)] 
     [string]$ManifestPath 
     ) 
 
     [bool]$result = $false 
     [string]$rawResult 
     [string]$timestamp 
 
     try{ 
         Write-Log "Validating Install at '$InstallPath'"
         if(Test-Path -Path $InstallPath) 
         { 
             Write-Log "Comparing '$InstallPath' to manifest"
             [System.Array]$installedfiles = @() 
             $installedFilesRaw = Get-ChildItem -Path $InstallPath -Recurse | Where {$_.PSIsContainer -eq $false} | Select-Object -Property Name 
            foreach($file in $installedFilesRaw){ 
                $installedfiles += $file.Name 
             } 
 
             if(Test-Path -Path $ManifestPath){ 
                 $manifestFiles = Get-Content -Path $ManifestPath 
                 $fileCompare = Compare-Object -ReferenceObject $manifestFiles -DifferenceObject $installedFiles -Property Name -PassThru 
                 $timestamp = (Get-Date).ToString() 
                 if($fileCompare -eq $null) 
                 { 
                     $rawResult = "Installed file ARE a match to the manifest" 
                     Write-Log "$rawResult"
                     $result = $true 
                 } 
                 else 
                 { 
                     $rawResult = ("{0} Files are missing." -f $fileCompare.Count ) 
                     Write-Log "$rawResult"
                 } 
             } 
             else{ 
                Throw "$ManifestPath does not exist." 
             } 
         } 
         else{ 
            Throw "$InstallPath does not exist." 
         } 
     } 
     catch{ 
         $rawResult = $_.Exception 
         $timestamp = (Get-Date).ToString() 
         Write-Log "ERROR: $($_.Exception) CALLSTACK: $_"
     } 
 
     if($result){ 
         $returnProperties = @{ 
             Result=1; 
            RawResults=$rawResult; 
            TimeStamp=$timestamp 
         } 
     } 
     else{ 
         $returnProperties = @{ 
             Result=0; 
            RawResults=$rawResult; 
            TimeStamp=$timestamp 
         } 
    } 
     $resultObject = New-Object PsObject -Property $returnProperties 
     return $resultObject 
} 
 
## Validate service is running 
function Validate-Service{ 
    [CmdletBinding()] 
    Param( 
     [Parameter(Mandatory = $true)] 
     [string]$ServiceName, 
     [Parameter(Mandatory = $true)] 
     [ValidateSet("Running","Stopped","Paused")] 
     [string]$CurrentState 
     ) 
 
     [bool]$result = $false 
     [string]$rawResult 
     [string]$timestamp 
 
     try{ 
         Write-Log "Validating Service: '$ServiceName' is $CurrentState"
         $thisService = Get-Service -Name $ServiceName 
         $timestamp = (Get-Date).ToString() 
         $rawResult = ("ServiceName: {0}; DisplayName: {1}; Status: {2}" -f $thisService.Name, $thisService.DisplayName, $thisService.Status) 
         if($thisService.Status.ToString() -eq $CurrentState) 
         { 
            $result = $true 
         } 
         Write-Log "Service: $ServiceName is $($thisService.Status)"
 
     } 
     catch{ 
         $rawResult = $_.Exception 
         $timestamp = (Get-Date).ToString() 
         Write-Log "ERROR: $($_.Exception) CALLSTACK: $_"
     } 
 
     if($result){ 
         $returnProperties = @{ 
             Result=1; 
            RawResults=$rawResult; 
            TimeStamp=$timestamp 
         } 
     } 
     else{ 
         $returnProperties = @{ 
             Result=0; 
            RawResults=$rawResult; 
            TimeStamp=$timestamp 
         } 
     } 
     $resultObject = New-Object PsObject -Property $returnProperties 
     return $resultObject 
} 
 
## Validate appPool is started 
function Validate-AppPool{ 
    [CmdletBinding()] 
    Param( 
     [Parameter(Mandatory = $true)] 
     [string]$AppPoolName, 
     [Parameter(Mandatory = $true)] 
     [ValidateSet("Started","Stopped")] 
     [string]$CurrentState 
     ) 
 
     [bool]$result = $false 
     [string]$rawResult 
     [string]$timestamp 
 
     try{ 
         Write-Log "Validating AppPool: '$AppPoolName' is $CurrentState"
         Get-WebAppPoolState 
         $appPoolStatus = Get-WebAppPoolState -Name $AppPoolName 
         $timestamp = (Get-Date).ToString() 
         $rawResult = ("AppPoolName: {0}; Status: {1}" -f $AppPoolName, $appPoolStatus) 
         if($appPoolStatus.Value -eq $CurrentState) 
         { 
            $result = $true 
         } 
         Write-Log "AppPool: $AppPoolName is $($appPoolStatus.Value)"
     } 
     catch{ 
         $rawResult = $_.Exception 
         $timestamp = (Get-Date).ToString() 
         Write-Log "ERROR: $($_.Exception) CALLSTACK: $_"
     } 
 
     if($result){ 
         $returnProperties = @{ 
             Result=1; 
            RawResults=$rawResult; 
            TimeStamp=$timestamp 
         } 
     } 
     else{ 
         $returnProperties = @{ 
             Result=0; 
            RawResults=$rawResult; 
            TimeStamp=$timestamp 
         } 
     } 
     $resultObject = New-Object PsObject -Property $returnProperties 
     return $resultObject 
} 




####################################################################################
## Parameter Setting
####################################################################################
Write-Log "Setting DVT execution parameters"

if(Test-Path -Path $InputXML)
{
    Write-Log "Parsing the xml for parameters/settings"
    [xml]$DVTParams = Get-Content -Path $InputXML
    [string]$ServiceName = $DVTParams.DVTParameters.ServiceName    
    [string]$AosWebrootPath = $DVTParams.DVTParameters.AosWebRootPath    
    [string]$XmlOutputPath = $DVTParams.DVTParameters.OutputPath    
	[string]$endPoint = $DVTParams.DVTParameters.EndPoint #Infrastructure.HostUrl
    [string]$installPath = $DVTParams.DVTParameters.InstallPath
	[string]$manifestFile = $DVTParams.DVTParameters.ManifestPath
	[string]$ServiceState = $DVTParams.DVTParameters.ServiceState
	[string]$AppPoolName = $DVTParams.DVTParameters.AppPoolName
	[string]$AppPoolState = $DVTParams.DVTParameters.AppPoolState
    [string]$BatchService = $DVTParams.DVTParameters.BatchService
}
else
{
    throw "Unable to parse settings from service model. Xml doesnt exist at: $InputXML"
}

if(-not ([string]::IsNullOrEmpty($CredentialsXml)))
{
    Write-Log "Parsing the CredentialsXml"
    if(Test-Path -Path $CredentialsXml)
    {
        Write-Log "Parsing the xml for local credentials"
        $localCredentials = Import-Clixml -Path $CredentialsXml
        [string]$UserName = $localCredentials.GetNetworkCredential().UserName
        [string]$UserPassword = $localCredentials.GetNetworkCredential().Password
    }
    else
    {
        throw "Unable to parse credentials from service model. Xml doesnt exist at: $CredentialsXML"
    }
}

Write-Log "Setting diagnostics-related parameters"
[string]$CollectorName = "$($ServiceName).DVT"
[string]$CollectorType = 'PowerShellCollector'
[string]$TargetName = (hostname)

if(-not (Test-Path -Path $XmlOutputPath))
{
    Write-Log "Creating diagnostics result directory at $XmlOutputPath"
    New-Item -Path $XmlOutputPath -Type Container | Out-Null
}

[string]$XMLFilePath = Join-Path -Path $XmlOutputPath -ChildPath "$([System.DateTime]::Now.ToFileTimeUtc())_$($ServiceName)DVTResults.xml"

####################################################################################
## Diagnostics Collector XML Template
####################################################################################
[xml]$xmlTemplate = @"
<?xml version="1.0"?>
<CollectionResult xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <CollectorName>$CollectorName</CollectorName>
  <CollectorType>$CollectorType</CollectorType>
  <ErrorMessages />
  <TabularResults>
    <TabularData>
      <TargetName>$TargetName</TargetName>
      <Columns>
        <string>TestName</string>
        <string>TestType</string>
        <string>PassResult</string>
        <string>RawResult</string>
        <string>TimeStamp</string>
      </Columns>
      <Rows>
      </Rows>
    </TabularData>
  </TabularResults>
</CollectionResult>
"@

####################################################################################
## Main Execution
####################################################################################

Write-Log "Running validations for $ServiceName"
try
{
     #End point validation 
     Write-Log "Validate-Endpoint -EndPointUrl" 
     $endpointResult = Validate-Endpoint -EndPointUrl $endPoint
 
     Append-RowToXML -TestName 'AOS.Validate-Endpoint' -TestType 'DVT' -TestResult $endpointResult.Result -RawResult $endpointResult.RawResults -TimeStamp $endpointResult.TimeStamp -xmlTemplate $xmlTemplate | Out-Null 

    $ValidateBatch = (![System.String]::IsNullOrWhiteSpace($DVTParams.DVTParameters.ValidateBatch) -and [System.Convert]::ToBoolean($DVTParams.DVTParameters.ValidateBatch))
    if ($ValidateBatch)
    {
        #AXBatch Service 
        Write-Log "Validate-Service -ServiceName $BatchService -CurrentState $ServiceState" 
        $serviceResult = Validate-Service -ServiceName $BatchService -CurrentState $ServiceState 

        Append-RowToXML -TestName 'AOS.Validate-Service' -TestType 'DVT' -TestResult $serviceResult.Result -RawResult $serviceResult.RawResults -TimeStamp $serviceResult.TimeStamp -xmlTemplate $xmlTemplate | Out-Null 
    } 

     #IIS AppPool Validation 
     Write-Log "Validate-AppPool -AppPoolName $AppPoolName -CurrentState $AppPoolState"
     $apppoolResult = Validate-AppPool -AppPoolName $AppPoolName -CurrentState $AppPoolState 

     Append-RowToXML -TestName 'AOS.Validate-AppPool' -TestType 'DVT' -TestResult $apppoolResult.Result -RawResult $apppoolResult.RawResults -TimeStamp $apppoolResult.TimeStamp -xmlTemplate $xmlTemplate | Out-Null 

    #Writing XML results
    Write-Log "Writing DVT results to $XMLFilePath"
    $xmlTemplate.InnerXml | Out-File -FilePath $XMLFilePath -Force -Encoding utf8

    [bool]$dvtResult = $endpointResult.Result -and $apppoolResult.Result
    if ($ValidateBatch)
    {
        $dvtResult = $dvtResult -and $serviceResult.Result
    }

}
catch
{
    Write-Exception $_
}

if($dvtResult)
{
    $exitProperties = @{'ExitCode'= 0}
    $exitObject = New-Object PsObject -Property $exitProperties
    Write-Log "DVT Script Completed, ExitCode: $($exitObject.ExitCode)"
    return $exitObject
}
else
{
    $exitProperties = @{'ExitCode'= 1; 'Message'="DVT Validation failed, see log: '$Log' for further details, and '$XMLFilePath' for test results"}
    $exitObject = New-Object PsObject -Property $exitProperties
    Write-Log "DVT Script Completed, ExitCode: $($exitObject.ExitCode)"
    throw $exitObject
}


# SIG # Begin signature block
# MIIoKgYJKoZIhvcNAQcCoIIoGzCCKBcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBPDETZSfEdM3Dd
# jYdA0NRlWVmqeL50qgjbytga87dgeaCCDXYwggX0MIID3KADAgECAhMzAAAEBGx0
# Bv9XKydyAAAAAAQEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTE0WhcNMjUwOTExMjAxMTE0WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQC0KDfaY50MDqsEGdlIzDHBd6CqIMRQWW9Af1LHDDTuFjfDsvna0nEuDSYJmNyz
# NB10jpbg0lhvkT1AzfX2TLITSXwS8D+mBzGCWMM/wTpciWBV/pbjSazbzoKvRrNo
# DV/u9omOM2Eawyo5JJJdNkM2d8qzkQ0bRuRd4HarmGunSouyb9NY7egWN5E5lUc3
# a2AROzAdHdYpObpCOdeAY2P5XqtJkk79aROpzw16wCjdSn8qMzCBzR7rvH2WVkvF
# HLIxZQET1yhPb6lRmpgBQNnzidHV2Ocxjc8wNiIDzgbDkmlx54QPfw7RwQi8p1fy
# 4byhBrTjv568x8NGv3gwb0RbAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU8huhNbETDU+ZWllL4DNMPCijEU4w
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwMjkyMzAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAIjmD9IpQVvfB1QehvpC
# Ge7QeTQkKQ7j3bmDMjwSqFL4ri6ae9IFTdpywn5smmtSIyKYDn3/nHtaEn0X1NBj
# L5oP0BjAy1sqxD+uy35B+V8wv5GrxhMDJP8l2QjLtH/UglSTIhLqyt8bUAqVfyfp
# h4COMRvwwjTvChtCnUXXACuCXYHWalOoc0OU2oGN+mPJIJJxaNQc1sjBsMbGIWv3
# cmgSHkCEmrMv7yaidpePt6V+yPMik+eXw3IfZ5eNOiNgL1rZzgSJfTnvUqiaEQ0X
# dG1HbkDv9fv6CTq6m4Ty3IzLiwGSXYxRIXTxT4TYs5VxHy2uFjFXWVSL0J2ARTYL
# E4Oyl1wXDF1PX4bxg1yDMfKPHcE1Ijic5lx1KdK1SkaEJdto4hd++05J9Bf9TAmi
# u6EK6C9Oe5vRadroJCK26uCUI4zIjL/qG7mswW+qT0CW0gnR9JHkXCWNbo8ccMk1
# sJatmRoSAifbgzaYbUz8+lv+IXy5GFuAmLnNbGjacB3IMGpa+lbFgih57/fIhamq
# 5VhxgaEmn/UjWyr+cPiAFWuTVIpfsOjbEAww75wURNM1Imp9NJKye1O24EspEHmb
# DmqCUcq7NqkOKIG4PVm3hDDED/WQpzJDkvu4FrIbvyTGVU01vKsg4UfcdiZ0fQ+/
# V0hf8yrtq9CkB8iIuk5bBxuPMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# 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
# Z25pbmcgUENBIDIwMTECEzMAAAQEbHQG/1crJ3IAAAAABAQwDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIFblnddwkWx06Q6BUqL75BZn
# V2OJrQnJQ/zIfszQnRDJMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEAZne+DN7G8YPA3iPWPUOAoYNO+WPoZSsbwbqED7xIJE3dZe7TCkwEniC2
# il+u3hX/wTussheH6plZnBdWeQ56++Bf4griMxL5yR9bP+8oZ9eK7/DfslFd2Drh
# CpJHC+KTTXajIAm0fQBDu2vixGt1CmOhBN1WTrp5piR2b3HKnh2mFXammFNz7A8O
# +I4sD/43/eY7ReaIXCafYGuDVJWE98ulwbCi7vEcepOXeG6CzfUuUqUy8jLaHVV3
# kljlhPgJLquUDqJcsqZJTRmVkSbjYG3L1cZJ6XKtV7GaMZazIDhLiTpsfgOET3Kg
# D640sNFegN6bqoKwG2/tv0b7eGGPsKGCF5QwgheQBgorBgEEAYI3AwMBMYIXgDCC
# F3wGCSqGSIb3DQEHAqCCF20wghdpAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCA+qlt0BsQbtcm8grttcBfMln23YLW5VSDynA5vBKQn1AIGZz86a9Xw
# GBMyMDI0MTIxMjA3MjEwMi40MTRaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046ODkwMC0w
# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
# ghHqMIIHIDCCBQigAwIBAgITMwAAAe3hX8vV96VdcwABAAAB7TANBgkqhkiG9w0B
# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMzEyMDYxODQ1
# NDFaFw0yNTAzMDUxODQ1NDFaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046ODkwMC0wNUUwLUQ5NDcxJTAjBgNV
# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQCoMMJskrrqapycLxPC1H7zD7g88NpbEaQ6SjcTIRbz
# CVyYQNsz8TaL1pqFTEAPL1X7ojL4/EaEW+UjNqZs/ayMyW4YIpFPZP2x4FBMVCdd
# seF2i+aMMjDHi0LcTQZxM2s3mFMrCZAWSfLYXYDIimFBz8j0oLWGy3VgLmBTKM4x
# Lqv7DZUz8B2SoAmbEtp62ngSl0hOoN73SFwE+Y24SvGQMWhykpG+vXDwcpWvwDe+
# TgnrLR7ATRFXN5JS26dm2yy6SYFMRYnME3dMHCQ/UQIQQNC8nLmIvdKkAoWEMXtJ
# sGEo3QrM2S2SBv4PpHRzRukzTtP+UAceGxM9JyrwUQP5OCEmW6YchEyRDSwP4hU9
# f7B0Ayh14Pw9vJo7jewNjeMPIkmneyLSi0ruv2ox/xRGtcJ9yBNC5BaRktjz7stP
# aojR+PDA2fuBtCo8xKlkt53mUb7AY+CZHHqhLm76pdMF6BHv2TvwlVBeQRN22Xja
# VVRwCgjgJnNewt7PejcrpUn0qHLgLq+1BN1DzYukWkTr7wT0zl0iXr+NtqUkWSOn
# WRfe8N21tB6uv3VkW8nFdChtbbZZz24peLtJEZuNrN8Xf9PTPMzZXDJBI1EciR/9
# 1QcGoZFmVbFVb2rUIAs01+ZkewvbhmGVDefX9oZG4/K4gGUsTvTW+r1JZMxUT2Mw
# qQIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFM4b8Oz33hAqBEfKlAZf0NKh4CIZMB8G
# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQCd1gK2Rd+eGL0eHi+iE6/qDY8sbbsO4ema
# ncp6KPN+xq5ZAatiBR4jmRRhm+9Vik0Fo0DLWi/N28bFI7dXYw09p3vCipbjy4Eo
# ifm0Nud7/4U30i9+7RvW7XOQ3rx37+U7vq9lk6yYpGCNp0jlJ188/CuRPgqJnfq5
# EdeafH2AoG46hKWTeB7DuXasGt6spJOenGedSre34MWZqeTIQ0raOItZnFuGDy4+
# xoD1qRz2QW+u2gCHaG8AQjhYUM4uTi9t6kttj6c7Xamr2zrWuceDhz7sKLttLTJ7
# ws5YrA2I8cTlbMAf2KW0GVjKbYGd+LZGduEK7/7fs4GUkMqc51FsNdG1n+zgc7zH
# u2oGGeCBg4s8ZR0ZFyx7jsgm9sSFCKQ5CsbAvlr/60Ndk5TeMR8Js2kNUicu2CqZ
# 03833TsvTgk7iD1KLgfS16HEvjN6m4VKJKgjJ7OJJzabtS4JQgUnJrIZfyosk4D1
# 8rZni9pUwN03WgTmd10WTwiZOu4g8Un6iKcPMY/iFqTu4ntkzFUxBBpbFG6k1CIN
# ZmoirEWmCtG3lyZ2IddmjtIefTkIvGWb4Jxzz7l2m/E2kGOixDJHsahZVmwsoNvh
# y5ku/inU++dXHzw+hlvqTSFT89rIFVhcmsWPDJPNRSSpMhoJ33V2Za/lkKcbkUM0
# SbQgS9qsdzCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
# 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
# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjg5MDAtMDVFMC1EOTQ3MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQDu
# HayKTCaYsYxJh+oWTx6uVPFw+aCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA6wS+MzAiGA8yMDI0MTIxMjAxNDMx
# NVoYDzIwMjQxMjEzMDE0MzE1WjB0MDoGCisGAQQBhFkKBAExLDAqMAoCBQDrBL4z
# AgEAMAcCAQACAg0gMAcCAQACAhMqMAoCBQDrBg+zAgEAMDYGCisGAQQBhFkKBAIx
# KDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZI
# hvcNAQELBQADggEBAFTNNjtI1hNcbfy1ri7T1sLyagXIvC4dOjHDBCsmRM0HBTZo
# 9EJGwoj3KVRE957QFu3uu1DCkmrZWxQbIB6neP9FdTMQZ/zuOwHJ+tgMDsde2NLz
# bmhgel+dyMzQdf+uCDq7wMI0BK6AA0QanWUMGZY1GiLeNKCFY6qOCV0Y9OTBlyS4
# S1dNUoK8EyRTX2O+Nayq5G4LVByZNlGsdmm+yddLBZZz/K8tnsq6d4S+c/adBUhj
# PS0juZ3VwzcQU6Xn/wWzJt+8n7IV+QF3F36QW+v7M3FynFoBUaTINIYlQ6uZ13Oz
# gmQhb77YYQ9+cQs/sDdNhUw2UylLEpXEdxEl6rYxggQNMIIECQIBATCBkzB8MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy
# b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAe3hX8vV96VdcwABAAAB7TAN
# BglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8G
# CSqGSIb3DQEJBDEiBCA3IwLDvRWbldXlQpmNu60gZHs9r/SYvvQZoCQSsHG2oDCB
# +gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EII0uDWg0CFseKxK3A16l1wrIwrsS
# DrXZ6xSf0F4xbMo5MIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
# MTACEzMAAAHt4V/L1felXXMAAQAAAe0wIgQglpI+qw0NrtaIFYymWSd5R6kLsJr4
# k7Qcb87UV1xzTHMwDQYJKoZIhvcNAQELBQAEggIAUVvUkrXCs/F0Qn+MUhhbK1sj
# L+tZOf/h+FXfwK7SsukyRbJjtIgNVh263hjcYiOojIDSS3AJnvG2tTclNkjQb2LV
# EqRaR5YK1wHvxUPoktxvu7xBJYog3Nzx/UsB6tQ63OtpNy0XR2Q4U328rKFlMera
# Ewdpb6Zz2/zuqSxc2K5bPgK2wL/um4C8poiFUQVYP37OAjnQCBtPTJQBymaoJlxB
# BtBOh4BKqJ+8TIKdg9PPKD3Ca9cAUbvkWB9N/YQb8tJQ9nfV/jUDr5EBZD0T767n
# bJ2VEjfci03MrNj1x5IIFPfex9H3pmwGC4JNcGRh985B20PVmccnawK7BDA3jIZS
# 3xaKddCcMHH1sNvoc4TyJ4KD20WHtKp3CChI6fOU4iqbj4yAYcinDxHZLanR0x7U
# 6+Jgp9mT8fD3XyjEVOgHK6sx+Cu8r9uMdxbJDclIrliJh2iRpir8swNP9zDeyZqJ
# qf8tvrLTvGhbbqjzUiZFKGgafZPgtcJ7DrSLWfGdiarCA0g/7Begr5lyLCKrZq0/
# QtqS4gLxd1xIJW8J/cez2bOdFK7JMaw3IDphRQKdQwTdsYEEuBFOt5yisEcEhOCN
# cbpU6hWr3nBMqtP88RRnIuV6TMMUeMk1RVfq6yP1k9aP9UwqwOY3UI1OAeGSHK34
# pynWtuLCfQ5Min05zc0=
# SIG # End signature block
