param
(
    [switch]$multibox,
    [Parameter(Mandatory = $false)]
    [string]$relatedFilesDir,
    [Parameter(Mandatory = $false)]
    [string]$targetDirectory,
    [Parameter(Mandatory = $false)]
    [string]$deploymentDir,
    [Parameter(Mandatory = $false, HelpMessage = "The path to the directory in which to write log files.")]
    [string]$LogDir,
    [Parameter(Mandatory = $false, HelpMessage = "Indicate that this is being run in a Service Fabric context.")]
    [switch]$useServiceFabric = $false,
    [Parameter(Mandatory = $false)]
    [string]$webroot,
    [Parameter(Mandatory = $false)]
    [string]$aosPackageDirectory,
    [Parameter(Mandatory = $false)]
    [string]$sourcePackageDirectory,
    [Parameter(Mandatory = $false, HelpMessage = "Indicate that this is being run on a staging environment.")]
    [switch]$useStaging,
    [Parameter(Mandatory = $false)]
    [string]$tempWorkFolder = "",
    [Parameter(Mandatory = $false, HelpMessage = "Indicates that packages should be applied even if they are labeled as Application or Platform packages.")]
    [switch]$skipPackageValidation = $false
)

$Global:installedPackages = @()

enum CleanUpSourceDirectoriesState
{
    NotStarted
    InProgress
    Failed
    Completed
}

<#
.SYNOPSIS
    Updates the execution status of the clean up source directories step during AOS Update on development machines
#>
function Update-CleanUpSourceDirectoriesProgressFile($stepState)
{
    try
    {
        $global:cleanUpSourceDirectoriesProgress[$global:cleanUpSourceDirectoriesStepName] = $stepState
        $global:cleanUpSourceDirectoriesProgress | ConvertTo-Json | Out-File $global:cleanUpSourceDirectoriesProgressFile -Force
    }
    catch [System.Exception]
    {
        Write-Warning "$_"
    }
}

<#
.SYNOPSIS
    Returns a boolean to indicate whether cleaning up of source files directory is required or not
#>
function Get-IsCleanUpRequired
{
    $global:cleanUpSourceDirectoriesStepName = "CleanUpSourceDirectoriesStep"
    $global:cleanUpSourceDirectoriesProgressFile = "$PSScriptRoot\CleanUpSourceDirectoriesProgress.json"
    $global:cleanUpSourceDirectoriesProgress = @{}

    if (-not (Test-Path $global:cleanUpSourceDirectoriesProgressFile) -or -not(Get-Content $global:cleanUpSourceDirectoriesProgressFile))
    {
        "[$(Get-TimestampPrefix)] Creating CleanUpSourceDirectoriesProgressFile: $global:cleanUpSourceDirectoriesProgressFile as it does not exist" >> $log
        $global:cleanUpSourceDirectoriesProgress.Add($global:cleanUpSourceDirectoriesStepName, [CleanUpSourceDirectoriesState]::NotStarted.ToString())
        $cleanUpSourceDirectoriesProgress | ConvertTo-Json | Out-File $global:CleanUpSourceDirectoriesProgressFile -Force >> $log
    }
    else
    {
        "[$(Get-TimestampPrefix)] The CleanUpSourceDirectoriesProgressFile: $global:cleanUpSourceDirectoriesProgressFile already exists. Getting the current step state."  >> $log
        $cleanUpSourceDirectoriesProgressTemp = Get-Content $global:cleanUpSourceDirectoriesProgressFile | ConvertFrom-Json
        $cleanUpSourceDirectoriesProgressTemp.psobject.properties | Foreach-Object { $global:cleanUpSourceDirectoriesProgress[$_.Name] = $_.Value }
    }

    $isCleanUpRequired = ($global:cleanUpSourceDirectoriesProgress[$global:cleanUpSourceDirectoriesStepName] -ne [CleanUpSourceDirectoriesState]::Completed.ToString())
    "[$(Get-TimestampPrefix)] CleanUpSourceDirectoriesProgressState: [$($global:cleanUpSourceDirectoriesProgress[$global:cleanUpSourceDirectoriesStepName])] and IsCleanUpRequired: [$isCleanUpRequired]."  >> $log

    return $isCleanUpRequired
}

function GenerateSymLinkNgen([string]$webroot, [string]$metadataPackagePath)
{
    if ($useServiceFabric)
    {
        $DeveloperBox = $false
    }
    else
    {
        $DeveloperBox = Get-DevToolsInstalled
    }

    if (!$DeveloperBox)
    {
        Write-Output "Updating Symlink and Ngen Assemblies..."
        $datetime = Get-Date -Format "MMddyyyyhhmmss"
        $SymLinkNgenLog = Join-Path -Path $LogDir -ChildPath "update_SymLink_NgenAssemblies.log"
        $argumentList = '–webroot:"$webroot" –packagedir:"$metadataPackagePath" –log:"$($SymLinkNgenLog)"'

        $NgenoutPutLog = Join-Path -Path $LogDir -ChildPath "update_NgenOutput_$datetime.log"

        if (!(Test-Path -Path $NgenoutPutLog))
        {
            New-Item -ItemType File -Path $NgenoutPutLog -Force | Out-Null
        }

        Invoke-Expression "$metadataPackagePath\bin\CreateSymLinkAndNgenAssemblies.ps1 $argumentList" >> $NgenoutPutLog
    }
}

function UpdateAdditionalFiles([string]$webRoot, [string]$packageDir)
{
    $directorys = Get-ChildItem $packageDir -Directory
    foreach ($moduleName in $directorys)
    {
        $modulePath = Join-Path $packageDir $moduleName
        $additionalFilesDir = Join-Path $modulePath "AdditionalFiles"

        if (Test-Path $additionalFilesDir)
        {
            Write-log "Processing additional files for '$moduleName' "
            $filelocationsfile = Join-Path "$modulePath" "FileLocations.xml"
            if (Test-Path "$filelocationsfile")
            {
                [System.Xml.XmlDocument] $xd = New-Object System.Xml.XmlDocument
                $xd.Load($filelocationsfile)
                $files = $xd.SelectNodes("//AdditionalFiles/File")
                foreach ($file in $files)
                {
                    $assembly = [System.IO.Path]::GetFileName($file.Source)
                    $destination = $file.Destination
                    $relativepath = $file.RelativePath
                    $fullassemblypath = Join-Path "$modulePath" "AdditionalFiles\$assembly"

                    # the reason why we need to check for IsNullorEmpty() for the parameters is because the c:\pakages\bin
                    # comes from both the platform and app side. If the app bin package gets installed first
                    # it will leave a FileLocations.xml file at c:\packages\bin which will be processed by the
                    # platform bin package when it gets installed. We want to ensure that we do not throw an exception
                    # even if we don't find the correct set of parameters being passed from the calling function.
                    switch ($destination)
                    {
                        "AOSWeb" #enum for AOS webroot
                        {
                            $target = Join-Path "$webRoot" "$relativepath"
                        }

                        "PackageBin" #enum for \packages\bin\<<relativepath>>
                        {
                            if (-not [string]::IsNullOrEmpty($packageDir))
                            {
                                $target = Join-Path "$packageDir" "bin"
                                # Assemblies like BPExtensions have relativepath configured in FileLocations.xml. Hence considering relativepath for PackageBin similiar to how it is done in Copy-Files.
                                if (-not [string]::IsNullOrEmpty(($relativepath)))
                                {
                                    $target = join-path "$target" "$relativepath"
                                }
                            }
                        }

                        "ModuleBin" #enum for \<<modulename>>\bin
                        {
                            $target = Join-Path "$modulePath" "bin"
                        }

                        "PackageDir" #enum for \packages\<<relativepath>>
                        {
                            if (-not [string]::IsNullOrEmpty($packageDir))
                            {
                                $target = Join-Path "$packageDir" "$relativepath"
                            }
                        }
                    }

                    if ((Test-Path "$fullassemblypath") -and (-not [string]::IsNullOrEmpty($target)))
                    {
                        if (!(Test-Path "$target"))
                        {
                            Write-log "Creating target directory '$target'"
                            New-Item -Path "$target" -ItemType "directory" -Force | Out-Null
                        }

                        $targetfile = Join-Path "$target" $assembly
                        Write-log "Copying '$fullassemblypath' to '$targetfile'"
                        Copy-Item -path:"$fullassemblypath" -destination:"$targetfile" -Force
                    }
                }
            }

            Write-log "Removing '$additionalFilesDir'..."
            Remove-Item -Path $additionalFilesDir -Recurse -Force | Out-Null
        }
    }
}

