|
|
# Copyright (c) .NET Foundation. All rights reserved.# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#### Assigning a "DefaultValue" to a ParameterDescription will result in emitting this parameter when## writing out a default compiler declaration.#### Setting IsRequired to $true will require the attribute to be set on all declarations in config.##Add-Type @"
using System; public class CompilerParameterDescription { public string Name; public string DefaultValue; public bool IsRequired; public bool IsProviderOption; }
public class CodeDomProviderDescription { public string TypeName; public string Assembly; public string Version; public string FileExtension; public CompilerParameterDescription[] Parameters; }"@
function InstallCodeDomProvider($providerDescription) { ##### Update/Rehydrate config declarations ##### $config = ReadConfigFile $rehydratedCount = RehydrateOldDeclarations $config $providerDescription $updatedCount = UpdateDeclarations $config $providerDescription
##### Add the default provider if it wasn't rehydrated above $defaultProvider = $config.xml.configuration["system.codedom"].compilers.compiler | where { $_.extension -eq $providerDescription.FileExtension } if ($defaultProvider -eq $null) { AddDefaultDeclaration $config $providerDescription } SaveConfigFile $config}
function UninstallCodeDomProvider($providerType) { ##### Dehydrate config declarations ##### $config = ReadConfigFile DehydrateDeclarations $config $providerType | Out-Null SaveConfigFile $config}
function GetConfigFileName() { # Try web.config first. Then fall back to app.config. $configFile = $project.ProjectItems | where { $_.Name -ieq "web.config" } if ($configFile -eq $null) { $configFile = $project.ProjectItems | where { $_.Name -ieq "app.config" } } $configPath = $configFile.Properties | where { $_.Name -ieq "LocalPath" } if ($configPath -eq $null) { $configPath = $configFile.Properties | where { $_.Name -ieq "FullPath" } } return $configPath.Value}
function GetTempFileName() { $uname = $project.UniqueName if ([io.path]::IsPathRooted($uname)) { $uname = $project.Name } return [io.path]::Combine($env:TEMP, "Microsoft.CodeDom.Providers.DotNetCompilerPlatform.Temp", $uname + ".xml")}
function ReadConfigFile() { $configFile = GetConfigFileName $configObj = @{ fileName = $configFile; xml = (Select-Xml -Path "$configFile" -XPath /).Node } $configObj.xml.PreserveWhitespace = $true return $configObj}
function DehydrateDeclarations($config, $typeName) { $tempFile = GetTempFileName $xml $count = 0
if ([io.file]::Exists($tempFile)) { $xml = (Select-Xml -Path "$tempFile" -XPath /).Node $xml.PreserveWhitespace = $true } else { $xml = New-Object System.Xml.XmlDocument $xml.PreserveWhitespace = $true $dd = $xml.CreateElement("driedDeclarations") $xml.AppendChild($dd) | Out-Null }
foreach ($rec in $config.xml.configuration["system.codedom"].compilers.compiler | where { IsSameType $_.type $typeName }) { # Remove records from config. $config.xml.configuration["system.codedom"].compilers.RemoveChild($rec) | Out-Null
# Add the record to the temp stash. Don't worry about duplicates. AppendChildNode $xml.ImportNode($rec, $true) $xml.DocumentElement $count++ }
# Save the dehydrated declarations $tmpFolder = Split-Path $tempFile md -Force $tmpFolder | Out-Null $xml.Save($tempFile) | Out-Null return $count}
function RehydrateOldDeclarations($config, $providerDescription) { $tempFile = GetTempFileName if (![io.file]::Exists($tempFile)) { return 0 }
$count = 0 $xml = (Select-Xml -Path "$tempFile" -XPath /).Node $xml.PreserveWhitespace = $true
foreach($rec in $xml.driedDeclarations.compiler | where { IsSameType $_.type ($providerDescription.TypeName + "," + $providerDescription.Assembly) }) { # Remove records that match type, even if we don't end up rehydrating them. $xml.driedDeclarations.RemoveChild($rec) | Out-Null
# Skip if an existing record of the same file extension already exists. $existingRecord = $config.xml.configuration["system.codedom"].compilers.compiler | where { $_.extension -eq $rec.extension } if ($existingRecord -ne $null) { continue }
# Bring the record back to life AppendChildNode $config.xml.ImportNode($rec, $true) $config.xml.configuration["system.codedom"]["compilers"] $count++ }
# Make dried record removal permanent $xml.Save($tempFile) | Out-Null
return $count}
function UpdateDeclarations($config, $providerDescription) { $count = 0
foreach ($provider in $config.xml.configuration["system.codedom"].compilers.compiler | where { IsSameType $_.type ($providerDescription.TypeName + "," + $providerDescription.Assembly) }) { # Count the existing declaration as found $count++
# Update type $provider.type = "$($providerDescription.TypeName), $($providerDescription.Assembly), Version=$($providerDescription.Version), Culture=neutral, PublicKeyToken=31bf3856ad364e35"
# Add default attributes if they are required and not already present foreach ($p in $providerDescription.Parameters | where { ($_.IsRequired -eq $true) -and ($_.IsProviderOption -eq $false) }) { if ($provider.($p.Name) -eq $null) { if ($p.DefaultValue -eq $null) { Write-Host "Failed to add parameter to '$($provider.name)' codeDom provider: '$($p.Name)' is required, but does not have a default value." return } $attr = $config.xml.CreateAttribute($p.Name) $attr.Value = $p.DefaultValue $provider.Attributes.InsertBefore($attr, $provider.Attributes["type"]) | Out-Null } }
# Do the same thing for default providerOptions if not already present foreach ($p in $providerDescription.Parameters | where { ($_.IsRequired -eq $true) -and ($_.IsProviderOption -eq $true)}) { $existing = $provider.providerOption | where { $_.name -eq $p.Name } if ($existing -eq $null) { if ($p.DefaultValue -eq $null) { Write-Host "Failed to add providerOption to '$($provider.name)' codeDom provider: '$($p.Name)' is required, but does not have a default value." return } $po = $config.xml.CreateElement("providerOption") $po.SetAttribute("name", $p.Name) $po.SetAttribute("value", $p.DefaultValue) AppendChildNode $po $provider 4 } } }
return $count}
function AddDefaultDeclaration($config, $providerDescription) { $dd = $config.xml.CreateElement("compiler")
# file extension first $dd.SetAttribute("extension", $providerDescription.FileExtension)
# everything else in the middle foreach ($p in $providerDescription.Parameters) { if ($p.IsRequired -and ($p.DefaultValue -eq $null)) { Write-Host "Failed to add default declaration for code dom extension '$($providerDescription.FileExtension)': '$($p.Name)' is required, but does not have a default value." return }
if ($p.DefaultValue -ne $null) { if ($p.IsProviderOption -eq $true) { $po = $config.xml.CreateElement("providerOption") $po.SetAttribute("name", $p.Name) $po.SetAttribute("value", $p.DefaultValue) AppendChildNode $po $dd 4 } else { $dd.SetAttribute($p.Name, $p.DefaultValue) } } }
# type last $dd.SetAttribute("type", "$($providerDescription.TypeName), $($providerDescription.Assembly), Version=$($providerDescription.Version), Culture=neutral, PublicKeyToken=31bf3856ad364e35")
AppendChildNode $dd $config.xml.configuration["system.codedom"]["compilers"]}
function AppendChildNode($provider, $parent, $indentLevel = 3) { $lastSibling = $parent.ChildNodes | where { $_ -isnot [System.Xml.XmlWhitespace] } | select -Last 1 if ($lastSibling -ne $null) { # If not the first child, then copy the whitespace convention of the existing child $ws = ""; $prev = $lastSibling.PreviousSibling | where { $_ -is [System.Xml.XmlWhitespace] } while ($prev -ne $null) { $ws = $prev.data + $ws $prev = $prev.PreviousSibling | where { $_ -is [System.Xml.XmlWhitespace] } } $parent.InsertAfter($provider, $lastSibling) | Out-Null if ($ws.length -gt 0) { $parent.InsertAfter($parent.OwnerDocument.CreateWhitespace($ws), $lastSibling) | Out-Null } return }
# Add on a new line with indents. Make sure there is no existing whitespace mucking this up. foreach ($exws in $parent.ChildNodes | where { $_ -is [System.Xml.XmlWhitespace] }) { $parent.RemoveChild($exws) } $parent.AppendChild($parent.OwnerDocument.CreateWhitespace("`r`n")) | Out-Null $parent.AppendChild($parent.OwnerDocument.CreateWhitespace(" " * $indentLevel)) | Out-Null $parent.AppendChild($provider) | Out-Null $parent.AppendChild($parent.OwnerDocument.CreateWhitespace("`r`n")) | Out-Null $parent.AppendChild($parent.OwnerDocument.CreateWhitespace(" " * ($indentLevel - 1))) | Out-Null}
function SaveConfigFile($config) { $config.xml.Save($config.fileName)}
function IsSameType($typeString1, $typeString2) {
if (($typeString1 -eq $null) -or ($typeString2 -eq $null)) { return $false }
# First check the type $t1 = $typeString1.Split(',')[0].Trim() $t2 = $typeString2.Split(',')[0].Trim() if ($t1 -cne $t2) { return $false }
# Then check for assembly match if possible $a1 = $typeString1.Split(',')[1] $a2 = $typeString2.Split(',')[1] if (($a1 -ne $null) -and ($a2 -ne $null)) { return ($a1.Trim() -eq $a2.Trim()) }
# Don't care about assembly. Match is good. return $true}
# SIG # Begin signature block# MIIjigYJKoZIhvcNAQcCoIIjezCCI3cCAQExDzANBglghkgBZQMEAgEFADB5Bgor# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAKaw8D28PUyqaj# 8cg1N507irkPJtijF01kKz3vbQKlfqCCDYUwggYDMIID66ADAgECAhMzAAABiK9S# 1rmSbej5AAAAAAGIMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p# bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ4WhcNMjEwMzAzMTgzOTQ4WjB0MQsw# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB# AQCSCNryE+Cewy2m4t/a74wZ7C9YTwv1PyC4BvM/kSWPNs8n0RTe+FvYfU+E9uf0# t7nYlAzHjK+plif2BhD+NgdhIUQ8sVwWO39tjvQRHjP2//vSvIfmmkRoML1Ihnjs# 9kQiZQzYRDYYRp9xSQYmRwQjk5hl8/U7RgOiQDitVHaU7BT1MI92lfZRuIIDDYBd# vXtbclYJMVOwqZtv0O9zQCret6R+fRSGaDNfEEpcILL+D7RV3M4uaJE4Ta6KAOdv# V+MVaJp1YXFTZPKtpjHO6d9pHQPZiG7NdC6QbnRGmsa48uNQrb6AfmLKDI1Lp31W# MogTaX5tZf+CZT9PSuvjOCLNAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUj9RJL9zNrPcL10RZdMQIXZN7MG8w# VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh# dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzQ1ODM4NjAfBgNVHSMEGDAW# gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw# MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx# XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB# ACnXo8hjp7FeT+H6iQlV3CcGnkSbFvIpKYafgzYCFo3UHY1VHYJVb5jHEO8oG26Q# qBELmak6MTI+ra3WKMTGhE1sEIlowTcp4IAs8a5wpCh6Vf4Z/bAtIppP3p3gXk2X# 8UXTc+WxjQYsDkFiSzo/OBa5hkdW1g4EpO43l9mjToBdqEPtIXsZ7Hi1/6y4gK0P# mMiwG8LMpSn0n/oSHGjrUNBgHJPxgs63Slf58QGBznuXiRaXmfTUDdrvhRocdxIM# i8nXQwWACMiQzJSRzBP5S2wUq7nMAqjaTbeXhJqD2SFVHdUYlKruvtPSwbnqSRWT# GI8s4FEXt+TL3w5JnwVZmZkUFoioQDMMjFyaKurdJ6pnzbr1h6QW0R97fWc8xEIz# LIOiU2rjwWAtlQqFO8KNiykjYGyEf5LyAJKAO+rJd9fsYR+VBauIEQoYmjnUbTXM# SY2Lf5KMluWlDOGVh8q6XjmBccpaT+8tCfxpaVYPi1ncnwTwaPQvVq8RjWDRB7Pa# 8ruHgj2HJFi69+hcq7mWx5nTUtzzFa7RSZfE5a1a5AuBmGNRr7f8cNfa01+tiWjV# Kk1a+gJUBSP0sIxecFbVSXTZ7bqeal45XSDIisZBkWb+83TbXdTGMDSUFKTAdtC+# r35GfsN8QVy59Hb5ZYzAXczhgRmk7NyE6jD0Ym5TKiW5MIIHejCCBWKgAwIBAgIK# YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV# BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv# c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm# aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw# OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD# VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG# 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la# UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc# 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D# dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+# lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk# kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6# A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd# X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL# 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd# sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3# T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS# 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI# bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL# BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD# uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv# c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf# MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3# dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf# MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF# BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h# cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA# YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn# 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7# v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b# pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/# KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy# CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp# mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi# hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb# BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS# oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL# gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX# cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCFVswghVXAgEBMIGVMH4x# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAGIr1LWuZJt6PkAAAAA# AYgwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIL5x# 0or5GQPS6af3tBiDwBk2UUOeG6wM9iNlhfHGNf+1MEIGCisGAQQBgjcCAQwxNDAy# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j# b20wDQYJKoZIhvcNAQEBBQAEggEATGapXiAQNux1fvxhV7On0D6F41Wxiek4L+4d# r0oeClirnH/LS/x/BIo/5jxTX7PSCBO+RoCjnX1UzVk+eXHLVt0ah0y2XktYBjI0# 7hvKQg2oC24LWbMNbRqNV/NuhXBQqPBrRJS8pd0FEbg4AclzmBWyvE3OAlYOouy3# A0M4Tj+w5hgg0MRTQ1XCyg5QeGvrmHg+NSejBQrCgatwhB4zr8QkARjyx7n6OBpj# JNQrsDog02X9mxJglQqBtNw2wqiOVjoZ6yOBJu50I5chgN7jrDZOkiNHzhj71G9O# xCcghyt+DSxsxNWT4kOeUijaIBazfNeQgH2CrWjabbDBU96rR6GCEuUwghLhBgor# BgEEAYI3AwMBMYIS0TCCEs0GCSqGSIb3DQEHAqCCEr4wghK6AgEDMQ8wDQYJYIZI# AWUDBAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGE# WQoDATAxMA0GCWCGSAFlAwQCAQUABCAIxnYmZyKGatNcxpWyN2p/5x8E5+Oxdr7E# usWmDSl8kwIGXvOkDyUPGBMyMDIwMDcwODIxNTQyMy4wODFaMASAAgH0oIHQpIHN# MIHKMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1JlZG1vbmQx# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9z# b2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMg# VFNTIEVTTjo4NkRGLTRCQkMtOTMzNTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt# U3RhbXAgU2VydmljZaCCDjwwggTxMIID2aADAgECAhMzAAABD4By9jqHCIitAAAA# AAEPMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw# MB4XDTE5MTAyMzIzMTkxOFoXDTIxMDEyMTIzMTkxOFowgcoxCzAJBgNVBAYTAlVT# MQswCQYDVQQIEwJXQTEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z# b2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVy# YXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjg2REYtNEJC# Qy05MzM1MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIB# IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3005QKre87GV4WKCCDXMQWYH# 5eWI0RsTG+2ZUI1Ana3OpPvM2mx32cdM5bSGx80uyTwvPEoKwgLPzJivRQcVw65y# dOdICgWYp6BECNwkiRGcOFrnwk/DuhQgJm5+TGq3rUnaoDiuJflc/gTlQ9C4qE0W# r19gnoOIiWBk3TspV4nmK6Q03fUZk4lAmIuFbuBBWViaGdmGqUxU2Fe8CHLgCGSg# 6LL/hGf8FSS98UmtX6AGAn/8PKhEW/DVYmpYzh9nxNy3+aEHoP4/+M1a5ie8YqT8# jTd5pbcSe2dV8hkOx/ZC7ZrFrxrAMJdEFlWuWVj+1L10fojPPQw/31VU7p3DMwID# AQABo4IBGzCCARcwHQYDVR0OBBYEFOeVIYAZbVLGoBeW7HaqypbvGOV7MB8GA1Ud# IwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0# dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0# YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKG# Pmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENB# XzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUH# AwgwDQYJKoZIhvcNAQELBQADggEBAFCCsTZ3FVppoaTLKFatxHl9n4WEyxHgyeh4# g3d83G7xLKIBX6be8avIga+GKYT6oYLOsmWsiuTRDOsjlxMew2Gjx99iRCyh2t5F# s91bF5SAFKyZORb1F2BGUtqNzoNhd0QbxrVEB83uGUfq6UgjYr0b42WLex0Df8+L# nFolQwiWXqvsjQoIBU3K1ilthYo+Ta3mHDrwaMevcR8jWu37qdoEqjtoex+baCDe# S0PebIUbfB3ERgC2spuFjrI0OTvbP+MqSybPOMymNpzECY2XuuMBA7heVJAGUAZK# 9csdRtB0j/ELCxm1xAVT/W4uZrtuarqA1bgeKPN9nisHMzZN2X4wggZxMIIEWaAD# AgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzET# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV# TWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBD# ZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3# MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x# JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkq# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWl# CgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/Fg# iIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeR# X4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/Xcf# PfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogI# Neh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB# 5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvF# M2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAP# BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjE# MFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kv# Y3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEF# BQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w# a2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8E# gZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5t# aWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcC# AjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUA# bgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Pr# psz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOM# zPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCv# OA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v# /rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99# lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1kl# D3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQ# Hm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30# uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp# 25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HS# xVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi6# 2jbb01+P3nSISRKhggLOMIICNwIBATCB+KGB0KSBzTCByjELMAkGA1UEBhMCVVMx# CzAJBgNVBAgTAldBMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv# ZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh# dGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046ODZERi00QkJD# LTkzMzUxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoB# ATAHBgUrDgMCGgMVACRBu0KfU5QdFnnbtKCSQXqhZLdpoIGDMIGApH4wfDELMAkG# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z# b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDisJc3MCIY# DzIwMjAwNzA5MDMwNDIzWhgPMjAyMDA3MTAwMzA0MjNaMHcwPQYKKwYBBAGEWQoE# ATEvMC0wCgIFAOKwlzcCAQAwCgIBAAICBTUCAf8wBwIBAAICEbswCgIFAOKx6LcC# AQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEK# MAgCAQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQBc60zftvglC4XTAWkGh+sdBLzQ# /uFSMGMdXjfNxlIFx6qOSLKISNiW/MbybfHppgXOeeGjV9Z1I148Yym5SvB3QaMB# t/qjGyrYKP9VkehxDIqHJ1ZWAItPwfKrftEDAG/8a1iKYsDZiGEhVCmMfFeTybXI# i27VVtb9BR5ITHlk4zGCAw0wggMJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYD# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w# IFBDQSAyMDEwAhMzAAABD4By9jqHCIitAAAAAAEPMA0GCWCGSAFlAwQCAQUAoIIB# SjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIMlo# MAROR4VzpJB1a9PL+n96Q2zmPkuwAduk3dc++74fMIH6BgsqhkiG9w0BCRACLzGB# 6jCB5zCB5DCBvQQgP5q9DnloLRRs8qdBDFvVa0QW4LZL99DesxTe8HR0Po4wgZgw# gYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAQ+AcvY6hwiI# rQAAAAABDzAiBCDG2xJLw7wsX4gKRkiaeIZzlzmdqHBm/mOZJqEMe548+TANBgkq# hkiG9w0BAQsFAASCAQCMbnwN0CmmJN/eok0yGkCf/8LkqWkC8Ihpe7AyjqbHqVdT# 9qJmYFtj/gYHECFbUEz3e9KcmqnKmp0xSRHCNQLzdeo/LfwojFCozmvbQ8JLc27b# vEX6C2IWh7D0J82GF1wgHkK5KxZk7bJISNkuAttlMRQF6stb50ygtv5B6/+7c6Xv# LzU4H9BuJU+joalojZt3ok2HQAyJHcPqOX+2uET+ozvclYybg2cJdAsXpgYGdi2X# CsPIC+VRyY69Zze6Bdmi0J+6VGdqBJ6tRSji9wGTrJ8NA6Iha2OkRzsXLy2hAHzs# JIpbNViNZTeRw7fp4LRoUwpNQf8vdmH/MPX8m8kp# SIG # End signature block
|