#
# Manifest.ps1
#

Class AppxManifest
{
    [xml] $_manifest = [xml] @"
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities">
  <Identity Name="SampleAppx"
            ProcessorArchitecture="x64"
            Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
            Version="1.0.0.0" />
    <Properties>
      <DisplayName>Sample app</DisplayName>
      <PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
      <Logo>Assets\SampleAppx.50x50.png</Logo>
    </Properties>
  <Resources>
    <Resource Language="en-us" />
  </Resources>
  <Dependencies>
    <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14316.0" MaxVersionTested="10.0.14316.0" />
  </Dependencies>
  <Capabilities>
    <rescap:Capability Name="runFullTrust" />
  </Capabilities>
</Package>
"@
    [string] $_manifestPath
    [string] $_schemaDir
    [PackageApplication[]] $_packageApplications

    Save()
    {
        $this._manifest.Save($this._manifestPath)
    }

    AppxManifestHelper([string] $appxManifestTargetDir)
    {
        if (!(Test-Path $this._schemaDir))
        {
            throw "Error: Could not find schema directory with path '$($this._schemaPath)'."
        }

        if (!(Test-Path $appxManifestTargetDir))
        {
            throw "Error: Could not find appx manifest directory with path '$($appxManifestTargetDir)'."
        }

        $this._manifestPath = Join-Path -Path $appxManifestTargetDir -ChildPath "AppxManifest.xml"

        $this.Validate()
    }

    AppxManifest([string] $appxManifestTargetDir)
    {
        $this._schemaDir = ".\schema"
        $this.AppxManifestHelper($appxManifestTargetDir)
    }

    AppxManifest([string] $appxManifestTargetDir, [string] $schemaDir)
    {
        $this._schemaDir = $schemaDir
        $this.AppxManifestHelper($appxManifestTargetDir)
    }

    [PackageApplication[]] GetPackageApplications()
    {
        return $this._packageApplications
    }

    [void] SetPackageIdentityName($value)
    {
        $this._manifest.Package.Identity.Name = $value
        $this.Validate()
    }

    [void] SetPackageIdentityPublisher($value)
    {
        $this._manifest.Package.Identity.Publisher = $value
        $this.Validate()
    }

    [void] SetPackageIdentityVersion($value)
    {
        $this._manifest.Package.Identity.Version = $value
        $this.Validate()
    }

    [void] SetPackagePropertiesDisplayName($value)
    {
        $this._manifest.Package.Properties.DisplayName = $value
        $this.Validate()
    }

    [void] SetPackagePropertiesPublisherDisplayName($value)
    {
        $this._manifest.Package.Properties.PublisherDisplayName = $value
        $this.Validate()
    }

    [void] SetPackagePropertiesLogo($path)
    {
        $this._manifest.Package.Properties.Logo = $path
        $this.Validate()
    }

    [void] SetPackageResourceLanguage($value)
    {
        $this._manifest.Package.Resources.Resource.Language = $value
        $this.Validate()
    }

    [System.Xml.Schema.XmlSchemaSet] GetSchemas()
    {
        $appxTypes = "http://schemas.microsoft.com/appx/manifest/types", "AppxManifestTypes.xsd"
        $appxSchema = "http://schemas.microsoft.com/appx/2010/manifest", "AppxManifestSchema.xsd"
        $foundationSchema = "http://schemas.microsoft.com/appx/manifest/foundation/windows10", "FoundationManifestSchema.xsd"
        $uapSchema = "http://schemas.microsoft.com/appx/manifest/uap/windows10", "UapManifestSchema.xsd"
        $rescapSchema = "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities", "RestrictedCapabilitiesManifestSchema.xsd"

        # The following schemas are needed in order to resolve various definitions in the schemas above.
        $phoneSchema2014 = "http://schemas.microsoft.com/appx/2014/phone/manifest", "AppxPhoneManifestSchema2014.xsd"
        $xboxSchema2013 = "http://schemas.microsoft.com/appx/2013/xbox/manifest", "XboxManifestSchema2013.xsd"

        $schemas = $appxTypes, $appxSchema, $foundationSchema, $uapSchema, $rescapSchema, $phoneSchema2014, $xboxSchema2013

        $schemaSet = New-Object -TypeName System.Xml.Schema.XmlSchemaSet

        foreach ($schema in $schemas)
        {
            $schemaFilePath = (Get-Item (Join-Path -Path $this._schemaDir -ChildPath $schema[1])).FullName

            if (!(Test-Path $schemaFilePath))
            {
                throw "Error: Could not find schema definition file with path '$($schemaFilePath)'."
            }

            # Passing in $null as the first parameter to Add is supposed to use the targetnamespace from the schema
            # specified, but this isn't working. An exception ends up being thrown. For now, specify the targetnamespace.

            $schemaSet.Add($schema[0], $schemaFilePath)
        }

        $schemaSet.Compile()

        return $schemaSet
    }

    Validate()
    {
        if ($this._manifest.Schemas.Count -eq 0)
        {
            $this._manifest.Schemas = $this.GetSchemas()
        }

        [string] $script:errorString = $null
        [int] $script:errorCount = 0
        $this._manifest.Validate({
            # Triggered each time an error is found in the XML
            $script:errorString += $("`nError found in XML (" + $_.Exception.LineNumber + "): " + $_.Message + "`n")
            $script:errorCount++
        })

        if ($script:errorCount -gt 0)
        {
            throw "Validating AppxManifest.xml against schemas failed with error(s):`n $($script:errorString) `n$($script:errorCount) schema validation failure(s).`n"
        }
    }

    [string] GetPackageIdentityName()
    {
        $value = $this._manifest.Package.Identity.Name
        return $value
    }

    [string] GetPackageIdentityPublisher()
    {
        $value = $this._manifest.Package.Identity.Publisher
        return $value
    }

    [string] GetPackageIdentityVersion()
    {
        $value = $this._manifest.Package.Identity.Version
        return $value
    }

    [string] GetPackagePropertiesDisplayName()
    {
        $value = $this._manifest.Package.Properties.DisplayName
        return $value
    }

    [string] GetPackagePropertiesPublisherDisplayName()
    {
        $value = $this._manifest.Package.Properties.PublisherDisplayName
        return $value
    }

    [string] GetPackagePropertiesLogo()
    {
        $value = $this._manifest.Package.Properties.Logo
        return $value
    }

    [string] GetPackageResourceLanguage()
    {
        $value = $this._manifest.Package.Resources.Resource.Language
        return $value
    }


    [PackageApplication] AddPackageApplication()
    {
        $packageApplication = [PackageApplication]::New($this)
        return $packageApplication
    }

    [PackageApplication] AddPackageApplication([string] $appId, [string] $appExecutable)
    {
        $packageApplication = [PackageApplication]::New($this, $appId, $appExecutable)
        return $packageApplication
    }

    [PackageApplication] AddPackageApplication([string] $appId, [string] $appExecutable, [string] $displayName, [string] $description,
        [string] $backgroundColor, [string] $square150x150LogoPath, [string] $square44x44LogoPath)
    {

        $packageApplication = [PackageApplication]::New($this, $appId, $appExecutable, $appExecutable, $displayName,
            $backgroundColor, $square150x150LogoPath, $square44x44LogoPath)
        return $packageApplication
    }
}