function Update-PackageReferenceFile([string]$metadataPath, [string]$packageZipPath, [string]$tempdir)
{
    $ErrorActionPreference = "stop"

    $7zip = Join-Path -Path $env:SystemDrive -ChildPath "DynamicsTools\7za.exe"
    $temppackagesdir = Join-Path -Path $tempdir -ChildPath "temp_$(New-Guid)"

    if (Test-Path -Path $packageZipPath)
    {
        $zipFileNoExt = [System.IO.Path]::GetFileNameWithoutExtension($packageZipPath)
        $updateRefLog = Join-Path -Path $LogDir -ChildPath "install-$zipFileNoExt-$datetime.log"
        $unzipLogName = "install-$zipFileNoExt-$datetime-unzip.log"
        $unzipLog = Join-Path -Path $LogDir -ChildPath $unzipLogName

        $start = (Get-Date).ToUniversalTime()
        ("[{0}] Begin: Updating references from '{1}'" -f $start.ToString("o"), $packageZipPath) >> $updateRefLog

        if (!(Test-Path -Path $temppackagesdir))
        {
            New-Item -Path $temppackagesdir -ItemType directory -Force | Out-Null
        }

        "Unzipping $packageZipPath to $temppackagesdir..."  >> $updateRefLog
        $zip = Start-Process $7zip -ArgumentList "x $packageZipPath -o$temppackagesdir -y -mmt" -Wait -WindowStyle Hidden -PassThru -RedirectStandardOutput $unzipLog

        if ($zip.ExitCode -ne "0")
        {
            "7zip failed to unzip $packageZipPath. See '$unzipLogName' for details." >> $updateRefLog
            throw "7Zip failed to extract dynamics packages reference file."
        }

        $directories = Get-ChildItem -Path $temppackagesdir -Directory
        foreach ($directory in $directories)
        {
            $TargetReferenceUpdateDirectory = Join-Path -Path $metadataPath -ChildPath $directory.Name
            if (Test-Path -Path $TargetReferenceUpdateDirectory)
            {
                "Copying '$($directory.FullName)' to '$TargetReferenceUpdateDirectory'..."  >> $updateRefLog
                Copy-Item -Path ([IO.Path]::Combine($directory.FullName, "*")) -Destination $TargetReferenceUpdateDirectory -Force -Recurse
            }
        }

        if (Test-Path -Path $temppackagesdir)
        {
            "Removing temp directory '$temppackagesdir'..." >> $updateRefLog
            Remove-Item -Path $temppackagesdir -Recurse -Force
        }

        $end = (Get-Date).ToUniversalTime()
        ("[{0}] End: Updating references from '{1}'" -f $end.ToString("o"), $packageZipPath) >> $updateRefLog
    }
}

