$ErrorActionPreference = 'Stop'
|
|
#
|
# Add-Migration
|
#
|
|
Register-TabExpansion Add-Migration @{
|
OutputDir = { <# Disabled. Otherwise, paths would be relative to the solution directory. #> }
|
Context = { param($x) GetContextTypes $x.Project $x.StartupProject }
|
Project = { GetProjects }
|
StartupProject = { GetProjects }
|
}
|
|
<#
|
.SYNOPSIS
|
Adds a new migration.
|
|
.DESCRIPTION
|
Adds a new migration.
|
|
.PARAMETER Name
|
The name of the migration.
|
|
.PARAMETER OutputDir
|
The directory (and sub-namespace) to use. Paths are relative to the project directory. Defaults to "Migrations".
|
|
.PARAMETER Context
|
The DbContext type to use.
|
|
.PARAMETER Project
|
The project to use.
|
|
.PARAMETER StartupProject
|
The startup project to use. Defaults to the solution's startup project.
|
|
.LINK
|
Remove-Migration
|
Update-Database
|
about_EntityFrameworkCore
|
#>
|
function Add-Migration
|
{
|
[CmdletBinding(PositionalBinding = $false)]
|
param(
|
[Parameter(Position = 0, Mandatory = $true)]
|
[string] $Name,
|
[string] $OutputDir,
|
[string] $Context,
|
[string] $Project,
|
[string] $StartupProject)
|
|
WarnIfEF6 'Add-Migration'
|
|
$dteProject = GetProject $Project
|
$dteStartupProject = GetStartupProject $StartupProject $dteProject
|
|
$params = 'migrations', 'add', $Name, '--json'
|
|
if ($OutputDir)
|
{
|
$params += '--output-dir', $OutputDir
|
}
|
|
$params += GetParams $Context
|
|
# NB: -join is here to support ConvertFrom-Json on PowerShell 3.0
|
$result = (EF $dteProject $dteStartupProject $params) -join "`n" | ConvertFrom-Json
|
Write-Host 'To undo this action, use Remove-Migration.'
|
|
$dteProject.ProjectItems.AddFromFile($result.migrationFile) | Out-Null
|
$DTE.ItemOperations.OpenFile($result.migrationFile) | Out-Null
|
ShowConsole
|
|
$dteProject.ProjectItems.AddFromFile($result.metadataFile) | Out-Null
|
|
$dteProject.ProjectItems.AddFromFile($result.snapshotFile) | Out-Null
|
}
|
|
#
|
# Drop-Database
|
#
|
|
Register-TabExpansion Drop-Database @{
|
Context = { param($x) GetContextTypes $x.Project $x.StartupProject }
|
Project = { GetProjects }
|
StartupProject = { GetProjects }
|
}
|
|
<#
|
.SYNOPSIS
|
Drops the database.
|
|
.DESCRIPTION
|
Drops the database.
|
|
.PARAMETER Context
|
The DbContext to use.
|
|
.PARAMETER Project
|
The project to use.
|
|
.PARAMETER StartupProject
|
The startup project to use. Defaults to the solution's startup project.
|
|
.LINK
|
Update-Database
|
about_EntityFrameworkCore
|
#>
|
function Drop-Database
|
{
|
[CmdletBinding(PositionalBinding = $false, SupportsShouldProcess = $true, ConfirmImpact = 'High')]
|
param([string] $Context, [string] $Project, [string] $StartupProject)
|
|
$dteProject = GetProject $Project
|
$dteStartupProject = GetStartupProject $StartupProject $dteProject
|
|
$info = Get-DbContext -Context $Context -Project $Project -StartupProject $StartupProject
|
|
if ($PSCmdlet.ShouldProcess("database '$($info.databaseName)' on server '$($info.dataSource)'"))
|
{
|
$params = 'database', 'drop', '--force'
|
$params += GetParams $Context
|
|
EF $dteProject $dteStartupProject $params -skipBuild
|
}
|
}
|
|
#
|
# Enable-Migrations (Obsolete)
|
#
|
|
function Enable-Migrations
|
{
|
WarnIfEF6 'Enable-Migrations'
|
Write-Warning 'Enable-Migrations is obsolete. Use Add-Migration to start using Migrations.'
|
}
|
|
#
|
# Get-DbContext
|
#
|
|
Register-TabExpansion Get-DbContext @{
|
Context = { param($x) GetContextTypes $x.Project $x.StartupProject }
|
Project = { GetProjects }
|
StartupProject = { GetProjects }
|
}
|
|
<#
|
.SYNOPSIS
|
Gets information about DbContext types.
|
|
.DESCRIPTION
|
Gets information about DbContext types.
|
|
.PARAMETER Context
|
The DbContext to use.
|
|
.PARAMETER Project
|
The project to use.
|
|
.PARAMETER StartupProject
|
The startup project to use. Defaults to the solution's startup project.
|
|
.LINK
|
about_EntityFrameworkCore
|
#>
|
function Get-DbContext
|
{
|
[CmdletBinding(PositionalBinding = $false)]
|
param([string] $Context, [string] $Project, [string] $StartupProject)
|
|
$dteProject = GetProject $Project
|
$dteStartupProject = GetStartupProject $StartupProject $dteProject
|
|
if ($PSBoundParameters.ContainsKey('Context'))
|
{
|
$params = 'dbcontext', 'info', '--json'
|
$params += GetParams $Context
|
# NB: -join is here to support ConvertFrom-Json on PowerShell 3.0
|
return (EF $dteProject $dteStartupProject $params) -join "`n" | ConvertFrom-Json
|
}
|
else
|
{
|
$params = 'dbcontext', 'list', '--json'
|
# NB: -join is here to support ConvertFrom-Json on PowerShell 3.0
|
return (EF $dteProject $dteStartupProject $params) -join "`n" | ConvertFrom-Json | Format-Table -Property safeName -HideTableHeaders
|
}
|
}
|
|
#
|
# Remove-Migration
|
#
|
|
Register-TabExpansion Remove-Migration @{
|
Context = { param($x) GetContextTypes $x.Project $x.StartupProject }
|
Project = { GetProjects }
|
StartupProject = { GetProjects }
|
}
|
|
<#
|
.SYNOPSIS
|
Removes the last migration.
|
|
.DESCRIPTION
|
Removes the last migration.
|
|
.PARAMETER Force
|
Revert the migration if it has been applied to the database.
|
|
.PARAMETER Context
|
The DbContext to use.
|
|
.PARAMETER Project
|
The project to use.
|
|
.PARAMETER StartupProject
|
The startup project to use. Defaults to the solution's startup project.
|
|
.LINK
|
Add-Migration
|
about_EntityFrameworkCore
|
#>
|
function Remove-Migration
|
{
|
[CmdletBinding(PositionalBinding = $false)]
|
param([switch] $Force, [string] $Context, [string] $Project, [string] $StartupProject)
|
|
$dteProject = GetProject $Project
|
$dteStartupProject = GetStartupProject $StartupProject $dteProject
|
|
$params = 'migrations', 'remove', '--json'
|
|
if ($Force)
|
{
|
$params += '--force'
|
}
|
|
$params += GetParams $Context
|
|
# NB: -join is here to support ConvertFrom-Json on PowerShell 3.0
|
$result = (EF $dteProject $dteStartupProject $params) -join "`n" | ConvertFrom-Json
|
|
$files = $result.migrationFile, $result.metadataFile, $result.snapshotFile
|
$files | ?{ $_ -ne $null } | %{
|
$projectItem = GetProjectItem $dteProject $_
|
if ($projectItem)
|
{
|
$projectItem.Remove()
|
}
|
}
|
}
|
|
#
|
# Scaffold-DbContext
|
#
|
|
Register-TabExpansion Scaffold-DbContext @{
|
Provider = { param($x) GetProviders $x.Project }
|
Project = { GetProjects }
|
StartupProject = { GetProjects }
|
OutputDir = { <# Disabled. Otherwise, paths would be relative to the solution directory. #> }
|
ContextDir = { <# Disabled. Otherwise, paths would be relative to the solution directory. #> }
|
}
|
|
<#
|
.SYNOPSIS
|
Scaffolds a DbContext and entity types for a database.
|
|
.DESCRIPTION
|
Scaffolds a DbContext and entity types for a database.
|
|
.PARAMETER Connection
|
The connection string to the database.
|
|
.PARAMETER Provider
|
The provider to use. (E.g. Microsoft.EntityFrameworkCore.SqlServer)
|
|
.PARAMETER OutputDir
|
The directory to put files in. Paths are relative to the project directory.
|
|
.PARAMETER ContextDir
|
The directory to put DbContext file in. Paths are relative to the project directory.
|
|
.PARAMETER Context
|
The name of the DbContext to generate.
|
|
.PARAMETER Schemas
|
The schemas of tables to generate entity types for.
|
|
.PARAMETER Tables
|
The tables to generate entity types for.
|
|
.PARAMETER DataAnnotations
|
Use attributes to configure the model (where possible). If omitted, only the fluent API is used.
|
|
.PARAMETER UseDatabaseNames
|
Use table and column names directly from the database.
|
|
.PARAMETER Force
|
Overwrite existing files.
|
|
.PARAMETER Project
|
The project to use.
|
|
.PARAMETER StartupProject
|
The startup project to use. Defaults to the solution's startup project.
|
|
.LINK
|
about_EntityFrameworkCore
|
#>
|
function Scaffold-DbContext
|
{
|
[CmdletBinding(PositionalBinding = $false)]
|
param(
|
[Parameter(Position = 0, Mandatory = $true)]
|
[string] $Connection,
|
[Parameter(Position = 1, Mandatory = $true)]
|
[string] $Provider,
|
[string] $OutputDir,
|
[string] $ContextDir,
|
[string] $Context,
|
[string[]] $Schemas = @(),
|
[string[]] $Tables = @(),
|
[switch] $DataAnnotations,
|
[switch] $UseDatabaseNames,
|
[switch] $Force,
|
[string] $Project,
|
[string] $StartupProject)
|
|
$dteProject = GetProject $Project
|
$dteStartupProject = GetStartupProject $StartupProject $dteProject
|
|
$params = 'dbcontext', 'scaffold', $Connection, $Provider, '--json'
|
|
if ($OutputDir)
|
{
|
$params += '--output-dir', $OutputDir
|
}
|
|
if ($ContextDir)
|
{
|
$params += '--context-dir', $ContextDir
|
}
|
|
if ($Context)
|
{
|
$params += '--context', $Context
|
}
|
|
$params += $Schemas | %{ '--schema', $_ }
|
$params += $Tables | %{ '--table', $_ }
|
|
if ($DataAnnotations)
|
{
|
$params += '--data-annotations'
|
}
|
|
if ($UseDatabaseNames)
|
{
|
$params += '--use-database-names'
|
}
|
|
if ($Force)
|
{
|
$params += '--force'
|
}
|
|
# NB: -join is here to support ConvertFrom-Json on PowerShell 3.0
|
$result = (EF $dteProject $dteStartupProject $params) -join "`n" | ConvertFrom-Json
|
|
$files = $result.entityTypeFiles + $result.contextFile
|
$files | %{ $dteProject.ProjectItems.AddFromFile($_) | Out-Null }
|
$DTE.ItemOperations.OpenFile($result.contextFile) | Out-Null
|
ShowConsole
|
}
|
|
#
|
# Script-DbContext
|
#
|
|
Register-TabExpansion Script-DbContext @{
|
Context = { param($x) GetContextTypes $x.Project $x.StartupProject }
|
Project = { GetProjects }
|
StartupProject = { GetProjects }
|
}
|
|
<#
|
.SYNOPSIS
|
Generates a SQL script from current DbContext.
|
|
.DESCRIPTION
|
Generates a SQL script from current DbContext.
|
|
.PARAMETER Output
|
The file to write the result to.
|
|
.PARAMETER Context
|
The DbContext to use.
|
|
.PARAMETER Project
|
The project to use.
|
|
.PARAMETER StartupProject
|
The startup project to use. Defaults to the solution's startup project.
|
|
.LINK
|
about_EntityFrameworkCore
|
#>
|
function Script-DbContext
|
{
|
[CmdletBinding(PositionalBinding = $false)]
|
param(
|
[string] $Output,
|
[string] $Context,
|
[string] $Project,
|
[string] $StartupProject)
|
|
$dteProject = GetProject $Project
|
$dteStartupProject = GetStartupProject $StartupProject $dteProject
|
|
if (!$Output)
|
{
|
$intermediatePath = GetIntermediatePath $dteProject
|
if (![IO.Path]::IsPathRooted($intermediatePath))
|
{
|
$projectDir = GetProperty $dteProject.Properties 'FullPath'
|
$intermediatePath = Join-Path $projectDir $intermediatePath -Resolve | Convert-Path
|
}
|
|
$scriptFileName = [IO.Path]::ChangeExtension([IO.Path]::GetRandomFileName(), '.sql')
|
$Output = Join-Path $intermediatePath $scriptFileName
|
}
|
elseif (![IO.Path]::IsPathRooted($Output))
|
{
|
$Output = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Output)
|
}
|
|
$params = 'dbcontext', 'script', '--output', $Output
|
|
$params += GetParams $Context
|
|
EF $dteProject $dteStartupProject $params
|
|
$DTE.ItemOperations.OpenFile($Output) | Out-Null
|
ShowConsole
|
}
|
|
#
|
# Script-Migration
|
#
|
|
Register-TabExpansion Script-Migration @{
|
From = { param($x) GetMigrations $x.Context $x.Project $x.StartupProject }
|
To = { param($x) GetMigrations $x.Context $x.Project $x.StartupProject }
|
Context = { param($x) GetContextTypes $x.Project $x.StartupProject }
|
Project = { GetProjects }
|
StartupProject = { GetProjects }
|
}
|
|
<#
|
.SYNOPSIS
|
Generates a SQL script from migrations.
|
|
.DESCRIPTION
|
Generates a SQL script from migrations.
|
|
.PARAMETER From
|
The starting migration. Defaults to '0' (the initial database).
|
|
.PARAMETER To
|
The ending migration. Defaults to the last migration.
|
|
.PARAMETER Idempotent
|
Generate a script that can be used on a database at any migration.
|
|
.PARAMETER Output
|
The file to write the result to.
|
|
.PARAMETER Context
|
The DbContext to use.
|
|
.PARAMETER Project
|
The project to use.
|
|
.PARAMETER StartupProject
|
The startup project to use. Defaults to the solution's startup project.
|
|
.LINK
|
Update-Database
|
about_EntityFrameworkCore
|
#>
|
function Script-Migration
|
{
|
[CmdletBinding(PositionalBinding = $false)]
|
param(
|
[Parameter(ParameterSetName = 'WithoutTo', Position = 0)]
|
[Parameter(ParameterSetName = 'WithTo', Position = 0, Mandatory = $true)]
|
[string] $From,
|
[Parameter(ParameterSetName = 'WithTo', Position = 1, Mandatory = $true)]
|
[string] $To,
|
[switch] $Idempotent,
|
[string] $Output,
|
[string] $Context,
|
[string] $Project,
|
[string] $StartupProject)
|
|
$dteProject = GetProject $Project
|
$dteStartupProject = GetStartupProject $StartupProject $dteProject
|
|
if (!$Output)
|
{
|
$intermediatePath = GetIntermediatePath $dteProject
|
if (![IO.Path]::IsPathRooted($intermediatePath))
|
{
|
$projectDir = GetProperty $dteProject.Properties 'FullPath'
|
$intermediatePath = Join-Path $projectDir $intermediatePath -Resolve | Convert-Path
|
}
|
|
$scriptFileName = [IO.Path]::ChangeExtension([IO.Path]::GetRandomFileName(), '.sql')
|
$Output = Join-Path $intermediatePath $scriptFileName
|
}
|
elseif (![IO.Path]::IsPathRooted($Output))
|
{
|
$Output = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Output)
|
}
|
|
$params = 'migrations', 'script', '--output', $Output
|
|
if ($From)
|
{
|
$params += $From
|
}
|
|
if ($To)
|
{
|
$params += $To
|
}
|
|
if ($Idempotent)
|
{
|
$params += '--idempotent'
|
}
|
|
$params += GetParams $Context
|
|
EF $dteProject $dteStartupProject $params
|
|
$DTE.ItemOperations.OpenFile($Output) | Out-Null
|
ShowConsole
|
}
|
|
#
|
# Update-Database
|
#
|
|
Register-TabExpansion Update-Database @{
|
Migration = { param($x) GetMigrations $x.Context $x.Project $x.StartupProject }
|
Context = { param($x) GetContextTypes $x.Project $x.StartupProject }
|
Project = { GetProjects }
|
StartupProject = { GetProjects }
|
}
|
|
<#
|
.SYNOPSIS
|
Updates the database to a specified migration.
|
|
.DESCRIPTION
|
Updates the database to a specified migration.
|
|
.PARAMETER Migration
|
The target migration. If '0', all migrations will be reverted. Defaults to the last migration.
|
|
.PARAMETER Context
|
The DbContext to use.
|
|
.PARAMETER Project
|
The project to use.
|
|
.PARAMETER StartupProject
|
The startup project to use. Defaults to the solution's startup project.
|
|
.LINK
|
Script-Migration
|
about_EntityFrameworkCore
|
#>
|
function Update-Database
|
{
|
[CmdletBinding(PositionalBinding = $false)]
|
param(
|
[Parameter(Position = 0)]
|
[string] $Migration,
|
[string] $Context,
|
[string] $Project,
|
[string] $StartupProject)
|
|
WarnIfEF6 'Update-Database'
|
|
$dteProject = GetProject $Project
|
$dteStartupProject = GetStartupProject $StartupProject $dteProject
|
|
$params = 'database', 'update'
|
|
if ($Migration)
|
{
|
$params += $Migration
|
}
|
|
$params += GetParams $Context
|
|
EF $dteProject $dteStartupProject $params
|
}
|
|
#
|
# (Private Helpers)
|
#
|
|
function GetProjects
|
{
|
return Get-Project -All | %{ $_.ProjectName }
|
}
|
|
function GetProviders($projectName)
|
{
|
if (!$projectName)
|
{
|
$projectName = (Get-Project).ProjectName
|
}
|
|
return Get-Package -ProjectName $projectName | %{ $_.Id }
|
}
|
|
function GetContextTypes($projectName, $startupProjectName)
|
{
|
$project = GetProject $projectName
|
$startupProject = GetStartupProject $startupProjectName $project
|
|
$params = 'dbcontext', 'list', '--json'
|
|
# NB: -join is here to support ConvertFrom-Json on PowerShell 3.0
|
$result = (EF $project $startupProject $params -skipBuild) -join "`n" | ConvertFrom-Json
|
|
return $result | %{ $_.safeName }
|
}
|
|
function GetMigrations($context, $projectName, $startupProjectName)
|
{
|
$project = GetProject $projectName
|
$startupProject = GetStartupProject $startupProjectName $project
|
|
$params = 'migrations', 'list', '--json'
|
$params += GetParams $context
|
|
# NB: -join is here to support ConvertFrom-Json on PowerShell 3.0
|
$result = (EF $project $startupProject $params -skipBuild) -join "`n" | ConvertFrom-Json
|
|
return $result | %{ $_.safeName }
|
}
|
|
function WarnIfEF6($cmdlet)
|
{
|
if (Get-Module 'EntityFramework6')
|
{
|
Write-Warning "Both Entity Framework Core and Entity Framework 6 are installed. The Entity Framework Core tools are running. Use 'EntityFramework6\$cmdlet' for Entity Framework 6."
|
}
|
elseif (Get-Module 'EntityFramework')
|
{
|
Write-Warning "Both Entity Framework Core and Entity Framework 6 are installed. The Entity Framework Core tools are running. Use 'EntityFramework\$cmdlet' for Entity Framework 6."
|
}
|
}
|
|
function GetProject($projectName)
|
{
|
if (!$projectName)
|
{
|
return Get-Project
|
}
|
|
return Get-Project $projectName
|
}
|
|
function GetStartupProject($name, $fallbackProject)
|
{
|
if ($name)
|
{
|
return Get-Project $name
|
}
|
|
$startupProjectPaths = $DTE.Solution.SolutionBuild.StartupProjects
|
if ($startupProjectPaths)
|
{
|
if ($startupProjectPaths.Length -eq 1)
|
{
|
$startupProjectPath = $startupProjectPaths[0]
|
if (![IO.Path]::IsPathRooted($startupProjectPath))
|
{
|
$solutionPath = Split-Path (GetProperty $DTE.Solution.Properties 'Path')
|
$startupProjectPath = Join-Path $solutionPath $startupProjectPath -Resolve | Convert-Path
|
}
|
|
$startupProject = GetSolutionProjects | ?{
|
try
|
{
|
$fullName = $_.FullName
|
}
|
catch [NotImplementedException]
|
{
|
return $false
|
}
|
|
if ($fullName -and $fullName.EndsWith('\'))
|
{
|
$fullName = $fullName.Substring(0, $fullName.Length - 1)
|
}
|
|
return $fullName -eq $startupProjectPath
|
}
|
if ($startupProject)
|
{
|
return $startupProject
|
}
|
|
Write-Warning "Unable to resolve startup project '$startupProjectPath'."
|
}
|
else
|
{
|
Write-Warning 'Multiple startup projects set.'
|
}
|
}
|
else
|
{
|
Write-Warning 'No startup project set.'
|
}
|
|
Write-Warning "Using project '$($fallbackProject.ProjectName)' as the startup project."
|
|
return $fallbackProject
|
}
|
|
function GetSolutionProjects()
|
{
|
$projects = New-Object 'System.Collections.Stack'
|
|
$DTE.Solution.Projects | %{
|
$projects.Push($_)
|
}
|
|
while ($projects.Count)
|
{
|
$project = $projects.Pop();
|
|
<# yield return #> $project
|
|
if ($project.ProjectItems)
|
{
|
$project.ProjectItems | ?{ $_.SubProject } | %{
|
$projects.Push($_.SubProject)
|
}
|
}
|
}
|
}
|
|
function GetParams($context)
|
{
|
$params = @()
|
|
if ($context)
|
{
|
$params += '--context', $context
|
}
|
|
return $params
|
}
|
|
function ShowConsole
|
{
|
$componentModel = Get-VSComponentModel
|
$powerConsoleWindow = $componentModel.GetService([NuGetConsole.IPowerConsoleWindow])
|
$powerConsoleWindow.Show()
|
}
|
|
function WriteErrorLine($message)
|
{
|
try
|
{
|
# Call the internal API NuGet uses to display errors
|
$componentModel = Get-VSComponentModel
|
$powerConsoleWindow = $componentModel.GetService([NuGetConsole.IPowerConsoleWindow])
|
$bindingFlags = [Reflection.BindingFlags]::Instance -bor [Reflection.BindingFlags]::NonPublic
|
$activeHostInfo = $powerConsoleWindow.GetType().GetProperty('ActiveHostInfo', $bindingFlags).GetValue($powerConsoleWindow)
|
$internalHost = $activeHostInfo.WpfConsole.Host
|
$reportErrorMethod = $internalHost.GetType().GetMethod('ReportError', $bindingFlags, $null, [Exception], $null)
|
$exception = New-Object Exception $message
|
$reportErrorMethod.Invoke($internalHost, $exception)
|
}
|
catch
|
{
|
Write-Host $message -ForegroundColor DarkRed
|
}
|
}
|
|
function EF($project, $startupProject, $params, [switch] $skipBuild)
|
{
|
if (IsDocker $startupProject)
|
{
|
throw "Startup project '$($startupProject.ProjectName)' is a Docker project. Select an ASP.NET Core Web " +
|
'Application as your startup project and try again.'
|
}
|
if (IsUWP $startupProject)
|
{
|
throw "Startup project '$($startupProject.ProjectName)' is a Universal Windows Platform app. This version of " +
|
'the Entity Framework Core Package Manager Console Tools doesn''t support this type of project. For more ' +
|
'information on using the EF Core Tools with UWP projects, see ' +
|
'https://go.microsoft.com/fwlink/?linkid=858496'
|
}
|
|
Write-Verbose "Using project '$($project.ProjectName)'."
|
Write-Verbose "Using startup project '$($startupProject.ProjectName)'."
|
|
if (!$skipBuild)
|
{
|
Write-Host 'Build started...'
|
|
# TODO: Only build startup project. Don't use BuildProject, you can't specify platform
|
$solutionBuild = $DTE.Solution.SolutionBuild
|
$solutionBuild.Build(<# WaitForBuildToFinish: #> $true)
|
if ($solutionBuild.LastBuildInfo)
|
{
|
throw 'Build failed.'
|
}
|
|
Write-Host 'Build succeeded.'
|
}
|
|
$startupProjectDir = GetProperty $startupProject.Properties 'FullPath'
|
$outputPath = GetProperty $startupProject.ConfigurationManager.ActiveConfiguration.Properties 'OutputPath'
|
$targetDir = [IO.Path]::GetFullPath([IO.Path]::Combine($startupProjectDir, $outputPath))
|
$startupTargetFileName = GetProperty $startupProject.Properties 'OutputFileName'
|
$startupTargetPath = Join-Path $targetDir $startupTargetFileName
|
$targetFrameworkMoniker = GetProperty $startupProject.Properties 'TargetFrameworkMoniker'
|
$frameworkName = New-Object 'System.Runtime.Versioning.FrameworkName' $targetFrameworkMoniker
|
$targetFramework = $frameworkName.Identifier
|
|
if ($targetFramework -in '.NETFramework')
|
{
|
$platformTarget = GetPlatformTarget $startupProject
|
if ($platformTarget -eq 'x86')
|
{
|
$exePath = Join-Path $PSScriptRoot 'net461\win-x86\ef.exe'
|
}
|
elseif ($platformTarget -in 'AnyCPU', 'x64')
|
{
|
$exePath = Join-Path $PSScriptRoot 'net461\any\ef.exe'
|
}
|
else
|
{
|
throw "Startup project '$($startupProject.ProjectName)' has an active platform of '$platformTarget'. Select " +
|
'a different platform and try again.'
|
}
|
}
|
elseif ($targetFramework -eq '.NETCoreApp')
|
{
|
$exePath = (Get-Command 'dotnet').Path
|
|
$startupTargetName = GetProperty $startupProject.Properties 'AssemblyName'
|
$depsFile = Join-Path $targetDir ($startupTargetName + '.deps.json')
|
$projectAssetsFile = GetCpsProperty $startupProject 'ProjectAssetsFile'
|
$runtimeConfig = Join-Path $targetDir ($startupTargetName + '.runtimeconfig.json')
|
$runtimeFrameworkVersion = GetCpsProperty $startupProject 'RuntimeFrameworkVersion'
|
$efPath = Join-Path $PSScriptRoot 'netcoreapp2.0\any\ef.dll'
|
|
$dotnetParams = 'exec', '--depsfile', $depsFile
|
|
if ($projectAssetsFile)
|
{
|
# NB: Don't use Get-Content. It doesn't handle UTF-8 without a signature
|
# NB: Don't use ReadAllLines. ConvertFrom-Json won't work on PowerShell 3.0
|
$projectAssets = [IO.File]::ReadAllText($projectAssetsFile) | ConvertFrom-Json
|
$projectAssets.packageFolders.psobject.Properties.Name | %{
|
$dotnetParams += '--additionalprobingpath', $_.TrimEnd('\')
|
}
|
}
|
|
if (Test-Path $runtimeConfig)
|
{
|
$dotnetParams += '--runtimeconfig', $runtimeConfig
|
}
|
elseif ($runtimeFrameworkVersion)
|
{
|
$dotnetParams += '--fx-version', $runtimeFrameworkVersion
|
}
|
|
$dotnetParams += $efPath
|
|
$params = $dotnetParams + $params
|
}
|
elseif ($targetFramework -eq '.NETStandard')
|
{
|
throw "Startup project '$($startupProject.ProjectName)' targets framework '.NETStandard'. There is no " +
|
'runtime associated with this framework, and projects targeting it cannot be executed directly. To use ' +
|
'the Entity Framework Core Package Manager Console Tools with this project, add an executable project ' +
|
'targeting .NET Framework or .NET Core that references this project, and set it as the startup project; ' +
|
'or, update this project to cross-target .NET Framework or .NET Core. For more information on using the ' +
|
'EF Core Tools with .NET Standard projects, see https://go.microsoft.com/fwlink/?linkid=2034705'
|
}
|
else
|
{
|
throw "Startup project '$($startupProject.ProjectName)' targets framework '$targetFramework'. " +
|
'The Entity Framework Core Package Manager Console Tools don''t support this framework.'
|
}
|
|
$projectDir = GetProperty $project.Properties 'FullPath'
|
$targetFileName = GetProperty $project.Properties 'OutputFileName'
|
$targetPath = Join-Path $targetDir $targetFileName
|
$rootNamespace = GetProperty $project.Properties 'RootNamespace'
|
$language = GetLanguage $project
|
|
$params += '--verbose',
|
'--no-color',
|
'--prefix-output',
|
'--assembly', $targetPath,
|
'--startup-assembly', $startupTargetPath,
|
'--project-dir', $projectDir,
|
'--language', $language,
|
'--working-dir', $PWD.Path
|
|
if (IsWeb $startupProject)
|
{
|
$params += '--data-dir', (Join-Path $startupProjectDir 'App_Data')
|
}
|
|
if ($rootNamespace)
|
{
|
$params += '--root-namespace', $rootNamespace
|
}
|
|
$arguments = ToArguments $params
|
$startInfo = New-Object 'System.Diagnostics.ProcessStartInfo' -Property @{
|
FileName = $exePath;
|
Arguments = $arguments;
|
UseShellExecute = $false;
|
CreateNoWindow = $true;
|
RedirectStandardOutput = $true;
|
StandardOutputEncoding = [Text.Encoding]::UTF8;
|
RedirectStandardError = $true;
|
WorkingDirectory = $startupProjectDir;
|
}
|
|
Write-Verbose "$exePath $arguments"
|
|
$process = [Diagnostics.Process]::Start($startInfo)
|
|
while (($line = $process.StandardOutput.ReadLine()) -ne $null)
|
{
|
$level = $null
|
$text = $null
|
|
$parts = $line.Split(':', 2)
|
if ($parts.Length -eq 2)
|
{
|
$level = $parts[0]
|
|
$i = 0
|
$count = 8 - $level.Length
|
while ($i -lt $count -and $parts[1][$i] -eq ' ')
|
{
|
$i++
|
}
|
|
$text = $parts[1].Substring($i)
|
}
|
|
switch ($level)
|
{
|
'error' { WriteErrorLine $text }
|
'warn' { Write-Warning $text }
|
'info' { Write-Host $text }
|
'data' { Write-Output $text }
|
'verbose' { Write-Verbose $text }
|
default { Write-Host $line }
|
}
|
}
|
|
$process.WaitForExit()
|
|
if ($process.ExitCode)
|
{
|
while (($line = $process.StandardError.ReadLine()) -ne $null)
|
{
|
WriteErrorLine $line
|
}
|
|
exit
|
}
|
}
|
|
function IsDocker($project)
|
{
|
return $project.Kind -eq '{E53339B2-1760-4266-BCC7-CA923CBCF16C}'
|
}
|
|
function IsCpsProject($project)
|
{
|
$hierarchy = GetVsHierarchy $project
|
$isCapabilityMatch = [Microsoft.VisualStudio.Shell.PackageUtilities].GetMethod(
|
'IsCapabilityMatch',
|
[type[]]([Microsoft.VisualStudio.Shell.Interop.IVsHierarchy], [string]))
|
|
return $isCapabilityMatch.Invoke($null, ($hierarchy, 'CPS'))
|
}
|
|
function IsWeb($project)
|
{
|
$types = GetProjectTypes $project
|
|
return $types -contains '{349C5851-65DF-11DA-9384-00065B846F21}'
|
}
|
|
function IsUWP($project)
|
{
|
$types = GetProjectTypes $project
|
|
return $types -contains '{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A}'
|
}
|
|
function GetIntermediatePath($project)
|
{
|
$intermediatePath = GetProperty $project.ConfigurationManager.ActiveConfiguration.Properties 'IntermediatePath'
|
if ($intermediatePath)
|
{
|
return $intermediatePath
|
}
|
|
return GetMSBuildProperty $project 'IntermediateOutputPath'
|
}
|
|
function GetPlatformTarget($project)
|
{
|
if (IsCpsProject $project)
|
{
|
$platformTarget = GetCpsProperty $project 'PlatformTarget'
|
if ($platformTarget)
|
{
|
return $platformTarget
|
}
|
|
return GetCpsProperty $project 'Platform'
|
}
|
|
$platformTarget = GetProperty $project.ConfigurationManager.ActiveConfiguration.Properties 'PlatformTarget'
|
if ($platformTarget)
|
{
|
return $platformTarget
|
}
|
|
# NB: For classic F# projects
|
$platformTarget = GetMSBuildProperty $project 'PlatformTarget'
|
if ($platformTarget)
|
{
|
return $platformTarget
|
}
|
|
return 'AnyCPU'
|
}
|
|
function GetLanguage($project)
|
{
|
if (IsCpsProject $project)
|
{
|
return GetCpsProperty $project 'Language'
|
}
|
|
return GetMSBuildProperty $project 'Language'
|
}
|
|
function GetVsHierarchy($project)
|
{
|
$solution = Get-VSService 'Microsoft.VisualStudio.Shell.Interop.SVsSolution' 'Microsoft.VisualStudio.Shell.Interop.IVsSolution'
|
$hierarchy = $null
|
$hr = $solution.GetProjectOfUniqueName($project.UniqueName, [ref] $hierarchy)
|
[Runtime.InteropServices.Marshal]::ThrowExceptionForHR($hr)
|
|
return $hierarchy
|
}
|
|
function GetProjectTypes($project)
|
{
|
$hierarchy = GetVsHierarchy $project
|
$aggregatableProject = Get-Interface $hierarchy 'Microsoft.VisualStudio.Shell.Interop.IVsAggregatableProject'
|
if (!$aggregatableProject)
|
{
|
return $project.Kind
|
}
|
|
$projectTypeGuidsString = $null
|
$hr = $aggregatableProject.GetAggregateProjectTypeGuids([ref] $projectTypeGuidsString)
|
[Runtime.InteropServices.Marshal]::ThrowExceptionForHR($hr)
|
|
return $projectTypeGuidsString.Split(';')
|
}
|
|
function GetProperty($properties, $propertyName)
|
{
|
try
|
{
|
return $properties.Item($propertyName).Value
|
}
|
catch
|
{
|
return $null
|
}
|
}
|
|
function GetCpsProperty($project, $propertyName)
|
{
|
$browseObjectContext = Get-Interface $project 'Microsoft.VisualStudio.ProjectSystem.Properties.IVsBrowseObjectContext'
|
$unconfiguredProject = $browseObjectContext.UnconfiguredProject
|
$configuredProject = $unconfiguredProject.GetSuggestedConfiguredProjectAsync().Result
|
$properties = $configuredProject.Services.ProjectPropertiesProvider.GetCommonProperties()
|
|
return $properties.GetEvaluatedPropertyValueAsync($propertyName).Result
|
}
|
|
function GetMSBuildProperty($project, $propertyName)
|
{
|
$msbuildProject = [Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.LoadedProjects |
|
? FullPath -eq $project.FullName
|
|
return $msbuildProject.GetProperty($propertyName).EvaluatedValue
|
}
|
|
function GetProjectItem($project, $path)
|
{
|
$fullPath = GetProperty $project.Properties 'FullPath'
|
|
if ([IO.Path]::IsPathRooted($path))
|
{
|
$path = $path.Substring($fullPath.Length)
|
}
|
|
$itemDirectory = (Split-Path $path -Parent)
|
|
$projectItems = $project.ProjectItems
|
if ($itemDirectory)
|
{
|
$directories = $itemDirectory.Split('\')
|
$directories | %{
|
if ($projectItems)
|
{
|
$projectItems = $projectItems.Item($_).ProjectItems
|
}
|
}
|
}
|
|
if (!$projectItems)
|
{
|
return $null
|
}
|
|
$itemName = Split-Path $path -Leaf
|
|
try
|
{
|
return $projectItems.Item($itemName)
|
}
|
catch [Exception]
|
{
|
}
|
|
return $null
|
}
|
|
function ToArguments($params)
|
{
|
$arguments = ''
|
for ($i = 0; $i -lt $params.Length; $i++)
|
{
|
if ($i)
|
{
|
$arguments += ' '
|
}
|
|
if (!$params[$i].Contains(' '))
|
{
|
$arguments += $params[$i]
|
|
continue
|
}
|
|
$arguments += '"'
|
|
$pendingBackslashs = 0
|
for ($j = 0; $j -lt $params[$i].Length; $j++)
|
{
|
switch ($params[$i][$j])
|
{
|
'"'
|
{
|
if ($pendingBackslashs)
|
{
|
$arguments += '\' * $pendingBackslashs * 2
|
$pendingBackslashs = 0
|
}
|
$arguments += '\"'
|
}
|
|
'\'
|
{
|
$pendingBackslashs++
|
}
|
|
default
|
{
|
if ($pendingBackslashs)
|
{
|
if ($pendingBackslashs -eq 1)
|
{
|
$arguments += '\'
|
}
|
else
|
{
|
$arguments += '\' * $pendingBackslashs * 2
|
}
|
|
$pendingBackslashs = 0
|
}
|
|
$arguments += $params[$i][$j]
|
}
|
}
|
}
|
|
if ($pendingBackslashs)
|
{
|
$arguments += '\' * $pendingBackslashs * 2
|
}
|
|
$arguments += '"'
|
}
|
|
return $arguments
|
}
|
|
# SIG # Begin signature block
|
# MIIjigYJKoZIhvcNAQcCoIIjezCCI3cCAQExDzANBglghkgBZQMEAgEFADB5Bgor
|
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
|
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCDg94dsttUKK3x
|
# GfzAiqKz10JdSqMMbQhO1phCT9nk0aCCDYUwggYDMIID66ADAgECAhMzAAABUptA
|
# n1BWmXWIAAAAAAFSMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
|
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
|
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
|
# bmcgUENBIDIwMTEwHhcNMTkwNTAyMjEzNzQ2WhcNMjAwNTAyMjEzNzQ2WjB0MQsw
|
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
|
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
|
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
# AQCxp4nT9qfu9O10iJyewYXHlN+WEh79Noor9nhM6enUNbCbhX9vS+8c/3eIVazS
|
# YnVBTqLzW7xWN1bCcItDbsEzKEE2BswSun7J9xCaLwcGHKFr+qWUlz7hh9RcmjYS
|
# kOGNybOfrgj3sm0DStoK8ljwEyUVeRfMHx9E/7Ca/OEq2cXBT3L0fVnlEkfal310
|
# EFCLDo2BrE35NGRjG+/nnZiqKqEh5lWNk33JV8/I0fIcUKrLEmUGrv0CgC7w2cjm
|
# bBhBIJ+0KzSnSWingXol/3iUdBBy4QQNH767kYGunJeY08RjHMIgjJCdAoEM+2mX
|
# v1phaV7j+M3dNzZ/cdsz3oDfAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE
|
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU3f8Aw1sW72WcJ2bo/QSYGzVrRYcw
|
# VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
|
# dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzQ1NDEzNjAfBgNVHSMEGDAW
|
# gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v
|
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw
|
# MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov
|
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx
|
# XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB
|
# AJTwROaHvogXgixWjyjvLfiRgqI2QK8GoG23eqAgNjX7V/WdUWBbs0aIC3k49cd0
|
# zdq+JJImixcX6UOTpz2LZPFSh23l0/Mo35wG7JXUxgO0U+5drbQht5xoMl1n7/TQ
|
# 4iKcmAYSAPxTq5lFnoV2+fAeljVA7O43szjs7LR09D0wFHwzZco/iE8Hlakl23ZT
|
# 7FnB5AfU2hwfv87y3q3a5qFiugSykILpK0/vqnlEVB0KAdQVzYULQ/U4eFEjnis3
|
# Js9UrAvtIhIs26445Rj3UP6U4GgOjgQonlRA+mDlsh78wFSGbASIvK+fkONUhvj8
|
# B8ZHNn4TFfnct+a0ZueY4f6aRPxr8beNSUKn7QW/FQmn422bE7KfnqWncsH7vbNh
|
# G929prVHPsaa7J22i9wyHj7m0oATXJ+YjfyoEAtd5/NyIYaE4Uu0j1EhuYUo5VaJ
|
# JnMaTER0qX8+/YZRWrFN/heps41XNVjiAawpbAa0fUa3R9RNBjPiBnM0gvNPorM4
|
# dsV2VJ8GluIQOrJlOvuCrOYDGirGnadOmQ21wPBoGFCWpK56PxzliKsy5NNmAXcE
|
# x7Qb9vUjY1WlYtrdwOXTpxN4slzIht69BaZlLIjLVWwqIfuNrhHKNDM9K+v7vgrI
|
# bf7l5/665g0gjQCDCN6Q5sxuttTAEKtJeS/pkpI+DbZ/MIIHejCCBWKgAwIBAgIK
|
# 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
|
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAFSm0CfUFaZdYgAAAAA
|
# AVIwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
|
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIKkY
|
# lrLB00LjAju/3sAO86SWJVzX5RhHY7kA3skK7c8FMEIGCisGAQQBgjcCAQwxNDAy
|
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
|
# b20wDQYJKoZIhvcNAQEBBQAEggEAJh/dfBp62u8SIDAP5o1n5UIlG+uh3r85ytjF
|
# iqhsok57z/4XS6CnALaC61dHXhYD7QMRDphsrJ8bR/MZjlAASliEWMkqNpnsy4at
|
# 1KNkMFccTTtnSSYSbRBRVti1/T4HTd0Y1ODudhQyoOvrjaVaN0M0sOSjuGM9RF+/
|
# hyYpgIb3zCClG8dDn1jIfnkMnk6ohwucf3sKalN02aUXhZ8hy7wr6vFj4n5IXW3l
|
# VaaJO236i4HD61lv9wpUVmZnMmxNyg7+DhFnroXFryjFFOS7GSEeHQhBElLoN84H
|
# NkYTseeofFhLTvi0snoqpPQmy7G0lTUh/BxddW5hkg3DCOGJ76GCEuUwghLhBgor
|
# BgEEAYI3AwMBMYIS0TCCEs0GCSqGSIb3DQEHAqCCEr4wghK6AgEDMQ8wDQYJYIZI
|
# AWUDBAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGE
|
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCBWoWOygI/Qm/rapqjm0pOqKEhUxTWa2UOh
|
# Z2slrT/OWAIGXfu3kzL7GBMyMDIwMDExODA1MDA1OS42ODZaMASAAgH0oIHQpIHN
|
# MIHKMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
|
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQL
|
# ExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMSYwJAYDVQQLEx1UaGFsZXMg
|
# VFNTIEVTTjpEMkNELUUzMTAtNEFGMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt
|
# U3RhbXAgU2VydmljZaCCDjwwggTxMIID2aADAgECAhMzAAABIhuPACYlzLHnAAAA
|
# AAEiMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
|
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
|
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
|
# MB4XDTE5MTExMzIxNDA0M1oXDTIxMDIxMTIxNDA0M1owgcoxCzAJBgNVBAYTAlVT
|
# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK
|
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVy
|
# aWNhIE9wZXJhdGlvbnMxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOkQyQ0QtRTMx
|
# MC00QUYxMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIB
|
# IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3xUDSGJBPsFy3A9lH5NrOJFC
|
# lIU0Pefkf0Og1IXbjhnSybEioaHFNSpfC9cxKpP5NZPuaFQogaeS/RTu8nEoe+/Q
|
# fkPE3ohESzPp2zHbAMVAmz40dLEOt5CUxaQ4Af+BzqXi1CzD0OohJdI3xLNrqnbf
|
# 4FiKuCsitGV6D/zqOku84Vs+Ao3M5O4EtIpQH0re8QeZRIUISwrZKfa8zugiqjC1
|
# ubo2FcoZhXH63ce+P2OhNhrPbtWDpPCrZ+GOHFv9hNnvuAXjLPQEvtF1m5PzWGNs
|
# Yjx42apc6FWRChpXTidPT/pCIf457ad06aq9jU3g7fTo09alGNcsyXXUdKXCyQID
|
# AQABo4IBGzCCARcwHQYDVR0OBBYEFI42PVVqa8Avcdg44+E0vZ0XM7fIMB8GA1Ud
|
# IwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0
|
# dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0
|
# YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKG
|
# Pmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENB
|
# XzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUH
|
# AwgwDQYJKoZIhvcNAQELBQADggEBAIukR27DIv8GtoNyflU7nIScojWdH2Zalroo
|
# TiTrsTefULwneuh6dqQWkQheI38fsG6xhHjnSeZbk2SFA/PISaH+EO0N+2V+/LJ2
|
# zHf4Ia9e+2dW3+7d8kTNnEN7x+o9tI1rZWnKFnhvwkbAl9FR8v+aPqicW/0n1QuV
|
# gfmmQXBf4+3Hcx5bOwjHE6cw2qJ9vquSdJgfm1fyO5Bsi8eJCEDoL6MdcXl8sMbR
|
# ToFXnwQimBy+fYS6EGbDlMK/JPJHfz/MFnJGg07lrf7kauNcM2MP53dwAs30x1Re
|
# g2PakBUFRBidEQOHBLOhCF/eLDf86VU51BvtDz3VwXIASlJIytswggZxMIIEWaAD
|
# 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
|
# EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT
|
# FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJp
|
# Y2EgT3BlcmF0aW9uczEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046RDJDRC1FMzEw
|
# LTRBRjExJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoB
|
# ATAHBgUrDgMCGgMVAFDsA/yXG6SlTF6RdlYe+zMlTZvZoIGDMIGApH4wfDELMAkG
|
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
|
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z
|
# b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDhzHEwMCIY
|
# DzIwMjAwMTE4MDE0NTIwWhgPMjAyMDAxMTkwMTQ1MjBaMHcwPQYKKwYBBAGEWQoE
|
# ATEvMC0wCgIFAOHMcTACAQAwCgIBAAICGlICAf8wBwIBAAICEZ0wCgIFAOHNwrAC
|
# AQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEK
|
# MAgCAQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQAzSH6Zy00LBfhcxRDJor5fC4Xa
|
# 4zfMlTpmmWCvN/mpqhkEhJk2UCbiQP57HfuWuUvVj14OEaoZXRYVNjwMnI9e1FsQ
|
# evYXr3Nf58FL/rbqiNVUIR3nz9dC6PmtBDjjwwoFG800tyoo0hSoeEi7Fc9oEGwQ
|
# XEpcF9TDyHhk5A/vCzGCAw0wggMJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYD
|
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
|
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
|
# IFBDQSAyMDEwAhMzAAABIhuPACYlzLHnAAAAAAEiMA0GCWCGSAFlAwQCAQUAoIIB
|
# SjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIDFd
|
# MkH6yGRSxVgHa1bGDi0JJqhp9mySyM5LWGf3mjmkMIH6BgsqhkiG9w0BCRACLzGB
|
# 6jCB5zCB5DCBvQQgu/BgiV5iMs5qslkpcOW35aMPckN4OL77N+KDUsJ4MQkwgZgw
|
# gYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
|
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
|
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAASIbjwAmJcyx
|
# 5wAAAAABIjAiBCDmn670jGWXYyXPMzuPsxJB+kSHGl6IMDIxDrFOk+4xDzANBgkq
|
# hkiG9w0BAQsFAASCAQDZde8/0IrN//bHtpPTgHBiqzxlVHWlRqhKPiXfBa4J8lK6
|
# t7tWOo5whQYgYxbVh8t3VGEr/1dDZcXHH0FAGqVjLhVlrU6zLw5vE5y23elHkzpI
|
# eYzxPVFHnkuSH9LORGNaYBiG4dVZWUQ+9Bd/SlfwgnBq0BpxLfULnlxg4O87B0yX
|
# uHNYv43/q/Otl33+p6D7zbkK+Qfm6peEYDiQ3L9T0BYZiwEhMrb50Hwczym76Sy7
|
# 4R/tTlQIn6fgEgbxDNGfo2FpBI9NjjQ6Tf5y9vdF1FFy246tzaf+Ka3IT+J7U1Td
|
# 4CxVK4bZ5WWzrsJLruzCSxW4KiVaKmE2o5AVqLKn
|
# SIG # End signature block
|