class PackageApplication
{
    [AppxManifest] $_appxManifestRef
    [System.Xml.XmlNode] $_applicationNode
    [boolean] $_isExecutableChangedFromDefault

    PackageApplicationHelper([ref] $appxManifest, [string] $appId, [string] $appExecutable, [string] $displayName, [string] $description,
        [string] $backgroundColor, [string] $square150x150LogoPath, [string] $square44x44LogoPath)
    {
        $this._appxManifestRef = $appxManifest.Value
       
        [xml] $applicationNodeTemplate = [xml] @"
<?xml version="1.0" encoding="utf-8"?>
<Applications xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10">
  <Application Id="MyApp" Executable="MyApp.exe" EntryPoint="Windows.FullTrustApplication">
    <uap:VisualElements DisplayName="MyApp" Description="MyApp" BackgroundColor="#777777" Square150x150Logo="Assets\SampleAppx.150x150.png" Square44x44Logo="Assets\SampleAppx.44x44.png" />
  </Application>
</Applications>
"@
        $this._applicationNode = $this._appxManifestRef._manifest.ImportNode($applicationNodeTemplate.Applications.Application, $True)
        $this._applicationNode.Id = $appId
        $this._applicationNode.Executable = $appExecutable
        $this._applicationNode.VisualElements.DisplayName = $displayName
        $this._applicationNode.VisualElements.Description = $description
        $this._applicationNode.VisualElements.BackgroundColor = $backgroundColor
        $this._applicationNode.VisualElements.Square150x150Logo = $square150x150LogoPath
        $this._applicationNode.VisualElements.Square44x44Logo = $square44x44LogoPath

        # Placing an <Applications></Applications> entry into the hard coded manifest doesn't allow selection of it
        # (maybe because it is empty? Not sure.) when using '$this._appxManifestRef._manifest.Package.Applications'.
        # Instead just add it here if it doesn't exist.

        $applicationsNode = $this._appxManifestRef._manifest.Package.Applications
        if (!$applicationsNode)
        {
            $applicationsNode = $this._appxManifestRef._manifest.Package.AppendChild($this._appxManifestRef._manifest.CreateElement("Applications", "http://schemas.microsoft.com/appx/manifest/foundation/windows10"))
        }

        $applicationsNode.AppendChild($this._applicationNode)

        $this._appxManifestRef.Validate()

        $this._appxManifestRef._packageApplications += $this
    }