function Install-Package([string]$packageName, [string]$metadataPath, [string]$source, [string]$log)
{
    $ErrorActionPreference = "stop"

    $dynamicstools = "DynamicsTools"
    $installationrecords = Join-Path $metadataPath "InstallationRecords"
    $packageinstallationrecord = Join-Path $installationrecords $packageName

    $nuget = Join-Path $env:SystemDrive "$dynamicstools\nuget.exe"

    "Removing package installation record $packageinstallationrecord.*" >> $log
    Get-ChildItem -path "$installationrecords" -filter "$packageName.*" | Remove-Item -force -recurse

    "Unpacking the Dynamics packages to $installationrecords" >> $log

    "Running command: $nuget install -OutputDirectory `"$installationrecords`" $packageName -Source $source" >> $log
    if ([System.Version]([System.Diagnostics.FileVersionInfo]::GetVersionInfo($nuget).FileVersion) -ge [System.Version]"2.9.0.0")
    {
        & $nuget install -OutputDirectory "$installationrecords" $packageName -Source $source -DependencyVersion highest #nuget version > 2.8 change behaviour and add a new switch to set it back
    }
    else
    {
        & $nuget install -OutputDirectory "$installationrecords" $packageName -Source $source
    }
    # check the last exit code and decide if the package(s) were installed correctly
    if ($LASTEXITCODE -ne 0)
    {
        Throw "Something went wrong when installing the Dynamics package '$packageName'. Make sure the package name is correct and that it exists at the source directory '$source'."
    }

}

function Install-ZipPackage ([string]$clickoncePath, [string]$metadataPath, [string]$frameworkPath, [string]$packageZipPath, [string]$source, [string]$webroot, [string]$log)
{
    $ErrorActionPreference = "stop"

    #install package
    $arguments = 'clickOnceInstallPath="{0}";metadataInstallPath="{1}";frameworkInstallPath="{2}";packageZipDrop="{3}";webroot="{4}";log="{5}"' -f $clickoncePath, $metadataPath, $frameworkPath, $packageZipPath, $webroot, $log
    $arguments
    $env:DynamicsPackageParameters = $arguments
    $dynamicstools = "DynamicsTools"
    $installationrecords = Join-Path $metadataPath "InstallationRecords"
    $packageinstallationrecord = Join-Path $installationrecords $packageName

    # iterate over every installed package and run the custom powershell script
    $packagesdir = [System.IO.Directory]::EnumerateDirectories($installationrecords, "*", [System.IO.SearchOption]::TopDirectoryOnly)
    foreach ($dir in $packagesdir)
    {
        $currentpackagename = [System.IO.Path]::GetFileName($dir)
        $toolsdir = Join-Path $dir "tools"
        $installscript = Join-Path $toolsdir "installpackage.ps1"
        if (Test-Path $installscript)
        {
            $Global:installedPackages += $currentpackagename

        }
    }
    Parallel-Install -packagesName:$Global:installedPackages -installationrecorddir:$installationrecords
}

function Get-PackageName([string] $fileName)
{
    return $fileName.Split("-")[1]
}

function Remove-MetadataSourceDirectory([string] $packageName, [string] $packageInstallPath)
{
    $basePackageName = Get-PackageName $packageName

    if ($packageName.EndsWith('-compile'))
    {
        $packageInstallPath = Join-Path $packageInstallPath $basePackageName
        $packageInstallPath = Join-Path $packageInstallPath 'XppMetadata'
        if (Test-Path $packageInstallPath)
        {
            #powershell bug - Remove-Item comlet doesn't implement -Recurse correctly
            #Remove-Item $packageInstallPath -Force -Recurse
            Get-ChildItem -path "$packageInstallPath" -force -recurse | Remove-Item -force -recurse
        }
    }
    if ($packageName.EndsWith('-develop'))
    {
        $packageInstallPath = Join-Path $packageInstallPath $basePackageName
        $packageInstallPath = Join-Path $packageInstallPath $basePackageName
        if (Test-Path $packageInstallPath)
        {
            #powershell bug - Remove-Item comlet doesn't implement -Recurse correctly
            #Remove-Item $packageInstallPath -Force -Recurse
            Get-ChildItem -path "$packageInstallPath" -force -recurse | Remove-Item -force -recurse
        }
    }
}

function Remove-SourceDirectory([string] $packageName, [string] $packageInstallPath)
{
    $packageDir = Join-Path $packageInstallPath $packageName
    if (Test-path $packageDir\Descriptor)
    {
        $packageDescriptorXmls = Get-ChildItem $packageDir\Descriptor -filter "*.xml"
        # Delete all folders with matching names with the xml filenames in descriptor
        foreach ($packageDescriptorXml in $packageDescriptorXmls)
        {
            $sourceDirectory = Join-Path $packageDir $packageDescriptorXml.BaseName
            if (Test-path $sourceDirectory)
            {
                Get-ChildItem -path "$sourceDirectory" -force -recurse | Remove-Item -force -recurse
            }
        }
    }
}

function Parallel-Install([string[]] $packagesName, [string] $installationrecorddir)
{
    $ErrorActionPreference = "stop"
    foreach ($pkg in $packagesName)
    {
        $dir = Join-Path $installationrecorddir $pkg
        $toolsdir = Join-Path $dir "tools"
        $installscript = Join-Path $toolsdir "installpackage.ps1"
        if (Test-Path $installscript)
        {
            Write-Output "Running script '$installScript'"
            & $installscript
            Move-Item $installscript ($installscript + ".executed") -Force
        }

    }
}

function Get-TimestampPrefix
{
    return $(Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
}

$ErrorActionPreference = "Stop"
if (!$useServiceFabric)
{
    Import-Module WebAdministration
}

Import-Module "$PSScriptRoot\CommonRollbackUtilities.psm1" -ArgumentList $useServiceFabric -DisableNameChecking
Import-Module "$PSScriptRoot\AosEnvironmentUtilities.psm1" -ArgumentList $useServiceFabric -Force -DisableNameChecking

if (!$useServiceFabric)
{
    if (Test-Path "$($PSScriptRoot)\NonAdminDevToolsInterject.ps1")
    {
        & "$PSScriptRoot\NonAdminDevToolsInterject.ps1"
    }
}

if ($tempWorkFolder -ne "")
{
    $tempPackagesDir = $tempWorkFolder
}
else
{
    $tempPackagesDir = [System.IO.Path]::GetTempPath()
}

if ($useStaging)
{
    $webroot = Join-Path $(Get-AosServiceStagingPath) "webroot"
    $metadataPackagePath = Join-Path $(Get-AosServiceStagingPath) "PackagesLocalDirectory"
    $frameworkPackagePath = Join-Path $(Get-AosServiceStagingPath) "PackagesLocalDirectory"
    $sourcePath = [IO.Path]::Combine($(Split-Path -parent $PSScriptRoot), "Packages")
}
elseif ($useServiceFabric)
{
    $webroot = (Resolve-Path $webroot).ProviderPath
    $clickOncePackagePath = Join-Path $webroot "apps"
    $sourcePath = $sourcePackageDirectory
    $metadataPackagePath = $aosPackageDirectory
    $frameworkPackagePath = $aosPackageDirectory
    if ($tempWorkFolder -eq "")
    {
        $tempPackagesDir = $sourcePath
    }
}
else
{
    $webroot = Get-AosWebSitePhysicalPath
    $metadataPackagePath = $(Get-AOSPackageDirectory)
    $frameworkPackagePath = $(Get-AOSPackageDirectory)
    $sourcePath = [IO.Path]::Combine($(Split-Path -parent $PSScriptRoot), "Packages")
}

if (!$useServiceFabric)
{
    $clickOncePackagePath = $(Get-InfrastructureClickonceAppsDirectory)
    $clickOncePackagePath = [IO.Path]::Combine($webroot, $clickOncePackagePath)
}

$resourcePath = [IO.Path]::Combine($webroot, "Resources")
$packageZipDrop = [IO.Path]::Combine($sourcePath, "files")

if ((![string]::IsNullOrWhiteSpace($targetDirectory)) -and (Test-Path $targetDirectory))
{
    $metadataPackagePath = $targetDirectory
    $frameworkPackagePath = $targetDirectory
}

if ((![string]::IsNullOrWhiteSpace($deploymentDir)) -and (Test-Path $deploymentDir))
{
    if ($multibox)
    {
        $clickOncePackagePath = [IO.Path]::Combine($deploymentDir, "WebRoot\apps")
        $webroot = [IO.Path]::Combine($deploymentDir, "WebRoot")
        $resourcePath = [IO.Path]::Combine($deploymentDir, "WebRoot\Resources")
    }
    else
    {
        $clickOncePackagePath = [IO.Path]::Combine($deploymentDir, "DObind\Packages\Cloud\AosWebApplication\AosWebApplication.csx\roles\AosWeb\approot\apps")
        $webroot = [IO.Path]::Combine($deploymentDir, "DObind\Packages\Cloud\AosWebApplication\AosWebApplication.csx\roles\AosWeb\approot")
        $resourcePath = [IO.Path]::Combine($deploymentDir, "DObind\Packages\Cloud\AosWebApplication\AosWebApplication.csx\roles\AosWeb\approot\Resources")
    }
}

if ((![string]::IsNullOrWhiteSpace($relatedFilesDir)) -and (Test-Path $relatedFilesDir))
{
    $sourcePath = $relatedFilesDir
    $packageZipDrop = [IO.Path]::Combine($relatedFilesDir, "files")
}

$datetime = Get-Date -Format "MMddyyyyhhmmss"

if (!$LogDir)
{
    $LogDir = $PSScriptRoot
}

$log = Join-Path -Path $LogDir -ChildPath "install-AXpackages_$datetime.log"
if (!(Test-Path -Path $log))
{
    New-Item -Path $log -ItemType File -Force | Out-Null
}

$innerlog = Join-Path -Path $LogDir -ChildPath "update-AXpackages_$datetime.log"
if (!(Test-Path -Path $innerlog))
{
    New-Item -Path $innerlog -ItemType File -Force | Out-Null
}


$startdatetime = Get-Date
"*******************************************************" >> $log
"** Starting the package deployment at $startdatetime **" >> $log
"*******************************************************" >> $log

$installationrecords = Join-Path -Path $metadataPackagePath -ChildPath "InstallationRecords"

if (!(Test-Path -Path $installationrecords))
{
    "[$(Get-TimestampPrefix)] Creating installation record directory '$($installationrecords)' to keep the installation history." >> $log
    New-Item -Path $installationrecords -ItemType Directory -Force | Out-Null
}
else
{
    # clean up prior nuget installation of the previous package that fail to install
    $packagesdir = [System.IO.Directory]::EnumerateDirectories($installationrecords, "*", [System.IO.SearchOption]::TopDirectoryOnly)
    foreach ($dir in $packagesdir)
    {
        $toolsdir = Join-Path -Path $dir -ChildPath "tools"
        $installscript = Join-Path -Path $toolsdir -ChildPath "installpackage.ps1"
        if (Test-Path -Path $installscript)
        {
            Move-Item -Path $installscript -Destination $($installscript + ".executed") -Force
        }
    }
}

if ($useServiceFabric)
{
    $DeveloperBox = $false
}
else
{
    $DeveloperBox = Get-DevToolsInstalled
}

$isAppSealed = Get-IsAppSealed -webroot:$webroot
$isPlatSealed = Get-IsPlatformUpdate3OrLater -webroot:$webroot
"[$(Get-TimestampPrefix)] Evaluating Microsoft packages with SealedPlatform: [$isPlatSealed] and SealedApplication: [$isAppSealed]." >> $log

#Check if this is a binary update package for RunOne environment
#Clean up source directories for Microsoft-owned module packages to support x++ refactoring
if ((Get-IsBinaryPackageTypeFromPackage) -and ($isAppSealed) -and ($DeveloperBox -eq $true) -and (Get-IsCleanUpRequired))
{
    # Get the list of currently installed packages based on installation records
    $installationrecords = Join-Path $metadataPackagePath "InstallationRecords"
    $nugetPackageFiles = Get-ChildItem -Path:$installationrecords -recurse  -filter "*-develop.*.nupkg"
    # Get the list of Microsoft-owned app and plat packages
    $applicationPackageNames = Get-PackageNamesFromDLL -productInfoDLL "bin\ProductInfo\Microsoft.Dynamics.BusinessPlatform.ProductInformation.Application.dll"
    $platformPackageNames = Get-PackageNamesFromDLL -productInfoDLL "bin\ProductInfo\Microsoft.Dynamics.BusinessPlatform.ProductInformation.Platform.dll"
    # Get the set of modules in the package being applied
    $metadataModuleHash = New-Object System.Collections.Generic.HashSet[string]
    Get-MetadataModuleListFromPackage | foreach { $metadataModuleHash.Add($_.Split(".")[0])} | Out-Null

    if (($applicationPackageNames.count -gt 0) -or ($platformPackageNames.count -gt 0))
    {
        Update-CleanUpSourceDirectoriesProgressFile([CleanUpSourceDirectoriesState]::InProgress.ToString())
        "[$(Get-TimestampPrefix)] Cleaning up develop records and directories for [$($nugetPackageFiles.Count)] Microsoft modules..." >> $log
        foreach ($nugetPackageFile in $nugetPackageFiles)
        {
            $packageName = Get-PackageName -fileName $nugetPackageFile.BaseName
            # Check whether module package is present in the deployable package being installed
            if ($metadataModuleHash.Contains($packageName))
            {
                # Check whether package is a Microsoft-owned application package
                if ((Get-IsModulePartOfApplicationAsBinary -PackageNugetFilePath $nugetPackageFile.FullName) -and ($applicationPackageNames -contains $packageName))
                {
                    "[$(Get-TimestampPrefix)] Removing source directories for package: $packageName" >> $log
                    Remove-SourceDirectory -packageName $packageName -packageInstallPath $metadataPackagePath

                    "[$(Get-TimestampPrefix)] Removing package installation record for package: $packageName-develop" >> $log
                    Get-ChildItem -path "$installationrecords" -filter "dynamicsax-$packageName-develop.*" | Remove-Item -force -recurse
                }
                # Check whether package is a Microsoft-owned platform package
                elseif ((Get-IsModulePartOfPlatformAsBinary -packageNugetFile $nugetPackageFile.FullName) -and ($platformPackageNames -contains $packageName))
                {
                    "[$(Get-TimestampPrefix)] Removing source directories for package: $packageName" >> $log
                    Remove-SourceDirectory -packageName $packageName -packageInstallPath $metadataPackagePath

                    "[$(Get-TimestampPrefix)] Removing package installation record for package: $packageName-develop" >> $log
                    Get-ChildItem -path "$installationrecords" -filter "dynamicsax-$packageName-develop.*" | Remove-Item -force -recurse
                }
            }
        }
        Update-CleanUpSourceDirectoriesProgressFile([CleanUpSourceDirectoriesState]::Completed.ToString())
        "[$(Get-TimestampPrefix)] Finished cleaning up develop records and directories for [$($nugetPackageFiles.Count)] Microsoft modules." >> $log
    }
}

#Check if this is a platform update package base on existence of the config file.
#if it's platformUpdate3 or later, also perform the meta package installation for platform binarys
if ((Test-Path -Path "$PSScriptRoot\PlatformUpdatePackages.Config") -or ($isPlatSealed))
{
    if (Test-Path -Path $sourcePath)
    {
        [Void][Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')
        if ($DeveloperBox -eq $true)
        {
            $PackageToInstall = "dynamicsax-meta-platform-development"
        }
        else
        {
            $PackageToInstall = "dynamicsax-meta-platform-runtime"
        }
        if (![string]::IsNullOrWhiteSpace($PackageToInstall))
        {
            $zipFile = Get-Item $sourcePath\$PackageToInstall*.nupkg
            if ($null -eq $zipFile)
            {
                #only throw error if it's a dedicated inplace upgrade package,
                #on any other package it's possible that the meta package doesn't existing thus no operation required
                if (Test-Path "$PSScriptRoot\PlatformUpdatePackages.Config")
                {
                    Throw "Unable to get package information"
                }
            }
            else
            {
                $PackFiles = [IO.Compression.ZipFile]::OpenRead($zipFile).Entries
                $PackageSpec = $PackFiles | Where-Object { ($_.Name -like '*.nuspec') }

                if (!($PackageSpec))
                {
                    Throw "Unable to get package information"
                }

                [System.Xml.XmlDocument] $xmlDoc = New-Object System.Xml.XmlDocument
                $XmlDoc.Load($PackageSpec.Open())

                $Dependencies = $xmlDoc.GetElementsByTagName('dependency').id

                if ($Dependencies.Contains("dynamicsax-systemhealth"))
                {
                    #Remove AxPulse due to the name change to SystemHealth in PlatUpdate3
                    $axPulsePath = Join-Path -Path $metadataPackagePath -ChildPath "axpulse"

                    if (Test-Path $axPulsePath)
                    {
                        Remove-Item $axPulsePath -Force -Recurse
                    }
                    if (Test-Path $installationrecords)
                    {
                        Get-ChildItem -path "$installationrecords" -filter "dynamicsax-axpulse.*" | Remove-Item -force -recurse
                    }
                }

                #Install all packages in meta-package definition
                forEach ($Package in $Dependencies)
                {
                    #if it's not appFall or later, install directory package from platform
                    #all other platform package specified in meta package will get installed
                    if (($(Get-PackageName $Package) -ne 'Directory') -or (!$(Get-IsAppFallOrLater -webroot:$webroot)))
                    {
                        "[$(Get-TimestampPrefix)] Removing package installation record $Package.*" >> $log
                        Get-ChildItem -path "$installationrecords" -filter "$Package.*" | Remove-Item -force -recurse

                        #Remove MetaData and Source Directories for the package before Installing
                        Remove-MetadataSourceDirectory -packageName $Package -packageInstallPath $metadataPackagePath
                    }
                }
                "[$(Get-TimestampPrefix)] Installing Platform meta-package '$PackageToInstall'..." >> $log
                Install-Package -packageName:$PackageToInstall -metadataPath:$metadataPackagePath -source:$sourcePath -log:$log >> $innerlog
                "[$(Get-TimestampPrefix)] Done installing Platform meta-package '$PackageToInstall'." >> $log
            }
        }
    }
}

#dependencyaos
#Install App packages if it is sealed
if ($isAppSealed)
{
    if (Test-Path $sourcePath)
    {
        [Void][Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')
        if ($useServiceFabric)
        {
            $DeveloperBox = $false
        }
        else
        {
            $DeveloperBox = Get-DevToolsInstalled
        }
        if ($DeveloperBox -eq $true)
        {
            $PackageToInstall = "dynamicsax-meta-application-development"
        }
        else
        {
            $PackageToInstall = "dynamicsax-meta-application-runtime"
        }
        if (![string]::IsNullOrWhiteSpace($PackageToInstall))
        {
            $zipFile = Get-Item $sourcePath\$PackageToInstall*.nupkg

            if ($null -ne $zipFile)
            {
                $PackFiles = [IO.Compression.ZipFile]::OpenRead($zipFile).Entries
                $PackageSpec = $PackFiles | Where-Object { ($_.Name -like "*.nuspec") }

                if (!($PackageSpec))
                {
                    Throw "Unable to get package information"
                }

                [System.Xml.XmlDocument] $xmlDoc = New-Object System.Xml.XmlDocument
                $XmlDoc.Load($PackageSpec.Open())

                $Dependencies = $xmlDoc.GetElementsByTagName('dependency').id

                #Install all packages in meta-package definition
                forEach ($Package in $Dependencies)
                {
                    "[$(Get-TimestampPrefix)] Removing package installation record $Package.*" >> $log
                    Get-ChildItem -path "$installationrecords" -filter "$Package.*" | Remove-Item -force -recurse

                    #Remove MetaData and Source Directories for the package before Installing
                    Remove-MetadataSourceDirectory -packageName $Package -packageInstallPath $metadataPackagePath
                }
                "[$(Get-TimestampPrefix)] Installing Application meta-package '$PackageToInstall'..." >> $log
                Install-Package -packageName:$PackageToInstall -metadataPath:$metadataPackagePath -source:$sourcePath -log:$log >> $innerlog
                "[$(Get-TimestampPrefix)] Done installing Application meta-package '$PackageToInstall'." >> $log
            }
        }
    }
}

#still need to perform the aot package installation that's not part of platform or app.
if (!(Test-Path "$PSScriptRoot\PlatformUpdatePackages.Config") -and (Test-Path $sourcePath))
{
    $files = Get-ChildItem -Path:$sourcePath *.nupkg
    $customerPackages = @()
    "[$(Get-TimestampPrefix)] Evaluating additional packages to install..." >> $log

    foreach ($packageFile in $files)
    {
        $packageName = ($packageFile.BaseName).Split(".")[0]

        # If the platform is not sealed, install all [Platform Package]
        if (Get-IsModulePartOfPlatformAsBinary -packageNugetFile $packageFile.FullName)
        {
            if (!$isPlatSealed -or $skipPackageValidation)
            {
                "[$(Get-TimestampPrefix)] Installing unsealed Platform package $packageName.*" >> $log
                Install-Package -packageName:$packageName -metadataPath:$metadataPackagePath -source:$sourcePath -log:$log >> $innerlog
            }
        }
        # If app is not sealed, install all [Application Package]
        elseif (Get-IsModulePartOfApplicationAsBinary -PackageNugetFilePath $packageFile.FullName)
        {
            if (!$isAppSealed -or $skipPackageValidation)
            {
                "[$(Get-TimestampPrefix)] Installing unsealed Application package $packageName.*" >> $log
                Install-Package -packageName:$packageName -metadataPath:$metadataPackagePath -source:$sourcePath -log:$log >> $innerlog
            }
        }
        # Allow customer extensions
        else
        {
            # Remove the customer's packages from the installation folder prior to installing them.
            "[$(Get-TimestampPrefix)] Removing package installation record $packageName.*" >> $log
            Get-ChildItem -path "$installationrecords" -filter "$packageName.*" | Remove-Item -force -recurse
            $customerPackages += $packageName
        }
    }

    "[$(Get-TimestampPrefix)] Done evaluating additional packages to install. [$($customerPackages.Count)] packages found." >> $log
        
    # Install the customer's packages.
    if ($customerPackages.Count -gt 0)
    {
        "[$(Get-TimestampPrefix)] Installing [$($customerPackages.Count)] customization packages..." >> $log
    }

    foreach ($customerPackage in $customerPackages)
    {
        Install-Package -packageName:$customerPackage -metadataPath:$metadataPackagePath -source:$sourcePath -log:$log >> $innerlog
    }

    if ($customerPackages.Count -gt 0)
    {
        "[$(Get-TimestampPrefix)] Done installing [$($customerPackages.Count)] customization packages." >> $log
    }
}

"[$(Get-TimestampPrefix)] Installing Zip Packages..." >>$log
Install-ZipPackage -metadataPath:$metadataPackagePath -clickoncePath:$clickOncePackagePath -frameworkPath:$frameworkPackagePath -packageZipPath:$packageZipDrop -source:$sourcePath -webroot:$webroot -log:$log >> $innerlog
"[$(Get-TimestampPrefix)] Done Installing Zip Packages." >>$log

Write-Output "$(Get-TimestampPrefix)] Updating Metadata Resources Files"
$UpdateResourcesLog = Join-Path -Path $LogDir "Update_Resources_$datetime.log"
$ResourceConfig = @{"Common.BinDir" = $metadataPackagePath; "Infrastructure.WebRoot" = $webroot }
$ResourceBase64Config = ConvertTo-Json $ResourceConfig
$ResourceBase64Config = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($ResourceBase64Config))
$argumentList = '–config:"$ResourceBase64Config" –log:"$($UpdateResourcesLog)"'

$Resourceslog = Join-Path -Path $LogDir -ChildPath "Update_Resources_Output_$datetime.log"
if (!(Test-Path -Path $Resourceslog))
{
    New-Item -ItemType File -Path $Resourceslog -Force | Out-Null
}

Invoke-Expression "$PSScriptRoot\DeployResources.ps1 $argumentList" >> $Resourceslog

Write-Output "Updating Metadata Reference File."
Update-PackageReferenceFile -metadataPath:$metadataPackagePath -packageZipPath:$(Join-Path -Path $packageZipDrop -ChildPath "MetadataReferenceApp.zip") -tempdir:$tempPackagesDir
Update-PackageReferenceFile -metadataPath:$metadataPackagePath -packageZipPath:$(Join-Path -Path $packageZipDrop -ChildPath "MetadataReferencePlat.zip") -tempdir:$tempPackagesDir

Write-Output "Updating Additional Files."
UpdateAdditionalFiles -webRoot:$webroot -packageDir:$metadataPackagePath

if (!$useServiceFabric)
{
    try
    {
        $DeveloperBox = Get-DevToolsInstalled
        if (!$DeveloperBox)
        {
            if (Test-Path -Path "$PSScriptRoot\RemoveSymLinkAndNgenAssemblies.ps1")
            {
                Write-Output "Removing SymLink And NgenAssemblies..."
                Invoke-Expression "$PSScriptRoot\RemoveSymLinkAndNgenAssemblies.ps1 -useStaging:`$$($useStaging)"
                Write-Output "Removing SymLink And NgenAssemblies completed."
            }
        }
    }
    catch
    {
        Write-Output "Warning: Failed to remove SymLink And NgenAssemblies: $($_)"
        Write-Output "Generating SymLink And NgenAssemblies..."
        # Always generate symlink point to the non-staging folder of the AOS service.
        GenerateSymLinkNgen -webroot:$webroot -metadataPackagePath:$(Get-AOSPackageDirectory)
        Write-Output "Generating SymLink And NgenAssemblies completed."
    }

    try
    {
        $CommonBin = Get-CommonBinDir
        $AXInstallationInfoPath = Join-Path -Path $CommonBin -ChildPath "bin\Microsoft.Dynamics.AX.AXInstallationInfo.dll"

        # Using Add-Type which will auto load all referenced assemblies.
        Add-Type -Path $AXInstallationInfoPath

        Write-Output "Creating Metadata Module Installation Info..."
        [Microsoft.Dynamics.AX.AXInstallationInfo.AXInstallationInfo]::ScanMetadataModelInRuntimePackage($metadataPackagePath)
        Write-Output "Creating Metadata Module Installation Info completed."
    }
    catch
    {
        Write-Warning "Failed to create metadata module installation record: $($_)"
    }
}

