functions/Publish-DosWebApplication.ps1

<#
    .SYNOPSIS
 
    Publishes the target DOS web application with the specified options
 
    .DESCRIPTION
 
    Publishes the target DOS web application with the specified options. Either uses WebDeploy (for older apps), or internal logic for new .Net Core applicaitons.
 
    .PARAMETER WebAppPackagePath
 
    File path to web application zip to publish
 
    .PARAMETER SettingsXmlPath
 
    ONLY USED in WebDeploy Applications - File path to xml settings
 
    .PARAMETER AppPoolName
 
    IIS Application Pool name
 
    .PARAMETER AppPoolCredential
 
    Credential object used to configure the built-in account the IIS Application Pool runs as
     
    .PARAMETER AuthenticationType
 
    ONLY USED in WebDeploy Applications - Windows or Anonymous authentication
 
    .PARAMETER WebDeploy
 
    A toggle for the web application to be deployed via WebDeploy or by other means
 
    .PARAMETER AppName
 
    ONLY USED in NON-Webdeploy applications. Specifies both the application's name AND the folder name where the application will be placed underneath the IIS site's root folder.
 
    .PARAMETER IISWebSite
 
    ONLY USED in NON-WebDeploy applications. Specifies the IIS site to publish the application to. Defaults to "Default Web Site"
 
    .PARAMETER WebDeployParameters
 
    ONLY USED in WebDeploy Applications - Arraylist object containing site settings
 
    .EXAMPLE
 
    Publish-DosWebApplication -WebAppPackagePath "testapp.zip" -SettingsXmlPath "testapp.settings.xml" -AppPoolName "x" -AppPoolCredential $creds -AuthenticationType "Windows" -WebDeploy -WebDeployParameters $webDeployParams
#>