    PackageApplication([ref] $manifest)
    {
        $this.PackageApplicationHelper($manifest, "MyApp", "MyApp.exe", "MyApp", "MyApp", "#777777",
            "Assets\SampleAppx.150x150.png", "Assets\SampleAppx.44x44.png")
        $this._isExecutableChangedFromDefault = $false
    }

    PackageApplication([ref] $manifest, [string] $appId, [string] $appExecutable)
    {
        $this.PackageApplicationHelper($manifest, $appId, $appExecutable, "MyApp", "MyApp", "#777777",
            "Assets\SampleAppx.150x150.png", "Assets\SampleAppx.44x44.png")
        $this._isExecutableChangedFromDefault = $true
    }

    PackageApplication([ref] $manifest, [string] $appId, [string] $appExecutable, [string] $displayName, [string] $description,
        [string] $backgroundColor, [string] $square150x150LogoPath, [string] $square44x44LogoPath)
    {
        $this.PackageApplicationHelper($manifest, $appId, $appExecutable, $displayName, $description, $backgroundColor,
            $square150x150LogoPath, $square44x44LogoPath)
        $this._isExecutableChangedFromDefault = $true
    }

    [void] SetId($value)
    {
        $this._applicationNode.Id = $value
        $this._appxManifestRef.Validate()
    }

    [void] SetExecutable($path)
    {
        $this._applicationNode.Executable = $path
        $this._appxManifestRef.Validate()
        $this._isExecutableChangedFromDefault = $true
    }

    [boolean] IsExecutableChangedFromDefault()
    {
        return $this._isExecutableChangedFromDefault
    }

    [void] SetVisualElementsDisplayName($value)
    {
        $this._applicationNode.VisualElements.DisplayName = $value
        $this._appxManifestRef.Validate()
    }

    [void] SetVisualElementsDescription($value)
    {
        $this._applicationNode.VisualElements.Description = $value
        $this._appxManifestRef.Validate()
    }

    [void] SetVisualElementsBackgroundColor($value)
    {
        $this._applicationNode.VisualElements.BackgroundColor = $value
        $this._appxManifestRef.Validate()
    }

    [void] SetVisualElementsSquare150x150Logo($path)
    {
        $this._applicationNode.VisualElements.Square150x150Logo = $path
        $this._appxManifestRef.Validate()
    }

    [void] SetVisualElementsSquare44x44Logo($path)
    {
        $this._applicationNode.VisualElements.Square44x44Logo = $path
        $this._appxManifestRef.Validate()
    }

    [string] GetId()
    {
        $value = $this.applicationNode.Id
        return $value
    }

    [string] GetExecutable()
    {
        $path = $this._applicationNode.Executable
        return $path
    }

    [string] GetVisualElementsDisplayName()
    {
        $value = $this._applicationNode.VisualElements.DisplayName
        return $value
    }

    [string] GetVisualElementsDescription()
    {
        $value = $this._applicationNode.VisualElements.Description
        return $value
    }

    [string] GetVisualElementsBackgroundColor()
    {
        $value = $this._applicationNode.VisualElements.BackgroundColor
        return $value
    }

    [string] GetVisualElementsSquare150x150Logo()
    {
        $path = $this._applicationNode.VisualElements.Square150x150Logo
        return $path
    }