$enddatetime = Get-Date
"******************************************************" >> $log
"** Completed the package deployment at $enddatetime **" >> $log
"******************************************************" >> $log
"" >> $log
$duration = $enddatetime - $startdatetime
"Package deployment duration:" >> $log
"$duration" >> $log

"" >> $log
"******************************************************" >> $log
"Packages installed in this session:" >> $log
"******************************************************" >> $log
foreach ($pkg in $Global:installedPackages)
{
    "$pkg" >> $log
}

""
"******************************************************"
"Packages installed in this session:"
"******************************************************"
foreach ($pkg in $Global:installedPackages)
{
    "$pkg"
}
""
"installation log file: $log"

# SIG # Begin signature block
# MIIr4wYJKoZIhvcNAQcCoIIr1DCCK9ACAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDwY2VRkCdWiDKw
# A6C9Xh1iSaCB1JwWlZuW391DpoN9EKCCEW4wggh+MIIHZqADAgECAhM2AAAB33OB
# lxa+Mv0NAAIAAAHfMA0GCSqGSIb3DQEBCwUAMEExEzARBgoJkiaJk/IsZAEZFgNH
# QkwxEzARBgoJkiaJk/IsZAEZFgNBTUUxFTATBgNVBAMTDEFNRSBDUyBDQSAwMTAe
# Fw0yNDAxMjAwMTMzNDRaFw0yNTAxMTkwMTMzNDRaMCQxIjAgBgNVBAMTGU1pY3Jv
# c29mdCBBenVyZSBDb2RlIFNpZ24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
# AoIBAQDVucAmkbIWpspYysyydQyyRh2L8q5igYFcy2vDk8xGvVMRBhxwbOsJIEd0
# wY8N7WU/xgkYMnSsM4vmc2B49DGdrAjSJqbsx0zf+DLFjrBITUecdRhlq0VKGX8U
# bVOkg0aIfFNLRs4DSrCZYh26zyB8qkL/jUmB7DhcBEhhgOlXRQ4LHnUv7qf+iXqD
# uwFz9tUTAh8JGsgLRBK0oSsRfUB+FJF2KyUxzmeFXJKiEynsWz4kqoM91ag1Yw0U
# 8d0e+RgAKi3Ft1cXA+3qKM6I1H11e/NdIjh7oThvrBtfEngwlwbTF3KZOHdhLBFZ
# 18U4v8VeTlb4r94346CY2+SKnQa7AgMBAAGjggWKMIIFhjApBgkrBgEEAYI3FQoE
# HDAaMAwGCisGAQQBgjdbAQEwCgYIKwYBBQUHAwMwPQYJKwYBBAGCNxUHBDAwLgYm
# KwYBBAGCNxUIhpDjDYTVtHiE8Ys+hZvdFs6dEoFgg93NZoaUjDICAWQCAQ4wggJ2
# BggrBgEFBQcBAQSCAmgwggJkMGIGCCsGAQUFBzAChlZodHRwOi8vY3JsLm1pY3Jv
# c29mdC5jb20vcGtpaW5mcmEvQ2VydHMvQlkyUEtJQ1NDQTAxLkFNRS5HQkxfQU1F
# JTIwQ1MlMjBDQSUyMDAxKDIpLmNydDBSBggrBgEFBQcwAoZGaHR0cDovL2NybDEu
# YW1lLmdibC9haWEvQlkyUEtJQ1NDQTAxLkFNRS5HQkxfQU1FJTIwQ1MlMjBDQSUy
# MDAxKDIpLmNydDBSBggrBgEFBQcwAoZGaHR0cDovL2NybDIuYW1lLmdibC9haWEv
# QlkyUEtJQ1NDQTAxLkFNRS5HQkxfQU1FJTIwQ1MlMjBDQSUyMDAxKDIpLmNydDBS
# BggrBgEFBQcwAoZGaHR0cDovL2NybDMuYW1lLmdibC9haWEvQlkyUEtJQ1NDQTAx
# LkFNRS5HQkxfQU1FJTIwQ1MlMjBDQSUyMDAxKDIpLmNydDBSBggrBgEFBQcwAoZG
# aHR0cDovL2NybDQuYW1lLmdibC9haWEvQlkyUEtJQ1NDQTAxLkFNRS5HQkxfQU1F
# JTIwQ1MlMjBDQSUyMDAxKDIpLmNydDCBrQYIKwYBBQUHMAKGgaBsZGFwOi8vL0NO
# PUFNRSUyMENTJTIwQ0ElMjAwMSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2Vy
# dmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1BTUUsREM9R0JM
# P2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0
# aG9yaXR5MB0GA1UdDgQWBBSO7i0qme7tjtjFjyuIjlmGM6cbCTAOBgNVHQ8BAf8E
# BAMCB4AwRQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjEWMBQGA1UEBRMNMjM2MTY3KzUwMTk3MDCCAeYGA1UdHwSCAd0wggHZMIIB
# 1aCCAdGgggHNhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpaW5mcmEvQ1JM
# L0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcmyGMWh0dHA6Ly9jcmwxLmFtZS5nYmwv
# Y3JsL0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcmyGMWh0dHA6Ly9jcmwyLmFtZS5n
# YmwvY3JsL0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcmyGMWh0dHA6Ly9jcmwzLmFt
# ZS5nYmwvY3JsL0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcmyGMWh0dHA6Ly9jcmw0
# LmFtZS5nYmwvY3JsL0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcmyGgb1sZGFwOi8v
# L0NOPUFNRSUyMENTJTIwQ0ElMjAwMSgyKSxDTj1CWTJQS0lDU0NBMDEsQ049Q0RQ
# LENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZp
# Z3VyYXRpb24sREM9QU1FLERDPUdCTD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0
# P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwHwYDVR0jBBgw
# FoAUllGE4Gtve/7YBqvD8oXmKa5q+dQwHwYDVR0lBBgwFgYKKwYBBAGCN1sBAQYI
# KwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAJe/YXNSCoXitLf/X5pfJZpep3cs
# jdqmBgg+8Kr++8XMjWwdm4tiLasJMUPCgmp5NYn3wC4GefGYwfF7Xm2FMSR2i6QU
# HjigGu6BjdWQh4EwGaNqXLkXlUM7Ww2Z0KrRtpCL16DCOTNZuCFPAytSHFskPWrr
# 6q3EBuiM6P5VLgFSKiAxcunldJorbrBrvZSZib1OINzFGAQszUR0ytovW6FOp+uo
# VhiQCqnOheC1ppnZPss7vnXoogyO0xgSW40bRlltGfwnlOd3IZ/43ZOj5XeeShg5
# 2SzVEiyYrZjD17MSNzQM1JKI07+mtAC7D+eZ/+g2pM/91oHcrDq9Nq4QrS0wggjo
# MIIG0KADAgECAhMfAAAAUeqP9pxzDKg7AAAAAABRMA0GCSqGSIb3DQEBCwUAMDwx
# EzARBgoJkiaJk/IsZAEZFgNHQkwxEzARBgoJkiaJk/IsZAEZFgNBTUUxEDAOBgNV
# BAMTB2FtZXJvb3QwHhcNMjEwNTIxMTg0NDE0WhcNMjYwNTIxMTg1NDE0WjBBMRMw
# EQYKCZImiZPyLGQBGRYDR0JMMRMwEQYKCZImiZPyLGQBGRYDQU1FMRUwEwYDVQQD
# EwxBTUUgQ1MgQ0EgMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJ
# mlIJfQGejVbXKpcyFPoFSUllalrinfEV6JMc7i+bZDoL9rNHnHDGfJgeuRIYO1LY
# /1f4oMTrhXbSaYRCS5vGc8145WcTZG908bGDCWr4GFLc411WxA+Pv2rteAcz0eHM
# H36qTQ8L0o3XOb2n+x7KJFLokXV1s6pF/WlSXsUBXGaCIIWBXyEchv+sM9eKDsUO
# LdLTITHYJQNWkiryMSEbxqdQUTVZjEz6eLRLkofDAo8pXirIYOgM770CYOiZrcKH
# K7lYOVblx22pdNawY8Te6a2dfoCaWV1QUuazg5VHiC4p/6fksgEILptOKhx9c+ia
# piNhMrHsAYx9pUtppeaFAgMBAAGjggTcMIIE2DASBgkrBgEEAYI3FQEEBQIDAgAC
# MCMGCSsGAQQBgjcVAgQWBBQSaCRCIUfL1Gu+Mc8gpMALI38/RzAdBgNVHQ4EFgQU
# llGE4Gtve/7YBqvD8oXmKa5q+dQwggEEBgNVHSUEgfwwgfkGBysGAQUCAwUGCCsG
# AQUFBwMBBggrBgEFBQcDAgYKKwYBBAGCNxQCAQYJKwYBBAGCNxUGBgorBgEEAYI3
# CgMMBgkrBgEEAYI3FQYGCCsGAQUFBwMJBggrBgEFBQgCAgYKKwYBBAGCN0ABAQYL
# KwYBBAGCNwoDBAEGCisGAQQBgjcKAwQGCSsGAQQBgjcVBQYKKwYBBAGCNxQCAgYK
# KwYBBAGCNxQCAwYIKwYBBQUHAwMGCisGAQQBgjdbAQEGCisGAQQBgjdbAgEGCisG
# AQQBgjdbAwEGCisGAQQBgjdbBQEGCisGAQQBgjdbBAEGCisGAQQBgjdbBAIwGQYJ
# KwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMBIGA1UdEwEB/wQI
# MAYBAf8CAQAwHwYDVR0jBBgwFoAUKV5RXmSuNLnrrJwNp4x1AdEJCygwggFoBgNV
# HR8EggFfMIIBWzCCAVegggFToIIBT4YxaHR0cDovL2NybC5taWNyb3NvZnQuY29t
# L3BraWluZnJhL2NybC9hbWVyb290LmNybIYjaHR0cDovL2NybDIuYW1lLmdibC9j
# cmwvYW1lcm9vdC5jcmyGI2h0dHA6Ly9jcmwzLmFtZS5nYmwvY3JsL2FtZXJvb3Qu
# Y3JshiNodHRwOi8vY3JsMS5hbWUuZ2JsL2NybC9hbWVyb290LmNybIaBqmxkYXA6
# Ly8vQ049YW1lcm9vdCxDTj1BTUVSb290LENOPUNEUCxDTj1QdWJsaWMlMjBLZXkl
# MjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPUFNRSxE
# Qz1HQkw/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNz
# PWNSTERpc3RyaWJ1dGlvblBvaW50MIIBqwYIKwYBBQUHAQEEggGdMIIBmTBHBggr
# BgEFBQcwAoY7aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraWluZnJhL2NlcnRz
# L0FNRVJvb3RfYW1lcm9vdC5jcnQwNwYIKwYBBQUHMAKGK2h0dHA6Ly9jcmwyLmFt
# ZS5nYmwvYWlhL0FNRVJvb3RfYW1lcm9vdC5jcnQwNwYIKwYBBQUHMAKGK2h0dHA6
# Ly9jcmwzLmFtZS5nYmwvYWlhL0FNRVJvb3RfYW1lcm9vdC5jcnQwNwYIKwYBBQUH
# MAKGK2h0dHA6Ly9jcmwxLmFtZS5nYmwvYWlhL0FNRVJvb3RfYW1lcm9vdC5jcnQw
# gaIGCCsGAQUFBzAChoGVbGRhcDovLy9DTj1hbWVyb290LENOPUFJQSxDTj1QdWJs
# aWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9u
# LERDPUFNRSxEQz1HQkw/Y0FDZXJ0aWZpY2F0ZT9iYXNlP29iamVjdENsYXNzPWNl
# cnRpZmljYXRpb25BdXRob3JpdHkwDQYJKoZIhvcNAQELBQADggIBAFAQI7dPD+jf
# XtGt3vJp2pyzA/HUu8hjKaRpM3opya5G3ocprRd7vdTHb8BDfRN+AD0YEmeDB5HK
# QoG6xHPI5TXuIi5sm/LeADbV3C2q0HQOygS/VT+m1W7a/752hMIn+L4ZuyxVeSBp
# fwf7oQ4YSZPh6+ngZvBHgfBaVz4O9/wcfw91QDZnTgK9zAh9yRKKls2bziPEnxeO
# ZMVNaxyV0v152PY2xjqIafIkUjK6vY9LtVFjJXenVUAmn3WCPWNFC1YTIIHw/mD2
# cTfPy7QA1pT+GPARAKt0bKtq9aCd/Ym0b5tPbpgCiRtzyb7fbNS1dE740re0COE6
# 7YV2wbeo2sXixzvLftH8L7s9xv9wV+G22qyKt6lmKLjFK1yMw4Ni5fMabcgmzRvS
# jAcbqgp3tk4a8emaaH0rz8MuuIP+yrxtREPXSqL/C5bzMzsikuDW9xH10graZzSm
# PjilzpRfRdu20/9UQmC7eVPZ4j1WNa1oqPHfzET3ChIzJ6Q9G3NPCB+7KwX0OQmK
# yv7IDimj8U/GlsHD1z+EF/fYMf8YXG15LamaOAohsw/ywO6SYSreVW+5Y0mzJutn
# BC9Cm9ozj1+/4kqksrlhZgR/CSxhFH3BTweH8gP2FEISRtShDZbuYymynY1un+Ry
# fiK9+iVTLdD1h/SxyxDpZMtimb4CgJQlMYIZyzCCGccCAQEwWDBBMRMwEQYKCZIm
# iZPyLGQBGRYDR0JMMRMwEQYKCZImiZPyLGQBGRYDQU1FMRUwEwYDVQQDEwxBTUUg
# Q1MgQ0EgMDECEzYAAAHfc4GXFr4y/Q0AAgAAAd8wDQYJYIZIAWUDBAIBBQCgga4w
# GQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisG
# AQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIFjumx8yXcHBYz814kuWkNKuXg2lhRNH
# b20HKJpoZrTwMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8AcwBvAGYA
# dKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEBBQAEggEA
# h9J85ktU+FZ1f9Ly8/xPeKAoaBZp5JAs73kIVx0Xd7DZ2qz+A/igjuQVhPoMILxo
# FyVqDpNd+kQX0P2mnfXMH7OKhW0tBI5rfjGTUiMhfPMOM0D6UtUotBp1tFtYXJ8Q
# Nmam6KL3nuFhyHOvHcgMyxRK2ZlXmbCr+It9B/sUQZ9m5RRgj0TJCu5FMNYOkqVd
# 884Nxb/Wz8NsVMjrzQTEyJfLT2izR+JjjGPQXnZ40cXylgarWJUQKQ2yzgyu78gs
# /V1mZAO/hqWkCniX1jUw55Tz4OYVh0CXSO88dG+IIIFQ0pBdlHGurowV1pDTcM2r
# wELIuhAzy/LU4b98I74YbKGCF5MwghePBgorBgEEAYI3AwMBMYIXfzCCF3sGCSqG
# SIb3DQEHAqCCF2wwghdoAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFRBgsqhkiG9w0B
# CRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUA
# BCBfkJWDtbayeUemeGWDIgkCUTPLLc80CpV/g7vxDQSTQAIGZuLcwDK/GBIyMDI0
# MTAwNDE0NTk1NS4wMlowBIACAfSggdGkgc4wgcsxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9w
# ZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo5MjAwLTA1RTAtRDk0
# NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCEeowggcg
# MIIFCKADAgECAhMzAAAB5y6PL5MLTxvpAAEAAAHnMA0GCSqGSIb3DQEBCwUAMHwx
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1p
# Y3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTIzMTIwNjE4NDUxOVoXDTI1
# MDMwNTE4NDUxOVowgcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
# b24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNV
# BAsTHm5TaGllbGQgVFNTIEVTTjo5MjAwLTA1RTAtRDk0NzElMCMGA1UEAxMcTWlj
# cm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
# ADCCAgoCggIBAMJXny/gi5Drn1c8zUO1pYy/38dFQLmR2IQXz1gE/r9GfuSOoyRn
# kRJ6Z/kSWLgIu1BVJ59GkXWPtLkssqKwxY4ZFotxpVsZN9yYjW8xEnW3MzAI0igK
# r+/LxYfxB1XUH8Bvmwr5D3Ii/MbDjtN9c8TxGWtq7Ar976dafAy3TrRqQRmIknPV
# WHUuFJgpqI/1nbcRmYYRMJaKCQpty4CeG+HfKsxrz24F9p4dBkQcZCp2yQzjwQFx
# ZJZ2mJJIGIDHKEdSRuSeX08/O0H9JTHNFmNTNYeD1t/WapnRwiIBYLQSMrs42GVB
# 8pJEdUsos0+mXf/5QvheNzRi92pzzyA4tSv/zhP3/Ermvza6W9GnYDz9qv1wbhbv
# rnS4poDFECaAviEqAhfn/RogCxvKok5ro4gZIX1r4N9eXUulA80pHv3axwXu2MPl
# arAi6J9L1hSIcy9EuOMqTRJIJX+alcLQGg+STlqx/GuslsKwl48dI4RuWknNGbNo
# /o4xfBFytvtNcVA6xOQq6qRa+9gg+9XMLrxQz4yyQs+V3V6p044wrtJtt/a0ZJl/
# f6I7BZAxxZcH2DDmArcAhgrTxaQkm7LM+p+K2C5t1EKZiv0JWw065b7AcNgaFyIk
# MXYuSuOQVSNRxdIgl31/ayxiK1n0K6sZXvgFBx+vGO+TUvyO+03ua6UjAgMBAAGj
# ggFJMIIBRTAdBgNVHQ4EFgQUz/7gmICfNjh2kR/9mWuHUrvej1gwHwYDVR0jBBgw
# FoAUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwVGltZS1T
# dGFtcCUyMFBDQSUyMDIwMTAoMSkuY3JsMGwGCCsGAQUFBwEBBGAwXjBcBggrBgEF
# BQcwAoZQaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNy
# b3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcnQwDAYDVR0TAQH/
# BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8EBAMCB4AwDQYJ
# KoZIhvcNAQELBQADggIBAHSh8NuT6WVaLVwLqex+J7km2nT2jpvoBEKm+0M+rYoU
# /6GL5Q00/ssZyIq5ySpcKYFMUiF8F4ZLG+TrJyiR1CvfzXmkQ5phZOce9DT7yErL
# zqvUXit8G7igcHlxPLTxPiiGsb85gb8H+A2fPQ6Xq/u7+oSPPjzNdnpmXEobJnAq
# YplZoF3YNgTDMql0uQHGzoDp6dZlHSNj6rkV1tXjmCEZMqBKvkQIA6csPieMnB+M
# irSZFlbANlChe0lJpUdK7aUdAvdgcQWKS6dtRMl818EMsvsa/6xOZGINmTLk4DGg
# sbaBpN+6IVt+mZJ89yCXkI5TN8xCfOkp9fr4WQjRBA2+4+lawNTyxH66eLZWYOju
# uaomuibiKGBU10tox81Sq8EvlmJIrXOZoQsEn1r5g6MTmmZJqtbmwZufuJWQXZb0
# lAg4fq0ZYsUlLkezfrNqGSgeHyIP3rct4aNmqQW6wppRbvbIyP/LFN4YQM6givfm
# TBfGvVS77OS6vbL4W41jShmOmnOn3kBbWV6E/TFo76gFXVd+9oK6v8Hk9UCnbHOu
# iwwRRwDCkmmKj5Vh8i58aPuZ5dwZBhYDxSavwroC6j4mWPwh4VLqVK8qGpCmZ0HM
# Awao85Aq3U7DdlfF6Eru8CKKbdmIAuUzQrnjqTSxmvF1k+CmbPs7zD2Acu7JkBB7
# MIIHcTCCBVmgAwIBAgITMwAAABXF52ueAptJmQAAAAAAFTANBgkqhkiG9w0BAQsF
# ADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
# B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UE
# AxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcN
# MjEwOTMwMTgyMjI1WhcNMzAwOTMwMTgzMjI1WjB8MQswCQYDVQQGEwJVUzETMBEG
# A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj
# cm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFt
# cCBQQ0EgMjAxMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOThpkzn
# tHIhC3miy9ckeb0O1YLT/e6cBwfSqWxOdcjKNVf2AX9sSuDivbk+F2Az/1xPx2b3
# lVNxWuJ+Slr+uDZnhUYjDLWNE893MsAQGOhgfWpSg0S3po5GawcU88V29YZQ3MFE
# yHFcUTE3oAo4bo3t1w/YJlN8OWECesSq/XJprx2rrPY2vjUmZNqYO7oaezOtgFt+
# jBAcnVL+tuhiJdxqD89d9P6OU8/W7IVWTe/dvI2k45GPsjksUZzpcGkNyjYtcI4x
# yDUoveO0hyTD4MmPfrVUj9z6BVWYbWg7mka97aSueik3rMvrg0XnRm7KMtXAhjBc
# TyziYrLNueKNiOSWrAFKu75xqRdbZ2De+JKRHh09/SDPc31BmkZ1zcRfNN0Sidb9
# pSB9fvzZnkXftnIv231fgLrbqn427DZM9ituqBJR6L8FA6PRc6ZNN3SUHDSCD/AQ
# 8rdHGO2n6Jl8P0zbr17C89XYcz1DTsEzOUyOArxCaC4Q6oRRRuLRvWoYWmEBc8pn
# ol7XKHYC4jMYctenIPDC+hIK12NvDMk2ZItboKaDIV1fMHSRlJTYuVD5C4lh8zYG
# NRiER9vcG9H9stQcxWv2XFJRXRLbJbqvUAV6bMURHXLvjflSxIUXk8A8FdsaN8cI
# FRg/eKtFtvUeh17aj54WcmnGrnu3tz5q4i6tAgMBAAGjggHdMIIB2TASBgkrBgEE
# AYI3FQEEBQIDAQABMCMGCSsGAQQBgjcVAgQWBBQqp1L+ZMSavoKRPEY1Kc8Q/y8E
# 7jAdBgNVHQ4EFgQUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXAYDVR0gBFUwUzBRBgwr
# BgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMBMGA1UdJQQMMAoGCCsGAQUF
# BwMIMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYG
# A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3Js
# L3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcB
# AQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kv
# Y2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MA0GCSqGSIb3DQEBCwUA
# A4ICAQCdVX38Kq3hLB9nATEkW+Geckv8qW/qXBS2Pk5HZHixBpOXPTEztTnXwnE2
# P9pkbHzQdTltuw8x5MKP+2zRoZQYIu7pZmc6U03dmLq2HnjYNi6cqYJWAAOwBb6J
# 6Gngugnue99qb74py27YP0h1AdkY3m2CDPVtI1TkeFN1JFe53Z/zjj3G82jfZfak
# Vqr3lbYoVSfQJL1AoL8ZthISEV09J+BAljis9/kpicO8F7BUhUKz/AyeixmJ5/AL
# aoHCgRlCGVJ1ijbCHcNhcy4sa3tuPywJeBTpkbKpW99Jo3QMvOyRgNI95ko+ZjtP
# u4b6MhrZlvSP9pEB9s7GdP32THJvEKt1MMU0sHrYUP4KWN1APMdUbZ1jdEgssU5H
# LcEUBHG/ZPkkvnNtyo4JvbMBV0lUZNlz138eW0QBjloZkWsNn6Qo3GcZKCS6OEua
# bvshVGtqRRFHqfG3rsjoiV5PndLQTHa1V1QJsWkBRH58oWFsc/4Ku+xBZj1p/cvB
# QUl+fpO+y/g75LcVv7TOPqUxUYS8vwLBgqJ7Fx0ViY1w/ue10CgaiQuPNtq6TPmb
# /wrpNPgkNWcr4A245oyZ1uEi6vAnQj0llOZ0dFtq0Z4+7X6gMTN9vMvpe784cETR
# kPHIqzqKOghif9lwY1NNje6CbaUFEMFxBmoQtB1VM1izoXBm8qGCA00wggI1AgEB
# MIH5oYHRpIHOMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ
# MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
# MSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQL
# Ex5uU2hpZWxkIFRTUyBFU046OTIwMC0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jv
# c29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoBATAHBgUrDgMCGgMVALNyBOcZqxLB
# 792u75w97U0X+/BDoIGDMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
# MTAwDQYJKoZIhvcNAQELBQACBQDqqloZMCIYDzIwMjQxMDA0MTIxMjA5WhgPMjAy
# NDEwMDUxMjEyMDlaMHQwOgYKKwYBBAGEWQoEATEsMCowCgIFAOqqWhkCAQAwBwIB
# AAICEx0wBwIBAAICE3YwCgIFAOqrq5kCAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYK
# KwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQsF
# AAOCAQEAg3tZ+FgIW08kpyzgd9Lu1Cje0RF74ilMMuNjwaxdKWHNq2tx0m4VqmjB
# 6j9T+LN8Q31oFRjS+/yPqiPtxIh2AVHc/Sg+Gpzc1lYVyPJw/6mNYk+RUi31yxHG
# +V2QHIuO7GCTJ9UA4eIzJwdd+Mt9xJn7Ty88dsjpgkYLtWnKvpEINupjjhyzEsTb
# +pUH/4tA8HeRZ/DcVrZH9kFDHEWovA+pykQpjS0d5tMRAspZw2eFi8h7OU0z2Sia
# GJhvrv/th8iuCLIfgDNIZEH+vpAlwnIxl3FxGdy1JtnGNbf/P3k9wRKvT63uM9E+
# +Ho80oYV3iGQ/qnuoKmGbKTktuSNVTGCBA0wggQJAgEBMIGTMHwxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU
# aW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB5y6PL5MLTxvpAAEAAAHnMA0GCWCGSAFl
# AwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcN
# AQkEMSIEIC5F2WI6erFjSC/4/gRpJ72CuMvlnLdYY8GQJjaVggCBMIH6BgsqhkiG
# 9w0BCRACLzGB6jCB5zCB5DCBvQQg5TZdDXZqhv0N4MVcz1QUd4RfvgW/QAG9Awbu
# oLnWc60wgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAA
# Aecujy+TC08b6QABAAAB5zAiBCBTtznLFdcyly24J5JBDHi+VKHk/PZKcAGdP5uS
# EVwIGDANBgkqhkiG9w0BAQsFAASCAgAUqciaaFoqHLdP1qLYsswIk2H3riKV9gUg
# 8TqstMUGS/KzEOhuHMY8GsaWmfHbIDFMUNZAwZEyEtrYupaqB8+gunYf8ao3tobE
# lzOP+aCvYiEOWpgN5s9VEX20vnFGtzVDW/90PWB6cKBRgTHmmBh0oEXxFcc9r4jh
# M/3QA4hqkhV4vlxVV8sRZLLZBhNI5nQfGNTTsf1ZHlg12Zb7OsLmCnQHrAbgghga
# hOpfovTfkGZlw2iLdRcumcMR+cUUaRw3QLXlPDE2Xz7TxGRGfP0dM8vX41lRiKio
# JHs+UMHWlkUOSfkFUYFvc/PSOT2F2eRDTP5LqlExvCChQFtTnFZUkEJn3iiWIshi
# A/1nZ+DpvE7UMQ57c//CFmVQnb9LzSLMhoEmMOq1q9uXhIM2uk8suQPTFDAUa0Up
# BlBkyKhQfZuwxvACzbFzwYxSNKFCqnxWYE/KjdTutAwFRyjaRsmKgODKRb99HTGL
# /Et93D9yA4HcfYt29w4PMZ4PlybvlO5SC7MJONa5GNwW8QfxiGxv9qiZUx2D28BS
# vm5HsDpLgVzJBeqpj6THlapVYvJrGkRhxHDPH17O3pc+2y3oK1+jztW0lF8vhvBM
# GidYXAREOT7Ge0oB/9febBeRhCea1poEKHh2wFmzJ3DgtltxGa99z1wefRlIDbbU
# LNie7stgXA==
# SIG # End signature block