function Publish-DosWebApplication {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [ValidateScript({
            if (!(Test-Path $_)) {
                Write-DosMessage -Level "Error" -Message "$_ does not exist. Please enter valid path." -ErrorAction Stop
            }
            else {
                $true
            }
        })]
        [string] $WebAppPackagePath,
        [string] $SettingsXmlPath,
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [ValidateLength(1,64)]
        [ValidateScript({
            if ($_ -match '[^a-zA-Z0-9]') {
                Write-DosMessage -Level "Error" -Message "$_ must only contain alphanumeric values. Please remove special characters." -ErrorAction Stop
            }
            else {
                $true
            }
        })]
        [string] $AppPoolName,
        [PSCredential] $AppPoolCredential,
        [ValidateSet("Windows", "Anonymous")]
        [string[]] $AuthenticationType,
        [switch] $WebDeploy,
        [string] $AppName,
        [string] $IISWebSite = "Default Web Site",
        [System.Collections.ArrayList] $WebDeployParameters,
        [switch] $NoCredential
    )

    Test-ElevatedPermission
    Import-Module WebAdministration -Force
    
    ###Only allow one source of input for webdeploy args

    try {
        if ($NoCredential.IsPresent) {
            Write-DosMessage -Level "Information" -Message "The NoCredential parameter was provided. Proceeding to application pool validation."
    
            if(!(Test-Path "IIS:\AppPools\$AppPoolName" -PathType Container)){
                New-AppPool -IISAppPoolName $AppPoolName
            }
            else {
                Set-AppPoolSettings -IISAppPoolName $AppPoolName -NoCredential $NoCredential.IsPresent
            }
        }
        else {
            if(!(Test-Path "IIS:\AppPools\$AppPoolName" -PathType Container)){
                if($AppPoolCredential -eq $null){
                    Write-DosMessage -Level "Fatal" -Message "No app pool found named $AppPoolName and no credentials specified. Please specify credentials -AppPoolCredential if you want to create a new application pool"
                    return
                }
                
                New-AppPool -IISAppPoolName $AppPoolName -IdentityCredential $AppPoolCredential
            }
            else {
                $existingAppPool = Get-Item -Path "IIS:\AppPools\$AppPoolName"

                # if app pool exists and credential is passed in / checks if the existing credential is the same / if it differs we fail out
                if ($null -ne $AppPoolCredential) {
                    if ($existingAppPool.processModel.userName -ne $AppPoolCredential.UserName -or $existingAppPool.processModel.password -ne $AppPoolCredential.GetNetworkCredential().Password) {
                        Write-DosMessage -Level "Fatal" -Message "The '$AppPoolName' app pool has an identity configured that differs from the identity credential provided. Halting deployment."
                    }
                }

                Set-AppPoolSettings -IISAppPoolName $AppPoolName -IdentityCredential $AppPoolCredential
                Write-DosMessage -Level "Information" -Message "Application Pool: $AppPoolName already exists. Deploying '$WebAppPackagePath' to $AppPoolName"
            }
        }
        
        $appPool = Get-Item "IIS:\AppPools\$AppPoolName"
        $appPool.Start()
    }
    catch {
        Write-DosMessage -Level "Error" -Message "Error occured getting, creating, or updating a IIS application pool. Exception: $($_.Exception)"
        return
    }

    #Deploy Website to IIS
    if ($WebDeploy.IsPresent){

        if([String]::IsNullOrEmpty($SettingsXmlPath) -and ($null -eq $WebDeployParameters)){
            Write-DosMessage -Level "Error" -Message "Must provide parameters through a settings xml file or webdeployparameters when deploying a web deploy application"
            return
        }

        if($SettingsXmlPath) {
            try {
                [xml] $parsedXml = Get-Content $SettingsXmlPath
            }
            catch {
                Write-DosMessage -Level "Error" -Message "Error occured parsing xml settings file. Exception: $($_.Exception)"
                return
            }
        }

        try {
            Write-DosMessage -Level "Information" -Message "Attempting to retrieve the IIS web application information."
            $siteName,$appNameFromSettings = Get-IisWebAppInfo -SettingsXmlPath $SettingsXmlPath -WebDeployParameters $WebDeployParameters -ParsedXml $parsedXml
            Write-DosMessage -Level "Information" -Message "Successfully retrieved the IIS web application information."
            Write-DosMessage -Level "Information" -Message "Deploying '$appNameFromSettings' through WebDeploy."
        }
        catch {
            Write-DosMessage -Level "Error" -Message "Unable to find node containing IIS Web Application Name values"
            return
        }
        
        Publish-WebDeployWebApp -WebDeployPackageFilePath $WebAppPackagePath -WebDeployParameterFilePath $SettingsXmlPath -WebParameters $WebDeployParameters -AppName $appNameFromSettings -IISWebSite $IISWebSite -AppPoolName $AppPoolName

        Set-ApplicationPool -SiteName $siteName -AppName $appNameFromSettings -AppPoolName $AppPoolName
        Set-AuthenticationType -SiteName $siteName -AppName $appNameFromSettings -AuthenticationType $AuthenticationType

        Write-DosTelemetry -Message "Publish-DosWebApplication called and published using Publish-WebDeployWebApp."
    }
    else {
        if([string]::IsNullOrEmpty($AppName)){
            Write-DosMessage -Level "Fatal" -Message "AppName must be non-null and non empty"
        }

        Publish-DotNetCoreWebApp -WebApplicationPackagePath $WebAppPackagePath -AppName $AppName -IISWebSite $IISWebSite -AppPoolName $AppPoolName
        
        Set-ApplicationPool -SiteName $IISWebSite -AppName $AppName -AppPoolName $AppPoolName

        if (-Not ([string]::IsNullOrEmpty($AuthenticationType))) {
            Install-UrlRewrite
            Set-AuthenticationType -SiteName $IISWebSite -AppName $AppName -AuthenticationType $AuthenticationType
        }

        Write-DosTelemetry -Message "Publish-DosWebApplication called and published using Publish-DotNetCoreWebApp."
    }
}

function Get-IisWebAppInfo {
    param (
        [string] $SettingsXmlPath,
        [System.Collections.ArrayList] $WebDeployParameters,
        [xml] $ParsedXml
    )

    if($SettingsXmlPath){
        # Parameter childnodes can be different
        $iisParameter = $ParsedXml.parameters.ChildNodes | Where-Object { $_.name -eq "IIS Web Application Name" }

        # Parameter attribute names differ (eg. defaultValue and value)
        $iisAppPath = $iisParameter.Attributes | Where-Object { $_ -like "*value" }
        $siteName,$appNameFromSettings = $iisAppPath.'#text'.split('/')
    }else{
        # Parameter attribute names differ (eg. defaultValue and value)
        foreach ($param in $WebDeployParameters)
        {
            if($param.Name -eq "IIS Web Application Name"){
                $iisAppPath = $param.Value
            }
        }
        $siteName,$appNameFromSettings = $iisAppPath.split('/')
    }

    return $siteName,$appNameFromSettings
}

