param
(
    [parameter(Position=0,Mandatory=$false)][boolean] $useServiceFabric=$false 
)

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

$script:EnvDllsLoaded = $false
function Get-ApplicationEnvironment
{
    $ErrorActionPreference = 'Stop'

    if (-not $script:EnvDllsLoaded)
    {        
        $webroot = Get-AosWebSitePhysicalPath
        $InstalledPlatformBuildVersion = Get-ProductPlatformBuildFullVersion
        $isKeyVault = Get-IsMSIKeyVault

        if (($isKeyVault -eq $true) -and ($InstalledPlatformBuildVersion -ne $null) -and ($InstalledPlatformBuildVersion.Build -ge 5644))
        {        
            # Get-PackageRoot comes from CommonRollbackUtilities.psm1. it resolves the root of the deployable package
            $packageRoot = Get-PackageRoot
            $packageTemp = ""

            if(![string]::IsNullOrEmpty($packageRoot) -and (Test-Path $packageRoot))
            {
                $packageTemp = Join-Path $packageRoot "RunbookWorkingFolder\KeyVaultAssemblyTemp"
            }

            if ([string]::IsNullOrEmpty($packageTemp))
            {   
                $suffix = $(Get-Date).ToString("yyyyMMdd_HHmmss")
                $dirName = "AssemblyTemp_$suffix"
                $packageTemp = Join-Path $env:Temp "dirName"
            }

            if(!(Test-Path $packageTemp -PathType Container))
            {
                New-Item $packageTemp -ItemType Container | Out-Null
            }
        
            #need to load the Microsoft.Dynamics.ApplicationPlatform.Environment.dll and all the dll it referenced
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.ApplicationPlatform.Environment.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.AX.Configuration.Base.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.AX.Security.Instrumentation.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.AX.Framework.EncryptionEngine.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.BusinessPlatform.SharedTypes.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.AX.Security.KeyVaultHelper.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Carbon.Flighting.Runtime.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Carbon.CertificateCommon.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Commerce.Flighting.Common.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.ApplicationPlatform.Flighting.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.ApplicationPlatform.XppServices.Instrumentation.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.CE.VaultSDK.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.CE.VaultSDK.ADALv2.AuthHelper.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Azure.KeyVault.Core.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Azure.KeyVault.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Azure.Common.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Azure.Common.NetFramework.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Hyak.Common.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.AX.Authentication.Instrumentation.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Threading.Tasks.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Threading.Tasks.Extensions.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Threading.Tasks.Extensions.Desktop.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.IdentityModel.Clients.ActiveDirectory.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Newtonsoft.Json.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.AX.Security.SharedUtility.dll'
            CopyDllToTempFolder -dllPath $dllPath -packageTemp $packageTemp            

            try
            {
                $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.ApplicationPlatform.Environment.dll'
                $fileTempPath =  Join-Path $packageTemp $(Get-Item $dllPath).Name
                if (Test-Path $fileTempPath)
                {
                    # Load file from temp folder
                    [System.Reflection.Assembly]::LoadFrom($fileTempPath)
                }
            }
            catch
            {    
                #write-log "Failed to load from temp folder with Exception: [$($_.Exception)]"
                throw $_
            }
        }              
        else
        {
            #need to load the Microsoft.Dynamics.ApplicationPlatform.Environment.dll and all the dll it referenced
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.ApplicationPlatform.Environment.dll'
            Load-DllinMemory -dllPath $dllPath
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.AX.Configuration.Base.dll'
            Load-DllinMemory -dllPath $dllPath
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.AX.Security.Instrumentation.dll'
            if (Test-Path $dllPath)
            {
                Load-DllinMemory -dllPath $dllPath
            }
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.AX.Framework.EncryptionEngine.dll'
            Load-DllinMemory -dllPath $dllPath
            $dllPath = Join-Path $webroot 'bin\Microsoft.Dynamics.BusinessPlatform.SharedTypes.dll'
            Load-DllinMemory -dllPath $dllPath  
        }

        $script:EnvDllsLoaded = $true
    }

    $config = [Microsoft.Dynamics.ApplicationPlatform.Environment.EnvironmentFactory]::GetApplicationEnvironment()
    
    return $config
}

function Load-DllinMemory([string] $dllPath)
{
    #try catch as not all dll exist in RTM version, some dependency/dll are introduced at update 1 or later
    #powershell cannot unload dll once it's loaded, the trick is to create an in-memory copy of the dll than load it
    #after the loading of in-memory dll, the physical dll stay unlocked

    try
    {
        if (Test-Path $dllPath)
        {
            $bytes = [System.IO.File]::ReadAllBytes($dllPath)
            [System.Reflection.Assembly]::Load($bytes) | Out-Null
        }
    }
    catch
    {}
}

function CopyDllToTempFolder([string] $dllPath, [string] $packageTemp)
{
    #try catch as not all dll exist in RTM version, some dependency/dll are introduced at update 1 or later    
    $fileTempPath =  Join-Path $packageTemp $(Get-Item $dllPath).Name
    try
    {
        if ((Test-Path $dllPath) -And !$(Test-Path $fileTempPath))
        {
            $Buffer = New-Object 'byte[]' 1024
            # Open file in read mode
            $SourceFile = [System.IO.File]::Open($dllPath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read)
            # Create the new file
            $DestinationFile = [System.IO.File]::Open($fileTempPath, [System.IO.FileMode]::CreateNew)
            try{
                # Copy the contents of the source file to the destination
                while(($readLength = $SourceFile.Read($Buffer, 0, $Buffer.Length)) -gt 0)
                {
                    $DestinationFile.Write($Buffer, 0, $readLength)
                }
            }
            catch{
                throw $_
            }
            finally{
                $SourceFile.Close()
                $DestinationFile.Close()
            }
        }
    }
    catch
    {
        Write-Log "Failed to copy file to temp folder with Exception: [$($_.Exception)]"
        throw $_
    }    
}