    [string] GetVisualElementsSquare44x44Logo()
    {
        $path = $this._applicationNode.VisualElements.Square44x44Logo
        return $path
    }

    [void] AddFileTypeAssocation([string[]] $fileTypes, [string] $fileTypeAssocationName)
    {
        if ($fileTypes.Count -eq 0)
        {
            throw "Error: No file type extension(s) specified: 1 or more expected."
        }
        
        [xml] $extensionNodeTemplate = [xml]@"
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10">
  <uap:Extension Category="windows.fileTypeAssociation">
    <uap:FileTypeAssociation>
      <uap:SupportedFileTypes>

      </uap:SupportedFileTypes>
    </uap:FileTypeAssociation>
  </uap:Extension>
</Application>
"@
        $uapSchemaUri = "http://schemas.microsoft.com/appx/manifest/uap/windows10"

        $extensionNode = $this._appxManifestRef._manifest.ImportNode($extensionNodeTemplate.Application.Extension, $True)
        $extensionNode.FileTypeAssociation.SetAttribute("Name", $fileTypeAssocationName)
        [System.Xml.XmlNamespaceManager] $nsmgr = $extensionNodeTemplate.NameTable
        $nsmgr.AddNamespace("uap", $uapSchemaUri)
        $supportedFileTypesNode = $extensionNode.SelectSingleNode("//uap:FileTypeAssociation//uap:SupportedFileTypes", $nsmgr)

        foreach ($fileType in $fileTypes)
        {
            $fileTypeElem = $this._appxManifestRef._manifest.CreateElement("uap:FileType", $uapSchemaUri)
            $fileTypeElem.InnerXml = $fileType
            $supportedFileTypesNode.AppendChild($fileTypeElem)
        }

        $extensionsNode = $this._applicationNode.Extensions
        if (!$extensionsNode)
        {
            $extensionsNode = $this._applicationNode.AppendChild($this._appxManifestRef._manifest.CreateElement("Extensions", "http://schemas.microsoft.com/appx/manifest/foundation/windows10"))
        }

        $extensionsNode.AppendChild($extensionNode)

        $this._appxManifestRef.Validate()
    }

