DeprecatedApiTranslator/vSphereRestApiTranslation.ps1
# Unhandled cases that algorithm is going to fail: # # 1. # "OldPath": "/rest/appliance/recovery/backup/schedules/{schedule}" # "NewPath": "/api/appliance/recovery/backup/schedules" # # 2. # "OldPath": "/rest/appliance/recovery/backup/system-name/{system_name}/archives", # "NewPath": "/api/appliance/recovery/backup/system-name/{system_name}/archives?action=list", # # 3. Structure with sefref properties # # # 4. Query parameters # # The algorithm searches for matching substructs in the translation scheme # comparing the first property of the Old and New structure scheme # There is a risk of wrong translation if in the New structure scheme # a property is added in front. Meaning the New APIs extend existing structure # with new property added on the first position. # Import All Translation Function . (Join-Path $PSScriptRoot 'CommonAPITranslation.ps1') . (Join-Path $PSScriptRoot 'InputTransformation.ps1') $script:apiToTranslationFunction = @{} # Example Function Registration # $script:apiToTranslationFunction['post./api/appliance/recovery/backup/system-name/{system_name}/archives?action=list'] = @{ # 'ConvertToDeprecatedBody' = (Get-Command -Name 'ConvertTo-DeprecatedBodyApplianceRecoveryBackupList') # 'ConvertFromDeprecatedBody' = $null # 'ConvertDeprecatedQueryParam' = $null # } function Get-ConvertToDeprecatedBodyTranslationFunction { param( [Parameter()] [PSCustomObject] $OperationTranslateSchema) if ($OperationTranslateSchema -ne $null -and ` $OperationTranslateSchema.NewVerb -ne $null -and ` $OperationTranslateSchema.NewPath -ne $null) { $apiToTranslationFunctionKey = "$($OperationTranslateSchema.NewVerb).$($OperationTranslateSchema.NewPath)" if ($script:apiToTranslationFunction.ContainsKey($apiToTranslationFunctionKey) -and ` $script:apiToTranslationFunction[$apiToTranslationFunctionKey]['ConvertToDeprecatedBody'] -ne $null) { return $script:apiToTranslationFunction[$apiToTranslationFunctionKey]['ConvertToDeprecatedBody'] } else { return (Get-Command -Name 'ConvertTo-DeprecatedBodyCommon') } } } function Get-ConvertFromDeprecatedBodyTranslationFunction { param( [Parameter()] [PSCustomObject] $OperationTranslateSchema) if ($OperationTranslateSchema -ne $null -and ` $OperationTranslateSchema.NewVerb -ne $null -and ` $OperationTranslateSchema.NewPath -ne $null) { $apiToTranslationFunctionKey = "$($OperationTranslateSchema.NewVerb).$($OperationTranslateSchema.NewPath)" if ($script:apiToTranslationFunction.ContainsKey($apiToTranslationFunctionKey) -and ` $script:apiToTranslationFunction[$apiToTranslationFunctionKey]['ConvertFromDeprecatedBody'] -ne $null) { return $script:apiToTranslationFunction[$apiToTranslationFunctionKey]['ConvertFromDeprecatedBody'] } else { return (Get-Command -Name 'ConvertFrom-DeprecatedBodyCommon') } } } function Get-ConvertDeprecatedQueryParamTranslationFunction { param( [Parameter()] [PSCustomObject] $OperationTranslateSchema) if ($OperationTranslateSchema -ne $null -and ` $OperationTranslateSchema.NewVerb -ne $null -and ` $OperationTranslateSchema.NewPath -ne $null) { $apiToTranslationFunctionKey = "$($OperationTranslateSchema.NewVerb).$($OperationTranslateSchema.NewPath)" if ($script:apiToTranslationFunction.ContainsKey($apiToTranslationFunctionKey) -and ` $script:apiToTranslationFunction[$apiToTranslationFunctionKey]['ConvertDeprecatedQueryParam'] -ne $null) { return $script:apiToTranslationFunction[$apiToTranslationFunctionKey]['ConvertDeprecatedQueryParam'] } else { return (Get-Command -Name 'ConvertTo-DeprecatedQueryParamCommon') } } } function Read-OperationTranslationSchema { param( [Parameter(Mandatory = $true)] [ValidateScript( { Test-Path $_ })] [string] $TranslationSchemeFilePath ) Get-Content $TranslationSchemeFilePath -Raw | ConvertFrom-JsonX -Depth 100 } $script:translationSchema = $null function Load-OperationTranslationSchema { if (-not $script:translationSchema) { $script:translationSchema = Read-OperationTranslationSchema (Join-Path $PSScriptRoot 'translation-scheme.json') } } function Get-OperationTranslationSchema { param( [Parameter()] [string] $operationPath = $null, [Parameter()] [string] $operationVerb = $null) Load-OperationTranslationSchema $script:translationSchema | Where-Object { ([string]::IsNullOrEmpty($operationPath) -or $_.NewPath -eq $operationPath) -and ` ([string]::IsNullOrEmpty($operationVerb) -or $_.NewVerb -eq $operationVerb) } } function Convert-OutputBody { <# .SYNOPSIS Converts Body Output object from Deprecated APIs to New APIs .PARAMETER OperationTranslateSchema Translation Schema Object retrieved from Get-OperationTranslationSchema .PARAMETER OperationOutputObject API Operation Ouput Body Object to translate #> param( [Parameter()] [PSCustomObject] $OperationTranslateSchema, [Parameter()] [PSCustomObject] $OperationOutputObject ) $translationFunction = Get-ConvertFromDeprecatedBodyTranslationFunction -OperationTranslateSchema $OperationTranslateSchema & $translationFunction -OperationTranslateSchema $OperationTranslateSchema -OperationOutputObject $OperationOutputObject } function ConvertTo-DeprecatedBody { <# .SYNOPSIS Converts Body Parameter object from new APIs to Deprecated APIs .PARAMETER OperationTranslateSchema Translation Schema Object retrieved from Get-OperationTranslationSchema .PARAMETER OperationQueryInputObject API Operation Input Body Parameter Object to translate #> param( [Parameter()] [PSCustomObject] $OperationTranslateSchema, [Parameter()] [PSCustomObject] $OperationInputObject ) $translationFunction = Get-ConvertToDeprecatedBodyTranslationFunction -OperationTranslateSchema $OperationTranslateSchema & $translationFunction -OperationTranslateSchema $OperationTranslateSchema -OperationInputObject $OperationInputObject } function ConvertTo-DeprecatedQueryParam { <# .SYNOPSIS Converts Query Param object from new APIs to Deprecated APIs .PARAMETER OperationTranslateSchema Translation Schema Object retrieved from Get-OperationTranslationSchema .PARAMETER OperationQueryInputObject API Operation Input Query Parameter Object to translate #> param( [Parameter()] [PSCustomObject] $OperationTranslateSchema, [Parameter()] [PSCustomObject] $OperationQueryInputObject ) $translationFunction = Get-ConvertDeprecatedQueryParamTranslationFunction -OperationTranslateSchema $OperationTranslateSchema & $translationFunction -OperationTranslateSchema $OperationTranslateSchema -OperationQueryInputObject $OperationQueryInputObject } function Convert-InputStructure { param( [Parameter()] [PSCustomObject] $OperationTranslateSchema, [Parameter()] [PSCustomObject] $OperationInputObject, [Parameter()] [ValidateSet('Body', 'Query')] [string] $InputType ) if ( $null -ne $OperationTranslateSchema.OldInQueryParams -and $null -eq $OperationTranslateSchema.OldInBodyStruct -and $null -eq $OperationTranslateSchema.NewInQueryParams -and $null -ne $OperationTranslateSchema.NewInBodyStruct -and $InputType -eq 'Query' ) { # Old operation has input in query that is migrated to body in the New APIs # Convert Body to Query $translationSchema = [PSCustomObject]@{ 'OldVerb' = $OperationTranslateSchema.OldVerb 'NewVerb' = $OperationTranslateSchema.NewVerb 'OldPath' = $OperationTranslateSchema.OldPath 'NewPath' = $OperationTranslateSchema.NewPath 'OldInQueryParams' = $OperationTranslateSchema.OldInQueryParams 'NewInQueryParams' = $OperationTranslateSchema.NewInBodyStruct } # return (ConvertTo-DeprecatedQueryParam -OperationTranslateSchema $translationSchema -OperationQueryInputObject $OperationInputObject) } if ( $null -eq $OperationTranslateSchema.OldInQueryParams -and $null -ne $OperationTranslateSchema.OldInBodyStruct -and $null -ne $OperationTranslateSchema.NewInQueryParams -and $null -eq $OperationTranslateSchema.NewInBodyStruct -and $InputType -eq 'Body' ) { # Old operation has input in body that is migrated to Query Params in the New APIs # Convert Query to Body $translationSchema = [PSCustomObject]@{ 'OldVerb' = $OperationTranslateSchema.OldVerb 'NewVerb' = $OperationTranslateSchema.NewVerb 'OldPath' = $OperationTranslateSchema.OldPath 'NewPath' = $OperationTranslateSchema.NewPath 'OldInBodyStruct' = $OperationTranslateSchema.OldInBodyStruct 'NewInBodyStruct' = $OperationTranslateSchema.NewInQueryParams } $queryInputParameter = $OperationInputObject $oldStructProps = $translationSchema.OldInBodyStruct | Get-Member -MemberType NoteProperty # Handles query input parameter which is array. if ( $OperationInputObject -is [array] -and $OperationInputObject.Count -gt 0 -and $oldStructProps.Count -eq 1 -and $translationSchema.NewInBodyStruct.Count -eq 1 -and $oldStructProps[0].Name -eq $translationSchema.NewInBodyStruct[0] ) { $queryInputParameter = [PSCustomObject] @{ $translationSchema.NewInBodyStruct[0] = $OperationInputObject } } # return (ConvertTo-DeprecatedBody -OperationTranslateSchema $translationSchema -OperationInputObject $queryInputParameter) } if ( $null -eq $OperationTranslateSchema.OldInQueryParams -and $null -ne $OperationTranslateSchema.OldInBodyStruct -and $null -eq $OperationTranslateSchema.NewInQueryParams -and $null -ne $OperationTranslateSchema.NewInBodyStruct -and $InputType -eq 'Body' ) { # Convert Body to Body # return (ConvertTo-DeprecatedBody -OperationTranslateSchema $OperationTranslateSchema -OperationInputObject $OperationInputObject) } if ( $null -ne $OperationTranslateSchema.OldInQueryParams -and $null -eq $OperationTranslateSchema.OldInBodyStruct -and $null -ne $OperationTranslateSchema.NewInQueryParams -and $null -eq $OperationTranslateSchema.NewInBodyStruct -and $InputType -eq 'Query' ) { # Convert Query to Query # return (ConvertTo-DeprecatedQueryParam -OperationTranslateSchema $OperationTranslateSchema -OperationQueryInputObject $OperationInputObject) } } # SIG # Begin signature block # MIIohgYJKoZIhvcNAQcCoIIodzCCKHMCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAPUgSTCsdjIQuv # I3FxXJTa8np+So3sH38nK9JMfa8Es6CCDdowggawMIIEmKADAgECAhAIrUCyYNKc # TJ9ezam9k67ZMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV # BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0z # NjA0MjgyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg # SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg # UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw # ggIKAoICAQDVtC9C0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0 # JAfhS0/TeEP0F9ce2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJr # Q5qZ8sU7H/Lvy0daE6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhF # LqGfLOEYwhrMxe6TSXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+F # LEikVoQ11vkunKoAFdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh # 3K3kGKDYwSNHR7OhD26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJ # wZPt4bRc4G/rJvmM1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQay # g9Rc9hUZTO1i4F4z8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbI # YViY9XwCFjyDKK05huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchAp # QfDVxW0mdmgRQRNYmtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRro # OBl8ZhzNeDhFMJlP/2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IB # WTCCAVUwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+ # YXsIiGX0TkIwHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P # AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAk # BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC # hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v # dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j # b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAED # MAgGBmeBDAEEATANBgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql # +Eg08yy25nRm95RysQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFF # UP2cvbaF4HZ+N3HLIvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1h # mYFW9snjdufE5BtfQ/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3Ryw # YFzzDaju4ImhvTnhOE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5Ubdld # AhQfQDN8A+KVssIhdXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw # 8MzK7/0pNVwfiThV9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnP # LqR0kq3bPKSchh/jwVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatE # QOON8BUozu3xGFYHKi8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bn # KD+sEq6lLyJsQfmCXBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQji # WQ1tygVQK+pKHJ6l/aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbq # yK+p/pQd52MbOoZWeE4wggciMIIFCqADAgECAhAOxvKydqFGoH0ObZNXteEIMA0G # CSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg # SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg # UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwHhcNMjEwODEwMDAwMDAwWhcNMjMwODEw # MjM1OTU5WjCBhzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQ # BgNVBAcTCVBhbG8gQWx0bzEVMBMGA1UEChMMVk13YXJlLCBJbmMuMRUwEwYDVQQD # EwxWTXdhcmUsIEluYy4xITAfBgkqhkiG9w0BCQEWEm5vcmVwbHlAdm13YXJlLmNv # bTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAMD6lJG8OWkM12huIQpO # /q9JnhhhW5UyW9if3/UnoFY3oqmp0JYX/ZrXogUHYXmbt2gk01zz2P5Z89mM4gqR # bGYC2tx+Lez4GxVkyslVPI3PXYcYSaRp39JsF3yYifnp9R+ON8O3Gf5/4EaFmbeT # ElDCFBfExPMqtSvPZDqekodzX+4SK1PIZxCyR3gml8R3/wzhb6Li0mG7l0evQUD0 # FQAbKJMlBk863apeX4ALFZtrnCpnMlOjRb85LsjV5Ku4OhxQi1jlf8wR+za9C3DU # ki60/yiWPu+XXwEUqGInIihECBbp7hfFWrnCCaOgahsVpgz8kKg/XN4OFq7rbh4q # 5IkTauqFhHaE7HKM5bbIBkZ+YJs2SYvu7aHjw4Z8aRjaIbXhI1G+NtaNY7kSRrE4 # fAyC2X2zV5i4a0AuAMM40C1Wm3gTaNtRTHnka/pbynUlFjP+KqAZhOniJg4AUfjX # sG+PG1LH2+w/sfDl1A8liXSZU1qJtUs3wBQFoSGEaGBeDQIDAQABo4ICJTCCAiEw # HwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0OBBYEFIhC+HL9 # QlvsWsztP/I5wYwdfCFNMB0GA1UdEQQWMBSBEm5vcmVwbHlAdm13YXJlLmNvbTAO # BgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwgbUGA1UdHwSBrTCB # qjBToFGgT4ZNaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3Rl # ZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwU6BRoE+GTWh0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWdu # aW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMD4GA1UdIAQ3MDUwMwYGZ4EMAQQB # MCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBlAYI # KwYBBQUHAQEEgYcwgYQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0 # LmNvbTBcBggrBgEFBQcwAoZQaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0Rp # Z2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5j # cnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEACQAYaQI6Nt2KgxdN # 6qqfcHB33EZRSXkvs8O9iPZkdDjEx+2fgbBPLUvk9A7T8mRw7brbcJv4PLTYJDFo # c5mlcmG7/5zwTOuIs2nBGXc/uxCnyW8p7kD4Y0JxPKEVQoIQ8lJS9Uy/hBjyakeV # ef982JyzvDbOlLBy6AS3ZpXVkRY5y3Va+3v0R/0xJ+JRxUicQhiZRidq2TCiWEas # d+tLL6jrKaBO+rmP52IM4eS9d4Yids7ogKEBAlJi0NbvuKO0CkgOlFjp1tOvD4sQ # taHIMmqi40p4Tjyf/sY6yGjROXbMeeF1vlwbBAASPWpQuEIxrNHoVN30YfJyuOWj # zdiJUTpeLn9XdjM3UlhfaHP+oIAKcmkd33c40SFRlQG9+P9Wlm7TcPxGU4wzXI8n # Cw/h235jFlAAiWq9L2r7Un7YduqsheJVpGoXmRXJH0T2G2eNFS5/+2sLn98kN2Cn # J7j6C242onjkZuGL2/+gqx8m5Jbpu9P4IAeTC1He/mX9j6XpIu+7uBoRVwuWD1i0 # N5SiUz7Lfnbr6Q1tHMXKDLFdwVKZos2AKEZhv4SU0WvenMJKDgkkhVeHPHbTahQf # P1MetR8tdRs7uyTWAjPK5xf5DLEkXbMrUkpJ089fPvAGVHBcHRMqFA5egexOb6sj # tKncUjJ1xAAtAExGdCh6VD2U5iYxghoCMIIZ/gIBATB9MGkxCzAJBgNVBAYTAlVT # MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1 # c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEzODQgMjAyMSBDQTECEA7G # 8rJ2oUagfQ5tk1e14QgwDQYJYIZIAWUDBAIBBQCggZYwGQYJKoZIhvcNAQkDMQwG # CisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwKgYKKwYB # BAGCNwIBDDEcMBqhGIAWaHR0cDovL3d3dy52bXdhcmUuY29tLzAvBgkqhkiG9w0B # CQQxIgQg2AkQLhskIzS/gRCDspFtHbet39NwU2Z0TB98kv0YL48wDQYJKoZIhvcN # AQEBBQAEggGAIusGpDS+1GOaCMy9kufUs9bQgjkI1j4sk6kgsl5pShlOtydtAZcD # 7E7wwEuawDzO5X67Mz+9cpDK1XJrImDsVReEWdrn7IvBND/LFlqCngwYmn2i1fp3 # VXhnpWd2wjd5ZJmhx090wZWHBfY4LQwFjIBHaqGQCWYzUxsWV0nY6162GeQl8bTP # Jpt7FehIOg42h2BSZpWz8gfMsi53p1J4D2tMrG22MZRPQxe2bKjQN70S7xdsKoZt # ivIWKpilc6nQXtvDU1MaA+5jQ8wxzAoTjdE5uejV8uOZGS2y+TkxcmCJHaybbY3f # /F828t466zfANIhJsvfTwjZWbA3Qi+veYzTDgkBpoQCCnyErTtJwaHp1MtUjf0N3 # 4FPSy1JgKmbFFps3Z7yfDrwRXLc44Q6CKRhrsdiQbNKU2ks9hIT0tgXVw17T6M1X # /ICTVDWydTcSTjYBtRwA8jXuhaAYLBQf+yL8PfRppUO9iZthmGIxf2PgSSBDcp1w # zWjXrHWhuG5boYIXPTCCFzkGCisGAQQBgjcDAwExghcpMIIXJQYJKoZIhvcNAQcC # oIIXFjCCFxICAQMxDzANBglghkgBZQMEAgEFADB3BgsqhkiG9w0BCRABBKBoBGYw # ZAIBAQYJYIZIAYb9bAcBMDEwDQYJYIZIAWUDBAIBBQAEIEuYDAHWS17Iza/+hrp1 # sczY3VHIk+RI/JtErz5/0MXFAhBtKRx/PCpmKyZ7B0WjRY/JGA8yMDIyMTAxMzE1 # MTQzMFqgghMHMIIGwDCCBKigAwIBAgIQDE1pckuU+jwqSj0pB4A9WjANBgkqhkiG # 9w0BAQsFADBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x # OzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGlt # ZVN0YW1waW5nIENBMB4XDTIyMDkyMTAwMDAwMFoXDTMzMTEyMTIzNTk1OVowRjEL # MAkGA1UEBhMCVVMxETAPBgNVBAoTCERpZ2lDZXJ0MSQwIgYDVQQDExtEaWdpQ2Vy # dCBUaW1lc3RhbXAgMjAyMiAtIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK # AoICAQDP7KUmOsap8mu7jcENmtuh6BSFdDMaJqzQHFUeHjZtvJJVDGH0nQl3PRWW # CC9rZKT9BoMW15GSOBwxApb7crGXOlWvM+xhiummKNuQY1y9iVPgOi2Mh0KuJqTk # u3h4uXoW4VbGwLpkU7sqFudQSLuIaQyIxvG+4C99O7HKU41Agx7ny3JJKB5MgB6F # VueF7fJhvKo6B332q27lZt3iXPUv7Y3UTZWEaOOAy2p50dIQkUYp6z4m8rSMzUy5 # Zsi7qlA4DeWMlF0ZWr/1e0BubxaompyVR4aFeT4MXmaMGgokvpyq0py2909ueMQo # P6McD1AGN7oI2TWmtR7aeFgdOej4TJEQln5N4d3CraV++C0bH+wrRhijGfY59/XB # T3EuiQMRoku7mL/6T+R7Nu8GRORV/zbq5Xwx5/PCUsTmFntafqUlc9vAapkhLWPl # WfVNL5AfJ7fSqxTlOGaHUQhr+1NDOdBk+lbP4PQK5hRtZHi7mP2Uw3Mh8y/CLiDX # gazT8QfU4b3ZXUtuMZQpi+ZBpGWUwFjl5S4pkKa3YWT62SBsGFFguqaBDwklU/G/ # O+mrBw5qBzliGcnWhX8T2Y15z2LF7OF7ucxnEweawXjtxojIsG4yeccLWYONxu71 # LHx7jstkifGxxLjnU15fVdJ9GSlZA076XepFcxyEftfO4tQ6dwIDAQABo4IBizCC # AYcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYI # KwYBBQUHAwgwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMB8GA1Ud # IwQYMBaAFLoW2W1NhS9zKXaaL3WMaiCPnshvMB0GA1UdDgQWBBRiit7QYfyPMRTt # lwvNPSqUFN9SnDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsMy5kaWdpY2Vy # dC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0YW1waW5n # Q0EuY3JsMIGQBggrBgEFBQcBAQSBgzCBgDAkBggrBgEFBQcwAYYYaHR0cDovL29j # c3AuZGlnaWNlcnQuY29tMFgGCCsGAQUFBzAChkxodHRwOi8vY2FjZXJ0cy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0YW1w # aW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQBVqioa80bzeFc3MPx140/WhSPx # /PmVOZsl5vdyipjDd9Rk/BX7NsJJUSx4iGNVCUY5APxp1MqbKfujP8DJAJsTHbCY # idx48s18hc1Tna9i4mFmoxQqRYdKmEIrUPwbtZ4IMAn65C3XCYl5+QnmiM59G7hq # opvBU2AJ6KO4ndetHxy47JhB8PYOgPvk/9+dEKfrALpfSo8aOlK06r8JSRU1Nlma # D1TSsht/fl4JrXZUinRtytIFZyt26/+YsiaVOBmIRBTlClmia+ciPkQh0j8cwJvt # fEiy2JIMkU88ZpSvXQJT657inuTTH4YBZJwAwuladHUNPeF5iL8cAZfJGSOA1zZa # X5YWsWMMxkZAO85dNdRZPkOaGK7DycvD+5sTX2q1x+DzBcNZ3ydiK95ByVO5/zQQ # Z/YmMph7/lxClIGUgp2sCovGSxVK05iQRWAzgOAj3vgDpPZFR+XOuANCR+hBNnF3 # rf2i6Jd0Ti7aHh2MWsgemtXC8MYiqE+bvdgcmlHEL5r2X6cnl7qWLoVXwGDneFZ/ # au/ClZpLEQLIgpzJGgV8unG1TnqZbPTontRamMifv427GFxD9dAq6OJi7ngE273R # +1sKqHB+8JeEeOMIA11HLGOoJTiXAdI/Otrl5fbmm9x+LMz/F0xNAKLY1gEOuIvu # 5uByVYksJxlh9ncBjDCCBq4wggSWoAMCAQICEAc2N7ckVHzYR6z9KGYqXlswDQYJ # KoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu # YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQg # VHJ1c3RlZCBSb290IEc0MB4XDTIyMDMyMzAwMDAwMFoXDTM3MDMyMjIzNTk1OVow # YzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQD # EzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGlu # ZyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMaGNQZJs8E9cklR # VcclA8TykTepl1Gh1tKD0Z5Mom2gsMyD+Vr2EaFEFUJfpIjzaPp985yJC3+dH54P # Mx9QEwsmc5Zt+FeoAn39Q7SE2hHxc7Gz7iuAhIoiGN/r2j3EF3+rGSs+QtxnjupR # PfDWVtTnKC3r07G1decfBmWNlCnT2exp39mQh0YAe9tEQYncfGpXevA3eZ9drMvo # hGS0UvJ2R/dhgxndX7RUCyFobjchu0CsX7LeSn3O9TkSZ+8OpWNs5KbFHc02DVzV # 5huowWR0QKfAcsW6Th+xtVhNef7Xj3OTrCw54qVI1vCwMROpVymWJy71h6aPTnYV # VSZwmCZ/oBpHIEPjQ2OAe3VuJyWQmDo4EbP29p7mO1vsgd4iFNmCKseSv6De4z6i # c/rnH1pslPJSlRErWHRAKKtzQ87fSqEcazjFKfPKqpZzQmiftkaznTqj1QPgv/Ci # PMpC3BhIfxQ0z9JMq++bPf4OuGQq+nUoJEHtQr8FnGZJUlD0UfM2SU2LINIsVzV5 # K6jzRWC8I41Y99xh3pP+OcD5sjClTNfpmEpYPtMDiP6zj9NeS3YSUZPJjAw7W4oi # qMEmCPkUEBIDfV8ju2TjY+Cm4T72wnSyPx4JduyrXUZ14mCjWAkBKAAOhFTuzuld # yF4wEr1GnrXTdrnSDmuZDNIztM2xAgMBAAGjggFdMIIBWTASBgNVHRMBAf8ECDAG # AQH/AgEAMB0GA1UdDgQWBBS6FtltTYUvcyl2mi91jGogj57IbzAfBgNVHSMEGDAW # gBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAww # CgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRwOi8v # b2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8MDow # OKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRS # b290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkq # hkiG9w0BAQsFAAOCAgEAfVmOwJO2b5ipRCIBfmbW2CFC4bAYLhBNE88wU86/GPvH # UF3iSyn7cIoNqilp/GnBzx0H6T5gyNgL5Vxb122H+oQgJTQxZ822EpZvxFBMYh0M # CIKoFr2pVs8Vc40BIiXOlWk/R3f7cnQU1/+rT4osequFzUNf7WC2qk+RZp4snuCK # rOX9jLxkJodskr2dfNBwCnzvqLx1T7pa96kQsl3p/yhUifDVinF2ZdrM8HKjI/rA # J4JErpknG6skHibBt94q6/aesXmZgaNWhqsKRcnfxI2g55j7+6adcq/Ex8HBanHZ # xhOACcS2n82HhyS7T6NJuXdmkfFynOlLAlKnN36TU6w7HQhJD5TNOXrd/yVjmScs # PT9rp/Fmw0HNT7ZAmyEhQNC3EyTN3B14OuSereU0cZLXJmvkOHOrpgFPvT87eK1M # rfvElXvtCl8zOYdBeHo46Zzh3SP9HSjTx/no8Zhf+yvYfvJGnXUsHicsJttvFXse # GYs2uJPU5vIXmVnKcPA3v5gA3yAWTyf7YGcWoWa63VXAOimGsJigK+2VQbc61RWY # MbRiCQ8KvYHZE/6/pNHzV9m8BPqC3jLfBInwAM1dwvnQI38AC+R2AibZ8GV2QqYp # hwlHK+Z/GqSFD/yYlvZVVCsfgPrA8g4r5db7qS9EFUrnEw4d2zc4GqEr9u3WfPww # ggWNMIIEdaADAgECAhAOmxiO+dAt5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9v # dCBDQTAeFw0yMjA4MDEwMDAwMDBaFw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYT # AlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2Vy # dC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJ # KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskh # PfKK2FnC4SmnPVirdprNrnsbhA3EMB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIP # Uh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZanMylNEQRBAu34LzB4TmdDttceItDBvu # INXJIB1jKS3O7F5OyJP4IWGbNOsFxl7sWxq868nPzaw0QF+xembud8hIqGZXV59U # WI4MK7dPpzDZVu7Ke13jrclPXuU15zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4 # AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJoz # QL8I11pJpMLmqaBn3aQnvKFPObURWBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw # 4KISG2aadMreSx7nDmOu5tTvkpI6nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sE # AMx9HJXDj/chsrIRt7t/8tWMcCxBYKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZD # pBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0viastkF13nqsX40/ybzTQRESW+UQUOsx # xcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+Y # HS312amyHeUbAgMBAAGjggE6MIIBNjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW # BBTs1+OC0nFdZEzfLmc/57qYrhwPTzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun # pyGd823IDzAOBgNVHQ8BAf8EBAMCAYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUF # BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6 # Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5j # cnQwRQYDVR0fBD4wPDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp # Z2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJ # KoZIhvcNAQEMBQADggEBAHCgv0NcVec4X6CjdBs9thbX979XB72arKGHLOyFXqka # uyL4hxppVCLtpIh3bb0aFPQTSnovLbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP # +fT3rDB6mouyXtTP0UNEm0Mh65ZyoUi0mcudT6cGAxN3J0TU53/oWajwvy8Lpuny # NDzs9wPHh6jSTEAZNUZqaVSwuKFWjuyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiE # n2/K2yCNNWAcAgPLILCsWKAOQGPFmCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4 # VC0nftg62fC2h5b9W9FcrBjDTZ9ztwGpn1eqXijiuZQxggN2MIIDcgIBATB3MGMx # CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMy # RGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcg # Q0ECEAxNaXJLlPo8Kko9KQeAPVowDQYJYIZIAWUDBAIBBQCggdEwGgYJKoZIhvcN # AQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yMjEwMTMxNTE0MzBa # MCsGCyqGSIb3DQEJEAIMMRwwGjAYMBYEFPOHIk2GM4KSNamUvL2Plun+HHxzMC8G # CSqGSIb3DQEJBDEiBCCLNrcoxWYZe1fHeRSPKV3cD30sgIHX+uAYAnoFesg1TzA3 # BgsqhkiG9w0BCRACLzEoMCYwJDAiBCDH9OG+MiiJIKviJjq+GsT8T+Z4HC1k0EyA # dVegI7W2+jANBgkqhkiG9w0BAQEFAASCAgC4y34cNTKmX19EWqkWQEjpmr1l+BBp # mYsO8TJX1zi+dc1K0wKVSPDbKhfosqS5KpKgIrORvqJTws0w0G4+VhxhfgDf0VE9 # v5OA9zH684xOZw5fkz3WBceQ1Z1oIOkdbE3CrzA28YxDzaos0UVfIl0dBeiWdn7c # pT2EPVgcDsd2Wk8uCKPCwLx3cNB9FyDykEkC0PBGMjfL/JNCS4uYDO1mjHSXDH8o # jbpfbtaQJETi6Yy6trH7v4CGmsrl4rAx7xDno25Edtv4ZlBlIY5rFemx9O/wlOxb # GfIPm6fy8pgp/W5qazsi51iOXXcOTwn37Amd65wzQeBKttnp4BxlwCk7S1Ht1IaI # qvLF1ke2E+wQa4DbvS3tw6/6l4MZrfMIf19lRHLlioO1BRcwGlqVKWCAkmE8mjWb # uIQU7G7iiUmAR8hPO1kxsRa18+SrzirBz7F/943sfVtuvLFyIIXyjYow1wFA4iep # 3ga8lHoxX+kAlUrZeDK8bz+ixpkJQnLfboGWWKFv8w8DXnl93MyPF+sIvk4UAj3L # nxMMggNrzz0ifxzxq7D1swj3n45yhK1ENjmLcVlqI9v7r/+KdcD3S8UIR+tiTcqn # 5g7bzqPKbovfnzUgZljiwgk5hlMJ52cmZ+Id19946XX0WFdCBuJP2BsN+SNRuIcd # dzVEZ6WHV7j+zg== # SIG # End signature block |