function Get-IsMSIKeyVault
{
    $webroot = Get-AosWebSitePhysicalPath
    $webconfig=join-path $webroot "web.config"
    $isMSIKeyVault=$false
    
    [System.Xml.XmlDocument] $xd=new-object System.Xml.XmlDocument
    $xd.Load($webconfig)
    $ns=New-Object System.Xml.XmlNamespaceManager($xd.NameTable)
    $ns.AddNamespace("ns",$xd.DocumentElement.NamespaceURI)

    $key="CertificateHandler.IsMSIKeyVault"

    $isKeyVaultValue = $xd.SelectSingleNode("//ns:add[@key='$key']",$ns)

    if($isKeyVaultValue -ne $null)
    {        
        $isMSIKeyVault = $isKeyVaultValue.GetAttribute("value")
    }

    return $isMSIKeyVault 
}

function GenerateMetadataModuleInstallationInfo
{
    try
    {
        $ErrorActionPreference = 'Stop'

        write-output "Creating Metadata Module Installation Info."
        
        $packagePath = Get-AOSPackageDirectory
        $CommonBin = $(Get-CommonBinDir)

        $dllPath = Join-Path $CommonBin 'bin\Microsoft.Dynamics.AX.AXInstallationInfo.dll'
        Load-DllinMemory -dllPath $dllPath
        $dllPath = Join-Path $CommonBin 'bin\Microsoft.Dynamics.AX.Metadata.Storage.dll'
        Load-DllinMemory -dllPath $dllPath
        $dllPath = Join-Path $CommonBin 'bin\Microsoft.Dynamics.AX.Metadata.dll'
        Load-DllinMemory -dllPath $dllPath
        $dllPath = Join-Path $CommonBin 'bin\Microsoft.Dynamics.AX.Metadata.Core.dll'
        Load-DllinMemory -dllPath $dllPath
        $dllPath = Join-Path $CommonBin 'bin\Microsoft.Dynamics.ApplicationPlatform.XppServices.Instrumentation.dll'
        Load-DllinMemory -dllPath $dllPath

        [Microsoft.Dynamics.AX.AXInstallationInfo.AXInstallationInfo]::ScanMetadataModelInRuntimePackage($packagePath)
    }
    catch
    {}
}

function Get-IsAppFallOrLater([Parameter(Mandatory=$false)] $webroot)
{
    $version = Get-ApplicationReleaseFromAOS -webroot:$webroot

    return $($version -ne "RTW")
}

function Get-ApplicationReleaseFromPackage
{
    $packageRoot = split-Path -parent "$(split-Path -parent $PSScriptRoot)" 
    $PackageInstallationInfo = "$packageRoot\HotfixInstallationInfo.xml"
    $XPath = '/HotfixInstallationInfo/ServiceModelList/ComponentModel/Release[../ServiceModelGroup = "Application"]'
    $ApplicationRelease =  Select-Xml -Path $PackageInstallationInfo -XPath $Xpath 
    $MRXPath = '/HotfixInstallationInfo/ServiceModelList/ComponentModel[Name = "MRApplicationService"]'
    $MRApplicationServiceModel =  Select-Xml -Path $PackageInstallationInfo -XPath $MRXpath 

    if($ApplicationRelease.Count -ge 1)
    {
        return $ApplicationRelease[0].Node.InnerText
    }
    elseif ($MRApplicationServiceModel -eq $null)
    {
        return ""
    }
    else
    {
        return "RTW"
    }
}

