Export.psm1
#----------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. #----------------------------------------------------------------------- # .EXTERNALHELP Export.psm1-Help.xml function Export-AzsMarketplaceItem { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string[]] $ProductId, [Parameter(Mandatory = $true)] [string] $RepositoryDir, [Parameter(Mandatory = $false)] [string] $JournalDir, [Parameter(Mandatory = $false)] [switch] $IgnoreDependencies, [Parameter(Mandatory = $false)] [switch] $AcceptLegalTerms, [Parameter(Mandatory = $false)] [ValidateSet('Resolve', 'Download', 'Cleanup')] [string] $From = 'Resolve', [Parameter(Mandatory = $false)] [ValidateSet('Resolve', 'Download', 'Cleanup')] [string] $UpTo = 'Cleanup', [Parameter(Mandatory = $false)] [ValidateRange(5, 60)] [int] $SleepInterval = 60 ) begin { $productQueue = [System.Collections.Queue]::new() } process { $ProductId | ForEach-Object { $productQueue.Enqueue($_) } } end { function Resolve-AllProducts { param () function Resolve-ProductDetails { param ( [ValidateNotNullOrEmpty()] [string] $ProductId ) $productName = $ProductId.Split('/')[-1] Start-Activity "Resolve-ProductDetails, productName: $ProductName" try { $productDetailsDir = "$RepositoryDir\$productName" $productDetailsFileName = "$productDetailsDir\productDetails.json" if (Test-Path -Path $productDetailsFileName) { Write-Verbose "Retriving product details from cache: $ProductName" -Verbose $productDetails = Get-Content -Path $productDetailsFileName -Raw | ConvertFrom-Json if (-not (Test-IsStale -ProductDetails $productDetails)) { return $productDetails } Write-Verbose "Product details is stale: $ProductName" -Verbose } Write-Verbose "Retriving details from the Cloud: $ProductName" -Verbose $productDetails = Get-ProductDetails -ProductName $productName -ProductId $ProductId if ($productDetails.Properties.legalTerms -and -not $AcceptLegalTerms.ToBool()) { Display-LegalTerms -ProductDetails $productDetails } New-Item -Path $productDetailsDir -ItemType Directory -Force | Out-Null $productDetails | ConvertTo-Json -Depth 99 | Set-Content -LiteralPath $productDetailsFileName -Encoding UTF8 return $productDetails } finally { Stop-Activity } } function Test-IsStale { param ( [ValidateNotNull()] [psobject] $ProductDetails ) $timestamp = [datetime]::ParseExact($ProductDetails.Timestamp, 'o', [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::AdjustToUniversal) if ([datetime]::UtcNow - $timestamp -gt [timespan]::FromDays(1)) { return $true } return $false } function Get-ProductDetails { param ( [ValidateNotNullOrEmpty()] [string] $ProductName, [ValidateNotNullOrEmpty()] [string] $ProductId ) $productDetails = [psobject]::new() $productDetails | Add-Member -MemberType NoteProperty -Name 'ProductName' -Value $ProductName $productDetails | Add-Member -MemberType NoteProperty -Name 'Timestamp' -Value ([datetime]::UtcNow.ToString('o')) $resourceDefinition = Get-AzResource -ResourceId $ProductId -ApiVersion 2016-01-01 $productDetails | Add-Member -MemberType NoteProperty -Name 'ResourceId' -Value $resourceDefinition.ResourceId $productDetails | Add-Member -MemberType NoteProperty -Name 'Properties' -Value $resourceDefinition.Properties $details = Invoke-AzResourceAction -ResourceId $ProductId -Action listDetails -ApiVersion 2016-01-01 -Force $productDetails | Add-Member -MemberType NoteProperty -Name 'Details' -Value $details $artifacts = Get-ProductArtifacts -ProductDetails $productDetails $productDetails | Add-Member -MemberType NoteProperty -Name 'Artifacts' -Value $artifacts return $productDetails } function Get-ProductArtifacts { param ( [ValidateNotNull()] [psobject] $ProductDetails ) $artifacts = @() if ($ProductDetails.Properties.iconUris.hero) { $artifacts += New-ArtifactDescriptor -SourceUri $ProductDetails.Properties.iconUris.hero -Type Icon -RelativeDir 'icons\hero' } if ($ProductDetails.Properties.iconUris.large) { $artifacts += New-ArtifactDescriptor -SourceUri $ProductDetails.Properties.iconUris.large -Type Icon -RelativeDir 'icons\large' } if ($ProductDetails.Properties.iconUris.medium) { $artifacts += New-ArtifactDescriptor -SourceUri $ProductDetails.Properties.iconUris.medium -Type Icon -RelativeDir 'icons\medium' } if ($ProductDetails.Properties.iconUris.small) { $artifacts += New-ArtifactDescriptor -SourceUri $ProductDetails.Properties.iconUris.small -Type Icon -RelativeDir 'icons\small' } if ($ProductDetails.Properties.iconUris.wide) { $artifacts += New-ArtifactDescriptor -SourceUri $ProductDetails.Properties.iconUris.wide -Type Icon -RelativeDir 'icons\wide' } if ($ProductDetails.Properties.galleryItemIdentity) { $artifacts += New-ArtifactDescriptor -SourceUri $ProductDetails.Details.galleryPackageBlobSasUri -Type GalleryPackage -RelativeDir 'galleryPackage' } $productKind = $ProductDetails.Properties.productKind switch ($productKind) { { $_ -eq 'VirtualMachine'} { $artifacts += New-ArtifactDescriptor -SourceUri $ProductDetails.Details.properties.osDiskImage.sourceBlobSasUri -Type VMDiskImage -RelativeDir 'osDiskImage' foreach ($dataDiskImage in $ProductDetails.Details.properties.dataDiskImages) { $artifacts += New-ArtifactDescriptor -SourceUri $dataDiskImage.sourceBlobSasUri -Type VMDiskImage -RelativeDir "dataDiskImages\$($dataDiskImage.lun)" } break } { $_ -eq 'VirtualMachineExtension' } { $artifacts += New-ArtifactDescriptor -SourceUri $ProductDetails.Details.properties.sourceBlob.uri -Type VMExtensionPackage -RelativeDir 'extension' break } { $_ -eq 'ResourceProvider' -or $_ -eq 'Solution'} { foreach ($fileContainer in $ProductDetails.Details.properties.fileContainers) { $artifacts += New-ArtifactDescriptor -SourceUri $fileContainer.sourceUri -Type FileContainer -RelativeDir ([System.IO.Path]::Combine('fileContainers', $fileContainer.id)) } break } default { throw "Product kind '$productKind' is invalid or not supported." } } return $artifacts } function New-ArtifactDescriptor { param ( [ValidateNotNullOrEmpty()] [string] $SourceUri, [ValidateSet('Icon', 'GalleryPackage', 'VMDiskImage', 'VMExtensionPackage', 'FileContainer')] [string] $Type, [ValidateNotNullOrEmpty()] [string] $RelativeDir ) $fileName = [System.IO.Path]::GetFileName([uri]::new($SourceUri, [System.UriKind]::Absolute).AbsolutePath) if ([string]::IsNullOrEmpty($fileName)) { throw "Unable to resolve file name, sourceUri: '$SourceUri'." } $artifact = [psobject]::new() $artifact | Add-Member -MemberType NoteProperty -Name SourceUri -Value $SourceUri $artifact | Add-Member -MemberType NoteProperty -Name Type -Value $Type $artifact | Add-Member -MemberType NoteProperty -Name RelativeFileName -Value ([System.IO.Path]::Combine($RelativeDir, $fileName)) return $artifact } function New-DependentProductId { param ( [ValidateNotNullOrEmpty()] [string] $OriginalProductId, [ValidateNotNullOrEmpty()] [string] $DependentProductName ) $segments = $OriginalProductId.Split('/') $segments[-1] = $DependentProductName return $segments -join '/' } function Display-LegalTerms { param ( [ValidateNotNull()] [psobject] $ProductDetails ) Write-Host "------- Legal Terms: $($productDetails.Properties.displayName)" -ForegroundColor DarkYellow Write-Host $productDetails.Properties.legalTerms -ForegroundColor DarkYellow Write-Host '-------' -ForegroundColor DarkYellow while ($true) { $result = Read-Host -Prompt 'Accept Legal Terms (Y/N)?' if ($result -eq 'Y') { break } if ($result -eq 'N') { throw 'You must accept Legal Terms to download this software.' } } } #----------------------------------------------------------------------- Start-Activity 'Resolve-AllProducts' $processedIds = @{} $productNames = @() while ($productQueue.Count -gt 0) { $productId = $productQueue.Dequeue() if ($processedIds.ContainsKey($productId)) { continue } $productDetails = Resolve-ProductDetails -ProductId $productId $processedIds.Add($productId, $true) $productNames += $productDetails.ProductName if (-not $IgnoreDependencies.ToBool()) { if ($productDetails.Details.properties.dependentProducts) { foreach ($dependentProductName in $productDetails.Details.properties.dependentProducts) { $productQueue.Enqueue((New-DependentProductId -OriginalProductId $productId -DependentProductName $dependentProductName)) } } } } @{ productNames = $productNames } | ConvertTo-Json -Depth 99 | Set-Content -LiteralPath "$JournalDir\.download-info.json" -Encoding UTF8 Stop-Activity } #----------------------------------------------------------------------- function Download-AllProducts { param () Start-Activity 'Download-AllProducts' while ($true) { & "$PSScriptRoot\SyndicationClient.exe" download $RepositoryDir $JournalDir if ($LASTEXITCODE -eq 0) { break } Write-Verbose "Sleep for $SleepInterval seconds" -Verbose Start-Sleep -Seconds $SleepInterval } Stop-Activity } #----------------------------------------------------------------------- function Invoke-Cleanup { param () Start-Activity 'Invoke-Cleanup' if (Test-Path $JournalDir) { Remove-Item $JournalDir -Recurse -Force } Stop-Activity } #----------------------------------------------------------------------- $Steps = @{ Resolve = 0 Download = 1 Cleanup = 2 } $FromValue = $Steps[$From] $UpToValue = $Steps[$UpTo] $RepositoryDir = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($RepositoryDir) New-Item -Path $RepositoryDir -ItemType Directory -Force | Out-Null if (-not $JournalDir) { $JournalDir = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [guid]::NewGuid().ToString()) } else { $JournalDir = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($JournalDir) } New-Item -Path $JournalDir -ItemType Directory -Force | Out-Null Start-Activity 'Export' Write-Verbose "RepositoryDir: $RepositoryDir" -Verbose Write-Verbose "JournalDir: $JournalDir" -Verbose if ($FromValue -le $Steps.Resolve -and $UpToValue -ge $Steps.Resolve) { Resolve-AllProducts } if ($FromValue -le $Steps.Download -and $UpToValue -ge $Steps.Download) { Download-AllProducts } if ($FromValue -le $Steps.Cleanup -and $UpToValue -ge $Steps.Cleanup) { Invoke-Cleanup } Stop-Activity } } #----------------------------------------------------------------------- $ErrorActionPreference = 'Stop' $InformationPreference = 'Continue' Import-Module "$PSScriptRoot\Activities.psm1" -Force -ErrorAction Stop Export-ModuleMember -Function @('Export-AzsMarketplaceItem') # SIG # Begin signature block # MIIjlAYJKoZIhvcNAQcCoIIjhTCCI4ECAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDKno9r1SLGQu+w # HD6eYtOJ2QUKDzWf0ZwDJDeYgj78OKCCDXYwggX0MIID3KADAgECAhMzAAABhk0h # daDZB74sAAAAAAGGMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ2WhcNMjEwMzAzMTgzOTQ2WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQC49eyyaaieg3Xb7ew+/hA34gqzRuReb9svBF6N3+iLD5A0iMddtunnmbFVQ+lN # Wphf/xOGef5vXMMMk744txo/kT6CKq0GzV+IhAqDytjH3UgGhLBNZ/UWuQPgrnhw # afQ3ZclsXo1lto4pyps4+X3RyQfnxCwqtjRxjCQ+AwIzk0vSVFnId6AwbB73w2lJ # +MC+E6nVmyvikp7DT2swTF05JkfMUtzDosktz/pvvMWY1IUOZ71XqWUXcwfzWDJ+ # 96WxBH6LpDQ1fCQ3POA3jCBu3mMiB1kSsMihH+eq1EzD0Es7iIT1MlKERPQmC+xl # K+9pPAw6j+rP2guYfKrMFr39AgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUhTFTFHuCaUCdTgZXja/OAQ9xOm4w # RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW # MBQGA1UEBRMNMjMwMDEyKzQ1ODM4NDAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci # tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG # CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0 # MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAEDkLXWKDtJ8rLh3d7XP # 1xU1s6Gt0jDqeHoIpTvnsREt9MsKriVGKdVVGSJow1Lz9+9bINmPZo7ZdMhNhWGQ # QnEF7z/3czh0MLO0z48cxCrjLch0P2sxvtcaT57LBmEy+tbhlUB6iz72KWavxuhP # 5zxKEChtLp8gHkp5/1YTPlvRYFrZr/iup2jzc/Oo5N4/q+yhOsRT3KJu62ekQUUP # sPU2bWsaF/hUPW/L2O1Fecf+6OOJLT2bHaAzr+EBAn0KAUiwdM+AUvasG9kHLX+I # XXlEZvfsXGzzxFlWzNbpM99umWWMQPTGZPpSCTDDs/1Ci0Br2/oXcgayYLaZCWsj # 1m/a0V8OHZGbppP1RrBeLQKfATjtAl0xrhMr4kgfvJ6ntChg9dxy4DiGWnsj//Qy # wUs1UxVchRR7eFaP3M8/BV0eeMotXwTNIwzSd3uAzAI+NSrN5pVlQeC0XXTueeDu # xDch3S5UUdDOvdlOdlRAa+85Si6HmEUgx3j0YYSC1RWBdEhwsAdH6nXtXEshAAxf # 8PWh2wCsczMe/F4vTg4cmDsBTZwwrHqL5krX++s61sLWA67Yn4Db6rXV9Imcf5UM # Cq09wJj5H93KH9qc1yCiJzDCtbtgyHYXAkSHQNpoj7tDX6ko9gE8vXqZIGj82mwD # TAY9ofRH0RSMLJqpgLrBPCKNMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg # Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03 # a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr # rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg # OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy # 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9 # sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh # dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k # A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB # w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn # Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90 # lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w # ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o # ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD # VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa # BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny # bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG # AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV # HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG # AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl # AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb # C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l # hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6 # I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0 # wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560 # STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam # ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa # J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah # XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA # 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt # Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr # /Xmfwb1tbWrJUnMTDXpQzTGCFXQwghVwAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAAGGTSF1oNkHviwAAAAAAYYwDQYJYIZIAWUDBAIB # BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIInvfB2ELkirmy2yZQfMiRZg # zmG4WSK3wEOJpEvlBObiMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A # cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB # BQAEggEAafPESlYHJEbalH1zgBbhXVcJwiAMt1+QHMaHHsDJABEyNtN/xspnsCVu # LelNHovlvQjxYgFLcxAN+w1x5UMEeGpx3F62i00vBGrU1u4+n6y72Qfiqy/liFdH # ZzdjScuCbRc3DUAsR6+0qSg8qht/ZnV466yIhefqUY9ZngNY1VMMwrV3nR9AtZDE # XhPxQ+LA8nAFsAexLOeD/l++miFojGTGvOns2XAL+gAMpIzkKqHP87TY8Tf4jJbT # BHLPf+/8HfIFa0/pxETb4qQU4uM+etEqofACagvV1Ekv8WQgkM1wW8Gw0EKn3HsV # b0IjrQEVyh5RI9zmBXW9AlOE3qPVaaGCEv4wghL6BgorBgEEAYI3AwMBMYIS6jCC # EuYGCSqGSIb3DQEHAqCCEtcwghLTAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFZBgsq # hkiG9w0BCRABBKCCAUgEggFEMIIBQAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl # AwQCAQUABCBD8/0efn7CpkLBIRza5AScefGXZRJF2CcYhKgWtBojTQIGX7wP4tmB # GBMyMDIwMTIwNDAwMDk1My42NjRaMASAAgH0oIHYpIHVMIHSMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl # bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNO # OkQwODItNEJGRC1FRUJBMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT # ZXJ2aWNloIIOTTCCBPkwggPhoAMCAQICEzMAAAFBr39Sl1zy3EUAAAAAAUEwDQYJ # KoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcNMjAx # MDE1MTcyODI3WhcNMjIwMTEyMTcyODI3WjCB0jELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3Bl # cmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpEMDgyLTRC # RkQtRUVCQTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCC # ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPIqy6i9vHWpfjyVJlCTsL2J # /7DghM0M2co/eF2xT7UYQ4T42oL7yjr9RoDKDrl75KTN7jOROu78jgj8aoUwM6uw # JN85BF1wb+yaDPF5tMeVHJwJKVIhKNHsnEZem52CAdypWVt7s+CXNr9hVdCghpC6 # 76nyj/Ff4toVcjfOeDno1qcfMBlGszOAmFFaMHIBA3O+jmPl2uFtuwwmSZtn/aJe # AY0i/m9i/0/J/yxBpJ2lMcEkEzdS0ArfrgQwgEnelUEeQiyyVbejAS9FtTZWlsRA # CcJSHcgZ0tYoS70YNY3PylGXtLERXQ934Sq4z2nN4aMtNOxb6+hqNFieKa9qyXUC # AwEAAaOCARswggEXMB0GA1UdDgQWBBQtKD8sbi6Q/UVwa/XPDTtBBRLGxDAfBgNV # HSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBHhkVo # dHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNUaW1T # dGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAC # hj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0YVBD # QV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUF # BwMIMA0GCSqGSIb3DQEBCwUAA4IBAQBSet8ifdgoagoKXsQ+PKJL4hrguIpDbL5s # JQknrdbBabyRMyyQfHExeM+KkE8/ALELXHsOpgFZkAmA7vX+XntdcV49S8B2LGRp # 0rPzn0bpdVSpmOdTkKaryuTvwreH7NCG5c6PHsjiycoE5Pe2l1QOFM6vBm5S+y0O # V4sAGOOOjDgC5zVxaPyqvbb84qcGNWHEZ/55TEPm/djoiy5h1TItsAFDkYihb2gH # 2Fo4UHftqhyzLHaTZbsAW1nuxReQAbA6NB0TjFsgoMXS0N76q9wzEh92ViooqxbL # 1iZnIX2TxkTm8KrM70lzxZjwWfaPnq/uFKC1fudBlp50JMux1YC5MIIGcTCCBFmg # AwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3Qg # Q2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcNMjUw # NzAxMjE0NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ # MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u # MSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIwDQYJ # KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0VBDV # pQoAgoX77XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEwRA/x # YIiEVEMM1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQedGFn # kV+BVLHPk0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKxXf13 # Hz3wV3WsvYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4GkbaI # CDXoeByw6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEAAaOC # AeYwggHiMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7fEYb # xTNoWoVtVTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYw # DwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoY # xDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtp # L2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYB # BQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20v # cGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0gAQH/ # BIGVMIGSMIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYBBQUH # AgIwNB4yIB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUAbQBl # AG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOhIW+z # 66bM9TG+zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS+7lT # jMz0YBKKdsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlKkVIA # rzgPF/UveYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon/VWv # L/625Y4zu2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOiPPp/ # fZZqkHimbdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/fmNZ # JQ96LjlXdqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCIIYdqw # UB5vvfHhAN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0cs0d # 9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7aKLix # qduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQcdeh # 0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+NR4I # uto229Nfj950iEkSoYIC1zCCAkACAQEwggEAoYHYpIHVMIHSMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl # bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNO # OkQwODItNEJGRC1FRUJBMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT # ZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQCq5b8ptQqriKEHK853C75A9VqVA6CBgzCB # gKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV # BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBBQUA # AgUA43O89zAiGA8yMDIwMTIwNDAzMzcyN1oYDzIwMjAxMjA1MDMzNzI3WjB3MD0G # CisGAQQBhFkKBAExLzAtMAoCBQDjc7z3AgEAMAoCAQACAiOyAgH/MAcCAQACAhHH # MAoCBQDjdQ53AgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAI # AgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQEFBQADgYEAZ4rPbHyZAHWN # 14SLrUonPdoItmVborM4zl+KVDcWkjJJW6RmZOHyEsTIAWQafvEw21TGrH3C494W # IwmI2WdT3RaFBIr8jcuMxoy+iqZ8tHsmhCT3PaqW8cOzprzBBNaQHFAFfb3GNM2J # VQlWBo5P+v62d5hbw0XNH4MhwRROjfMxggMNMIIDCQIBATCBkzB8MQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQg # VGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAUGvf1KXXPLcRQAAAAABQTANBglghkgB # ZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3 # DQEJBDEiBCCqZitgUegtLeE0g4tenJ9kDFwemeEtoMjdu2sJwjwy6zCB+gYLKoZI # hvcNAQkQAi8xgeowgecwgeQwgb0EIFE/ATyM6nN0nnB0TyygbVtLzjp0/u/IWlqP # l3MVXq3eMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0 # b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh # dGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMA # AAFBr39Sl1zy3EUAAAAAAUEwIgQgVmGlO7T9bw8jjRAkw5TYkRkOCbYloDy7u/8x # s4AnDhIwDQYJKoZIhvcNAQELBQAEggEAf6b1ynChcpumMZucjC3Qc3Ng89KuHYIg # DnGe62GbUi7e6C08l5mHlQESIZiJm6C32okkzsZQx97aIJvHSXvi4YGzseJK7IdY # TiEzkfHY2kQlfTcnjuwhcmKwgdxPWyEPbBK4rvMYWoU94jiT1o5xB3Blptw2mbvh # 8GVWUTo+7A4OJ3MH7KygLUIiqnKZcuC/4r/Pv4r6qNEdzdTeYR156IRFvn2HBhWH # b4V0oUD7bWmngXn5eDHJur75+e7ZAfUOE0KyXORMr61UTMBY5gxomwaMjyONx2dk # aPjb8tLpnOXLMtTtDmcLFRCK2xPk32G8wgFTKyOHuZoQjJJjpOnA5Q== # SIG # End signature block |