懒羊羊
2023-12-28 e46d3baaf3e8d7d85f4bafec3aad75e52b078408
提交 | 用户 | 时间
e46d3b 1 # Copyright (c) Microsoft Corporation.  All rights reserved.
2
3 $InitialDatabase = '0'
4
5 $knownExceptions = @(
6     'System.Data.Entity.Migrations.Infrastructure.MigrationsException',
7     'System.Data.Entity.Migrations.Infrastructure.AutomaticMigrationsDisabledException',
8     'System.Data.Entity.Migrations.Infrastructure.AutomaticDataLossException',
9     'System.Data.Entity.Migrations.Infrastructure.MigrationsPendingException',
10     'System.Data.Entity.Migrations.ProjectTypeNotSupportedException'
11 )
12
13 <#
14 .SYNOPSIS
15     Adds or updates an Entity Framework provider entry in the project config
16     file.
17
18 .DESCRIPTION
19     Adds an entry into the 'entityFramework' section of the project config
20     file for the specified provider invariant name and provider type. If an
21     entry for the given invariant name already exists, then that entry is
22     updated with the given type name, unless the given type name already
23     matches, in which case no action is taken. The 'entityFramework'
24     section is added if it does not exist. The config file is automatically
25     saved if and only if a change was made.
26     
27     This command is typically used only by Entity Framework provider NuGet
28     packages and is run from the 'install.ps1' script.
29
30 .PARAMETER Project
31     The Visual Studio project to update. When running in the NuGet install.ps1
32     script the '$project' variable provided as part of that script should be
33     used.
34
35 .PARAMETER InvariantName
36     The provider invariant name that uniquely identifies this provider. For
37     example, the Microsoft SQL Server provider is registered with the invariant
38     name 'System.Data.SqlClient'.
39
40 .PARAMETER TypeName
41     The assembly-qualified type name of the provider-specific type that
42     inherits from 'System.Data.Entity.Core.Common.DbProviderServices'. For
43     example, for the Microsoft SQL Server provider, this type is 
44     'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer'.
45 #>
46 function Add-EFProvider
47 {
48     param (
49         [parameter(Position = 0,
50             Mandatory = $true)]
51         $Project,
52         [parameter(Position = 1,
53             Mandatory = $true)]
54         [string] $InvariantName,
55         [parameter(Position = 2,
56             Mandatory = $true)]
57         [string] $TypeName
58     )
59
60     Check-Project $project
61
62     $runner = New-EFConfigRunner $Project
63
64     try
65     {
66         Invoke-RunnerCommand $runner System.Data.Entity.ConnectionFactoryConfig.AddProviderCommand @( $InvariantName, $TypeName )
67         $error = Get-RunnerError $runner
68
69         if ($error)
70         {
71             if ($knownExceptions -notcontains $error.TypeName)
72             {
73                 Write-Host $error.StackTrace
74             }
75             else
76             {
77                 Write-Verbose $error.StackTrace
78             }
79
80             throw $error.Message
81         }
82     }
83     finally
84     {                
85         Remove-Runner $runner
86     }
87 }
88
89 <#
90 .SYNOPSIS
91     Adds or updates an Entity Framework default connection factory in the
92     project config file.
93
94 .DESCRIPTION
95     Adds an entry into the 'entityFramework' section of the project config
96     file for the connection factory that Entity Framework will use by default
97     when creating new connections by convention. Any existing entry will be
98     overridden if it does not match. The 'entityFramework' section is added if
99     it does not exist. The config file is automatically saved if and only if
100     a change was made.
101     
102     This command is typically used only by Entity Framework provider NuGet
103     packages and is run from the 'install.ps1' script.
104
105 .PARAMETER Project
106     The Visual Studio project to update. When running in the NuGet install.ps1
107     script the '$project' variable provided as part of that script should be
108     used.
109
110 .PARAMETER TypeName
111     The assembly-qualified type name of the connection factory type that
112     implements the 'System.Data.Entity.Infrastructure.IDbConnectionFactory'
113     interface.  For example, for the Microsoft SQL Server Express provider
114     connection factory, this type is
115     'System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework'.
116
117 .PARAMETER ConstructorArguments
118     An optional array of strings that will be passed as arguments to the
119     connection factory type constructor.
120 #>
121 function Add-EFDefaultConnectionFactory
122 {
123     param (
124         [parameter(Position = 0,
125             Mandatory = $true)]
126         $Project,
127         [parameter(Position = 1,
128             Mandatory = $true)]
129         [string] $TypeName,
130         [string[]] $ConstructorArguments
131     )
132
133     Check-Project $project
134
135     $runner = New-EFConfigRunner $Project
136
137     try
138     {
139         Invoke-RunnerCommand $runner System.Data.Entity.ConnectionFactoryConfig.AddDefaultConnectionFactoryCommand @( $TypeName, $ConstructorArguments )
140         $error = Get-RunnerError $runner
141
142         if ($error)
143         {
144             if ($knownExceptions -notcontains $error.TypeName)
145             {
146                 Write-Host $error.StackTrace
147             }
148             else
149             {
150                 Write-Verbose $error.StackTrace
151             }
152
153             throw $error.Message
154         }
155     }
156     finally
157     {                
158         Remove-Runner $runner
159     }
160 }
161
162 <#
163 .SYNOPSIS
164     Initializes the Entity Framework section in the project config file
165     and sets defaults.
166
167 .DESCRIPTION
168     Creates the 'entityFramework' section of the project config file and sets
169     the default connection factory to use SQL Express if it is running on the
170     machine, or LocalDb otherwise. Note that installing a different provider
171     may change the default connection factory.  The config file is
172     automatically saved if and only if a change was made.
173
174     In addition, any reference to 'System.Data.Entity.dll' in the project is
175     removed.
176     
177     This command is typically used only by Entity Framework provider NuGet
178     packages and is run from the 'install.ps1' script.
179
180 .PARAMETER Project
181     The Visual Studio project to update. When running in the NuGet install.ps1
182     script the '$project' variable provided as part of that script should be
183     used.
184 #>
185 function Initialize-EFConfiguration
186 {
187     param (
188         [parameter(Position = 0,
189             Mandatory = $true)]
190         $Project
191     )
192
193     Check-Project $project
194
195     $runner = New-EFConfigRunner $Project
196
197     try
198     {
199         Invoke-RunnerCommand $runner System.Data.Entity.ConnectionFactoryConfig.InitializeEntityFrameworkCommand
200         $error = Get-RunnerError $runner
201
202         if ($error)
203         {
204             if ($knownExceptions -notcontains $error.TypeName)
205             {
206                 Write-Host $error.StackTrace
207             }
208             else
209             {
210                 Write-Verbose $error.StackTrace
211             }
212
213             throw $error.Message
214         }
215     }
216     finally
217     {                
218         Remove-Runner $runner
219     }
220 }
221
222 <#
223 .SYNOPSIS
224     Enables Code First Migrations in a project.
225
226 .DESCRIPTION
227     Enables Migrations by scaffolding a migrations configuration class in the project. If the
228     target database was created by an initializer, an initial migration will be created (unless
229     automatic migrations are enabled via the EnableAutomaticMigrations parameter).
230
231 .PARAMETER ContextTypeName
232     Specifies the context to use. If omitted, migrations will attempt to locate a
233     single context type in the target project.
234
235 .PARAMETER EnableAutomaticMigrations
236     Specifies whether automatic migrations will be enabled in the scaffolded migrations configuration.
237     If omitted, automatic migrations will be disabled.
238
239 .PARAMETER MigrationsDirectory
240     Specifies the name of the directory that will contain migrations code files.
241     If omitted, the directory will be named "Migrations". 
242
243 .PARAMETER ProjectName
244     Specifies the project that the scaffolded migrations configuration class will
245     be added to. If omitted, the default project selected in package manager
246     console is used.
247
248 .PARAMETER StartUpProjectName
249     Specifies the configuration file to use for named connection strings. If
250     omitted, the specified project's configuration file is used.
251
252 .PARAMETER ContextProjectName
253     Specifies the project which contains the DbContext class to use. If omitted,
254     the context is assumed to be in the same project used for migrations.
255
256 .PARAMETER ConnectionStringName
257     Specifies the name of a connection string to use from the application's
258     configuration file.
259
260 .PARAMETER ConnectionString
261     Specifies the the connection string to use. If omitted, the context's
262     default connection will be used.
263
264 .PARAMETER ConnectionProviderName
265     Specifies the provider invariant name of the connection string.
266
267 .PARAMETER Force
268     Specifies that the migrations configuration be overwritten when running more
269     than once for a given project.
270 #>
271 function Enable-Migrations
272 {
273     [CmdletBinding(DefaultParameterSetName = 'ConnectionStringName')] 
274     param (
275         [string] $ContextTypeName,
276         [alias('Auto')]
277         [switch] $EnableAutomaticMigrations,
278         [string] $MigrationsDirectory,
279         [string] $ProjectName,
280         [string] $StartUpProjectName,
281         [string] $ContextProjectName,
282         [parameter(ParameterSetName = 'ConnectionStringName')]
283         [string] $ConnectionStringName,
284         [parameter(ParameterSetName = 'ConnectionStringAndProviderName',
285             Mandatory = $true)]
286         [string] $ConnectionString,
287         [parameter(ParameterSetName = 'ConnectionStringAndProviderName',
288             Mandatory = $true)]
289         [string] $ConnectionProviderName,
290         [switch] $Force
291     )
292
293     $runner = New-MigrationsRunner $ProjectName $StartUpProjectName $ContextProjectName $null $ConnectionStringName $ConnectionString $ConnectionProviderName
294
295     try
296     {
297         Invoke-RunnerCommand $runner System.Data.Entity.Migrations.EnableMigrationsCommand @( $EnableAutomaticMigrations.IsPresent, $Force.IsPresent ) @{ 'ContextTypeName' = $ContextTypeName; 'MigrationsDirectory' = $MigrationsDirectory }                
298         $error = Get-RunnerError $runner                    
299
300         if ($error)
301         {
302             if ($knownExceptions -notcontains $error.TypeName)
303             {
304                 Write-Host $error.StackTrace
305             }
306             else
307             {
308                 Write-Verbose $error.StackTrace
309             }
310
311             throw $error.Message
312         }
313
314         $(Get-VSComponentModel).GetService([NuGetConsole.IPowerConsoleWindow]).Show()            
315     }
316     finally
317     {                
318         Remove-Runner $runner        
319     }
320 }
321
322 <#
323 .SYNOPSIS
324     Scaffolds a migration script for any pending model changes.
325
326 .DESCRIPTION
327     Scaffolds a new migration script and adds it to the project.
328
329 .PARAMETER Name
330     Specifies the name of the custom script.
331
332 .PARAMETER Force
333     Specifies that the migration user code be overwritten when re-scaffolding an
334     existing migration.
335
336 .PARAMETER ProjectName
337     Specifies the project that contains the migration configuration type to be
338     used. If omitted, the default project selected in package manager console
339     is used.
340
341 .PARAMETER StartUpProjectName
342     Specifies the configuration file to use for named connection strings. If
343     omitted, the specified project's configuration file is used.
344
345 .PARAMETER ConfigurationTypeName
346     Specifies the migrations configuration to use. If omitted, migrations will
347     attempt to locate a single migrations configuration type in the target
348     project.
349
350 .PARAMETER ConnectionStringName
351     Specifies the name of a connection string to use from the application's
352     configuration file.
353
354 .PARAMETER ConnectionString
355     Specifies the the connection string to use. If omitted, the context's
356     default connection will be used.
357
358 .PARAMETER ConnectionProviderName
359     Specifies the provider invariant name of the connection string.
360
361 .PARAMETER IgnoreChanges
362     Scaffolds an empty migration ignoring any pending changes detected in the current model.
363     This can be used to create an initial, empty migration to enable Migrations for an existing
364     database. N.B. Doing this assumes that the target database schema is compatible with the
365     current model.
366
367 #>
368 function Add-Migration
369 {
370     [CmdletBinding(DefaultParameterSetName = 'ConnectionStringName')]
371     param (
372         [parameter(Position = 0,
373             Mandatory = $true)]
374         [string] $Name,
375         [switch] $Force,
376         [string] $ProjectName,
377         [string] $StartUpProjectName,
378         [string] $ConfigurationTypeName,
379         [parameter(ParameterSetName = 'ConnectionStringName')]
380         [string] $ConnectionStringName,
381         [parameter(ParameterSetName = 'ConnectionStringAndProviderName',
382             Mandatory = $true)]
383         [string] $ConnectionString,
384         [parameter(ParameterSetName = 'ConnectionStringAndProviderName',
385             Mandatory = $true)]
386         [string] $ConnectionProviderName,
387         [switch] $IgnoreChanges)
388
389     $runner = New-MigrationsRunner $ProjectName $StartUpProjectName $null $ConfigurationTypeName $ConnectionStringName $ConnectionString $ConnectionProviderName
390
391     try
392     {
393         Invoke-RunnerCommand $runner System.Data.Entity.Migrations.AddMigrationCommand @( $Name, $Force.IsPresent, $IgnoreChanges.IsPresent )
394         $error = Get-RunnerError $runner               
395
396         if ($error)
397         {
398             if ($knownExceptions -notcontains $error.TypeName)
399             {
400                 Write-Host $error.StackTrace
401             }
402             else
403             {
404                 Write-Verbose $error.StackTrace
405             }
406
407             throw $error.Message
408         }        
409         $(Get-VSComponentModel).GetService([NuGetConsole.IPowerConsoleWindow]).Show()            
410     }
411     finally
412     {            
413         Remove-Runner $runner        
414     }    
415 }
416
417 <#
418 .SYNOPSIS
419     Applies any pending migrations to the database.
420
421 .DESCRIPTION
422     Updates the database to the current model by applying pending migrations.
423
424 .PARAMETER SourceMigration
425     Only valid with -Script. Specifies the name of a particular migration to use
426     as the update's starting point. If omitted, the last applied migration in
427     the database will be used.
428
429 .PARAMETER TargetMigration
430     Specifies the name of a particular migration to update the database to. If
431     omitted, the current model will be used.
432
433 .PARAMETER Script
434     Generate a SQL script rather than executing the pending changes directly.
435
436 .PARAMETER Force
437     Specifies that data loss is acceptable during automatic migration of the
438     database.
439
440 .PARAMETER ProjectName
441     Specifies the project that contains the migration configuration type to be
442     used. If omitted, the default project selected in package manager console
443     is used.
444
445 .PARAMETER StartUpProjectName
446     Specifies the configuration file to use for named connection strings. If
447     omitted, the specified project's configuration file is used.
448
449 .PARAMETER ConfigurationTypeName
450     Specifies the migrations configuration to use. If omitted, migrations will
451     attempt to locate a single migrations configuration type in the target
452     project.
453
454 .PARAMETER ConnectionStringName
455     Specifies the name of a connection string to use from the application's
456     configuration file.
457
458 .PARAMETER ConnectionString
459     Specifies the the connection string to use. If omitted, the context's
460     default connection will be used.
461
462 .PARAMETER ConnectionProviderName
463     Specifies the provider invariant name of the connection string.
464 #>
465 function Update-Database
466 {
467     [CmdletBinding(DefaultParameterSetName = 'ConnectionStringName')]
468     param (
469         [string] $SourceMigration,
470         [string] $TargetMigration,
471         [switch] $Script,
472         [switch] $Force,
473         [string] $ProjectName,
474         [string] $StartUpProjectName,
475         [string] $ConfigurationTypeName,
476         [parameter(ParameterSetName = 'ConnectionStringName')]
477         [string] $ConnectionStringName,
478         [parameter(ParameterSetName = 'ConnectionStringAndProviderName',
479             Mandatory = $true)]
480         [string] $ConnectionString,
481         [parameter(ParameterSetName = 'ConnectionStringAndProviderName',
482             Mandatory = $true)]
483         [string] $ConnectionProviderName)
484
485     $runner = New-MigrationsRunner $ProjectName $StartUpProjectName $null $ConfigurationTypeName $ConnectionStringName $ConnectionString $ConnectionProviderName
486
487     try
488     {
489         Invoke-RunnerCommand $runner System.Data.Entity.Migrations.UpdateDatabaseCommand @( $SourceMigration, $TargetMigration, $Script.IsPresent, $Force.IsPresent, $Verbose.IsPresent )
490         $error = Get-RunnerError $runner
491         
492         if ($error)
493         {
494             if ($knownExceptions -notcontains $error.TypeName)
495             {
496                 Write-Host $error.StackTrace
497             }
498             else
499             {
500                 Write-Verbose $error.StackTrace
501             }
502
503             throw $error.Message
504         }        
505         $(Get-VSComponentModel).GetService([NuGetConsole.IPowerConsoleWindow]).Show()            
506     }
507     finally
508     {             
509         Remove-Runner $runner
510     }
511 }
512
513 <#
514 .SYNOPSIS
515     Displays the migrations that have been applied to the target database.
516
517 .DESCRIPTION
518     Displays the migrations that have been applied to the target database.
519
520 .PARAMETER ProjectName
521     Specifies the project that contains the migration configuration type to be
522     used. If omitted, the default project selected in package manager console
523     is used.
524
525 .PARAMETER StartUpProjectName
526     Specifies the configuration file to use for named connection strings. If
527     omitted, the specified project's configuration file is used.
528
529 .PARAMETER ConfigurationTypeName
530     Specifies the migrations configuration to use. If omitted, migrations will
531     attempt to locate a single migrations configuration type in the target
532     project.
533
534 .PARAMETER ConnectionStringName
535     Specifies the name of a connection string to use from the application's
536     configuration file.
537
538 .PARAMETER ConnectionString
539     Specifies the the connection string to use. If omitted, the context's
540     default connection will be used.
541
542 .PARAMETER ConnectionProviderName
543     Specifies the provider invariant name of the connection string.
544 #>
545 function Get-Migrations
546 {
547     [CmdletBinding(DefaultParameterSetName = 'ConnectionStringName')]
548     param (
549         [string] $ProjectName,
550         [string] $StartUpProjectName,
551         [string] $ConfigurationTypeName,
552         [parameter(ParameterSetName = 'ConnectionStringName')]
553         [string] $ConnectionStringName,
554         [parameter(ParameterSetName = 'ConnectionStringAndProviderName',
555             Mandatory = $true)]
556         [string] $ConnectionString,
557         [parameter(ParameterSetName = 'ConnectionStringAndProviderName',
558             Mandatory = $true)]
559         [string] $ConnectionProviderName)
560
561     $runner = New-MigrationsRunner $ProjectName $StartUpProjectName $null $ConfigurationTypeName $ConnectionStringName $ConnectionString $ConnectionProviderName
562
563     try
564     {
565         Invoke-RunnerCommand $runner System.Data.Entity.Migrations.GetMigrationsCommand
566         $error = Get-RunnerError $runner
567         
568         if ($error)
569         {
570             if ($knownExceptions -notcontains $error.TypeName)
571             {
572                 Write-Host $error.StackTrace
573             }
574             else
575             {
576                 Write-Verbose $error.StackTrace
577             }
578
579             throw $error.Message
580         }
581     }
582     finally
583     {
584         Remove-Runner $runner
585     }
586 }
587
588 function New-MigrationsRunner($ProjectName, $StartUpProjectName, $ContextProjectName, $ConfigurationTypeName, $ConnectionStringName, $ConnectionString, $ConnectionProviderName)
589 {
590     $startUpProject = Get-MigrationsStartUpProject $StartUpProjectName $ProjectName
591     Build-Project $startUpProject
592
593     $project = Get-MigrationsProject $ProjectName
594     Build-Project $project
595
596     $contextProject = $project
597     if ($ContextProjectName)
598     {
599         $contextProject = Get-SingleProject $ContextProjectName
600         Build-Project $contextProject
601     }
602
603     $installPath = Get-EntityFrameworkInstallPath $project
604     $toolsPath = Join-Path $installPath tools
605
606     $info = New-AppDomainSetup $project $installPath
607
608     $domain = [AppDomain]::CreateDomain('Migrations', $null, $info)
609     $domain.SetData('project', $project)
610     $domain.SetData('contextProject', $contextProject)
611     $domain.SetData('startUpProject', $startUpProject)
612     $domain.SetData('configurationTypeName', $ConfigurationTypeName)
613     $domain.SetData('connectionStringName', $ConnectionStringName)
614     $domain.SetData('connectionString', $ConnectionString)
615     $domain.SetData('connectionProviderName', $ConnectionProviderName)
616     
617     $dispatcher = New-DomainDispatcher $toolsPath
618     $domain.SetData('efDispatcher', $dispatcher)
619
620     return @{
621         Domain = $domain;
622         ToolsPath = $toolsPath
623     }
624 }
625
626 function New-EFConfigRunner($Project)
627 {
628     $installPath = Get-EntityFrameworkInstallPath $Project
629     $toolsPath = Join-Path $installPath tools
630     $info = New-AppDomainSetup $Project $installPath
631
632     $domain = [AppDomain]::CreateDomain('EFConfig', $null, $info)
633     $domain.SetData('project', $Project)
634     
635     $dispatcher = New-DomainDispatcher $toolsPath
636     $domain.SetData('efDispatcher', $dispatcher)
637
638     return @{
639         Domain = $domain;
640         ToolsPath = $toolsPath
641     }
642 }
643
644 function New-AppDomainSetup($Project, $InstallPath)
645 {
646     $info = New-Object System.AppDomainSetup -Property @{
647             ShadowCopyFiles = 'true';
648             ApplicationBase = $InstallPath;
649             PrivateBinPath = 'tools';
650             ConfigurationFile = ([AppDomain]::CurrentDomain.SetupInformation.ConfigurationFile)
651         }
652     
653     $targetFrameworkVersion = (New-Object System.Runtime.Versioning.FrameworkName ($Project.Properties.Item('TargetFrameworkMoniker').Value)).Version
654
655     if ($targetFrameworkVersion -lt (New-Object Version @( 4, 5 )))
656     {
657         $info.PrivateBinPath += ';lib\net40'
658     }
659     else
660     {
661         $info.PrivateBinPath += ';lib\net45'
662     }
663
664     return $info
665 }
666
667 function New-DomainDispatcher($ToolsPath)
668 {
669     $utilityAssembly = [System.Reflection.Assembly]::LoadFrom((Join-Path $ToolsPath EntityFramework.PowerShell.Utility.dll))
670     $dispatcher = $utilityAssembly.CreateInstance(
671         'System.Data.Entity.Migrations.Utilities.DomainDispatcher',
672         $false,
673         [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::Public,
674         $null,
675         $PSCmdlet,
676         $null,
677         $null)
678
679     return $dispatcher
680 }
681
682 function Remove-Runner($runner)
683 {
684     [AppDomain]::Unload($runner.Domain)
685 }
686
687 function Invoke-RunnerCommand($runner, $command, $parameters, $anonymousArguments)
688 {
689     $domain = $runner.Domain
690
691     if ($anonymousArguments)
692     {
693         $anonymousArguments.GetEnumerator() | %{
694             $domain.SetData($_.Name, $_.Value)
695         }
696     }
697
698     $domain.CreateInstanceFrom(
699         (Join-Path $runner.ToolsPath EntityFramework.PowerShell.dll),
700         $command,
701         $false,
702         0,
703         $null,
704         $parameters,
705         $null,
706         $null) | Out-Null
707 }
708
709 function Get-RunnerError($runner)
710 {
711     $domain = $runner.Domain
712
713     if (!$domain.GetData('wasError'))
714     {
715         return $null
716     }
717
718     return @{
719             Message = $domain.GetData('error.Message');
720             TypeName = $domain.GetData('error.TypeName');
721             StackTrace = $domain.GetData('error.StackTrace')
722     }
723 }
724
725 function Get-MigrationsProject($name, $hideMessage)
726 {
727     if ($name)
728     {
729         return Get-SingleProject $name
730     }
731
732     $project = Get-Project
733     $projectName = $project.Name
734
735     if (!$hideMessage)
736     {
737         Write-Verbose "Using NuGet project '$projectName'."
738     }
739
740     return $project
741 }
742
743 function Get-MigrationsStartUpProject($name, $fallbackName)
744 {    
745     $startUpProject = $null
746
747     if ($name)
748     {
749         $startUpProject = Get-SingleProject $name
750     }
751     else
752     {
753         $startupProjectPaths = $DTE.Solution.SolutionBuild.StartupProjects
754
755         if ($startupProjectPaths)
756         {
757             if ($startupProjectPaths.Length -eq 1)
758             {
759                 $startupProjectPath = $startupProjectPaths[0]
760
761                 if (!(Split-Path -IsAbsolute $startupProjectPath))
762                 {
763                     $solutionPath = Split-Path $DTE.Solution.Properties.Item('Path').Value
764                     $startupProjectPath = Join-Path $solutionPath $startupProjectPath -Resolve
765                 }
766
767                 $startupProject = Get-SolutionProjects | ?{
768                     try
769                     {
770                         $fullName = $_.FullName
771                     }
772                     catch [NotImplementedException]
773                     {
774                         return $false
775                     }
776
777                     if ($fullName -and $fullName.EndsWith('\'))
778                     {
779                         $fullName = $fullName.Substring(0, $fullName.Length - 1)
780                     }
781
782                     return $fullName -eq $startupProjectPath
783                 }
784             }
785             else
786             {
787                 Write-Verbose 'More than one start-up project found.'
788             }
789         }
790         else
791         {
792             Write-Verbose 'No start-up project found.'
793         }
794     }
795
796     if (!($startUpProject -and (Test-StartUpProject $startUpProject)))
797     {
798         $startUpProject = Get-MigrationsProject $fallbackName $true
799         $startUpProjectName = $startUpProject.Name
800
801         Write-Warning "Cannot determine a valid start-up project. Using project '$startUpProjectName' instead. Your configuration file and working directory may not be set as expected. Use the -StartUpProjectName parameter to set one explicitly. Use the -Verbose switch for more information."
802     }
803     else
804     {
805         $startUpProjectName = $startUpProject.Name
806
807         Write-Verbose "Using StartUp project '$startUpProjectName'."
808     }
809
810     return $startUpProject
811 }
812
813 function Get-SolutionProjects()
814 {
815     $projects = New-Object System.Collections.Stack
816     
817     $DTE.Solution.Projects | %{
818         $projects.Push($_)
819     }
820     
821     while ($projects.Count -ne 0)
822     {
823         $project = $projects.Pop();
824         
825         # NOTE: This line is similar to doing a "yield return" in C#
826         $project
827
828         if ($project.ProjectItems)
829         {
830             $project.ProjectItems | ?{ $_.SubProject } | %{
831                 $projects.Push($_.SubProject)
832             }
833         }
834     }
835 }
836
837 function Get-SingleProject($name)
838 {
839     $project = Get-Project $name
840
841     if ($project -is [array])
842     {
843         throw "More than one project '$name' was found. Specify the full name of the one to use."
844     }
845
846     return $project
847 }
848
849 function Test-StartUpProject($project)
850 {    
851     if ($project.Kind -eq '{cc5fd16d-436d-48ad-a40c-5a424c6e3e79}')
852     {
853         $projectName = $project.Name
854         Write-Verbose "Cannot use start-up project '$projectName'. The Windows Azure Project type isn't supported."
855         
856         return $false
857     }
858     
859     return $true
860 }
861
862 function Build-Project($project)
863 {
864     $configuration = $DTE.Solution.SolutionBuild.ActiveConfiguration.Name
865
866     $DTE.Solution.SolutionBuild.BuildProject($configuration, $project.UniqueName, $true)
867
868     if ($DTE.Solution.SolutionBuild.LastBuildInfo)
869     {
870         $projectName = $project.Name
871
872         throw "The project '$projectName' failed to build."
873     }
874 }
875
876 function Get-EntityFrameworkInstallPath($project)
877 {
878     $package = Get-Package -ProjectName $project.FullName | ?{ $_.Id -eq 'EntityFramework' }
879
880     if (!$package)
881     {
882         $projectName = $project.Name
883
884         throw "The EntityFramework package is not installed on project '$projectName'."
885     }
886     
887     return Get-PackageInstallPath $package
888 }
889     
890 function Get-PackageInstallPath($package)
891 {
892     $componentModel = Get-VsComponentModel
893     $packageInstallerServices = $componentModel.GetService([NuGet.VisualStudio.IVsPackageInstallerServices])
894
895     $vsPackage = $packageInstallerServices.GetInstalledPackages() | ?{ $_.Id -eq $package.Id -and $_.Version -eq $package.Version }
896     
897     return $vsPackage.InstallPath
898 }
899
900 function Check-Project($project)
901 {
902     if (!$project.FullName)
903     {
904         throw "The Project argument must refer to a Visual Studio project. Use the '`$project' variable provided by NuGet when running in install.ps1."
905     }
906 }
907
908 Export-ModuleMember @( 'Enable-Migrations', 'Add-Migration', 'Update-Database', 'Get-Migrations', 'Add-EFProvider', 'Add-EFDefaultConnectionFactory', 'Initialize-EFConfiguration') -Variable InitialDatabase
909
910 # SIG # Begin signature block
911 # MIIarwYJKoZIhvcNAQcCoIIaoDCCGpwCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
912 # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
913 # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUGD2nrGYv22CsZ8TVTLPYVoMj
914 # HJGgghWCMIIEwzCCA6ugAwIBAgITMwAAACs5MkjBsslI8wAAAAAAKzANBgkqhkiG
915 # 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
916 # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw
917 # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTIwOTA0MjExMjM0
918 # WhcNMTMxMjA0MjExMjM0WjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
919 # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
920 # b3JhdGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNO
921 # OkMwRjQtMzA4Ni1ERUY4MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT
922 # ZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAprYwDgNlrlBa
923 # hmuFn0ihHsnA7l5JB4XgcJZ8vrlfYl8GJtOLObsYIqUukq3YS4g6Gq+bg67IXjmM
924 # wjJ7FnjtNzg68WL7aIICaOzru0CKsf6hLDZiYHA5YGIO+8YYOG+wktZADYCmDXiL
925 # NmuGiiYXGP+w6026uykT5lxIjnBGNib+NDWrNOH32thc6pl9MbdNH1frfNaVDWYM
926 # Hg4yFz4s1YChzuv3mJEC3MFf/TiA+Dl/XWTKN1w7UVtdhV/OHhz7NL5f5ShVcFSc
927 # uOx8AFVGWyiYKFZM4fG6CRmWgUgqMMj3MyBs52nDs9TDTs8wHjfUmFLUqSNFsq5c
928 # QUlPtGJokwIDAQABo4IBCTCCAQUwHQYDVR0OBBYEFKUYM1M/lWChQxbvjsav0iu6
929 # nljQMB8GA1UdIwQYMBaAFCM0+NlSRnAK7UD7dvuzK7DDNbMPMFQGA1UdHwRNMEsw
930 # SaBHoEWGQ2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3Rz
931 # L01pY3Jvc29mdFRpbWVTdGFtcFBDQS5jcmwwWAYIKwYBBQUHAQEETDBKMEgGCCsG
932 # AQUFBzAChjxodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jv
933 # c29mdFRpbWVTdGFtcFBDQS5jcnQwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZI
934 # hvcNAQEFBQADggEBAH7MsHvlL77nVrXPc9uqUtEWOca0zfrX/h5ltedI85tGiAVm
935 # aiaGXv6HWNzGY444gPQIRnwrc7EOv0Gqy8eqlKQ38GQ54cXV+c4HzqvkJfBprtRG
936 # 4v5mMjzXl8UyIfruGiWgXgxCLBEzOoKD/e0ds77OkaSRJXG5q3Kwnq/kzwBiiXCp
937 # uEpQjO4vImSlqOZNa5UsHHnsp6Mx2pBgkKRu/pMCDT8sJA3GaiaBUYNKELt1Y0Sq
938 # aQjGA+vizwvtVjrs73KnCgz0ANMiuK8icrPnxJwLKKCAyuPh1zlmMOdGFxjn+oL6
939 # WQt6vKgN/hz/A4tjsk0SAiNPLbOFhDvioUfozxUwggTsMIID1KADAgECAhMzAAAA
940 # sBGvCovQO5/dAAEAAACwMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNVBAYTAlVTMRMw
941 # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
942 # aWNyb3NvZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNp
943 # Z25pbmcgUENBMB4XDTEzMDEyNDIyMzMzOVoXDTE0MDQyNDIyMzMzOVowgYMxCzAJ
944 # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
945 # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIx
946 # HjAcBgNVBAMTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjCCASIwDQYJKoZIhvcNAQEB
947 # BQADggEPADCCAQoCggEBAOivXKIgDfgofLwFe3+t7ut2rChTPzrbQH2zjjPmVz+l
948 # URU0VKXPtIupP6g34S1Q7TUWTu9NetsTdoiwLPBZXKnr4dcpdeQbhSeb8/gtnkE2
949 # KwtA+747urlcdZMWUkvKM8U3sPPrfqj1QRVcCGUdITfwLLoiCxCxEJ13IoWEfE+5
950 # G5Cw9aP+i/QMmk6g9ckKIeKq4wE2R/0vgmqBA/WpNdyUV537S9QOgts4jxL+49Z6
951 # dIhk4WLEJS4qrp0YHw4etsKvJLQOULzeHJNcSaZ5tbbbzvlweygBhLgqKc+/qQUF
952 # 4eAPcU39rVwjgynrx8VKyOgnhNN+xkMLlQAFsU9lccUCAwEAAaOCAWAwggFcMBMG
953 # A1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBRZcaZaM03amAeA/4Qevof5cjJB
954 # 8jBRBgNVHREESjBIpEYwRDENMAsGA1UECxMETU9QUjEzMDEGA1UEBRMqMzE1OTUr
955 # NGZhZjBiNzEtYWQzNy00YWEzLWE2NzEtNzZiYzA1MjM0NGFkMB8GA1UdIwQYMBaA
956 # FMsR6MrStBZYAck3LjMWFrlMmgofMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9j
957 # cmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY0NvZFNpZ1BDQV8w
958 # OC0zMS0yMDEwLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6
959 # Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljQ29kU2lnUENBXzA4LTMx
960 # LTIwMTAuY3J0MA0GCSqGSIb3DQEBBQUAA4IBAQAx124qElczgdWdxuv5OtRETQie
961 # 7l7falu3ec8CnLx2aJ6QoZwLw3+ijPFNupU5+w3g4Zv0XSQPG42IFTp8263Os8ls
962 # ujksRX0kEVQmMA0N/0fqAwfl5GZdLHudHakQ+hywdPJPaWueqSSE2u2WoN9zpO9q
963 # GqxLYp7xfMAUf0jNTbJE+fA8k21C2Oh85hegm2hoCSj5ApfvEQO6Z1Ktwemzc6bS
964 # Y81K4j7k8079/6HguwITO10g3lU/o66QQDE4dSheBKlGbeb1enlAvR/N6EXVruJd
965 # PvV1x+ZmY2DM1ZqEh40kMPfvNNBjHbFCZ0oOS786Du+2lTqnOOQlkgimiGaCMIIF
966 # vDCCA6SgAwIBAgIKYTMmGgAAAAAAMTANBgkqhkiG9w0BAQUFADBfMRMwEQYKCZIm
967 # iZPyLGQBGRYDY29tMRkwFwYKCZImiZPyLGQBGRYJbWljcm9zb2Z0MS0wKwYDVQQD
968 # EyRNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMTAwODMx
969 # MjIxOTMyWhcNMjAwODMxMjIyOTMyWjB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
970 # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
971 # IENvcnBvcmF0aW9uMSMwIQYDVQQDExpNaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBD
972 # QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJyWVwZMGS/HZpgICBC
973 # mXZTbD4b1m/My/Hqa/6XFhDg3zp0gxq3L6Ay7P/ewkJOI9VyANs1VwqJyq4gSfTw
974 # aKxNS42lvXlLcZtHB9r9Jd+ddYjPqnNEf9eB2/O98jakyVxF3K+tPeAoaJcap6Vy
975 # c1bxF5Tk/TWUcqDWdl8ed0WDhTgW0HNbBbpnUo2lsmkv2hkL/pJ0KeJ2L1TdFDBZ
976 # +NKNYv3LyV9GMVC5JxPkQDDPcikQKCLHN049oDI9kM2hOAaFXE5WgigqBTK3S9dP
977 # Y+fSLWLxRT3nrAgA9kahntFbjCZT6HqqSvJGzzc8OJ60d1ylF56NyxGPVjzBrAlf
978 # A9MCAwEAAaOCAV4wggFaMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMsR6MrS
979 # tBZYAck3LjMWFrlMmgofMAsGA1UdDwQEAwIBhjASBgkrBgEEAYI3FQEEBQIDAQAB
980 # MCMGCSsGAQQBgjcVAgQWBBT90TFO0yaKleGYYDuoMW+mPLzYLTAZBgkrBgEEAYI3
981 # FAIEDB4KAFMAdQBiAEMAQTAfBgNVHSMEGDAWgBQOrIJgQFYnl+UlE/wq4QpTlVnk
982 # pDBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtp
983 # L2NybC9wcm9kdWN0cy9taWNyb3NvZnRyb290Y2VydC5jcmwwVAYIKwYBBQUHAQEE
984 # SDBGMEQGCCsGAQUFBzAChjhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2Nl
985 # cnRzL01pY3Jvc29mdFJvb3RDZXJ0LmNydDANBgkqhkiG9w0BAQUFAAOCAgEAWTk+
986 # fyZGr+tvQLEytWrrDi9uqEn361917Uw7LddDrQv+y+ktMaMjzHxQmIAhXaw9L0y6
987 # oqhWnONwu7i0+Hm1SXL3PupBf8rhDBdpy6WcIC36C1DEVs0t40rSvHDnqA2iA6VW
988 # 4LiKS1fylUKc8fPv7uOGHzQ8uFaa8FMjhSqkghyT4pQHHfLiTviMocroE6WRTsgb
989 # 0o9ylSpxbZsa+BzwU9ZnzCL/XB3Nooy9J7J5Y1ZEolHN+emjWFbdmwJFRC9f9Nqu
990 # 1IIybvyklRPk62nnqaIsvsgrEA5ljpnb9aL6EiYJZTiU8XofSrvR4Vbo0HiWGFzJ
991 # NRZf3ZMdSY4tvq00RBzuEBUaAF3dNVshzpjHCe6FDoxPbQ4TTj18KUicctHzbMrB
992 # 7HCjV5JXfZSNoBtIA1r3z6NnCnSlNu0tLxfI5nI3EvRvsTxngvlSso0zFmUeDord
993 # EN5k9G/ORtTTF+l5xAS00/ss3x+KnqwK+xMnQK3k+eGpf0a7B2BHZWBATrBC7E7t
994 # s3Z52Ao0CW0cgDEf4g5U3eWh++VHEK1kmP9QFi58vwUheuKVQSdpw5OPlcmN2Jsh
995 # rg1cnPCiroZogwxqLbt2awAdlq3yFnv2FoMkuYjPaqhHMS+a3ONxPdcAfmJH0c6I
996 # ybgY+g5yjcGjPa8CQGr/aZuW4hCoELQ3UAjWwz0wggYHMIID76ADAgECAgphFmg0
997 # AAAAAAAcMA0GCSqGSIb3DQEBBQUAMF8xEzARBgoJkiaJk/IsZAEZFgNjb20xGTAX
998 # BgoJkiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBSb290
999 # IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNzA0MDMxMjUzMDlaFw0yMTA0MDMx
1000 # MzAzMDlaMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
1001 # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xITAf
1002 # BgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQTCCASIwDQYJKoZIhvcNAQEB
1003 # BQADggEPADCCAQoCggEBAJ+hbLHf20iSKnxrLhnhveLjxZlRI1Ctzt0YTiQP7tGn
1004 # 0UytdDAgEesH1VSVFUmUG0KSrphcMCbaAGvoe73siQcP9w4EmPCJzB/LMySHnfL0
1005 # Zxws/HvniB3q506jocEjU8qN+kXPCdBer9CwQgSi+aZsk2fXKNxGU7CG0OUoRi4n
1006 # rIZPVVIM5AMs+2qQkDBuh/NZMJ36ftaXs+ghl3740hPzCLdTbVK0RZCfSABKR2YR
1007 # JylmqJfk0waBSqL5hKcRRxQJgp+E7VV4/gGaHVAIhQAQMEbtt94jRrvELVSfrx54
1008 # QTF3zJvfO4OToWECtR0Nsfz3m7IBziJLVP/5BcPCIAsCAwEAAaOCAaswggGnMA8G
1009 # A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCM0+NlSRnAK7UD7dvuzK7DDNbMPMAsG
1010 # A1UdDwQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADCBmAYDVR0jBIGQMIGNgBQOrIJg
1011 # QFYnl+UlE/wq4QpTlVnkpKFjpGEwXzETMBEGCgmSJomT8ixkARkWA2NvbTEZMBcG
1012 # CgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMkTWljcm9zb2Z0IFJvb3Qg
1013 # Q2VydGlmaWNhdGUgQXV0aG9yaXR5ghB5rRahSqClrUxzWPQHEy5lMFAGA1UdHwRJ
1014 # MEcwRaBDoEGGP2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1
1015 # Y3RzL21pY3Jvc29mdHJvb3RjZXJ0LmNybDBUBggrBgEFBQcBAQRIMEYwRAYIKwYB
1016 # BQUHMAKGOGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljcm9z
1017 # b2Z0Um9vdENlcnQuY3J0MBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEB
1018 # BQUAA4ICAQAQl4rDXANENt3ptK132855UU0BsS50cVttDBOrzr57j7gu1BKijG1i
1019 # uFcCy04gE1CZ3XpA4le7r1iaHOEdAYasu3jyi9DsOwHu4r6PCgXIjUji8FMV3U+r
1020 # kuTnjWrVgMHmlPIGL4UD6ZEqJCJw+/b85HiZLg33B+JwvBhOnY5rCnKVuKE5nGct
1021 # xVEO6mJcPxaYiyA/4gcaMvnMMUp2MT0rcgvI6nA9/4UKE9/CCmGO8Ne4F+tOi3/F
1022 # NSteo7/rvH0LQnvUU3Ih7jDKu3hlXFsBFwoUDtLaFJj1PLlmWLMtL+f5hYbMUVbo
1023 # nXCUbKw5TNT2eb+qGHpiKe+imyk0BncaYsk9Hm0fgvALxyy7z0Oz5fnsfbXjpKh0
1024 # NbhOxXEjEiZ2CzxSjHFaRkMUvLOzsE1nyJ9C/4B5IYCeFTBm6EISXhrIniIh0EPp
1025 # K+m79EjMLNTYMoBMJipIJF9a6lbvpt6Znco6b72BJ3QGEe52Ib+bgsEnVLaxaj2J
1026 # oXZhtG6hE6a/qkfwEm/9ijJssv7fUciMI8lmvZ0dhxJkAj0tr1mPuOQh5bWwymO0
1027 # eFQF1EEuUKyUsKV4q7OglnUa2ZKHE3UiLzKoCG6gW4wlv6DvhMoh1useT8ma7kng
1028 # 9wFlb4kLfchpyOZu6qeXzjEp/w7FW1zYTRuh2Povnj8uVRZryROj/TGCBJcwggST
1029 # AgEBMIGQMHkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
1030 # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xIzAh
1031 # BgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBAhMzAAAAsBGvCovQO5/d
1032 # AAEAAACwMAkGBSsOAwIaBQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
1033 # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFHlP
1034 # wIpDUAGAnbgDrTywRVvTXuBEMFAGCisGAQQBgjcCAQwxQjBAoCKAIABFAG4AdABp
1035 # AHQAeQAgAEYAcgBhAG0AZQB3AG8AcgBroRqAGGh0dHA6Ly9tc2RuLmNvbS9kYXRh
1036 # L2VmIDANBgkqhkiG9w0BAQEFAASCAQBGhre2E1qw0m8EQgJBaVLi6CgwVn7+qSCY
1037 # WqIIcygRNohB5i3zj61/qTEa4DZLc0F3hvGC6aNwwjUbnoU4nZoqOSQgta2DaVul
1038 # uhm7Y+BTZsXvYY9q26UjgUbo1jdBrWelIbu+3YV+pE00UVuV0RabWkEdFBr9HeOV
1039 # nZYczzdVvnYkkkFxO25SVHZWT2nyWhYxMYv+HLoUBND1BmZzNYWnJqegL4BrczNm
1040 # exycbGbRVEO45QOJEK+3vA4o6GKPk09wcFEmkvlncGKTz4fGhYWf5ELykT0TSQuL
1041 # vP1PN35OUNzlpqc2FuWCDosVl8FUhphYXpiw/1sUnI5nPG8aGiUboYICKDCCAiQG
1042 # CSqGSIb3DQEJBjGCAhUwggIRAgEBMIGOMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
1043 # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
1044 # ZnQgQ29ycG9yYXRpb24xITAfBgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD
1045 # QQITMwAAACs5MkjBsslI8wAAAAAAKzAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkD
1046 # MQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTMwOTExMTYwNDU5WjAjBgkq
1047 # hkiG9w0BCQQxFgQU0jwg1lgVl4Ydsz+7YfTew/L6w9EwDQYJKoZIhvcNAQEFBQAE
1048 # ggEAT5kurkrFiaB7YVAWU7VrrXF4Pr9kGEnSMBr0VEfztrVGNOLsdyZYk12tRYnj
1049 # 6MB0x1bajZMYXCj+0Z8oTzaG+JXASkNNIm4uWP1t6TsfixCw9Sr4p4cQUaIXwYj6
1050 # AN+tmLT82knMkW8Q/8lcc8BzfL45pjXonMNCJm3QOUwQ3SqXKgEMTsKLULFvUmsm
1051 # dlwbdl2nlNdNyF5t8NkQZX5NPkpXJ9gdz34XSXPADxBiuE1haiV8ckyfhBIgiq2A
1052 # CM2eGdggysiSVJcQGJ/GzsAsRC89FQQeqcKisHrFz7UOL8oX8ZxJ/7CWHPQUmk/t
1053 # gRpD2K2HFoKdbJziPMLEhoQ5yQ==
1054 # SIG # End signature block