function Get-IsModulePartOfPlatformAsBinary ([string] $packageNugetFile)
{
    [Void][Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') 
    $PackFiles = [IO.Compression.ZipFile]::OpenRead($packageNugetFile)
    $PackageSpec =  $PackFiles.Entries | where {($_.Name -like '*.nuspec')}

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

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

    $PackFiles.Dispose()

    $Description = $xmlDoc.GetElementsByTagName('description').Item(0).InnerText

    if($Description.Contains("[Platform Package]"))
    {
        return $true
    }
    else
    {
        return $false
    }
}

function Get-IsModulePartOfApplicationAsBinary ([string] $PackageNugetFilePath)
{
    [Void][Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') 
    $PackFiles = [IO.Compression.ZipFile]::OpenRead($PackageNugetFilePath)
    $PackageSpec =  $PackFiles.Entries | 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())

    $PackFiles.Dispose()

    $Description = $xmlDoc.GetElementsByTagName('description').Item(0).InnerText

    if($Description.Contains("[Application Package]"))
    {
        return $true
    }
    else
    {
        return $false
    }
}

function Get-IsPlatformUpdate3OrLater([Parameter(Mandatory=$false)] $webroot)
{
    if (!$webroot) {
    $webroot = Get-AosWebSitePhysicalPath
    }

    #must use job or process to load the production information provider dll or it'll lock it self
    #in memory copy is not usable as this dll have some special hard coded reference dll which won't resolve when loaded in memory.
    $job = Start-Job -ScriptBlock  {
        param($webrootBlock)
        $VersionDLLPath = Join-Path $webrootBlock 'bin\Microsoft.Dynamics.BusinessPlatform.ProductInformation.Provider.dll'
        Add-Type -Path $VersionDLLPath
        $provider = [Microsoft.Dynamics.BusinessPlatform.ProductInformation.Provider.ProductInfoProvider]::get_Provider();
        $version = $provider.get_PlatformVersion();
        $version
    } -ArgumentList $webroot
    Wait-Job -Job $job | Out-Null
    $version = Receive-Job -Job $job

    return $(($version -ne '7.0') -and ($version -ne '7.0.0.0') -and (![string]::IsNullOrEmpty($version)))    
}

function Get-IsPackageContainUpgradeBinaryForUpdate3
{
    $sourcePath = [IO.Path]::Combine($(split-Path -parent $PSScriptRoot), "Packages")
    #using a framework package from platform which customer cannot generate to identify if it's from platform update 3
    $files=get-childitem -Path:$sourcePath dynamicsax-framework-bin.*.nupkg
    foreach ($packageFile in $files) 
    {
        if(Get-IsModulePartOfPlatformAsBinary -packageNugetFile $packageFile.FullName)
        {
            return $true
        }
    }

    return $false
}

function Get-ProductPlatformBuildVersion([Parameter(Mandatory=$false)] $webroot)
{
    if (!$webroot) {
       $webroot = Get-AosWebSitePhysicalPath
    }

    #must use job or process to load the production information provider dll or it'll lock it self
    #in memory copy is not usable as this dll have some special hard coded reference dll which won't resolve when loaded in memory.
    $job = Start-Job -ScriptBlock  {
        param($webrootBlock)
        $VersionDLLPath = Join-Path $webrootBlock 'bin\Microsoft.Dynamics.BusinessPlatform.ProductInformation.Provider.dll'
        Add-Type -Path $VersionDLLPath
        $provider = [Microsoft.Dynamics.BusinessPlatform.ProductInformation.Provider.ProductInfoProvider]::get_Provider();
        $version = $provider.get_PlatformBuildVersion();
        $version
    } -ArgumentList $webroot
    Wait-Job -Job $job | Out-Null
    $version = Receive-Job -Job $job
   
    $build = [System.Version]::new()
    $releaseBuild
    if([System.Version]::TryParse($Version, [ref]$build))
    {
        $releaseBuild = $build.Build
    }
    else
    {
        #default to 0 from 7.0.0.0 
        $releaseBuild = 0
    }   

    return  $releaseBuild
}

function Get-ProductPlatformBuildFullVersion
{
    $webroot = Get-AosWebSitePhysicalPath

    #must use job or process to load the production information provider dll or it'll lock it self
    #in memory copy is not usable as this dll have some special hard coded reference dll which won't resolve when loaded in memory.
    $job = Start-Job -ScriptBlock  {
        param($webrootBlock)
        $VersionDLLPath = Join-Path $webrootBlock 'bin\Microsoft.Dynamics.BusinessPlatform.ProductInformation.Provider.dll'
        Add-Type -Path $VersionDLLPath
        $provider = [Microsoft.Dynamics.BusinessPlatform.ProductInformation.Provider.ProductInfoProvider]::get_Provider();
        $version = $provider.get_PlatformBuildVersion();
        $version
    } -ArgumentList $webroot
    Wait-Job -Job $job | Out-Null
    $version = Receive-Job -Job $job
   
    $build = [System.Version]::new()
    
    if([System.Version]::TryParse($Version, [ref]$build))
    {
        return $build
    }
    
    return $null
}

function Get-ProductApplicationVersion ([Parameter(Mandatory=$false)] $webroot)
{
    if($webroot -eq $null)
    {
        $webroot = Get-AosWebSitePhysicalPath
    }

    #must use job or process to load the production information provider dll or it'll lock it self
    #in memory copy is not usable as this dll have some special hard coded reference dll which won't resolve when loaded in memory.
    $job = Start-Job -ScriptBlock  {
        param($webrootBlock)
        $VersionDLLPath = Join-Path $webrootBlock 'bin\Microsoft.Dynamics.BusinessPlatform.ProductInformation.Provider.dll'
        Add-Type -Path $VersionDLLPath
        $provider = [Microsoft.Dynamics.BusinessPlatform.ProductInformation.Provider.ProductInfoProvider]::get_Provider();
        $version = $provider.get_ApplicationBuildVersion();
        $version
    } -ArgumentList $webroot
    Wait-Job -Job $job | Out-Null
    $version = Receive-Job -Job $job    
    
    return  $version
}

function Get-DataAccessSqlPwd
{
    $Config = Get-ApplicationEnvironment
    return $Config.DataAccess.SqlPwd
}

function Get-DataAccessDatabase
{
    $Config = Get-ApplicationEnvironment
    return $Config.DataAccess.Database
}

function Get-DataAccessSqlUsr
{
    $Config = Get-ApplicationEnvironment
    return $Config.DataAccess.SqlUser
}

function Get-DataAccessDbServer
{
    $Config = Get-ApplicationEnvironment
    return $Config.DataAccess.DbServer
}


function Get-AOSPackageDirectory
{
    $Config = Get-ApplicationEnvironment
    return $Config.Aos.PackageDirectory
}

function Get-CommonBinDir
{
    $Config = Get-ApplicationEnvironment
    return $Config.Common.BinDir
}

function Get-BiReportingPersistentVirtualMachineIPAddressSSRS
{
    $Config = Get-ApplicationEnvironment
    return $Config.BiReporting.PersistentVirtualMachineIPAddressSSRS
}

function Get-BiReportingReportingServers
{
    $Config = Get-ApplicationEnvironment
    $reportingServers = $Config.BiReporting.ReportingServers
    if ([System.String]::IsNullOrWhiteSpace($reportingServers))
    {
        $reportingServers = $Config.BiReporting.PersistentVirtualMachineIPAddressSSRS
    }

    return $reportingServers
}

function Get-UseReportingCluster
{
    $webRoot = Get-AosWebSitePhysicalPath
    $webConfigPath = join-path $webRoot "web.config"
    
    if(Test-Path $webConfigPath){
        [System.Xml.XmlDocument] $webConfig = new-object System.Xml.XmlDocument
        $webConfig.Load($webConfigPath)

        $ns = New-Object System.Xml.XmlNamespaceManager($webConfig.NameTable)
        $ns.AddNamespace("ns",$webConfig.DocumentElement.NamespaceURI)
        $key = "UseReportingCluster"
        $userClusterKey = $webConfig.SelectSingleNode("//ns:add[@key='$key']",$ns)

        if($null -ne $userClusterKey){
            if($userClusterKey.Value -eq $true){
                return $true
            }
        }
    }

    return $false
}

function Get-InfrastructureClickonceAppsDirectory
{
    $Config = Get-ApplicationEnvironment
    return $Config.Infrastructure.ClickonceAppsDirectory
}

function Get-DevToolsInstalled
{
    $webroot = Get-AosWebSitePhysicalPath
    $webconfig=join-path $webroot "web.config"
    $DevInstall=$false
    
    [System.Xml.XmlDocument] $xd=new-object System.Xml.XmlDocument
    $xd.Load($webconfig)
    $ns=New-Object System.Xml.XmlNamespaceManager($xd.NameTable)
    $ns.AddNamespace("ns",$xd.DocumentElement.NamespaceURI)

    $key="Infrastructure.VSToolsCount"

    $VScount = $xd.SelectSingleNode("//ns:add[@key='$key']",$ns)

    if($VScount -ne $null){
        
        if($VScount.GetAttribute("value") -gt 0)
        {
            $DevInstall=$true
        }
    }
    return $DevInstall 
}

function Get-ProductVersionMajorMinor
{
    [string]  $productVersionMajorMinorString = '7.0'
    return $productVersionMajorMinorString
}

function Get-IsRetailProductSku
{
    $productVersion = Get-ProductVersionMajorMinor    
    $retailHQConfigurationLocationRegistryPath = "HKLM:\SOFTWARE\Microsoft\Dynamics\$productVersion\Setup\Metadata"
    if(Test-Path $retailHQConfigurationLocationRegistryPath)
    {
        $retailProductSku = Get-ItemProperty -Path $retailHQConfigurationLocationRegistryPath -Name 'ProductSku' -ErrorAction SilentlyContinue
        
        if($retailProductSku -and $retailProductSku.ProductSku -and ($retailProductSku.ProductSku -eq 'Dynamics365ForRetail'))
        {
            return $true
        }
    }

    return $false
}

function Get-IsOverlayeringDisabled
{
    $productVersion = Get-ProductVersionMajorMinor    
    $retailHQConfigurationLocationRegistryPath = "HKLM:\SOFTWARE\Microsoft\Dynamics\$productVersion\Setup\Metadata"
    if(Test-Path $retailHQConfigurationLocationRegistryPath)
    {
        $isOverlayeringDisabled = Get-ItemProperty -Path $retailHQConfigurationLocationRegistryPath -Name 'DisableOverlayering' -ErrorAction SilentlyContinue
        
        if($isOverlayeringDisabled -and $isOverlayeringDisabled.DisableOverlayering -and ($isOverlayeringDisabled.DisableOverlayering -like 'true'))
        {
            return $true
        }
    }

    return $false
}

function Get-IsAppSealed ([Parameter(Mandatory=$false)] $webroot)
{
    if($webroot -eq $null)
    {
        $webroot = Get-AosWebSitePhysicalPath
    }

    $Version = (Get-ProductApplicationVersion -webroot:$webroot)
    $build = [System.Version]::new()
    $minSealedVersion = new-object System.Version "8.1"

    if([System.Version]::TryParse($Version, [ref]$build))
    {
        # Any build major/minor 8.1+ is considered sealed.
        if($build.CompareTo($minSealedVersion) -ge 0)
        {
           return $true
        }

        # Sealing logic for 8.0 and earlier
        if($build.Major -ge "8")
        {
            ##Bug 240512: Receipt designer bits are not updated with the uptake of latest binary hotfix
            ##The appseal have a different meaning during package deployment than development
            ##if the appSeal == true we expect full binary hotfix, other wise we expect seperate x++ hotfix and special handle the remaining mofule (ie, clickonce... package)
            ##the app8.0, even though it's sealed from dev point of view, it's still releasing seperate x++ hotfix and the special handling code path for none sealed need to be used during package deployment
            if($build.Minor -ge "1") 
            {
                return $true
            }
        }
        elseif($build.Minor -ge "2")
        {
            if($build.Build.ToString().StartsWith("2"))
            {
                return $true
            }
        }
    }
    
    return $false
    
}

function Get-DependencyAXModelList([string] $sourcePath, [string] $metaPackageName)
{
    $microsoftPackages = @()
    [Void][Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')
    $zipFile = Get-Item $sourcePath\$metaPackageName*.nupkg
    if($zipFile -ne $null)
    {
        $PackFiles = [IO.Compression.ZipFile]::OpenRead($zipFile).Entries
        $PackageSpec =  $PackFiles | where {($_.Name -like "*.nuspec")}

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

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

        $Dependencies = $xmlDoc.GetElementsByTagName('dependency').id
        
        foreach($d in $Dependencies)
        {
            $microsoftPackages += $d
        }
    }
    
    return $microsoftPackages
}

function Get-ALMPackageCopyPath
{
    [string]$ALMBackupPath = ""

    # Is the ALM Service registered (environment variable "DynamicsSDK" would be set)
    if ($env:DynamicsSDK)
    {
        $RegPath = "HKLM:\SOFTWARE\Microsoft\Dynamics\AX\7.0\SDK"

        [string]$ALMBackupPath = $null
        
        # Do not fail when registry key is not found
        try
        {
            # Get the Dynamics SDK (ALM Service) registry key (throws if not found).
            $RegKey = Get-ItemProperty -Path $RegPath
            if ($RegKey -ne $null)
            {
                # Check if backup path set in registry
                $ALMBackupPath = $RegKey.BackupPath
            }
        }
        catch
        {
        }
        
        # If path not found in registry, check default paths
        if (-not $ALMBackupPath)
        {
            if (Test-Path "I:\DynamicsBackup")
            {
                $ALMBackupPath = "I:\DynamicsBackup"
            }
            elseif (Test-Path "$($env:SystemDrive)\DynamicsBackup")
            {
                $ALMBackupPath = "$($env:SystemDrive)\DynamicsBackup"
            }
        }
    }

    return $ALMBackupPath
}

function Get-EnvironmentId
{
    $Config = Get-ApplicationEnvironment
    return $Config.LCS.LCSEnvironmentId
}

function Get-DataAccessFlightingCachePath
{
    $Config = Get-ApplicationEnvironment
    return $Config.DataAccess.FlightingCachePath
}

function Get-DataAccessFlightingEnvironment
{
    $Config = Get-ApplicationEnvironment
    return $Config.DataAccess.FlightingEnvironment
}

function Get-DataAccessFlightingCertificateThumbprint
{
    $Config = Get-ApplicationEnvironment
    return $Config.DataAccess.FlightingCertificateThumbprint
}

function Get-DataAccessFlightingServiceCatalogID
{
    $Config = Get-ApplicationEnvironment
    return $Config.DataAccess.FlightingServiceCatalogID
}

function Get-TenantDomainGUID
{
    $Config = Get-ApplicationEnvironment
    return $Config.Aad.TenantDomainGUID
}

function Get-AADTenantId
{
    $Config = Get-ApplicationEnvironment
    return $Config.Aad.AADTenantId
}

function Get-S2SCertificate
{
    try
    {
        $config = Get-ApplicationEnvironment
        $certHandlerSetttings = $config.CertificateHandler.GetCertificateHandlerSettings()

        $certificateHandler = [Microsoft.Dynamics.AX.Configuration.CertificateHandler.CertificateHandlerFactory]::CreateCertificateHandler($certHandlerSetttings)
    
        $s2sCertificate = $certificateHandler.GetSingleCertificateForId($config.Infrastructure.S2SCertThumbprint)

        return $s2sCertificate
    }
    catch
    {
        return $null
    }
}

function Load-FlightingDlls
{
    $webroot = Get-AosWebSitePhysicalPath

    Load-DllinMemory "$webroot\bin\Microsoft.Carbon.CertificateCommon.dll"
    Load-DllinMemory "$webroot\bin\Microsoft.Carbon.Flighting.Runtime.dll"
    Load-DllinMemory "$webroot\bin\Microsoft.Commerce.Flighting.Common.dll"

    Load-DllinMemory "$webroot\bin\Microsoft.Dynamics.BusinessPlatform.SharedTypes.dll"
    Load-DllinMemory "$webroot\bin\Microsoft.Dynamics.ApplicationPlatform.XppServices.Instrumentation.dll"
    Load-DllinMemory "$webroot\bin\Microsoft.Dynamics.ApplicationPlatform.Services.Instrumentation.dll"
    Load-DllinMemory "$webroot\bin\Microsoft.Dynamics.AX.Data.Sql.Shared.dll"
    Load-DllinMemory "$webroot\bin\Microsoft.Dynamics.ApplicationPlatform.Flighting.dll"
    Load-DllinMemory "$webroot\bin\Microsoft.Dynamics.ApplicationPlatform.AOSFlighting.dll"
    Load-DllinMemory "$webroot\bin\Microsoft.Dynamics.ApplicationPlatform.PerformanceCounters.dll"
    Load-DllinMemory "$webroot\bin\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll"
    Load-DllinMemory "$webroot\bin\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Data.dll"
    Load-DllinMemory "$webroot\bin\Newtonsoft.Json.dll"

    # Contained in XppServices.Instrumentation in earlier releases
    $dbSyncInstrumentationPath = "$webroot\bin\Microsoft.Dynamics.ApplicationPlatform.DatabaseSynchronize.Instrumentation.dll"
    if (Test-Path $dbSyncInstrumentationPath)
    {
        Load-DllinMemory $dbSyncInstrumentationPath
    }
}

$script:FlightingProvider = $null
function Get-IsFlightEnabled([string] $flightName)
{
    $ErrorActionPreference = 'Stop'

    if ([String]::IsNullOrWhiteSpace($flightName))
    {
        return $false
    }

    if ($script:FlightingProvider -eq $null)
    {
        $sqlPwd    = Get-DataAccessSqlPwd
        $sqlUser   = Get-DataAccessSqlUsr
        $sqlServer = Get-DataAccessDbServer
        $sqlDB     = Get-DataAccessDatabase
        $connectionString = "Data Source=$sqlServer; " +
            "Integrated Security=False; " +
            "User Id=$sqlUser; " +
            "Password=`"$sqlPwd`"; " +
            "Initial Catalog=$sqlDB"

        $flightingCacheFolder = Get-DataAccessFlightingCachePath
        if ([String]::IsNullOrWhiteSpace($flightingCacheFolder))
        {
            $flightingCacheFolder = Get-AosWebSitePhysicalPath # webroot
        }

        Load-FlightingDlls

        $flightingConfiguration = New-Object -TypeName Microsoft.Dynamics.ApplicationPlatform.AOSFlighting.StaticFlightingServiceConfiguration -ArgumentList `
            (Get-DataAccessFlightingEnvironment), `
            (Get-DataAccessFlightingCertificateThumbprint), `
            (Get-DataAccessFlightingServiceCatalogID), `
            $flightingCacheFolder, `
            $null, # object extraInformation `
            $connectionString, `
            (60 * 60) # int refreshDataIntervalInSec

        $script:FlightingProvider = [Microsoft.Dynamics.ApplicationPlatform.AOSFlighting.AOSFlightingSystem]::InitializeFlightService($flightingConfiguration)
        $script:FlightingProvider.AddInformationToCommonContext("TenantID", (Get-TenantDomainGUID))
        $script:FlightingProvider.AddInformationToCommonContext("EnvironmentId", (Get-EnvironmentId))

        Write-Log "Flighting provider is a $($script:FlightingProvider.GetType().Name)."
    }

    return $script:FlightingProvider.IsFeatureEnabled($flightName)
}

function IsLocalServer([string] $serverName)
{
    if ($serverName -eq $null) { return $false }
    
    if ("." -eq $serverName) { return $true }
    if ("(local)" -eq $serverName) { return $true }
    if ("localhost" -eq $serverName) { return $true }
    if ("127.0.0.1" -eq $serverName) { return $true }
    if ([System.Environment]::MachineName -eq $serverName.Split('.')[0]) { return $true }

    return $false
}

function Invoke-XppStaticMethod()
{
    Param(
        [Parameter(Mandatory=$true)]
        [ValidatePattern('^[a-zA-Z0-9_]+$')]
        [String]
        $ClassName,

        [Parameter(Mandatory=$true)]
        [ValidatePattern('^[a-zA-Z0-9_]+$')]
        [String]
        $MethodName,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $RedirectStandardError
    )

    $commandParameter = "-bindir `"$(Get-CommonBinDir)`""
    $commandParameter += " -metadatadir `"$(Get-AOSPackageDirectory)`""
    $commandParameter += " -sqluser `"$(Get-DataAccessSqlUsr)`""
    $commandParameter += " -sqlserver `"$(Get-DataAccessDbServer)`""
    $commandParameter += " -sqldatabase `"$(Get-DataAccessDatabase)`""
    $commandParameter += " -sqlpwd `"$(Get-DataAccessSqlPwd)`""
    $commandParameter += " -setupmode runstaticxppmethod"
    $commandParameter += " -classname $ClassName"
    $commandParameter += " -methodname $MethodName"

    $webroot = Get-AosWebSitePhysicalPath
    $startProcessArgs = @{
        FilePath = "$webroot\bin\Microsoft.Dynamics.AX.Deployment.Setup.exe"
        ArgumentList = $commandParameter
        PassThru = $true
        Wait = $true
        RedirectStandardError = $RedirectStandardError
    }

    $process = Start-Process @startProcessArgs
    
    if ($process.ExitCode -ne 0)
    {
        $errorContent = Get-Content "$RedirectStandardError"
        if ($errorContent -eq $null)
        {
            $errorContent = "Process terminated with exit code $($process.ExitCode) (error stream is empty)."
        }
        throw $errorContent
    }
}

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

function Get-IsBinaryPackageTypeFromPackage
{
    $packageRoot = split-Path -parent "$(split-Path -parent $PSScriptRoot)"

    # Using job to load the AXInstallationInfo dll to avoid file locks
    $job = Start-Job -ScriptBlock  {
        param($packageRootBlock)
        $axInstallationInfoDLLPath = Join-Path $packageRootBlock "Microsoft.Dynamics.AX.AXInstallationInfo.dll"
        $hotfixInstallationInfoFilePath = Join-Path $packageRootBlock "HotfixInstallationInfo.xml"
        try
        {
            if (Test-Path $axInstallationInfoDLLPath)
            {
                # Load AXInstallationInfo.dll
                [void][System.Reflection.Assembly]::LoadFrom($axInstallationInfoDLLPath)
                $hotfixInstallationInfo = New-Object Microsoft.Dynamics.AX.AXInstallationInfo.HotfixInstallationInfo

                if (Test-Path $hotfixInstallationInfoFilePath)
                {
                    # Initialize HotfixInstallationInfo from HotfixInstallationInfo.xml
                    $hotfixInstallationInfo.InitFromFile($hotfixInstallationInfoFilePath)
                    # Get package type
                    $hotfixInstallationInfo.Type
                }
            }
        }
        catch
        {
            Write-Warning "Failed to get package type from deployable package"
            return $null
        }
    } -ArgumentList $packageRoot
    Wait-Job -Job $job | Out-Null
    $packageType  = Receive-Job -Job $job
    if(![string]::IsNullOrEmpty($packageType))
    {
        return ($packageType -eq 'PlatAppBinaryHotfixPackage' -or $packageType -eq 'MergedPackage')
    }
    return $false
}

function Get-PackageNamesFromDLL([Parameter(Mandatory=$false)] $webroot, [Parameter(Mandatory=$true)][string] $productInfoDLL)
{
    if (!$webroot) {
    $webroot = Get-AosWebSitePhysicalPath
    }

    # Using job to load the Product Information dll to avoid file locks
    $job = Start-Job -ScriptBlock  {
        param($webrootBlock, $productInfoDLLBlock)
        $metadataCoreDLLPath = Join-Path $webrootBlock "bin\Microsoft.Dynamics.AX.Metadata.Core.dll"
        $productInfoDLLPath = Join-Path $webrootBlock $productInfoDLLBlock
        try
        {
            if (Test-Path $metadataCoreDLLPath)
            {
                # Load Metadata.Core.dll
                [void][System.Reflection.Assembly]::LoadFrom($metadataCoreDLLPath)
                if (Test-Path $productInfoDLLPath)
                {
                    # Get package names from Product Information dll
                    $packageNames = [Microsoft.Dynamics.AX.Metadata.Core.CoreHelper]::GetPackagesNames($productInfoDLLPath, $null)
                    $packageNames
                }
            }
        }
        catch
        {
            Write-Warning "Failed to get package names from product information dll."
            return $null
        }
    } -ArgumentList $webroot,$productInfoDLL
    Wait-Job -Job $job | Out-Null
    $packageNames  = Receive-Job -Job $job
    return $packageNames
}

Export-ModuleMember -Function Get-DataAccessSqlPwd
Export-ModuleMember -Function Get-DataAccessDatabase
Export-ModuleMember -Function Get-DataAccessSqlUsr
Export-ModuleMember -Function Get-DataAccessDbServer
Export-ModuleMember -Function Get-AOSPackageDirectory
Export-ModuleMember -Function Get-CommonBinDir
Export-ModuleMember -Function Get-BiReportingPersistentVirtualMachineIPAddressSSRS
Export-ModuleMember -Function Get-BiReportingReportingServers
Export-ModuleMember -Function Get-UseReportingCluster
Export-ModuleMember -Function Get-InfrastructureClickonceAppsDirectory
Export-ModuleMember -Function Get-DevToolsInstalled
Export-ModuleMember -Function Get-IsModulePartOfPlatformAsBinary
Export-ModuleMember -Function Get-IsAppFallOrLater
Export-ModuleMember -Function Get-IsPlatformUpdate3OrLater
Export-ModuleMember -Function Get-IsPackageContainUpgradeBinaryForUpdate3
Export-ModuleMember -Function Get-ProductPlatformBuildVersion
Export-ModuleMember -Function Get-ProductApplicationVersion
Export-ModuleMember -Function Get-ProductPlatformBuildFullVersion
Export-ModuleMember -Function Get-ApplicationReleaseFromPackage
Export-ModuleMember -Function Get-ProductVersionMajorMinor
Export-ModuleMember -Function Get-IsRetailProductSku
Export-ModuleMember -Function Get-IsOverlayeringDisabled
Export-ModuleMember -Function Get-DependencyAXModelList
Export-ModuleMember -Function Get-IsAppSealed
Export-ModuleMember -Function Get-IsModulePartOfApplicationAsBinary
Export-ModuleMember -Function Get-ALMPackageCopyPath
Export-ModuleMember -Function Get-IsFlightEnabled
Export-ModuleMember -Function GenerateMetadataModuleInstallationInfo
Export-ModuleMember -Function Get-EnvironmentId
Export-ModuleMember -Function Get-AADTenantId
Export-ModuleMember -Function Get-TenantDomainGUID
Export-ModuleMember -Function Get-S2SCertificate
Export-ModuleMember -Function IsLocalServer
Export-ModuleMember -Function Invoke-XppStaticMethod
Export-ModuleMember -Function Get-IsBinaryPackageTypeFromPackage
Export-ModuleMember -Function Get-PackageNamesFromDLL
# SIG # Begin signature block
# MIIjkgYJKoZIhvcNAQcCoIIjgzCCI38CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAUbNJ5xjDJqOI0
# zX0VqY/fDMDmA3XjbxWfxP5kV2fbJKCCDYEwggX/MIID56ADAgECAhMzAAABh3IX
# chVZQMcJAAAAAAGHMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ3WhcNMjEwMzAzMTgzOTQ3WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDOt8kLc7P3T7MKIhouYHewMFmnq8Ayu7FOhZCQabVwBp2VS4WyB2Qe4TQBT8aB
# znANDEPjHKNdPT8Xz5cNali6XHefS8i/WXtF0vSsP8NEv6mBHuA2p1fw2wB/F0dH
# sJ3GfZ5c0sPJjklsiYqPw59xJ54kM91IOgiO2OUzjNAljPibjCWfH7UzQ1TPHc4d
# weils8GEIrbBRb7IWwiObL12jWT4Yh71NQgvJ9Fn6+UhD9x2uk3dLj84vwt1NuFQ
# itKJxIV0fVsRNR3abQVOLqpDugbr0SzNL6o8xzOHL5OXiGGwg6ekiXA1/2XXY7yV
# Fc39tledDtZjSjNbex1zzwSXAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUhov4ZyO96axkJdMjpzu2zVXOJcsw
# UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1
# ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDU4Mzg1MB8GA1UdIwQYMBaAFEhu
# ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu
# bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w
# Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx
# MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAixmy
# S6E6vprWD9KFNIB9G5zyMuIjZAOuUJ1EK/Vlg6Fb3ZHXjjUwATKIcXbFuFC6Wr4K
# NrU4DY/sBVqmab5AC/je3bpUpjtxpEyqUqtPc30wEg/rO9vmKmqKoLPT37svc2NV
# BmGNl+85qO4fV/w7Cx7J0Bbqk19KcRNdjt6eKoTnTPHBHlVHQIHZpMxacbFOAkJr
# qAVkYZdz7ikNXTxV+GRb36tC4ByMNxE2DF7vFdvaiZP0CVZ5ByJ2gAhXMdK9+usx
# zVk913qKde1OAuWdv+rndqkAIm8fUlRnr4saSCg7cIbUwCCf116wUJ7EuJDg0vHe
# yhnCeHnBbyH3RZkHEi2ofmfgnFISJZDdMAeVZGVOh20Jp50XBzqokpPzeZ6zc1/g
# yILNyiVgE+RPkjnUQshd1f1PMgn3tns2Cz7bJiVUaqEO3n9qRFgy5JuLae6UweGf
# AeOo3dgLZxikKzYs3hDMaEtJq8IP71cX7QXe6lnMmXU/Hdfz2p897Zd+kU+vZvKI
# 3cwLfuVQgK2RZ2z+Kc3K3dRPz2rXycK5XCuRZmvGab/WbrZiC7wJQapgBodltMI5
# GMdFrBg9IeF7/rP4EqVQXeKtevTlZXjpuNhhjuR+2DMt/dWufjXpiW91bo3aH6Ea
# jOALXmoxgltCp1K7hrS6gmsvj94cLRf50QQ4U8Qwggd6MIIFYqADAgECAgphDpDS
# 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/BvW1taslScxMNelDNMYIVZzCCFWMCAQEwgZUwfjELMAkG
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z
# b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAYdyF3IVWUDHCQAAAAABhzAN
# BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor
# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgncArcvoC
# Q97EJoNgremjObK4Ri/FF4BwwjPlL6eMCG0wQgYKKwYBBAGCNwIBDDE0MDKgFIAS
# AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN
# BgkqhkiG9w0BAQEFAASCAQBw1DDdVM4kaNPqMj86LcPGDiX3x6ihhywtmy6IuUCt
# XT52NzYbP9ij2mjNTZm7nx3V/gmc3yiVoJWEXrSkcPsVKM72WT86VsPk0eVHwyBf
# k7ROnGs8RztWp1xAS56KUXwBYrT3n5e0NSELWWNEELfVH0u5E57NWWDMCnO/l4JD
# 094/z0NEF5ResID/tZuxM1mIi3xiVwE6kpW0bw+5JZFi6ZmVKjN+21T76w7ovXTB
# C0Eb8ps/Hp6IIC7y5hZ+dIS65/sdWw6WSpajvc+/GSSyI92ldmjptyhYgAqfVmRP
# zyYXhjbUq5nvTPMzCEizU4hRFhrnVTwR2KB6YEeGTdLIoYIS8TCCEu0GCisGAQQB
# gjcDAwExghLdMIIS2QYJKoZIhvcNAQcCoIISyjCCEsYCAQMxDzANBglghkgBZQME
# AgEFADCCAVUGCyqGSIb3DQEJEAEEoIIBRASCAUAwggE8AgEBBgorBgEEAYRZCgMB
# MDEwDQYJYIZIAWUDBAIBBQAEIFjiu4B0w/CCPuLHFbnxE0CG7NBkm+n9mpCz8W2a
# jbDYAgZftBABPLkYEzIwMjAxMTE5MjAzNjU2LjQwNVowBIACAfSggdSkgdEwgc4x
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1p
# Y3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMg
# VFNTIEVTTjpEOURFLUUzOUEtNDNGRTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt
# U3RhbXAgU2VydmljZaCCDkQwggT1MIID3aADAgECAhMzAAABLS5NQcpjZTOgAAAA
# AAEtMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
# MB4XDTE5MTIxOTAxMTUwNFoXDTIxMDMxNzAxMTUwNFowgc4xCzAJBgNVBAYTAlVT
# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVy
# YXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpEOURF
# LUUzOUEtNDNGRTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vydmlj
# ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKlhjfR1STqYRTS3s0i4
# jIcSMV+G4N0oYgwlQK+pl4DVMFmr1iTZHFLj3Tt7V6F+M/BXx0h9i0uu1yBnqCqN
# OkuJERTbVnM4u3JvRxzsQfCjBfqD/CNwoMNekoylIBzxP50Skjp1pPsnQBKHaCP8
# tguvYVzoTQ54q2VpYEP/+OYTQeEPqWFi8WggvsckuercUGkhYWM8DV/4JU7N/rbD
# rtamYbe8LtkViTQYbigUSCAor9DhtAZvq8A0A73XFH2df2wDlLtAnKCcsVvXSmZ3
# 5bAqneN4uEQVy8NQdReGI1tI6UxoC7XnjGvK4McDdKhavNJ7DAnSP5+G/DTkdWD+
# lN8CAwEAAaOCARswggEXMB0GA1UdDgQWBBTZbGR8QgEh+E4Oiv8vQ7408p2GzTAf
# BgNVHSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBH
# hkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNU
# aW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUF
# BzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0
# YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsG
# AQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IBAQB9awNk906recBuoO7Ezq7B8UGu9EoF
# XiL8ac0bbsZDBY9z/3p8atVZRCxHN43a3WGbCMZoKYxSBH6UCkcDcwXIfNKEbVMz
# nF1mjpQEGbqhR+rPNqHXZotSV+vn85AxmefAM3bcLt+WNBpEuOZZ4kPZVcFtMo4Y
# yQjxoNRPiwmp+B0HkhQs/l/VIg0XJY6k5FRKE/JFEcVY4256NdqUZ+3jou3b4OAk
# tE2urr4V6VRw1fffOlxZb8MyvE5mqvTVJOStVxCuhuqg1rIe8la1gZ5iiuIyWeft
# ONfMw0nSZchGLigDeInw6XfwwgFnC5Ql8Pbf2jOxCUluAYbzykI+MnBiMIIGcTCC
# BFmgAwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJv
# b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcN
# MjUwNzAxMjE0NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIw
# DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0
# VBDVpQoAgoX77XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEw
# RA/xYIiEVEMM1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQe
# dGFnkV+BVLHPk0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKx
# Xf13Hz3wV3WsvYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4G
# kbaICDXoeByw6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEA
# AaOCAeYwggHiMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7
# fEYbxTNoWoVtVTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0g
# AQH/BIGVMIGSMIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93
# d3cubWljcm9zb2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYB
# BQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUA
# bQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOh
# IW+z66bM9TG+zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS
# +7lTjMz0YBKKdsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlK
# kVIArzgPF/UveYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon
# /VWvL/625Y4zu2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOi
# PPp/fZZqkHimbdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/
# fmNZJQ96LjlXdqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCII
# YdqwUB5vvfHhAN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0
# cs0d9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7a
# KLixqduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQ
# cdeh0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+
# NR4Iuto229Nfj950iEkSoYIC0jCCAjsCAQEwgfyhgdSkgdEwgc4xCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBP
# cGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpE
# OURFLUUzOUEtNDNGRTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy
# dmljZaIjCgEBMAcGBSsOAwIaAxUAn85fx36He7F0vgmyUlz2w82l0LGggYMwgYCk
# fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF
# AONhMWcwIhgPMjAyMDExMTkyMjAxMTFaGA8yMDIwMTEyMDIyMDExMVowdzA9Bgor
# BgEEAYRZCgQBMS8wLTAKAgUA42ExZwIBADAKAgEAAgIPfgIB/zAHAgEAAgIRmDAK
# AgUA42KC5wIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB
# AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAJza2SqRI63/te9b
# AsoZhaHYq7LWFOFaPJybwYTI3+HpBZtxUXo9eF9u9FR5BCkvz2UkXyEx6kYJMyOr
# njzKQfLjcw+bx7SQGUSGOWBsRFSbU0yabtS7nTeZCIXd2SlF6CRdmztR6iC83qxY
# F1fThRKANBDBwSpTMOqS39rF0mKBMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTACEzMAAAEtLk1BymNlM6AAAAAAAS0wDQYJYIZIAWUD
# BAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0B
# CQQxIgQgzkwWrWsdsTHyJmfsWlhFdpVxYfwHECyjf0QIcG5oy4kwgfoGCyqGSIb3
# DQEJEAIvMYHqMIHnMIHkMIG9BCCO8Vpycn0gB4/ilRAPPDbS+Cmbqj/uC011moc5
# oeGDwTCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB
# LS5NQcpjZTOgAAAAAAEtMCIEIGufYE4ePdTuWjwhLJFyrmLa0379I7YkYeOg00OI
# Tf87MA0GCSqGSIb3DQEBCwUABIIBACETPQv17zO9BagEPKl0UUcsUugF3IW8G7p1
# o2nO2RviHYv3GVqxQxh0NuceAMqBqgF/38J1tINzVTT9pipID5yCVAEIXJOzc29R
# UapIbbXVY3LHxOF0AwxW43TO0JP64pCzCF6g53sqMmuYGG49FlqqOHF63PYKF7D8
# 1yJ/MPtSo4NYsrhpNUBYq1v3rxA1cRuqOGTcC79JRRFj5/hDI4XRMvs8p8yON0TP
# cz4wtTmEEMdOOC7f9hneN1eUKc2t1ccBSyXnhiMJPocLiP+lIQR3GhNJKVJawnlz
# DC7HUaN2YSidZtVvXVI9F43HO4V4ijmiOoFdpmDtVapgSnUgb0M=
# SIG # End signature block