    [void] AddFileTypeAssocation([string[]] $fileTypes)
    {
        $this.AddFileTypeAssocation($fileTypes, "myfiletypes")
    }
}
# SIG # Begin signature block
# MIIkJwYJKoZIhvcNAQcCoIIkGDCCJBQCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCwiR0pfh5r/l1Z
# 2lNJlpR0mcBozozzhGv9CrHtEspC56CCDZIwggYQMIID+KADAgECAhMzAAAAZEeE
# lIbbQRk4AAAAAABkMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMTUxMDI4MjAzMTQ2WhcNMTcwMTI4MjAzMTQ2WjCBgzEL
# MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
# bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjENMAsGA1UECxMETU9Q
# UjEeMBwGA1UEAxMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMIIBIjANBgkqhkiG9w0B
# AQEFAAOCAQ8AMIIBCgKCAQEAky7a2OY+mNkbD2RfTahYTRQ793qE/DwRMTrvicJK
# LUGlSF3dEp7vq2YoNNV9KlV7TE2K8sDxstNSFYu2swi4i1AL3X/7agmg3GcExPHf
# vHUYIEC+eCyZVt3u9S7dPkL5Wh8wrgEUirCCtVGg4m1l/vcYCo0wbU06p8XzNi3u
# XyygkgCxHEziy/f/JCV/14/A3ZduzrIXtsccRKckyn6B5uYxuRbZXT7RaO6+zUjQ
# hiyu3A4hwcCKw+4bk1kT9sY7gHIYiFP7q78wPqB3vVKIv3rY6LCTraEbjNR+phBQ
# EL7hyBxk+ocu+8RHZhbAhHs2r1+6hURsAg8t4LAOG6I+JQIDAQABo4IBfzCCAXsw
# HwYDVR0lBBgwFgYIKwYBBQUHAwMGCisGAQQBgjdMCAEwHQYDVR0OBBYEFFhWcQTw
# vbsz9YNozOeARvdXr9IiMFEGA1UdEQRKMEikRjBEMQ0wCwYDVQQLEwRNT1BSMTMw
# MQYDVQQFEyozMTY0Mis0OWU4YzNmMy0yMzU5LTQ3ZjYtYTNiZS02YzhjNDc1MWM0
# YjYwHwYDVR0jBBgwFoAUSG5k5VAF04KqFzc3IrVtqMp1ApUwVAYDVR0fBE0wSzBJ
# oEegRYZDaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljQ29k
# U2lnUENBMjAxMV8yMDExLTA3LTA4LmNybDBhBggrBgEFBQcBAQRVMFMwUQYIKwYB
# BQUHMAKGRWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWlj
# Q29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNydDAMBgNVHRMBAf8EAjAAMA0GCSqG
# SIb3DQEBCwUAA4ICAQCI4gxkQx3dXK6MO4UktZ1A1r1mrFtXNdn06DrARZkQTdu0
# kOTLdlGBCfCzk0309RLkvUgnFKpvLddrg9TGp3n80yUbRsp2AogyrlBU+gP5ggHF
# i7NjGEpj5bH+FDsMw9PygLg8JelgsvBVudw1SgUt625nY7w1vrwk+cDd58TvAyJQ
# FAW1zJ+0ySgB9lu2vwg0NKetOyL7dxe3KoRLaztUcqXoYW5CkI+Mv3m8HOeqlhyf
# FTYxPB5YXyQJPKQJYh8zC9b90JXLT7raM7mQ94ygDuFmlaiZ+QSUR3XVupdEngrm
# ZgUB5jX13M+Pl2Vv7PPFU3xlo3Uhj1wtupNC81epoxGhJ0tRuLdEajD/dCZ0xIni
# esRXCKSC4HCL3BMnSwVXtIoj/QFymFYwD5+sAZuvRSgkKyD1rDA7MPcEI2i/Bh5O
# MAo9App4sR0Gp049oSkXNhvRi/au7QG6NJBTSBbNBGJG8Qp+5QThKoQUk8mj0ugr
# 4yWRsA9JTbmqVw7u9suB5OKYBMUN4hL/yI+aFVsE/KJInvnxSzXJ1YHka45ADYMK
# AMl+fLdIqm3nx6rIN0RkoDAbvTAAXGehUCsIod049A1T3IJyUJXt3OsTd3WabhIB
# XICYfxMg10naaWcyUePgW3+VwP0XLKu4O1+8ZeGyaDSi33GnzmmyYacX3BTqMDCC
# B3owggVioAMCAQICCmEOkNIAAAAAAAMwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29m
# dCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDExMB4XDTExMDcwODIwNTkw
# OVoXDTI2MDcwODIxMDkwOVowfjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAx
# MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKvw+nIQHC6t2G6qghBN
# NLrytlghn0IbKmvpWlCquAY4GgRJun/DDB7dN2vGEtgL8DjCmQawyDnVARQxQtOJ
# DXlkh36UYCRsr55JnOloXtLfm1OyCizDr9mpK656Ca/XllnKYBoF6WZ26DJSJhIv
# 56sIUM+zRLdd2MQuA3WraPPLbfM6XKEW9Ea64DhkrG5kNXimoGMPLdNAk/jj3gcN
# 1Vx5pUkp5w2+oBN3vpQ97/vjK1oQH01WKKJ6cuASOrdJXtjt7UORg9l7snuGG9k+
# sYxd6IlPhBryoS9Z5JA7La4zWMW3Pv4y07MDPbGyr5I4ftKdgCz1TlaRITUlwzlu
# ZH9TupwPrRkjhMv0ugOGjfdf8NBSv4yUh7zAIXQlXxgotswnKDglmDlKNs98sZKu
# HCOnqWbsYR9q4ShJnV+I4iVd0yFLPlLEtVc/JAPw0XpbL9Uj43BdD1FGd7P4AOG8
# rAKCX9vAFbO9G9RVS+c5oQ/pI0m8GLhEfEXkwcNyeuBy5yTfv0aZxe/CHFfbg43s
# TUkwp6uO3+xbn6/83bBm4sGXgXvt1u1L50kppxMopqd9Z4DmimJ4X7IvhNdXnFy/
# dygo8e1twyiPLI9AN0/B4YVEicQJTMXUpUMvdJX3bvh4IFgsE11glZo+TzOE2rCI
# F96eTvSWsLxGoGyY0uDWiIwLAgMBAAGjggHtMIIB6TAQBgkrBgEEAYI3FQEEAwIB
# ADAdBgNVHQ4EFgQUSG5k5VAF04KqFzc3IrVtqMp1ApUwGQYJKwYBBAGCNxQCBAwe
# CgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
# BBgwFoAUci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0
# cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2Vy
# QXV0MjAxMV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRSMFAwTgYIKwYBBQUH
# MAKGQmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2Vy
# QXV0MjAxMV8yMDExXzAzXzIyLmNydDCBnwYDVR0gBIGXMIGUMIGRBgkrBgEEAYI3
# LgMwgYMwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lv
# cHMvZG9jcy9wcmltYXJ5Y3BzLmh0bTBABggrBgEFBQcCAjA0HjIgHQBMAGUAZwBh
# AGwAXwBwAG8AbABpAGMAeQBfAHMAdABhAHQAZQBtAGUAbgB0AC4gHTANBgkqhkiG
# 9w0BAQsFAAOCAgEAZ/KGpZjgVHkaLtPYdGcimwuWEeFjkplCln3SeQyQwWVfLiw+
# +MNy0W2D/r4/6ArKO79HqaPzadtjvyI1pZddZYSQfYtGUFXYDJJ80hpLHPM8QotS
# 0LD9a+M+By4pm+Y9G6XUtR13lDni6WTJRD14eiPzE32mkHSDjfTLJgJGKsKKELuk
# qQUMm+1o+mgulaAqPyprWEljHwlpblqYluSD9MCP80Yr3vw70L01724lruWvJ+3Q
# 3fMOr5kol5hNDj0L8giJ1h/DMhji8MUtzluetEk5CsYKwsatruWy2dsViFFFWDgy
# cScaf7H0J/jeLDogaZiyWYlobm+nt3TDQAUGpgEqKD6CPxNNZgvAs0314Y9/HG8V
# fUWnduVAKmWjw11SYobDHWM2l4bf2vP48hahmifhzaWX0O5dY0HjWwechz4GdwbR
# BrF1HxS+YWG18NzGGwS+30HHDiju3mUv7Jf2oVyW2ADWoUa9WfOXpQlLSBCZgB/Q
# ACnFsZulP0V3HjXG0qKin3p6IvpIlR+r+0cjgPWe+L9rt0uX4ut1eBrs6jeZeRhL
# /9azI2h15q/6/IvrC4DqaTuv/DDtBEyO3991bWORPdGdVk5Pv4BXIqF4ETIheu9B
# CrE/+6jMpF3BoYibV3FWTkhFwELJm3ZbCoBIa/15n8G9bW1qyVJzEw16UM0xghXr
# MIIV5wIBATCBlTB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ
# MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
# MSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExAhMzAAAA
# ZEeElIbbQRk4AAAAAABkMA0GCWCGSAFlAwQCAQUAoIHWMBkGCSqGSIb3DQEJAzEM
# BgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqG
# SIb3DQEJBDEiBCA9rTixQN97PY8FWDhKV7B8NL1WPvvimwIaNeY2v3Op8zBqBgor
# BgEEAYI3AgEMMVwwWqAugCwAVwBpAG4AZABvAHcAcwAgAFAAaABvAG4AZQAgAFAA
# YQBjAGsAYQBnAGUAc6EogCZodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vd2luZG93
# c3Bob25lLzANBgkqhkiG9w0BAQEFAASCAQAnl/zN1dw4V6Crq7GnVmWCtZ6Zpwpa
# f4OZnh/yQn5BvWGLnuAjtthwBCpK+wgNZn9RVUHK7rss8Q4NtRndusuQTauCcQC2
# OuAdwfMFWfrvMGb4caRJFeDy9QPaTfuVwpbDYtA4Awismhmh3EIaOBmPMmYQH93A
# B46TR0I5k6+yQ213WwX4vfcsnKFJ3yUZJAVRBzXhMuF3cptIo+o5bhJRBbjpJ9Cb
# fg9adIRpuAwpPCNa6rm9zAVpeM+UVfaYh+eAj7Icngcrkm2M+9Jqr1O3tinvV3mp
# 8w6/f6IuY6PIzsGrXgmKhFwAqaVnlxhF3vJYzb5Ow8eUExvwFpkKc6gKoYITTTCC
# E0kGCisGAQQBgjcDAwExghM5MIITNQYJKoZIhvcNAQcCoIITJjCCEyICAQMxDzAN
# BglghkgBZQMEAgEFADCCAT0GCyqGSIb3DQEJEAEEoIIBLASCASgwggEkAgEBBgor
# BgEEAYRZCgMBMDEwDQYJYIZIAWUDBAIBBQAEIIelXWoNHHaTgn35flEBtzAbf2Yj
# seI1lboichlepAQLAgZW7Bhoeh8YEzIwMTYwNDA2MDQxNDA5Ljk1N1owBwIBAYAC
# AfSggbmkgbYwgbMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# DTALBgNVBAsTBE1PUFIxJzAlBgNVBAsTHm5DaXBoZXIgRFNFIEVTTjpCOEVDLTMw
# QTQtNzE0NDElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCC
# DtAwggZxMIIEWaADAgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNy
# b3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEy
# MTM2NTVaFw0yNTA3MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX
# YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
# Q29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAy
# MDEwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwT
# l/X6f2mUa3RUENWlCgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4J
# E458YTBZsTBED/FgiIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhg
# RvJYR4YyhB50YWeRX4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchoh
# iq9LZIlQYrFd/XcfPfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajy
# eioKMfDaTgaRtogINeh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwB
# BU8iTQIDAQABo4IB5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVj
# OlyKMZDzQ3t8RhvFM2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsG
# A1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJc
# YmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9z
# b2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIz
# LmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0
# MIGgBgNVHSABAf8EgZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYx
# aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0
# bTBABggrBgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMA
# dABhAHQAZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCY
# P4FxAz2do6Ehb7Prpsz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1r
# VFcIK1GCRBL7uVOMzPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3
# fVo/HPKZeUqRUgCvOA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2
# /QThcJ8ySif9Va8v/rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFj
# nXshbcOco6I8+n99lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjgg
# tSXlZOz39L9+Y1klD3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7
# cQnfXXSYIghh2rBQHm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwms
# ObvsxsvYgrRyzR30uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAv
# VCch98isTtoouLGp25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGv
# WbWu3EQ8l1Bx16HSxVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA1
# 2u8JJxzVs341Hgi62jbb01+P3nSISRIwggTaMIIDwqADAgECAhMzAAAAc3fTOK84
# 07/2AAAAAABzMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD
# QSAyMDEwMB4XDTE1MTAwNzE4MTczOVoXDTE3MDEwNzE4MTczOVowgbMxCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIxJzAl
# BgNVBAsTHm5DaXBoZXIgRFNFIEVTTjpCOEVDLTMwQTQtNzE0NDElMCMGA1UEAxMc
# TWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCCASIwDQYJKoZIhvcNAQEBBQAD
# ggEPADCCAQoCggEBAMhZzBh3zDUXC/Ma3rmrccVaDyis35sdXu31PPVrPBiqf01d
# k/GKYtvBDKaU1hpJL9w78gCHM6K1eFHgwtxe++YPb/sYdLz40wgNn7QtKuKhOmp+
# uU5mvU9INfllMFevPX3ONNkMoRCgNpJi4W7TSKstFpnq7UPzSPNVWKsprgL27Liq
# tirLLOZoH+lKFXM8DTJPFnDJ1Z0bqnw17N87fJeSDoG3on9xzeENf5BjaS9RGywO
# q62S71AKJRhmSqX2udDB457kQht2x5/XKjrbNYFKIN7DoZxPQB2YyNTRQlyuCq1S
# pcTpj69F+30K4uGNLGXPGmNcwMYaeyb9CR7eP0sCAwEAAaOCARswggEXMB0GA1Ud
# DgQWBBQgB/Dz6/Zg9UiuqNdS8iSEpwLY8zAfBgNVHSMEGDAWgBTVYzpcijGQ80N7
# fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29m
# dC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNUaW1TdGFQQ0FfMjAxMC0wNy0wMS5j
# cmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jv
# c29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0YVBDQV8yMDEwLTA3LTAxLmNydDAM
# BgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEBCwUA
# A4IBAQBIekskQP8Z/sF7CaxuxJxcSLFY5m6OzEP0FaWpihfsBEUsGcP9Kqcghc/7
# +2t3ZuBM5BG/Xv/lOhUVvJpg//pAaX+EZ+P+Z+QIPbQPqmv8RgO1vz67h2d2K/CU
# QIXrDz4zew/cIABmnU6gQksopL2Kn+SRR1Sa/8PWoD3EJQ6LBtLPaVLAd9skdTQV
# nDlh9TX2/0xNEpkqXFkguOFzMfmDESv2Kq93+97a1yGwVqL7KbqHB4TNumbS+Ia7
# lIyShC5uZ5EXMi6UBR35CjX+bN2PwFSn56NMNIBk+BKk74wlLlPRdbViEjaCdvQr
# xZIzapGo7sGEWzE+6QbOTO48tmmSoYIDeTCCAmECAQEwgeOhgbmkgbYwgbMxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIx
# JzAlBgNVBAsTHm5DaXBoZXIgRFNFIEVTTjpCOEVDLTMwQTQtNzE0NDElMCMGA1UE
# AxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIlCgEBMAkGBSsOAwIaBQAD
# FQBxFPp+oG0/M+3e5xPr3uOtAg5mzKCBwjCBv6SBvDCBuTELMAkGA1UEBhMCVVMx
# EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT
# FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMe
# bkNpcGhlciBOVFMgRVNOOjU3RjYtQzFFMC01NTRDMSswKQYDVQQDEyJNaWNyb3Nv
# ZnQgVGltZSBTb3VyY2UgTWFzdGVyIENsb2NrMA0GCSqGSIb3DQEBBQUAAgUA2q7V
# hDAiGA8yMDE2MDQwNjAwMjMzMloYDzIwMTYwNDA3MDAyMzMyWjB3MD0GCisGAQQB
# hFkKBAExLzAtMAoCBQDartWEAgEAMAoCAQACAga0AgH/MAcCAQACAh3NMAoCBQDa
# sCcEAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwGgCjAIAgEAAgMW
# 42ChCjAIAgEAAgMHoSAwDQYJKoZIhvcNAQEFBQADggEBAEAVCyMmyqcPDNCP5vcV
# mNcNRGGq/EgLo4+pDwSJl6PLscjEJR25P/aojoFYnPwBwuYPae2qfWb3+3Id5xfr
# RzQseTJsNxjyI7qWzvJv0E29xRGe/s2b5I7WmSuhl4vufyK5lgz2h8+NBXZP8Q4G
# 7s5nUVZ90XiTZ+TxrQiJRAYRPrfwkOsH9I+xib8kiW20PvgT1OF4I01yIzBlywYa
# YMkfIylgohYr3/qeJyZqI1+84rKeAG++3ac38/SsYQyJgVGCXjhgS0mbTGhy2uiG
# Ujd71ionbpwmTfJuY3RtRysobDzUOUHwm1WTT2vlsgy77Sy04e6/I8/g9tDIN4zA
# tbMxggL1MIIC8QIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
# cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAIT
# MwAAAHN30zivONO/9gAAAAAAczANBglghkgBZQMEAgEFAKCCATIwGgYJKoZIhvcN
# AQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCD/5bIMERMEkLy1JujB
# 3x3yK1c5r/p92RGcwi5YhlU1ETCB4gYLKoZIhvcNAQkQAgwxgdIwgc8wgcwwgbEE
# FHEU+n6gbT8z7d7nE+ve460CDmbMMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzAR
# BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p
# Y3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3Rh
# bXAgUENBIDIwMTACEzMAAABzd9M4rzjTv/YAAAAAAHMwFgQUfE9jONtJ7XquH2ya
# HGlKAT9bK5YwDQYJKoZIhvcNAQELBQAEggEAKA0rFb7ENRv88cG5tOsWjtNhPeLR
# NE96lDkX3/jWylHygSlLI3FTQ0j58wMBmfJfKZEPTzg7yw4hndcME6iKTTL1MS8+
# aHbiJ1reI8DcQSoznW+5QRu8hiYtVZcneMdLhLoEPloukOTuQbFP5Pj4YZZ62G4L
# nhqT/AJDIlKw4Ci7NnnWyLouBu0TUNFnNJvYVV7z4ZKVYT5SfkBOKTW5C/Vci5hn
# rj4+yH5Nocw/NGsqVeGKzJj2Z1KN+C69gqnzDsh0uGRnxGurEK8yzKQaN9ExQBzd
# +iWbgiz7NG/AkPTuVsZ33vvfI0U4Jqfgxprv4/aXEzp/TmcsV2Xg261F0g==
# SIG # End signature block
