Home | History | Annotate | Download | only in windowsRuntimeInstaller
      1 # Copyright (c) 2015-2016 The Khronos Group Inc.
      2 # Copyright (c) 2015-2016 Valve Corporation
      3 # Copyright (c) 2015-2016 LunarG, Inc.
      4 #
      5 # Permission is hereby granted, free of charge, to any person obtaining a copy
      6 # of this software and/or associated documentation files (the "Materials"), to
      7 # deal in the Materials without restriction, including without limitation the
      8 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      9 # sell copies of the Materials, and to permit persons to whom the Materials are
     10 # furnished to do so, subject to the following conditions:
     11 #
     12 # The above copyright notice(s) and this permission notice shall be included in
     13 # all copies or substantial portions of the Materials.
     14 #
     15 # THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     18 #
     19 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     20 # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     21 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
     22 # USE OR OTHER DEALINGS IN THE MATERIALS.
     23 #
     24 # Author: David Pinedo <david (a] LunarG.com>
     25 # Author: Mark Young <mark (a] LunarG.com>
     26 #
     27 
     28 
     29 # This Powershell script is used by the Vulkan Run Time Installer/Uninstaller to:
     30 #   - Copy the most recent vulkan-<majorabi>-*.dll in C:\Windows\System32
     31 #     to vulkan-<majorabi>.dll
     32 #   - Copy the most recent version of vulkaninfo-<abimajor>-*.exe in
     33 #     C:\Windows\System32 to vulkaninfo.exe
     34 #   - The same thing is done for those files in C:\Windows\SysWOW64 on a 64-bit
     35 #     target.
     36 #   - Set the layer registry entries to point to the layer json files
     37 #     in the Vulkan SDK associated with the most recent vulkan*dll.
     38 #
     39 # This script takes the following parameters:
     40 #   $majorabi : a single string number specifying the major abi version.
     41 #   $ossize     : an integer indicating if the target is a 64 (64) or 32 (32) bit OS.
     42 #
     43 
     44 Param(
     45  [string]$majorabi,
     46  [int]$ossize
     47 )
     48 
     49 $vulkandll = "vulkan-"+$majorabi+".dll"
     50 $windrive  = $env:SYSTEMDRIVE
     51 $winfolder = $env:SYSTEMROOT
     52 $script:VulkanDllList=@()
     53 
     54 function notNumeric ($x) {
     55     try {
     56         0 + $x | Out-Null
     57         return $false
     58     } catch {
     59         return $true
     60     }
     61 }
     62 
     63 # The name of the versioned vulkan dll file is one of the following:
     64 #
     65 #   vulkan-<majorabi>-<major>-<minor>-<patch>-<buildno>-<prerelease>-<prebuildno>
     66 #   vulkan-<majorabi>-<major>-<minor>-<patch>-<buildno>-<prerelease>
     67 #   vulkan-<majorabi>-<major>-<minor>-<patch>-<buildno>-<prebuildno>
     68 #   vulkan-<majorabi>-<major>-<minor>-<patch>-<buildno>.dll
     69 #
     70 # <major>, <minor>, <patch>, <buildno> and <prebuildno> are 1 to 10 numeric digits.
     71 # <prerelease> is any combination of alpha and numeric characters.
     72 # If <prerelease> and/or <prebuildno> are present, this identifies a prerelease,
     73 # and the vulkan dll file will be considered less recent than one with the same
     74 # <major>, <minor>, <patch>, <buildno> numbers without the <prerelease> and/or
     75 # <prebuildno>.
     76 
     77 
     78 # We first create an array, with one array element for each vulkan-*dll in
     79 # C:\Windows\System32 (and C:\Windows\SysWOW64 on 64-bit systems), with each element
     80 # containing:
     81 #    <major>=<minor>=<patch>=<buildno>=<prerelease>=<prebuildno>=
     82 #     filename
     83 #    @<major>@<minor>@<patch>@<buildno>@<prerelease>@<prebuildno>@
     84 # [Note that the above three lines are one element in the array.]
     85 # The build identifiers separated by "=" are suitable for sorting, i.e.
     86 # expanded to 10 digits with leading 0s. If <prerelease> or <prebuildno> are
     87 # not specified, "zzzzzzzzzz" is substituted for them, so that they sort
     88 # to a position after those that do specify them.
     89 # The build identifiers separated by "@" are the original values extracted
     90 # from the file name. They are used later to find the path to the SDK
     91 # install directory for the given filename.
     92 
     93 
     94 function UpdateVulkanSysFolder([string]$dir, [int]$writeSdkName)
     95 {
     96    # Push the current path on the stack and go to $dir
     97    Push-Location -Path $dir
     98 
     99    # Create a list for all the DLLs in the folder.
    100    # First Initialize the list to empty
    101    $script:VulkanDllList = @()
    102 
    103    # Find all DLL objects in this directory
    104    dir -name vulkan-$majorabi-*.dll |
    105    ForEach-Object {
    106        if ($_ -match "=" -or
    107            $_ -match "@" -or
    108            $_ -match " " -or
    109            ($_.Split('-').count -lt 6)  -or
    110            ($_.Split('-').count -gt 8))
    111        {
    112            # If a file name contains "=", "@", or " ", or it contains less then 5 dashes or more than
    113            # 7 dashes, it wasn't installed by the Vulkan Run Time.
    114            # Note that we need to use return inside of ForEach-Object is to continue with iteration.
    115            return
    116        }
    117        $major=$_.Split('-')[2]
    118        $majorOrig=$major
    119        $minor=$_.Split('-')[3]
    120        $minorOrig=$minor
    121        $patch=$_.Split('-')[4]
    122        $patchOrig=$patch
    123        $buildno=$_.Split('-')[5]
    124 
    125        if ($buildno -match ".dll") {
    126           # prerelease and prebuildno are not in the name
    127           # Extract buildno, and set prerelease and prebuildno to "z"s
    128           $buildno=$buildno -replace ".dll",""
    129           $buildnoOrig=$buildno
    130           $prerelease="z"*10
    131           $prereleaseOrig=""
    132           $prebuildno="z"*10
    133           $prebuildnoOrig=""
    134        } else {
    135           # Extract buildno, prerelease, and prebuildno
    136           $f=$_ -replace ".dll",""
    137           $buildno=$f.Split('-')[5]
    138           $buildnoOrig=$buildno
    139           $prerelease=$f.Split('-')[6]
    140           $prebuildno=$f.Split('-')[7]
    141           if ($prebuildno.Length -eq 0) {
    142               if ($prerelease -match "^[0-9]") {
    143                   # prerelease starts with a digit, it must be the prebuildno
    144                   $prebuildno=$prerelease
    145                   $prerelease=""
    146               }
    147           }
    148           $prereleaseOrig=$prerelease
    149           $prebuildnoOrig=$prebuildno
    150 
    151           if ($prerelease.Length -eq 0) {
    152               $prerelease="z"*10
    153           }
    154           if ($prebuildno.Length -eq 0) {
    155               $prebuildno="z"*10
    156           }
    157        }
    158 
    159        # Make sure fields that are supposed to be numbers are numbers
    160        if (notNumeric($major)) {return}
    161        if (notNumeric($minor)) {return}
    162        if (notNumeric($patch)) {return}
    163        if (notNumeric($buildno)) {return}
    164        if (notNumeric($prebuildno)) {
    165            if ($prebuildno -ne "z"*10) {return}
    166        }
    167 
    168        $major = $major.padleft(10,'0')
    169        $minor = $minor.padleft(10,'0')
    170        $patch = $patch.padleft(10,'0')
    171        $buildno = $buildno.padleft(10,'0')
    172        $prerelease = $prerelease.padleft(10,'0')
    173        $prebuildno = $prebuildno.padleft(10,'0')
    174 
    175        # Add a new element to the $VulkanDllList array
    176        $script:VulkanDllList+="$major=$minor=$patch=$buildno=$prerelease=$prebuildno= $_ @$majorOrig@$minorOrig@$patchOrig@$buildnoOrig@$prereleaseOrig@$prebuildnoOrig@"
    177    }
    178 
    179     # If $VulkanDllList contains at least one element, there's at least one vulkan*.dll file.
    180     # Copy the most recent vulkan*.dll (named in the last element of $VulkanDllList) to vulkan-$majorabi.dll.
    181 
    182     if ($script:VulkanDllList.Length -gt 0) {
    183 
    184         # Sort the list. The most recent vulkan-*.dll will be in the last element of the list.
    185         [array]::sort($script:VulkanDllList)
    186 
    187         # Put the name of the most recent vulkan-*.dll in $mrVulkanDLL.
    188         # The most recent vulkanDLL is the second word in the last element of the
    189         # sorted $VulkanDllList. Copy it to $vulkandll.
    190         $mrVulkanDll=$script:VulkanDllList[-1].Split(' ')[1]
    191         copy $mrVulkanDll $vulkandll
    192 
    193         # Copy the most recent version of vulkaninfo-<abimajor>-*.exe to vulkaninfo.exe.
    194         # We create the source file name for the copy from $mrVulkanDll.
    195         $mrVulkaninfo=$mrVulkanDll -replace ".dll",".exe"
    196         $mrVulkaninfo=$mrVulkaninfo -replace "vulkan","vulkaninfo"
    197         copy $mrVulkaninfo vulkaninfo.exe
    198 
    199         # Create the name used in the registry for the SDK associated with $mrVulkanDll.
    200         $major=$script:VulkanDllList[-1].Split('@')[1]
    201         $minor=$script:VulkanDllList[-1].Split('@')[2]
    202         $patch=$script:VulkanDllList[-1].Split('@')[3]
    203         $buildno=$script:VulkanDllList[-1].Split('@')[4]
    204         $prerelease=$script:VulkanDllList[-1].Split('@')[5]
    205         $prebuildno=$script:VulkanDllList[-1].Split('@')[6]
    206 
    207         $sdktempname="VulkanSDK"+$major + "." + $minor + "." + $patch + "." + $buildno
    208         if ($prerelease -ne "") {
    209             $sdktempname=$sdktempname + "." + $prerelease
    210         }
    211         if ($prebuildno -ne "") {
    212             $sdktempname=$sdktempname + "." + $prebuildno
    213         }
    214     }
    215 
    216     # Return to our previous folder
    217     Pop-Location
    218 
    219     # Only update the overall script-scope SDK name if we're told to
    220     if ($writeSdkName -ne 0) {
    221         $script:sdkname = $sdktempname
    222     }
    223 
    224     return
    225 }
    226 
    227 # We only care about SYSWOW64 if we're targeting a 64-bit OS
    228 if ($ossize -eq 64) {
    229     # Update the SYSWOW64 Vulkan DLLS/EXEs
    230     UpdateVulkanSysFolder $winfolder\SYSWOW64 0
    231 }
    232 
    233 # Update the SYSTEM32 Vulkan DLLS/EXEs
    234 UpdateVulkanSysFolder $winfolder\SYSTEM32 1
    235 
    236 # Create an array of vulkan sdk install dirs
    237 
    238 $mrVulkanDllInstallDir=""
    239 $VulkanSdkDirs=@()
    240 Get-ChildItem -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |
    241    ForEach-Object {
    242        $regkey=$_ -replace ".*\\",""
    243        if ($_ -match "\\VulkanSDK") {
    244            # Get the install path from UninstallString
    245            $tmp=Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$regkey -Name UninstallString
    246            $tmp=$tmp -replace "\\Uninstall.exe.*",""
    247            $tmp=$tmp -replace ".*=.",""
    248            $VulkanSdkDirs+=$tmp
    249            if ($regkey -eq $script:sdkname) {
    250                # Save away the sdk install dir for the the most recent vulkandll
    251                $mrVulkanDllInstallDir=$tmp
    252            }
    253        }
    254    }
    255 
    256 
    257 # Search list of sdk install dirs for an sdk compatible with $script:sdkname.
    258 # We go backwards through VulkanDllList to generate SDK names, because we want the most recent SDK.
    259 if ($mrVulkanDllInstallDir -eq "") {
    260     ForEach ($idx in ($script:VulkanDllList.Length-1)..0) {
    261         $vulkanDllMajor=$script:VulkanDllList[$idx].Split('@')[1]
    262         $vulkanDllMinor=$script:VulkanDllList[$idx].Split('@')[2]
    263         $vulkanDllPatch=$script:VulkanDllList[$idx].Split('@')[3]
    264         $vulkanDllBuildno=$script:VulkanDllList[$idx].Split('@')[4]
    265         $vulkanDllPrerelease=$script:VulkanDllList[$idx].Split('@')[5]
    266         $vulkanDllPrebuildno=$script:VulkanDllList[$idx].Split('@')[6]
    267         $regEntry="VulkanSDK"+$vulkanDllMajor+"."+$vulkanDllMinor+"."+$vulkanDllPatch+"."+$vulkanDllBuildno
    268         if ($vulkanDllPrerelease) {
    269             $regEntry=$regEntry+"."+$vulkanDllPrerelease
    270         }
    271         if ($vulkanDllPrebuildno) {
    272             $regEntry=$regEntry+"."+$vulkanDllPrebuildno
    273         }
    274         $rval=Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$regEntry -ErrorAction SilentlyContinue
    275         $instDir=$rval
    276         $instDir=$instDir -replace "\\Uninstall.exe.*",""
    277         $instDir=$instDir -replace ".*=.",""
    278         if ($rval) {
    279             $rval=$rval -replace ".* DisplayVersion=",""
    280             $rval=$rval -replace ";.*",""
    281             $reMajor=$rval.Split('.')[0]
    282             $reMinor=$rval.Split('.')[1]
    283             $rePatch=$rval.Split('.')[2]
    284             if ($reMajor+$reMinor+$rePatch -eq $vulkanDllMajor+$vulkanDllMinor+$vulkanDllPatch) {
    285                 $mrVulkanDllInstallDir=$instDir
    286                 break
    287             }
    288         }
    289     }
    290 }
    291 
    292 # Add C:\Vulkan\SDK\0.9.3 to list of SDK install dirs.
    293 # We do this because there is in a bug in SDK 0.9.3 in which layer
    294 # reg entries were not removed on uninstall. So we'll try to clean up
    295 # and remove them now.
    296 # This works only if 0.9.3 was installed to the default location.
    297 # If it was not installed to the default location, those entries will
    298 # need to be cleaned up manually.
    299 
    300 $VulkanSdkDirs+="C:\VulkanSDK\0.9.3"
    301 $VulkanSdkDirs+="$windrive\VulkanSDK\0.9.3"
    302 
    303 # Remove layer registry entries associated with all installed Vulkan SDKs.
    304 # Note that we remove only those entries created by Vulkan SDKs. If other
    305 # layers were installed that are not from an SDK, we don't mess with them.
    306 
    307 Get-Item -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\ExplicitLayers | Select-Object -ExpandProperty Property |
    308    ForEach-Object {
    309        $regval=$_
    310        ForEach ($sdkdir in $VulkanSdkDirs) {
    311           if ($regval -like "$sdkdir\*.json") {
    312               Remove-ItemProperty -ErrorAction SilentlyContinue -Path HKLM:\SOFTWARE\Khronos\Vulkan\ExplicitLayers -name $regval
    313           }
    314        }
    315    }
    316 # Remove 32-bit layer registry entries if we're targeting a 64-bit OS
    317 if ($ossize -eq 64) {
    318    Get-Item -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Khronos\Vulkan\ExplicitLayers | Select-Object -ExpandProperty Property |
    319       ForEach-Object {
    320           $regval=$_
    321           ForEach ($sdkdir in $VulkanSdkDirs) {
    322              if ($regval -like "$sdkdir\*.json") {
    323                  Remove-ItemProperty -ErrorAction SilentlyContinue -Path HKLM:\SOFTWARE\WOW6432Node\Khronos\Vulkan\ExplicitLayers -name $regval
    324              }
    325           }
    326       }
    327 }
    328 
    329 
    330 # Create layer registry entries associated with Vulkan SDK from which $mrVulkanDll is from
    331 
    332 if ($mrVulkanDllInstallDir -ne "") {
    333     if ($ossize -eq 64) {
    334     
    335         # Create registry entires in normal registry location for 64-bit items on a 64-bit OS
    336         New-Item -Force -ErrorAction SilentlyContinue -Path HKLM:\SOFTWARE\Khronos\Vulkan\ExplicitLayers | out-null
    337         Get-ChildItem $mrVulkanDllInstallDir\Bin -Filter VkLayer*json |
    338            ForEach-Object {
    339                New-ItemProperty -Path HKLM:\SOFTWARE\Khronos\Vulkan\ExplicitLayers -Name $mrVulkanDllInstallDir\Bin\$_ -PropertyType DWord -Value 0 | out-null
    340            }
    341 
    342         # Create registry entires for the WOW6432Node registry location for 32-bit items on a 64-bit OS
    343         New-Item -Force -ErrorAction SilentlyContinue -Path HKLM:\SOFTWARE\WOW6432Node\Khronos\Vulkan\ExplicitLayers | out-null
    344         Get-ChildItem $mrVulkanDllInstallDir\Bin32 -Filter VkLayer*json |
    345            ForEach-Object {
    346                New-ItemProperty -Path HKLM:\SOFTWARE\WOW6432Node\Khronos\Vulkan\ExplicitLayers -Name $mrVulkanDllInstallDir\Bin32\$_ -PropertyType DWord -Value 0 | out-null
    347            }
    348            
    349     } else {
    350     
    351         # Create registry entires in normal registry location for 32-bit items on a 32-bit OS
    352         New-Item -Force -ErrorAction SilentlyContinue -Path HKLM:\SOFTWARE\Khronos\Vulkan\ExplicitLayers | out-null
    353         Get-ChildItem $mrVulkanDllInstallDir\Bin32 -Filter VkLayer*json |
    354            ForEach-Object {
    355                New-ItemProperty -Path HKLM:\SOFTWARE\Khronos\Vulkan\ExplicitLayers -Name $mrVulkanDllInstallDir\Bin32\$_ -PropertyType DWord -Value 0 | out-null
    356            }
    357     
    358     }
    359 }
    360 
    361 # SIG # Begin signature block
    362 # MIIcZgYJKoZIhvcNAQcCoIIcVzCCHFMCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
    363 # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
    364 # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUdeZMvyfevbCm2d9Sn02g0L39
    365 # 6EKggheVMIIFHjCCBAagAwIBAgIQDmYEpPtQ2iBY4vC2AGq6uzANBgkqhkiG9w0B
    366 # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
    367 # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz
    368 # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE1MDQzMDAwMDAwMFoXDTE2MDcw
    369 # NjEyMDAwMFowZTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCENvbG9yYWRvMRUwEwYD
    370 # VQQHEwxGb3J0IENvbGxpbnMxFTATBgNVBAoTDEx1bmFyRywgSW5jLjEVMBMGA1UE
    371 # AxMMTHVuYXJHLCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
    372 # jaLJm/Joxsn/IeopiGY3XPeSZeIhjSjSlQUkDyIyDGcBG7CvfiSsXIw3EgdGkjQg
    373 # yBcW5YsPz9bPGPUjo5go7CwZaRkhW7/LmSkAlx0UAv8EMLuJrAZ3jBNZvpPPqfWd
    374 # zgi/Rkm2gWQ6eSKouy7IjcLk+EwkeBbB+UBnYfMp0BfCPzR3mPgGAJH6efAmEaqQ
    375 # FBCrX97joYgDqp3v8u42jALLl/Ict/GNMHLxP+QWagIHIICCRgS6s02OsildLF6R
    376 # nqJOOG/43f2qUD4Cab65kzlI+0+uQyOl1UlxNxp0XareghGTqECsYA03j64Esxyo
    377 # 2xrNbV2LJm9crTX6QthxywIDAQABo4IBuzCCAbcwHwYDVR0jBBgwFoAUWsS5eyoK
    378 # o6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYEFOSdVsqodGWApfCjHtAcn8sAzLBGMA4G
    379 # A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNVHR8EcDBuMDWg
    380 # M6Axhi9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcx
    381 # LmNybDA1oDOgMYYvaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJl
    382 # ZC1jcy1nMS5jcmwwQgYDVR0gBDswOTA3BglghkgBhv1sAwEwKjAoBggrBgEFBQcC
    383 # ARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBhAYIKwYBBQUHAQEEeDB2
    384 # MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTgYIKwYBBQUH
    385 # MAKGQmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1
    386 # cmVkSURDb2RlU2lnbmluZ0NBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEB
    387 # CwUAA4IBAQCIt1S8zfvzMQEVmdAssjrwqBaq78xhtGPLjkNF06EvtWoV6VMLI/A6
    388 # 45KoULsaXeYuszLxNI+OT/b4HfD0e2LxImaTDZRmCLeIs+2pMLSlWDSV4okm8Vk2
    389 # rObLBlgiI1x0PiMa1le9D832COWM4EJcH7pxM+9JfiHYMLlZbcfNEVgv6Dhhl4MG
    390 # mOTMTl7vQNNQaJ1coNVf9m5Bez1DV9Iu2Cgd8BHp1oLVCQCHjVv0Ifj48RIPi4SQ
    391 # khzalrnrf+L/BWRDhpLnxYasazdV5WfrMHurPuBvYUiLQNkU9SqKgRk9XrzDAfMe
    392 # gPbGybMr0kqtbE/A/cDcTVnvRuTZnhXSMIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1
    393 # U0O1b5VQCDANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM
    394 # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQD
    395 # ExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcN
    396 # MjgxMDIyMTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQg
    397 # SW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2Vy
    398 # dCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0B
    399 # AQEFAAOCAQ8AMIIBCgKCAQEA+NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid
    400 # 2zLXcep2nQUut4/6kkPApfmJ1DcZ17aq8JyGpdglrA55KDp+6dFn08b7KSfH03sj
    401 # lOSRI5aQd4L5oYQjZhJUM1B0sSgmuyRpwsJS8hRniolF1C2ho+mILCCVrhxKhwjf
    402 # DPXiTWAYvqrEsq5wMWYzcT6scKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzL
    403 # fnQ5Ng2Q7+S1TqSp6moKq4TzrGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR
    404 # 93O8vYWxYoNzQYIH5DiLanMg0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckw
    405 # EgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYI
    406 # KwYBBQUHAwMweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
    407 # cC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2lj
    408 # ZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgw
    409 # OqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ
    410 # RFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdp
    411 # Q2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIE
    412 # MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYI
    413 # YIZIAYb9bAMwHQYDVR0OBBYEFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQY
    414 # MBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1a
    415 # JLPzItEVyCx8JSl2qB1dHC06GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew4fbRknUP
    416 # UbRupY5a4l4kgU4QpO4/cY5jDhNLrddfRHnzNhQGivecRk5c/5CxGwcOkRX7uq+1
    417 # UcKNJK4kxscnKqEpKBo6cSgCPC6Ro8AlEeKcFEehemhor5unXCBc2XGxDI+7qPjF
    418 # Emifz0DLQESlE/DmZAwlCEIysjaKJAL+L3J+HNdJRZboWR3p+nRka7LrZkPas7CM
    419 # 1ekN3fYBIM6ZMWM9CBoYs4GbT8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhs
    420 # RDKyZqHnGKSaZFHvMIIGajCCBVKgAwIBAgIQAwGaAjr/WLFr1tXq5hfwZjANBgkq
    421 # hkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
    422 # MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBB
    423 # c3N1cmVkIElEIENBLTEwHhcNMTQxMDIyMDAwMDAwWhcNMjQxMDIyMDAwMDAwWjBH
    424 # MQswCQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNlcnQxJTAjBgNVBAMTHERpZ2lD
    425 # ZXJ0IFRpbWVzdGFtcCBSZXNwb25kZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
    426 # ggEKAoIBAQCjZF38fLPggjXg4PbGKuZJdTvMbuBTqZ8fZFnmfGt/a4ydVfiS457V
    427 # WmNbAklQ2YPOb2bu3cuF6V+l+dSHdIhEOxnJ5fWRn8YUOawk6qhLLJGJzF4o9GS2
    428 # ULf1ErNzlgpno75hn67z/RJ4dQ6mWxT9RSOOhkRVfRiGBYxVh3lIRvfKDo2n3k5f
    429 # 4qi2LVkCYYhhchhoubh87ubnNC8xd4EwH7s2AY3vJ+P3mvBMMWSN4+v6GYeofs/s
    430 # jAw2W3rBerh4x8kGLkYQyI3oBGDbvHN0+k7Y/qpA8bLOcEaD6dpAoVk62RUJV5lW
    431 # MJPzyWHM0AjMa+xiQpGsAsDvpPCJEY93AgMBAAGjggM1MIIDMTAOBgNVHQ8BAf8E
    432 # BAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDCCAb8G
    433 # A1UdIASCAbYwggGyMIIBoQYJYIZIAYb9bAcBMIIBkjAoBggrBgEFBQcCARYcaHR0
    434 # cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCCAWQGCCsGAQUFBwICMIIBVh6CAVIA
    435 # QQBuAHkAIAB1AHMAZQAgAG8AZgAgAHQAaABpAHMAIABDAGUAcgB0AGkAZgBpAGMA
    436 # YQB0AGUAIABjAG8AbgBzAHQAaQB0AHUAdABlAHMAIABhAGMAYwBlAHAAdABhAG4A
    437 # YwBlACAAbwBmACAAdABoAGUAIABEAGkAZwBpAEMAZQByAHQAIABDAFAALwBDAFAA
    438 # UwAgAGEAbgBkACAAdABoAGUAIABSAGUAbAB5AGkAbgBnACAAUABhAHIAdAB5ACAA
    439 # QQBnAHIAZQBlAG0AZQBuAHQAIAB3AGgAaQBjAGgAIABsAGkAbQBpAHQAIABsAGkA
    440 # YQBiAGkAbABpAHQAeQAgAGEAbgBkACAAYQByAGUAIABpAG4AYwBvAHIAcABvAHIA
    441 # YQB0AGUAZAAgAGgAZQByAGUAaQBuACAAYgB5ACAAcgBlAGYAZQByAGUAbgBjAGUA
    442 # LjALBglghkgBhv1sAxUwHwYDVR0jBBgwFoAUFQASKxOYspkH7R7for5XDStnAs0w
    443 # HQYDVR0OBBYEFGFaTSS2STKdSip5GoNL9B6Jwcp9MH0GA1UdHwR2MHQwOKA2oDSG
    444 # Mmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRENBLTEu
    445 # Y3JsMDigNqA0hjJodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1
    446 # cmVkSURDQS0xLmNybDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6
    447 # Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMu
    448 # ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0EtMS5jcnQwDQYJKoZIhvcN
    449 # AQEFBQADggEBAJ0lfhszTbImgVybhs4jIA+Ah+WI//+x1GosMe06FxlxF82pG7xa
    450 # FjkAneNshORaQPveBgGMN/qbsZ0kfv4gpFetW7easGAm6mlXIV00Lx9xsIOUGQVr
    451 # NZAQoHuXx/Y/5+IRQaa9YtnwJz04HShvOlIJ8OxwYtNiS7Dgc6aSwNOOMdgv420X
    452 # Ewbu5AO2FKvzj0OncZ0h3RTKFV2SQdr5D4HRmXQNJsQOfxu19aDxxncGKBXp2JPl
    453 # VRbwuwqrHNtcSCdmyKOLChzlldquxC5ZoGHd2vNtomHpigtt7BIYvfdVVEADkitr
    454 # wlHCCkivsNRu4PQUCjob4489yq9qjXvc2EQwggbNMIIFtaADAgECAhAG/fkDlgOt
    455 # 6gAK6z8nu7obMA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
    456 # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
    457 # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBa
    458 # Fw0yMTExMTAwMDAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
    459 # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD
    460 # ZXJ0IEFzc3VyZWQgSUQgQ0EtMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
    461 # ggEBAOiCLZn5ysJClaWAc0Bw0p5WVFypxNJBBo/JM/xNRZFcgZ/tLJz4FlnfnrUk
    462 # FcKYubR3SdyJxArar8tea+2tsHEx6886QAxGTZPsi3o2CAOrDDT+GEmC/sfHMUiA
    463 # fB6iD5IOUMnGh+s2P9gww/+m9/uizW9zI/6sVgWQ8DIhFonGcIj5BZd9o8dD3QLo
    464 # Oz3tsUGj7T++25VIxO4es/K8DCuZ0MZdEkKB4YNugnM/JksUkK5ZZgrEjb7Szgau
    465 # rYRvSISbT0C58Uzyr5j79s5AXVz2qPEvr+yJIvJrGGWxwXOt1/HYzx4KdFxCuGh+
    466 # t9V3CidWfA9ipD8yFGCV/QcEogkCAwEAAaOCA3owggN2MA4GA1UdDwEB/wQEAwIB
    467 # hjA7BgNVHSUENDAyBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEF
    468 # BQcDBAYIKwYBBQUHAwgwggHSBgNVHSAEggHJMIIBxTCCAbQGCmCGSAGG/WwAAQQw
    469 # ggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9zc2wtY3Bz
    470 # LXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUA
    471 # cwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMA
    472 # bwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYA
    473 # IAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQA
    474 # IAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUA
    475 # bQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkA
    476 # dAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAA
    477 # aABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMAsGCWCGSAGG
    478 # /WwDFTASBgNVHRMBAf8ECDAGAQH/AgEAMHkGCCsGAQUFBwEBBG0wazAkBggrBgEF
    479 # BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRw
    480 # Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0Eu
    481 # Y3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v
    482 # RGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsNC5k
    483 # aWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMB0GA1UdDgQW
    484 # BBQVABIrE5iymQftHt+ivlcNK2cCzTAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
    485 # pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEARlA+ybcoJKc4HbZbKa9Sz1LpMUer
    486 # Vlx71Q0LQbPv7HUfdDjyslxhopyVw1Dkgrkj0bo6hnKtOHisdV0XFzRyR4WUVtHr
    487 # uzaEd8wkpfMEGVWp5+Pnq2LN+4stkMLA0rWUvV5PsQXSDj0aqRRbpoYxYqioM+Sb
    488 # OafE9c4deHaUJXPkKqvPnHZL7V/CSxbkS3BMAIke/MV5vEwSV/5f4R68Al2o/vsH
    489 # OE8Nxl2RuQ9nRc3Wg+3nkg2NsWmMT/tZ4CMP0qquAHzunEIOz5HXJ7cW7g/DvXwK
    490 # oO4sCFWFIrjrGBpN/CohrUkxg0eVd3HcsRtLSxwQnHcUwZ1PL1qVCCkQJjGCBDsw
    491 # ggQ3AgEBMIGGMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx
    492 # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI
    493 # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0ECEA5mBKT7UNogWOLwtgBqursw
    494 # CQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcN
    495 # AQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUw
    496 # IwYJKoZIhvcNAQkEMRYEFCQBfl/Xm3/R6yW/EO6kbSmkdowDMA0GCSqGSIb3DQEB
    497 # AQUABIIBADCbC3HqswOLfqwjX9+TM0hW9sG02WMHPbz0fFBTH5J/tck4wZECl9ct
    498 # DK0pUzHoJBY9EuBnH9OD46MiVCIYwYHQ9w/xiaypUNRbfXYEwSVL9EXCIcYkkqAN
    499 # pSpDrQJu0TzmGyvN1fSvYj/qahvIVKz/cxbzzQbYl4NqNXRfiD26Pa5JOdNABP8g
    500 # WL5Ruk/MPvMJE0dIW3em40hoanGKQhP0xgQ/BGJygumYrZsigENfhQkRVngH/aUP
    501 # f5k78VKL3DFoCMmneIxAfIwspTC37izb/AjlqDNUbqEmfBBIsbLgu6teZVIyPBI/
    502 # nktk5kwOOhzuyeQxLAcn0z+8ToF5frKhggIPMIICCwYJKoZIhvcNAQkGMYIB/DCC
    503 # AfgCAQEwdjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw
    504 # FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBBc3N1
    505 # cmVkIElEIENBLTECEAMBmgI6/1ixa9bV6uYX8GYwCQYFKw4DAhoFAKBdMBgGCSqG
    506 # SIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE2MDMyMjIwMjM0
    507 # N1owIwYJKoZIhvcNAQkEMRYEFM6NeSjPd00j7j25copMrjENL7GXMA0GCSqGSIb3
    508 # DQEBAQUABIIBAHJbUlt2mxIX5hbiigRw3kIoug57G5sDYWQK8rcTjHUif6PAdEqj
    509 # 5c1UhxQHJxEasddUAqbEtCsG8qiz1lq76KKiwaWxffSRQ2JwjYEvnYQ2TK9rtnMs
    510 # zeYnQajrIUP44z7ysqoikB0bEgup0QVDScm4SSa1SmqQzHMsUX5rCygsM3PlpF5K
    511 # dH2u3eSK4zDhGiye6/SQkcddvsI2lLFRcxQIyfUD4+W9oFdXuYkKhNBGPLUlOH9V
    512 # DEDQG9zH6CAzvla/r1iYnX8RZ4rz7yacdrMBq5g92HAEcuXFTBQfaeAZSGQBhNSn
    513 # p1rVWgLb0T3a/5zlOtZvp+bLyDRbms+w8BY=
    514 # SIG # End signature block
    515