function Set-ApplicationPool {
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "", Justification="WhatIf support not implemented.")]
    param (
        [string] $SiteName,
        [string] $AppName,
        [string] $AppPoolName
    )

    try {
        # Set-Application Pool with specific app
        Push-Location -Path IIS:\Sites\$SiteName\
        Set-ItemProperty -Path $AppName -Name applicationPool -Value $AppPoolName
    }
    catch {
        Write-DosMessage -Level "Error" -Message "Error occured associating application to the app pool. Exception: $($_.Exception)"
        return
    }
    finally {
        Pop-Location
    }
}

function Set-AuthenticationType {
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "", Justification="WhatIf support not implemented.")]
    param (
        [string] $SiteName,
        [string] $AppName,
        [string[]] $AuthenticationType
    )

    try{
        Push-Location -Path IIS:\Sites\$SiteName\$AppName
        # Set-Authentication and transform the web config
        Set-IISAuthentication -AuthenticationType $AuthenticationType -SiteName $SiteName -ApplicationName $AppName
    }
    catch {
        Write-DosMessage -Level "Error" -Message "Error occured altering authentication types. Exception: $($_.Exception)"
        return
    }
    finally {
        Pop-Location
    }
}

function Install-UrlRewrite {
    # Check if URL Rewrite is installed before setting authentication
    $urlRewriteRegistry = "HKLM:\SOFTWARE\Microsoft\IIS Extensions\URL Rewrite"

    if (-Not (Test-Path $urlRewriteRegistry)) {
        Write-DosMessage -Level "Information" -Message "UrlRewrite not installed"

        # Install Web Platform Installer if not present
        if (-Not (Test-Path "$($env:ProgramFiles)\Microsoft\Web Platform Installer")) {
            Write-DosMessage -Level "Information" -Message "Web Platform Installer not found"
            Get-WebRequestDownload "https://go.microsoft.com/fwlink/?LinkId=287166" -OutFile "$PSScriptRoot\Web-Platform-Install.msi"
            Write-DosMessage -Level "Information" -Message "Installing Web Platform Installer"
            Start-Process "$PSScriptRoot\Web-Platform-Install.msi" '/qn' -PassThru | Wait-Process
            Remove-Item "$PSScriptRoot\Web-Platform-Install.msi"
        }

        # Install UrlRewrite using Web Platform Installer
        if (Test-Path "$($env:ProgramFiles)\Microsoft\Web Platform Installer\WebpiCmd.exe") {
            Write-DosMessage -Level "Information" -Message "Installing UrlRewrite"
            Start-Process "$($env:ProgramFiles)\Microsoft\Web Platform Installer\WebpiCmd.exe" "/Install /Products:'UrlRewrite2' /AcceptEULA" -PassThru | Wait-Process

            if (-Not (Test-Path $urlRewriteRegistry)) {
                Write-DosMessage -Level "Warning" -Message "UrlRewrite did not install correctly"
            }
        }
        else {
            Write-DosMessage -Level "Warning" -Message "Unable to install UrlRewrite, WebpiCmd.exe not found at $($env:ProgramFiles)\Microsoft\Web Platform Installer\WebpiCmd.exe"
        }
    }
}
# SIG # Begin signature block
# MIIcRgYJKoZIhvcNAQcCoIIcNzCCHDMCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCHmyaJewPx+iRt
# kApQvkOZLCYovzlRyfTKArY0r1YiwqCCCqAwggUwMIIEGKADAgECAhAECRgbX9W7
# ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBa
# Fw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lD
# ZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3
# DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/l
# qJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fT
# eyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqH
# CN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+
# bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLo
# LFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIB
# yTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK
# BggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9v
# Y3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHow
# eDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl
# ZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp
# Z2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwA
# AgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAK
# BghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0j
# BBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7s
# DVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGS
# dQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6
# r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo
# +MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qz
# sIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHq
# aGxEMrJmoecYpJpkUe8wggVoMIIEUKADAgECAhAKRecO+XBAYPQ5XoaaebXrMA0G
# CSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0
# IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwHhcNMTcwNDEzMDAwMDAw
# WhcNMjAwNDE1MTIwMDAwWjCBpDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcw
# FQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVSGVhbHRoIENhdGFseXN0
# LCBJbmMuMR4wHAYDVQQDExVIZWFsdGggQ2F0YWx5c3QsIEluYy4xLzAtBgkqhkiG
# 9w0BCQEWIGFkbWluaXN0cmF0b3JAaGVhbHRoY2F0YWx5c3QuY29tMIIBIjANBgkq
# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv8AEfB5imOv8J17fvW8w+WKuE0keRub9
# 1+QzkiI+nSa9y2yADr/ZCEXqxGqDKdg47CjlvpOmKg8K88NPaTPvGN5fm7p7avmn
# Cfp7IGXLGtutZ1RnFW2fYC8+kl86WinKVQ7eHLe7Rsvn9CyurIzttJpJcTikxqrr
# U45yE8Iw/H9ziiwP+grfm8AiGN3C2vuxbhs8YwG2pbbn2aa5hN5q4bbFzoQ4xHGO
# kFiqhRYVyGbVZNeoGTpkf/DNXJh07RuSDdcFXoh7whwwvfXhrk9Z5YzE6GEk2CUF
# adTjqWHuGyfpBpY7bYZ8/mbDTmUqLNeGsTQrVmowv4r+usyK6lz6LwIDAQABo4IB
# xTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYE
# FDCXth9LjWUWNRWEPkEw5VZAVdBSMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK
# BggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdpY2Vy
# dC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2NybDQu
# ZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3
# BglghkgBhv1sAwEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu
# Y29tL0NQUzAIBgZngQwBBAEwgYQGCCsGAQUFBwEBBHgwdjAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME4GCCsGAQUFBzAChkJodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyQXNzdXJlZElEQ29kZVNpZ25p
# bmdDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAkIewxl/k
# WdhH2w7hIW0jT2WXhasjLk/UVeJtON2V7uj6J5/geg9huBlF9UDASBN9Po3sULeE
# /WQ+Lxbd3BDLq+jcENPKdEE7v9NFOCzs142tBJ+tng5uSD4KCG7wStTggI8XElpu
# 0uraecK21bq4T4A2uGXpruEVNdS8DkANh34AwLJWanhaavbqunHZMkjQU0oluktS
# ikJ1BVeyROM0Xh11VBnM5nSftS4c8eC66ZXhsuc268wwzwb3eD81jKwXdli3SrvT
# zFKtAFqzh2/1bVIceq+iT7zketpGuFTg3BOkhbiJhIEjAS9pA3v+tVKrWcdTp/HC
# mT2XH0Xyeg2GhzGCEPwwghD4AgEBMIGGMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV
# BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0ECEApF
# 5w75cEBg9Dlehpp5teswDQYJYIZIAWUDBAIBBQCgfDAQBgorBgEEAYI3AgEMMQIw
# ADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYK
# KwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgeccMmZVXc2VNCLghWE6MLJuaEmPQ
# pLjPKo/wht3VPVQwDQYJKoZIhvcNAQEBBQAEggEAv45iHaSHWrjOhiPnyTtEaNIu
# vFqkhQObCInB97IcquM+onzh+sRSDrfoflOPG7JpLMlqxBY3/uNUDYt7L4Ar2S4M
# ksrJMS9JN3Vupk/bpTXtCxn+ngG1ugO4gtsKll7GhuU02/LMlL0ncspDvzd2fpaJ
# GysFga2qbPEyHt+VSTnIIZR/e77sIDypukyLnk8sxRYI5d6ORF911ZPrLjXjPSbz
# M4LZx0C62P5prJMdy9TngzPtbJHW38V5/RxwRorcVSsz92J5GcdvNa+a8i9K6TCP
# jprTduA08Mrn2mxAogQAeAlHAKnhQk5LLa1fPyGwlyCTILq/uLZqQphKOGaiWaGC
# Dsgwgg7EBgorBgEEAYI3AwMBMYIOtDCCDrAGCSqGSIb3DQEHAqCCDqEwgg6dAgED
# MQ8wDQYJYIZIAWUDBAIBBQAwdwYLKoZIhvcNAQkQAQSgaARmMGQCAQEGCWCGSAGG
# /WwHATAxMA0GCWCGSAFlAwQCAQUABCBPGmQEMco1W6wcrGrpz9q9zdbpVcl2xuZv
# jpOYDuqtvAIQYp2EJDF4bvivtYtXoZCNNBgPMjAyMDAyMjgxNzI2MzFaoIILuzCC
# BoIwggVqoAMCAQICEATNP4VornbGG7D+cWDMp20wDQYJKoZIhvcNAQELBQAwcjEL
# MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
# LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElE
# IFRpbWVzdGFtcGluZyBDQTAeFw0xOTEwMDEwMDAwMDBaFw0zMDEwMTcwMDAwMDBa
# MEwxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEkMCIGA1UE
# AxMbVElNRVNUQU1QLVNIQTI1Ni0yMDE5LTEwLTE1MIIBIjANBgkqhkiG9w0BAQEF
# AAOCAQ8AMIIBCgKCAQEA6WQ1nPqpmGVkG+QX3LgpNsxnCViFTTDgyf/lOzwRKFCv
# BzHiXQkYwvaJjGkIBCPgdy2dFeW46KFqjv/UrtJ6Fu/4QbUdOXXBzy+nrEV+lG2s
# AwGZPGI+fnr9RZcxtPq32UI+p1Wb31pPWAKoMmkiE76Lgi3GmKtrm7TJ8mURDHQN
# svAIlnTE6LJIoqEUpfj64YlwRDuN7/uk9MO5vRQs6wwoJyWAqxBLFhJgC2kijE7N
# xtWyZVkh4HwsEo1wDo+KyuDT17M5d1DQQiwues6cZ3o4d1RA/0+VBCDU68jOhxQI
# /h2A3dDnK3jqvx9wxu5CFlM2RZtTGUlinXoCm5UUowIDAQABo4IDODCCAzQwDgYD
# VR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUH
# AwgwggG/BgNVHSAEggG2MIIBsjCCAaEGCWCGSAGG/WwHATCCAZIwKAYIKwYBBQUH
# AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwggFkBggrBgEFBQcCAjCC
# AVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBlAHIAdABp
# AGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBw
# AHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAAQwBQ
# AC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAAYQBy
# AHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0
# ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAgAGEAcgBlACAAaQBuAGMAbwBy
# AHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBmAGUAcgBl
# AG4AYwBlAC4wCwYJYIZIAYb9bAMVMB8GA1UdIwQYMBaAFPS24SAd/imu0uRhpbKi
# JbLIFzVuMB0GA1UdDgQWBBRWUw/BxgenTdfYbldygFBM5OyewTBxBgNVHR8EajBo
# MDKgMKAuhixodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLXRz
# LmNybDAyoDCgLoYsaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJl
# ZC10cy5jcmwwgYUGCCsGAQUFBwEBBHkwdzAkBggrBgEFBQcwAYYYaHR0cDovL29j
# c3AuZGlnaWNlcnQuY29tME8GCCsGAQUFBzAChkNodHRwOi8vY2FjZXJ0cy5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRTSEEyQXNzdXJlZElEVGltZXN0YW1waW5nQ0EuY3J0
# MA0GCSqGSIb3DQEBCwUAA4IBAQAug6FEBUoE47kyUvrZgfAau/gJjSO5PdiSoeZG
# HEovbno8Y243F6Mav1gjskOclINOOQmwLOjH4eLM7ct5a87eIwFH7ZVUgeCAexKx
# rwKGqTpzav74n8GN0SGM5CmCw4oLYAACnR9HxJ+0CmhTf1oQpvgi5vhTkjFf2IKD
# LW0TQq6DwRBOpCT0R5zeDyJyd1x/T+k5mCtXkkTX726T2UPHBDNjUTdWnkcEEcOj
# WFQh2OKOVtdJP1f8Cp8jXnv0lI3dnRq733oqptJFplUMj/ZMivKWz4lG3DGykZCj
# XzMwYFX1/GswrKHt5EdOM55naii1TcLtW5eC+MupCGxTCbT3MIIFMTCCBBmgAwIB
# AgIQCqEl1tYyG35B5AXaNpfCFTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJV
# UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
# Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTYw
# MTA3MTIwMDAwWhcNMzEwMTA3MTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UE
# ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYD
# VQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBMIIB
# IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvdAy7kvNj3/dqbqCmcU5VChX
# tiNKxA4HRTNREH3Q+X1NaH7ntqD0jbOI5Je/YyGQmL8TvFfTw+F+CNZqFAA49y4e
# O+7MpvYyWf5fZT/gm+vjRkcGGlV+Cyd+wKL1oODeIj8O/36V+/OjuiI+GKwR5PCZ
# A207hXwJ0+5dyJoLVOOoCXFr4M8iEA91z3FyTgqt30A6XLdR4aF5FMZNJCMwXbzs
# PGBqrC8HzP3w6kfZiFBe/WZuVmEnKYmEUeaC50ZQ/ZQqLKfkdT66mA+Ef58xFNat
# 1fJky3seBdCEGXIX8RcG7z3N1k3vBkL9olMqT4UdxB08r8/arBD13ays6Vb/kwID
# AQABo4IBzjCCAcowHQYDVR0OBBYEFPS24SAd/imu0uRhpbKiJbLIFzVuMB8GA1Ud
# IwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMBIGA1UdEwEB/wQIMAYBAf8CAQAw
# DgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHkGCCsGAQUFBwEB
# BG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsG
# AQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1
# cmVkSURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsNC5k
# aWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRo
# dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0Eu
# Y3JsMFAGA1UdIARJMEcwOAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRw
# czovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAsGCWCGSAGG/WwHATANBgkqhkiG9w0B
# AQsFAAOCAQEAcZUS6VGHVmnN793afKpjerN4zwY3QITvS4S/ys8DAv3Fp8MOIEIs
# r3fzKx8MIVoqtwU0HWqumfgnoma/Capg33akOpMP+LLR2HwZYuhegiUexLoceywh
# 4tZbLBQ1QwRostt1AuByx5jWPGTlH0gQGF+JOGFNYkYkh2OMkVIsrymJ5Xgf1gsU
# pYDXEkdws3XVk4WTfraSZ/tTYYmo9WuWwPRYaQ18yAGxuSh1t5ljhSKMYcp5lH5Z
# /IwP42+1ASa2bKXuh1Eh5Fhgm7oMLSttosR+u8QlK0cCCHxJrhO24XxCQijGGFbP
# QTS2Zl22dHv1VjMiLyI2skuiSpXY9aaOUjGCAk0wggJJAgEBMIGGMHIxCzAJBgNV
# BAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp
# Y2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1l
# c3RhbXBpbmcgQ0ECEATNP4VornbGG7D+cWDMp20wDQYJYIZIAWUDBAIBBQCggZgw
# GgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yMDAy
# MjgxNzI2MzFaMCsGCyqGSIb3DQEJEAIMMRwwGjAYMBYEFAMlvVBe2pYwLcIvT6Ae
# TCi+KDTFMC8GCSqGSIb3DQEJBDEiBCBVP6+fzDZm0IuO21kI6hYwlrPuuNJIAhBz
# xgAfAJOt6jANBgkqhkiG9w0BAQEFAASCAQBy+AtNfz9hl+wRkjqefDlMYM9g5MBz
# cR1RC6gtN6ylN8s3ZI1rN0uQBBIuoDASbjG1XV2IennBb0R6gscSx53UMU0ikNZu
# aEIu3AeFJ48uaLq0Ulcjm9H4xZ9NuOxZ7I8Q1M3lLExfFHCTc8PS7D7or2wGXNdl
# znyizI4EawVlaI8VzicF3VaNjj9vRUcrB8pN+efxOWpdnD0ec5uOH5NoPJJLow1M
# MGT+qzjoU2bz4h654e3tu5Zd1uf/ohNXN5nUacFC61XcDhJtNj9BeatBp+IltB+s
# ByxQtzYfjsQttuYYhBdguIVRSPGzxPQHz4F3NpVPOFMwgvy//G2h1UvJ
# SIG # End signature block