FILE: C:\Program Files\IIS\Microsoft Web Deploy V3\Scripts\SetupSiteForPublish.ps1

--
 param( [parameter(Mandatory = $false)] $siteName, [parameter(Mandatory = $false)] $sitePhysicalPath, [parameter(Mandatory = $false)] $siteAppPoolName, [parameter(Mandatory = $false)] [int]$sitePort, [parameter(Mandatory = $false)] $deploymentUserName, [parameter(Mandatory = $false)] $deploymentUserPassword, [parameter(Mandatory = $false)] $managedRunTimeVersion, [parameter(Mandatory = $false)] $publishSettingSavePath, [parameter(Mandatory = $false)] $publishSettingFileName ) Import-LocalizedData -BindingVariable Resources -FileName Resources.psd1 # ================================== #constants $SCRIPTERROR = 0 $WARNING = 1 $INFO = 2 $logfile = ".\HostingLog-$(get-date -format MMddyyHHmmss).log" $template = @" "@ #the order is important. Check for apppool name first. Its possible that #the user gave just a sitename to set permissions. In this case leave apppool emtpy. #else give a default name to the apppool. if(!$siteAppPoolName) { if(!$siteName) { $siteAppPoolName = "WDeployAppPool" } } else { $siteAppPoolName = $siteAppPoolName.Trim() } #now the sitename check. If its empty give it a default name if(!$siteName) { $siteName = "WDeploySite" } else { $siteName = $siteName.Trim() } if(!$sitePhysicalPath) { $sitePhysicalPath = $env:SystemDrive + "\inetpub\WDeploySite" } else { $sitePhysicalPath = $sitePhysicalPath.Trim() } #global variable. Because we need to return two values from MWA from one function. [REF] has bugs. Hence global $global:sitePath = $sitePhysicalPath $global:publishURL = $null # this function does logging function write-log([int]$type, [string]$info){ $message = $info -f $args $logMessage = get-date -format HH:mm:ss Switch($type) { $SCRIPTERROR { $logMessage = $logMessage + "`t" + $Resources.Error + "`t" + $message write-host -foregroundcolor white -backgroundcolor red $logMessage } $WARNING { $logMessage = $logMessage + "`t" + $Resources.Warning + "`t" + $message write-host -foregroundcolor black -backgroundcolor yellow $logMessage } default { $logMessage = $logMessage + "`t" + $Resources.Info + "`t" + $message write-host -foregroundcolor black -backgroundcolor green $logMessage } } $logMessage >> $logfile } function GetPublishSettingSavePath() { if(!$publishSettingFileName) { $publishSettingFileName = "WDeploy.PublishSettings" } if(!$publishSettingSavePath) { $publishSettingSavePath = [System.Environment]::GetFolderPath("Desktop") } if((test-path $publishSettingSavePath) -eq $false) { write-log $SCRIPTERROR $Resources.FailedToAccessScriptsFolder $publishSettingSavePath return $null } return Join-Path $publishSettingSavePath $publishSettingFileName } # returns false if OS is not server SKU function NotServerOS { $sku = $((gwmi win32_operatingsystem).OperatingSystemSKU) $server_skus = @(7,8,9,10,12,13,14,15,17,18,19,20,21,22,23,24,25) return ($server_skus -notcontains $sku) } # gives a user access to an IIS site's scope function GrantAccessToSiteScope($username, $websiteName) { trap [Exception] { write-log $SCRIPTERROR $Resources.FailedToGrantUserAccessToSite $username $websiteName return $false } foreach($mInfo in [Microsoft.Web.Management.Server.ManagementAuthorization]::GetAuthorizedUsers($websiteName, $false, 0,[int]::MaxValue)) { if($mInfo.Name -eq $username) { write-log $INFO $Resources.UserHasAccessToSite $username $websiteName return $true } } [Microsoft.Web.Management.Server.ManagementAuthorization]::Grant($username, $websiteName, $FALSE) | out-null write-log $INFO $Resources.GrantedUserAccessToSite $username $websiteName return $true } # gives a user permissions to a file on disk function GrantPermissionsOnDisk($username, $type, $options) { trap [Exception] { write-log $SCRIPTERROR $Resources.NotGrantedPermissions $type $username $global:sitePath } $acl = (Get-Item $global:sitePath).GetAccessControl("Access") $accessrule = New-Object system.security.AccessControl.FileSystemAccessRule($username, $type, $options, "None", "Allow") $acl.AddAccessRule($accessrule) set-acl -aclobject $acl $global:sitePath write-log $INFO $Resources.GrantedPermissions $type $username $global:sitePath } function AddUser($username, $password) { if(-not (CheckLocalUserExists($username) -eq $true)) { $comp = [adsi] "WinNT://$env:computername,computer" $user = $comp.Create("User", $username) $user.SetPassword($password) $user.SetInfo() write-log $INFO $Resources.CreatedUser $username } } function CheckLocalUserExists($username) { $objComputer = [ADSI]("WinNT://$env:computername") $colUsers = ($objComputer.psbase.children | Where-Object {$_.psBase.schemaClassName -eq "User"} | Select-Object -expand Name) $blnFound = $colUsers -contains $username if ($blnFound) { return $true } else { return $false } } function CheckIfUserIsAdmin($username) { $computer = [ADSI]("WinNT://$env:computername,computer") $group = $computer.psbase.children.find("Administrators") $colMembers = $group.psbase.invoke("Members") | %{$_.GetType().InvokeMember("Name",'GetProperty',$null,$_,$null)} $bIsMember = $colMembers -contains $username if($bIsMember) { return $true } else { return $false } } function CreateLocalUser($username, $password, $isAdmin) { AddUser $username $password if($isAdmin) { if(-not(CheckIfUserIsAdmin($username) -eq $true)) { $group = [ADSI]"WinNT://$env:computername/Administrators,group" $group.add("WinNT://$env:computername/$username") write-log $INFO $Resources.AddedUserAsAdmin $username } else { write-log $INFO $Resources.IsAdmin $username } } return $true } function Initialize { trap [Exception] { write-log $SCRIPTERROR $Resources.CheckIIS7Installed break } $inetsrvPath = ${env:windir} + "\system32\inetsrv\" [System.Reflection.Assembly]::LoadFrom( $inetsrvPath + "Microsoft.Web.Administration.dll" ) > $null [System.Reflection.Assembly]::LoadFrom( $inetsrvPath + "Microsoft.Web.Management.dll" ) > $null } function GetPublicHostname() { $ipProperties = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties() if($ipProperties.DomainName -eq "") { return $ipProperties.HostName } else { return "{0}.{1}" -f $ipProperties.HostName, $ipProperties.DomainName } } function GenerateStrongPassword() { [System.Reflection.Assembly]::LoadWithPartialName("System.Web") > $null return [System.Web.Security.Membership]::GeneratePassword(12,4) } function GetPublishURLFromBindingInfo($bindingInfo, $protocol, $hostname) { $port = 80 trap [Exception] { #return defaults return "http://$hostname" } if(($bindingInfo -match "(.*):(\d*):([^:]*)$") -and ($Matches.Count -eq 4 )) { $port = $Matches[2] $header = $Matches[3] $ipaddress = $Matches[1] if($header) { $hostname = $header } elseif(($ipaddress) -AND (-not($ipaddress -eq "*"))) { $bracketsArray = @('[',']') $hostname = $ipaddress.Trim($bracketsArray) } if(-not($port -eq 80)) { $hostname = $hostname + ":" + $port } } return $protocol + "://" + $hostname } function GetUnusedPortForSiteBinding() { [int[]] $portArray = $null $serverManager = (New-Object Microsoft.Web.Administration.ServerManager) foreach($site in $serverManager.Sites) { foreach($binding in $site.Bindings) { if($binding.IsIPPortHostBinding) { if($binding.Protocol -match "https?") { if(($binding.BindingInformation -match "(.*):(\d*):([^:]*)$") -and ($Matches.Count -eq 4 )) { $portArray = $portArray + $Matches[2] } } } } } if(-not($portArray -eq $null)) { $testPortArray = 8080..8200 foreach($port in $testPortArray) { if($portArray -notcontains $port) { return $port } } } return 8081 #default } function CreateSite($name, $appPoolName, $port, $dotnetVersion) { trap [Exception] { write-log $SCRIPTERROR $Resources.SiteCreationFailed return $false } $hostname = GetPublicHostName $global:publishURL = "http://$hostname" if(-not($port -eq 80)) { $global:publishURL = $global:publishURL + ":" + $port } $configHasChanges = $false $serverManager = (New-Object Microsoft.Web.Administration.ServerManager) #appPool might be empty. WHen the user gave just a site name to #set the permissions on. As long as the sitename is not empty if($appPoolName) { $appPool = $serverManager.ApplicationPools[$appPoolName] if ($appPool -eq $null) { $appPool = $serverManager.ApplicationPools.Add($appPoolName) $appPool.Enable32BitAppOnWin64 = $true if( ($dotnetVersion) -and (CheckVersionWithinAllowedRange $dotnetVersion) ) { $appPool.ManagedRuntimeVersion = $dotnetVersion } $configHasChanges = $true write-log $INFO $Resources.AppPoolCreated $appPoolName } else { write-log $WARNING $Resources.AppPoolExists $appPoolName } } $newSite = $serverManager.Sites[$name] if ($newSite -eq $null) { $newSite = $serverManager.Sites.Add($name,$global:sitePath, $port) if($appPool) { $newSite.Applications[0].ApplicationPoolName = $appPool.Name } if((test-path $global:sitePath) -eq $false) { [System.IO.Directory]::CreateDirectory($global:sitePath) } else { write-log $WARNING $Resources.SiteVirtualDirectoryExists $global:sitePath } $newSite.ServerAutoStart = $true $configHasChanges = $true write-log $INFO $Resources.SiteCreated $name } else { #get virtual directory and siteport $global:sitePath = [System.Environment]::ExpandEnvironmentVariables($newSite.Applications["/"].VirtualDirectories["/"].PhysicalPath) foreach($binding in $newSite.Bindings) { if($binding.IsIPPortHostBinding) { if($binding.Protocol -match "https?") { $global:publishURL = GetPublishURLFromBindingInfo $binding.BindingInformation $binding.Protocol $hostname } } } if($appPoolName) { if (-not($newSite.Applications[0].ApplicationPoolName -eq $appPool.Name )) { $newSite.Applications[0].ApplicationPoolName = $appPool.Name $configHasChanges = $true write-log $INFO $Resources.SiteAppPoolUpdated $name $appPoolName } else { write-log $INFO $Resources.SiteExists $name $appPoolName } } else { write-log $INFO $Resources.SiteExists $name $newSite.Applications[0].ApplicationPoolName } } if ($configHasChanges) { $serverManager.CommitChanges() } return $true } function CheckUserViaLogon($username, $password) { $signature = @' [DllImport("advapi32.dll")] public static extern int LogonUser( string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); '@ $type = Add-Type -MemberDefinition $signature -Name Win32Utils -Namespace LogOnUser -PassThru [IntPtr]$token = [IntPtr]::Zero $value = $type::LogOnUser($username, $env:computername, $password, 2, 0, [ref] $token) if($value -eq 0) { return $false } return $true } function CheckUsernamePasswordCombination($user, $password) { if(($user) -AND ($password)) { if(CheckLocalUserExists($user) -eq $true) { if(CheckUserViaLogon $user $password) { return $true } else { write-Log $SCRIPTERROR $Resources.FailedToValidateUserWithSpecifiedPassword $user return $false } } } return $true } function CreateProfileXml([string]$nameofSite, [string]$username, $password, [string]$hostname, $pathToSaveFile) { trap [Exception] { write-log $SCRIPTERROR $Resources.FailedToWritePublishSettingsFile $pathToSaveFile return } $xml = New-Object xml if(Test-Path $pathToSaveFile) { $xml.Load($pathToSaveFile) } else { $xml.LoadXml($template) } $newProfile = (@($xml.publishData.publishProfile)[0]) $newProfile.publishUrl = $hostname $newProfile.msdeploySite = $nameofSite $newProfile.destinationAppUrl = $global:publishURL.ToString() $newProfile.userName = $username if(-not ($password -eq $null)) { $newProfile.userPWD = $password.ToString() } else { write-log $WARNING $Resources.NoPasswordForExistingUserForPublish } $xml.Save($pathToSaveFile) write-log $INFO $Resources.SavingPublishXmlToPath $pathToSaveFile } function CheckVersionWithinAllowedRange($managedVersion) { trap [Exception] { return $false } $KeyPath = "HKLM:\Software\Microsoft\.NETFramework" $key = Get-ItemProperty -path $KeyPath $path = $key.InstallRoot $files = [System.IO.Directory]::GetFiles($path, "mscorlib.dll", [System.IO.SearchOption]::AllDirectories) foreach($file in $files) { if($file -match "\\(v\d\.\d).\d*\\") { if($Matches[1] -eq $managedVersion) { return $true } } } return $false } #================= Main Script ================= if(NotServerOS) { write-log $SCRIPTERROR $Resources.NotServerOS break } Initialize if(CheckUsernamePasswordCombination $deploymentUserName $deploymentUserPassword) { if(!$sitePort) { $sitePort = GetUnusedPortForSiteBinding } if(CreateSite $siteName $siteAppPoolName $sitePort $managedRunTimeVersion) { if(!$deploymentUserName) { $idx = $siteName.IndexOf(' ') if( ($idx -gt 0) -or ($siteName.Length -gt 16)) { $deploymentUserName = "WDeployuser" } else { $deploymentUserName = $siteName + "user" } } if( (CheckLocalUserExists($deploymentUserName) -eq $true)) { $deploymentUserPassword = $null } else { if(!$deploymentUserPassword) { $deploymentUserPassword = GenerateStrongPassword } } if(CreateLocalUser $deploymentUserName $deploymentUserPassword $false) { GrantPermissionsOnDisk $deploymentUserName "FullControl" "ContainerInherit,ObjectInherit" if(GrantAccessToSiteScope ($env:computername + "\" + $deploymentUserName) $siteName) { $hostname = GetPublicHostName $savePath = GetPublishSettingSavePath if($savePath) { CreateProfileXml $siteName $deploymentUserName $deploymentUserPassword $hostname $savePath } } } } } # SIG # Begin signature block # MIIdhQYJKoZIhvcNAQcCoIIddjCCHXICAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU4AUtviQq7SNFU/aDJqnC6g+j # QX6gghhlMIIEwzCCA6ugAwIBAgITMwAAAMp9MhZ8fv0FAwAAAAAAyjANBgkqhkiG # 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTYwOTA3MTc1ODU1 # WhcNMTgwOTA3MTc1ODU1WjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw # b3JhdGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNO # OjcyOEQtQzQ1Ri1GOUVCMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT # ZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj3CeDl2ll7S4 # 96ityzOt4bkPI1FucwjpTvklJZLOYljFyIGs/LLi6HyH+Czg8Xd/oDQYFzmJTWac # A0flGdvk8Yj5OLMEH4yPFFgQsZA5Wfnz/Cg5WYR2gmsFRUFELCyCbO58DvzOQQt1 # k/tsTJ5Ns5DfgCb5e31m95yiI44v23FVpKnTY9CUJbIr8j28O3biAhrvrVxI57GZ # nzkUM8GPQ03o0NGCY1UEpe7UjY22XL2Uq816r0jnKtErcNqIgglXIurJF9QFJrvw # uvMbRjeTBTCt5o12D4b7a7oFmQEDgg+koAY5TX+ZcLVksdgPNwbidprgEfPykXiG # ATSQlFCEXwIDAQABo4IBCTCCAQUwHQYDVR0OBBYEFGb30hxaE8ox6QInbJZnmt6n # G7LKMB8GA1UdIwQYMBaAFCM0+NlSRnAK7UD7dvuzK7DDNbMPMFQGA1UdHwRNMEsw # SaBHoEWGQ2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3Rz # L01pY3Jvc29mdFRpbWVTdGFtcFBDQS5jcmwwWAYIKwYBBQUHAQEETDBKMEgGCCsG # AQUFBzAChjxodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jv # c29mdFRpbWVTdGFtcFBDQS5jcnQwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZI # hvcNAQEFBQADggEBAGyg/1zQebvX564G4LsdYjFr9ptnqO4KaD0lnYBECEjMqdBM # 4t+rNhN38qGgERoc+ns5QEGrrtcIW30dvMvtGaeQww5sFcAonUCOs3OHR05QII6R # XYbxtAMyniTUPwacJiiCSeA06tLg1bebsrIY569mRQHSOgqzaO52EzJlOtdLrGDk # Ot1/eu8E2zN9/xetZm16wLJVCJMb3MKosVFjFZ7OlClFTPk6rGyN9jfbKKDsDtNr # jfAiZGVhxrEqMiYkj4S4OyvJ2uhw/ap7dbotTCfZu1yO57SU8rE06K6j8zWB5L9u # DmtgcqXg3ckGvdmWVWBrcWgnmqNMYgX50XSzffQwggYHMIID76ADAgECAgphFmg0 # AAAAAAAcMA0GCSqGSIb3DQEBBQUAMF8xEzARBgoJkiaJk/IsZAEZFgNjb20xGTAX # BgoJkiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBSb290 # IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNzA0MDMxMjUzMDlaFw0yMTA0MDMx # MzAzMDlaMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xITAf # BgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQTCCASIwDQYJKoZIhvcNAQEB # BQADggEPADCCAQoCggEBAJ+hbLHf20iSKnxrLhnhveLjxZlRI1Ctzt0YTiQP7tGn # 0UytdDAgEesH1VSVFUmUG0KSrphcMCbaAGvoe73siQcP9w4EmPCJzB/LMySHnfL0 # Zxws/HvniB3q506jocEjU8qN+kXPCdBer9CwQgSi+aZsk2fXKNxGU7CG0OUoRi4n # rIZPVVIM5AMs+2qQkDBuh/NZMJ36ftaXs+ghl3740hPzCLdTbVK0RZCfSABKR2YR # JylmqJfk0waBSqL5hKcRRxQJgp+E7VV4/gGaHVAIhQAQMEbtt94jRrvELVSfrx54 # QTF3zJvfO4OToWECtR0Nsfz3m7IBziJLVP/5BcPCIAsCAwEAAaOCAaswggGnMA8G # A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCM0+NlSRnAK7UD7dvuzK7DDNbMPMAsG # A1UdDwQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADCBmAYDVR0jBIGQMIGNgBQOrIJg # QFYnl+UlE/wq4QpTlVnkpKFjpGEwXzETMBEGCgmSJomT8ixkARkWA2NvbTEZMBcG # CgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMkTWljcm9zb2Z0IFJvb3Qg # Q2VydGlmaWNhdGUgQXV0aG9yaXR5ghB5rRahSqClrUxzWPQHEy5lMFAGA1UdHwRJ # MEcwRaBDoEGGP2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1 # Y3RzL21pY3Jvc29mdHJvb3RjZXJ0LmNybDBUBggrBgEFBQcBAQRIMEYwRAYIKwYB # BQUHMAKGOGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljcm9z # b2Z0Um9vdENlcnQuY3J0MBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEB # BQUAA4ICAQAQl4rDXANENt3ptK132855UU0BsS50cVttDBOrzr57j7gu1BKijG1i # uFcCy04gE1CZ3XpA4le7r1iaHOEdAYasu3jyi9DsOwHu4r6PCgXIjUji8FMV3U+r # kuTnjWrVgMHmlPIGL4UD6ZEqJCJw+/b85HiZLg33B+JwvBhOnY5rCnKVuKE5nGct # xVEO6mJcPxaYiyA/4gcaMvnMMUp2MT0rcgvI6nA9/4UKE9/CCmGO8Ne4F+tOi3/F # NSteo7/rvH0LQnvUU3Ih7jDKu3hlXFsBFwoUDtLaFJj1PLlmWLMtL+f5hYbMUVbo # nXCUbKw5TNT2eb+qGHpiKe+imyk0BncaYsk9Hm0fgvALxyy7z0Oz5fnsfbXjpKh0 # NbhOxXEjEiZ2CzxSjHFaRkMUvLOzsE1nyJ9C/4B5IYCeFTBm6EISXhrIniIh0EPp # K+m79EjMLNTYMoBMJipIJF9a6lbvpt6Znco6b72BJ3QGEe52Ib+bgsEnVLaxaj2J # oXZhtG6hE6a/qkfwEm/9ijJssv7fUciMI8lmvZ0dhxJkAj0tr1mPuOQh5bWwymO0 # eFQF1EEuUKyUsKV4q7OglnUa2ZKHE3UiLzKoCG6gW4wlv6DvhMoh1useT8ma7kng # 9wFlb4kLfchpyOZu6qeXzjEp/w7FW1zYTRuh2Povnj8uVRZryROj/TCCBhEwggP5 # oAMCAQICEzMAAACOh5GkVxpfyj4AAAAAAI4wDQYJKoZIhvcNAQELBQAwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMTAeFw0xNjExMTcyMjA5MjFaFw0xODAy # MTcyMjA5MjFaMIGDMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ # MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u # MQ0wCwYDVQQLEwRNT1BSMR4wHAYDVQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24w # ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQh9RCK36d2cZ61KLD4xWS # 0lOdlRfJUjb6VL+rEK/pyefMJlPDwnO/bdYA5QDc6WpnNDD2Fhe0AaWVfIu5pCzm # izt59iMMeY/zUt9AARzCxgOd61nPc+nYcTmb8M4lWS3SyVsK737WMg5ddBIE7J4E # U6ZrAmf4TVmLd+ArIeDvwKRFEs8DewPGOcPUItxVXHdC/5yy5VVnaLotdmp/ZlNH # 1UcKzDjejXuXGX2C0Cb4pY7lofBeZBDk+esnxvLgCNAN8mfA2PIv+4naFfmuDz4A # lwfRCz5w1HercnhBmAe4F8yisV/svfNQZ6PXlPDSi1WPU6aVk+ayZs/JN2jkY8fP # AgMBAAGjggGAMIIBfDAfBgNVHSUEGDAWBgorBgEEAYI3TAgBBggrBgEFBQcDAzAd # BgNVHQ4EFgQUq8jW7bIV0qqO8cztbDj3RUrQirswUgYDVR0RBEswSaRHMEUxDTAL # BgNVBAsTBE1PUFIxNDAyBgNVBAUTKzIzMDAxMitiMDUwYzZlNy03NjQxLTQ0MWYt # YmM0YS00MzQ4MWU0MTVkMDgwHwYDVR0jBBgwFoAUSG5k5VAF04KqFzc3IrVtqMp1 # ApUwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3Br # aW9wcy9jcmwvTWljQ29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNybDBhBggrBgEF # BQcBAQRVMFMwUQYIKwYBBQUHMAKGRWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w # a2lvcHMvY2VydHMvTWljQ29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNydDAMBgNV # HRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQBEiQKsaVPzxLa71IxgU+fKbKhJ # aWa+pZpBmTrYndJXAlFq+r+bltumJn0JVujc7SV1eqVHUqgeSxZT8+4PmsMElSnB # goSkVjH8oIqRlbW/Ws6pAR9kRqHmyvHXdHu/kghRXnwzAl5RO5vl2C5fAkwJnBpD # 2nHt5Nnnotp0LBet5Qy1GPVUCdS+HHPNIHuk+sjb2Ns6rvqQxaO9lWWuRi1XKVjW # kvBs2mPxjzOifjh2Xt3zNe2smjtigdBOGXxIfLALjzjMLbzVOWWplcED4pLJuavS # Vwqq3FILLlYno+KYl1eOvKlZbiSSjoLiCXOC2TWDzJ9/0QSOiLjimoNYsNSa5jH6 # lEeOfabiTnnz2NNqMxZQcPFCu5gJ6f/MlVVbCL+SUqgIxPHo8f9A1/maNp39upCF # 0lU+UK1GH+8lDLieOkgEY+94mKJdAw0C2Nwgq+ZWtd7vFmbD11WCHk+CeMmeVBoQ # YLcXq0ATka6wGcGaM53uMnLNZcxPRpgtD1FgHnz7/tvoB3kH96EzOP4JmtuPe7Y6 # vYWGuMy8fQEwt3sdqV0bvcxNF/duRzPVQN9qyi5RuLW5z8ME0zvl4+kQjOunut6k # LjNqKS8USuoewSI4NQWF78IEAA1rwdiWFEgVr35SsLhgxFK1SoK3hSoASSomgyda # Qd691WZJvAuceHAJvDCCB3owggVioAMCAQICCmEOkNIAAAAAAAMwDQYJKoZIhvcN # AQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAw # BgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEx # MB4XDTExMDcwODIwNTkwOVoXDTI2MDcwODIxMDkwOVowfjELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUg # U2lnbmluZyBQQ0EgMjAxMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB # AKvw+nIQHC6t2G6qghBNNLrytlghn0IbKmvpWlCquAY4GgRJun/DDB7dN2vGEtgL # 8DjCmQawyDnVARQxQtOJDXlkh36UYCRsr55JnOloXtLfm1OyCizDr9mpK656Ca/X # llnKYBoF6WZ26DJSJhIv56sIUM+zRLdd2MQuA3WraPPLbfM6XKEW9Ea64DhkrG5k # NXimoGMPLdNAk/jj3gcN1Vx5pUkp5w2+oBN3vpQ97/vjK1oQH01WKKJ6cuASOrdJ # Xtjt7UORg9l7snuGG9k+sYxd6IlPhBryoS9Z5JA7La4zWMW3Pv4y07MDPbGyr5I4 # ftKdgCz1TlaRITUlwzluZH9TupwPrRkjhMv0ugOGjfdf8NBSv4yUh7zAIXQlXxgo # tswnKDglmDlKNs98sZKuHCOnqWbsYR9q4ShJnV+I4iVd0yFLPlLEtVc/JAPw0Xpb # L9Uj43BdD1FGd7P4AOG8rAKCX9vAFbO9G9RVS+c5oQ/pI0m8GLhEfEXkwcNyeuBy # 5yTfv0aZxe/CHFfbg43sTUkwp6uO3+xbn6/83bBm4sGXgXvt1u1L50kppxMopqd9 # Z4DmimJ4X7IvhNdXnFy/dygo8e1twyiPLI9AN0/B4YVEicQJTMXUpUMvdJX3bvh4 # IFgsE11glZo+TzOE2rCIF96eTvSWsLxGoGyY0uDWiIwLAgMBAAGjggHtMIIB6TAQ # BgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUSG5k5VAF04KqFzc3IrVtqMp1ApUw # GQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB # /wQFMAMBAf8wHwYDVR0jBBgwFoAUci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0f # BFMwUTBPoE2gS4ZJaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJv # ZHVjdHMvTWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcB # AQRSMFAwTgYIKwYBBQUHMAKGQmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kv # Y2VydHMvTWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNydDCBnwYDVR0gBIGX # MIGUMIGRBgkrBgEEAYI3LgMwgYMwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj # cm9zb2Z0LmNvbS9wa2lvcHMvZG9jcy9wcmltYXJ5Y3BzLmh0bTBABggrBgEFBQcC # AjA0HjIgHQBMAGUAZwBhAGwAXwBwAG8AbABpAGMAeQBfAHMAdABhAHQAZQBtAGUA # bgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAZ/KGpZjgVHkaLtPYdGcimwuWEeFj # kplCln3SeQyQwWVfLiw++MNy0W2D/r4/6ArKO79HqaPzadtjvyI1pZddZYSQfYtG # UFXYDJJ80hpLHPM8QotS0LD9a+M+By4pm+Y9G6XUtR13lDni6WTJRD14eiPzE32m # kHSDjfTLJgJGKsKKELukqQUMm+1o+mgulaAqPyprWEljHwlpblqYluSD9MCP80Yr # 3vw70L01724lruWvJ+3Q3fMOr5kol5hNDj0L8giJ1h/DMhji8MUtzluetEk5CsYK # wsatruWy2dsViFFFWDgycScaf7H0J/jeLDogaZiyWYlobm+nt3TDQAUGpgEqKD6C # PxNNZgvAs0314Y9/HG8VfUWnduVAKmWjw11SYobDHWM2l4bf2vP48hahmifhzaWX # 0O5dY0HjWwechz4GdwbRBrF1HxS+YWG18NzGGwS+30HHDiju3mUv7Jf2oVyW2ADW # oUa9WfOXpQlLSBCZgB/QACnFsZulP0V3HjXG0qKin3p6IvpIlR+r+0cjgPWe+L9r # t0uX4ut1eBrs6jeZeRhL/9azI2h15q/6/IvrC4DqaTuv/DDtBEyO3991bWORPdGd # Vk5Pv4BXIqF4ETIheu9BCrE/+6jMpF3BoYibV3FWTkhFwELJm3ZbCoBIa/15n8G9 # bW1qyVJzEw16UM0xggSKMIIEhgIBATCBlTB+MQswCQYDVQQGEwJVUzETMBEGA1UE # CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z # b2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5n # IFBDQSAyMDExAhMzAAAAjoeRpFcaX8o+AAAAAACOMAkGBSsOAwIaBQCggZ4wGQYJ # KoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQB # gjcCARUwIwYJKoZIhvcNAQkEMRYEFEUMF5prSvgmieyveBSCFo1x/0mtMD4GCisG # AQQBgjcCAQwxMDAuoBaAFABXAGUAYgAgAEQAZQBwAGwAbwB5oRSAEmh0dHA6Ly93 # d3cuaWlzLm5ldDANBgkqhkiG9w0BAQEFAASCAQBHzXW4UeIl+Gfj4qA43uINE+cA # zald/rSVSTUm3T56kBMDGyiOjQsnqKvJoSNXhfEOmqzj6fCaaU2kKzsuBTU3lhoZ # V9ZVkei+ibIhHCFKgIAMSK+IfPAGSCgHTNdY79p7lx7Z9m/tRBbo2BUv5sVPIrpB # 684Vw3Z2BcGRDIk8ui4trIIulxAkH+19Ot0kM/lAOpDZYNTe7GtfOe5ZnqqQY/+I # efhUgrFZHTup59x9gNWRdCYkOVBqGl3O+14BYFvWj1TZgLclEbVQBZ/ooDQqn9yy # faFozhnSJj2P+MEgulLs94gtacYBR1RuhEMGmOP35TXplM+m6h42wVrZsN91oYIC # KDCCAiQGCSqGSIb3DQEJBjGCAhUwggIRAgEBMIGOMHcxCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xITAfBgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0 # YW1wIFBDQQITMwAAAMp9MhZ8fv0FAwAAAAAAyjAJBgUrDgMCGgUAoF0wGAYJKoZI # hvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTcwNDI4MDExNTAz # WjAjBgkqhkiG9w0BCQQxFgQUrofrE8/aSiUlnEdo40IAKhNkk30wDQYJKoZIhvcN # AQEFBQAEggEAIYnJGVZHpdoXO17y3H+PxB1o7C4PmffFqPD5qRnuTzw6RiyFMzBr # sSnZhI7YTHkMmk7MlchegKohZ8Ipfcncq1k1h9AlyLJqpxI7qs8yobqaAAn5IIns # XgsWVe47ZWluX57B4bFgJWOTuHsuXMqSYDHv6Dr4YaEwY7zntUww9AyIhwl+1lKS # WzlZk2hbcri7xB+qHmx7l2wbuerQRqvhrWB0pZx71NFGdx0M/2xyCg42iYmJEbrM # k7EsJb8Mt77k2K8FrlZ99TFJN6KIxZl672NeFRmboo+kTjlzwdJ5GVR3kjcmUKfs # cNo23hNAGeSwhAW0kJeq0YSZcpAXFZLWpA== # SIG # End signature block
--