UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

1,064 lines (1,061 loc) 45.2 kB
import { of } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; import { Crypto } from './crypto'; /** * Net communication class. * @dynamic */ export class Net { static cachedErrorCodeMap; static get errorCodeMap() { if (!Net.cachedErrorCodeMap) { const strings = MsftSme.getStrings().MsftSmeShell.Core; Net.cachedErrorCodeMap = { // added from https://msdn.microsoft.com/en-us/library/aa392154(v=vs.85).aspx 0: strings.ErrorCode.Code0.message, 5: strings.ErrorCode.Code5.message, 50: strings.ErrorCode.Code50.message, 87: strings.ErrorCode.Code87.message, 110: strings.ErrorCode.Code110.message, 1323: strings.ErrorCode.Code1323.message, 1326: strings.ErrorCode.Code1326.message, 1355: strings.ErrorCode.Code1355.message, 2224: strings.ErrorCode.Code2224.message, 2691: strings.ErrorCode.Code2691.message, 2692: strings.ErrorCode.Code2692.message, 0x80041087: strings.ErrorCode.Code8004108.message }; } return Net.cachedErrorCodeMap; } /** * The static definition of Web API URLs. */ static apiVersionParam = 'api-version'; static apiVersion20190201 = '2019-02-01'; static apiRoot = '/api/{0}'; static batch = '/batch'; static streamSocket = '{0}/api/streams/socket/{1}'; static downlevel = 'features/downlevelSupport'; static downlevelInstall = Net.downlevel + '/install'; static downlevelComponents = Net.downlevel + '/components'; static extensionsSettings = '/settings/extension'; static installedExtensions = '/settings/extension/installed'; static extensions = '/extensions'; static updatesSettings = '/settings/updates'; static isExtensionUpdateAvailable = Net.extensions + '/isUpdateAvailable'; static cimClass = 'features/cim/namespaces/{0}/classes/{1}'; static cimQuery = 'features/cim/query'; static cimInvoke = '/methods/{0}/invoke'; static powerShellApiInvokeCommand = 'features/powershellApi/invokeCommand'; static powerShellApiSessions = 'features/powershellApi/pssessions/{0}'; static powerShellApiExecuteCommand = Net.powerShellApiSessions + '/invokeCommand'; static powerShellApiRetrieveOutput = Net.powerShellApiSessions + '?$expand=output'; static powerShellApiCancelCommand = Net.powerShellApiSessions + '/cancel'; static powerShellConsoleSessions = 'features/powershellConsole/pssessions/{0}'; static powerShellConsoleExecuteCommand = Net.powerShellConsoleSessions + '/invokeCommand'; static powerShellConsoleRetrieveOutput = Net.powerShellConsoleSessions + '?$expand=output'; static stopCommand = Net.powerShellConsoleSessions + '/cancel'; static tabCommand = Net.powerShellConsoleSessions + '/tab'; static userProfile = '/settings/user'; static applicationSettings = '/settings/all'; static adminSettings = '/settings/admin'; static user = '/user'; static fileTransferFormat = 'features/fileTransfer/files/{0}'; static fileTransferDownloadPost = Net.fileTransferFormat + '/download'; static fileTransferUpload = Net.fileTransferFormat + '/uploadlink'; static jeaFeature = 'features/jea/endpoint'; static jeaExport = Net.jeaFeature + '/export'; static gateway = '/gateway'; static gatewayAccessCheck = Net.gateway + '/access/check'; static gatewayStatus = Net.gateway + '/status'; // {HttpMethod} {relativeNodeUrl} HTTP/1.1 static multiPartCallBodyUrl = '{0} {1} HTTP/1.1'; /** * Gateway version 2.0.0 Node API set. */ /** * WinREST service on Windows platform. */ static serviceWinRest = 'WinREST'; /** * WinStream service on Windows platform. */ static serviceWinStream = 'WinStream'; /** * LinuxBase on Linux platform. */ static serviceLinuxBase = 'LinuxBase'; /** * ActiveDirectory on WinREST. */ static controllerActiveDirectory = 'ActiveDirectory'; /** * CIM on WinREST. */ static controllerCim = 'CIM'; /** * Extensions on WinREST. */ static controllerExtensions = 'Extensions'; /** * FileTransfer on WinREST. */ static controllerFileTransfer = 'FileTransfer'; /** * JEA on WinREST. */ static controllerJea = 'JEA'; /** * Nuget on WinREST. */ static controllerNuget = 'Nuget'; /** * PerformanceCounter on WinREST. */ static controllerPerformanceCounter = 'PerformanceCounter'; /** * PowerShell on WinREST. */ static controllerPowerShell = 'PowerShell'; /** * PseudoConsole on WinStream. */ static controllerPseudoConsole = 'PseudoConsole'; /** * Ssh on LinuxBase. */ static controllerSsh = 'Ssh'; /** * SshFile on LinuxBase. */ static controllerSshFile = 'SshFile'; /** * State on WinREST. */ static controllerState = 'State'; /** * Stream on WinStream. */ static controllerStream = 'Stream'; /** * Stream on LinuxBase. */ static controllerStreamSsh = 'StreamSsh'; /** * Tcp on WinStream and LinuxBase. */ static controllerTcp = 'Tcp'; /** * Wdac on WinREST. */ static controllerWdac = 'Wdac'; /** * Socket URL on WinStream. */ static streamSocketV200 = '{0}/api/services/' + Net.serviceWinStream + '/' + Net.controllerStream + '/socket/{1}'; /** * Socket URL on LinuxBase. */ static sshStreamSocket = '{0}/api/services/' + Net.serviceLinuxBase + '/' + Net.controllerStreamSsh + '/socket'; /** * Encodes the specified data as Base64-encoded URL. * * If the resultant URL is longer than 260 characters, it is converted to a * relative path where each segment (e.g. '/') defines the character length boundary. * The HTTP.SYS subsystem in Windows does now allow a URL segment larger than 260 * characters without changing a Registry key and restarting the OS. * @param data The data to be encoded. * @return An encoded Base64 URL, potentially segmented by '/' every 260 characters. */ static toSegmentedBase64Url(data) { const MAX_HTTP_SYS_URL_SEGMENT_LENGTH = 260; const base64Url = Net.utf8Base64UrlEncode(data); const parts = Net.splitByLength(base64Url, MAX_HTTP_SYS_URL_SEGMENT_LENGTH); return parts.join('/'); } /** * Update URL with api-version=20190201. * @param url the original URL * @returns new url string added version parameter. */ static updateApiVersion20190201(url) { const index = url.indexOf('?'); const prefix = index > 0 ? '&' : '?'; if (index > 0 && url.indexOf(`${Net.apiVersionParam}=`) > 0) { return url; } return `${url}${prefix}${Net.apiVersionParam}=${Net.apiVersion20190201}`; } /** * Convert IPV6 address to literal format. * * @param ipv6Address the ipv6 address format. */ static convertIPv6ToLiteral(ipv6Address) { let data = ''; for (let i = 0; i < ipv6Address.length; i++) { let ch = ipv6Address.charAt(i); if (ch === ':') { ch = '-'; } else if (ch === '%') { ch = 's'; } data += ch; } return `${data}.ipv6-literal.net`; } /** * Convert IPV6 address to literal format. * * @param ipv6Address the ipv6 address format. */ static convertLiteralToIPv6(literal) { const firstSegment = literal.split('.ipv6-literal.net')[0]; if (!firstSegment) { throw new Error('Not recognized as an IPv6 literal format: \'{0}\'!'.format(literal || 'null')); } let data = ''; for (let i = 0; i < firstSegment.length; i++) { let ch = firstSegment.charAt(i); if (ch === '-') { ch = ':'; } else if (ch === 's') { ch = '%'; } data += ch; } return data; } /** * Encode a string with base64url. * * @param data the input string. * @return string the encoded string. */ static base64urlEncode(data) { // REF: https://tools.ietf.org/html/rfc4648#section-5 const base64 = window.btoa(data); let base64Url = ''; for (let i = 0; i < base64.length; i++) { const ch = base64.charAt(i); switch (ch) { case '+': base64Url += '-'; break; case '/': base64Url += '_'; break; case '=': return base64Url; default: base64Url += ch; break; } } return base64Url; } /** * Decode a base64 url string. * * @param data the string to decode. * @return string the decoded string. */ static base64urlDecode(data) { while (data.length % 4 !== 0) { data += '='; } data = data.replaceAll('-', '+').replaceAll('_', '/'); return window.atob(data); } /** * Encode utf8 string. * * @param data the unencoded string. */ static utf8Encode(data) { return unescape(encodeURIComponent(data)); } /** * Decode utf8 string. * * @param data the encoded UTF8 string. */ static utf8Decode(data) { return decodeURIComponent(escape(data)); } /** * Encode with utf8 (first) and base64url (second). * * @param data data the original string to encode. The string can be full unicode character string. * @return string the encoded string used on a part of URL. */ static utf8Base64UrlEncode(data) { const utf8 = Net.utf8Encode(data); return Net.base64urlEncode(utf8); } /** * Decode with utf8 (second) and base64url (first). * * @param data data the encoded URL string to decode. * @return string the decoded unicode string. */ static utf8Base64UrlDecode(data) { const utf8 = Net.base64urlDecode(data); return Net.utf8Decode(utf8); } /** * Create a key name from key value pairs. * * @param properties the key value pairs. * @return string the key name. */ static cimCreateName(properties) { const data = JSON.stringify(properties); const utf8 = Net.utf8Encode(data); return Net.base64urlEncode(utf8); } /** * Get properties of the item from the response. * * @param data the item in the response object. * @return any the properties. */ static getItemProperties(data) { if (data && data.properties) { return data.properties; } return data; } /** * Get properties of first item from the response. * * @param data the response object. * @return any the properties. */ static getFirstProperties(data) { if (data && data.value && data.value.length) { if (data.value[0].properties) { return data.value[0].properties; } } else if (data && data.length) { return data[0]; } return Net.getItemProperties(data); } /** * Get array of items from the response. * * @param data the response object. * @return any the item array. */ static getItemArray(data) { if (data && data.value) { return data.value; } return data; } /** * Create JSON string with properties. * * @param data the input data. * @return string the JSON string with properties. */ static createPropertiesJSONString(data) { return JSON.stringify({ properties: data }); } /** * Creates an encoded authentication header. * * @param usersName name of user. * @param password the password. * @return the token string. */ static createEncodedAuthenticationHeader(userNames, password, passwordEncryptedWith = null) { const credentials = { ...Net.toUsernameAndDomain(userNames), password: password }; if (!MsftSme.isNullOrWhiteSpace(passwordEncryptedWith)) { credentials.passwordEncryptedWith = passwordEncryptedWith; } return window.btoa(Net.utf8Encode(JSON.stringify(credentials))); } static toUsernameAndDomain(value) { let username; if (Array.isArray(value)) { username = value; } else if (value.indexOf('@') >= 0) { // domain is empty if UPN is used. username = ["", value]; } else { username = value.split('\\'); } return { // if only a username was provided, use '.' (shorthand for the locale machine hostname) domain: username.length === 1 ? '.' : username[0], username: username.length === 1 ? username[0] : username[1] }; } /** * Creates an encrypted authentication header value. * * @param jwk the JWK (Json Web Key) * @param usersName name of user. * @param password the password. * @param logonUser the gateway user * @param expirationTimeInMs manage as token expiration time in milliseconds * @return the token string. */ static createEncryptedAuthenticationHeader(jwk, userNames, password, logonUser, expirationTimeInMs) { const credentials = { ...Net.toUsernameAndDomain(userNames), password: password, passwordEncryptedWith: undefined }; const passwordData = Net.createPasswordData(credentials, logonUser, expirationTimeInMs); return Crypto.encryptRsaSha1(jwk, passwordData) .pipe(map(encryptedPassword => { credentials.password = encryptedPassword; credentials.passwordEncryptedWith = 'JWK2'; return window.btoa(Net.utf8Encode(JSON.stringify(credentials))); }), catchError(() => of(window.btoa(Net.utf8Encode(JSON.stringify(credentials)))))); } static createPasswordData(credentials, logOnUser, expirationTimeInMs) { const millisecondsInHour = 60 * 60 * 1000; const hoursInYear = 365 * 24; const currentTimeStamp = Date.now(); const expirationOffsetInMilliseconds = expirationTimeInMs || (hoursInYear * millisecondsInHour); const passwordData = { p: credentials.password, l: logOnUser, t: currentTimeStamp, e: currentTimeStamp + expirationOffsetInMilliseconds }; return JSON.stringify(passwordData); } /** * Creates encrypted data for auth header * @param jwk the JSON web key to be used to encrypt data * @param data the data to be encrypted * @returns an encrypted string */ static createEncryptedExtensionDataHeader(jwk, data) { return Crypto.encryptRsaSha1(jwk, data) .pipe(map(encryptedData => window.btoa(Net.utf8Encode(encryptedData)))); } /** * Create /api/nodes URL with relativeUrl. * * @param gatewayName The name of gateway. * @param nodeName The name of node. * @param relativeUrl The relative Url. */ static gatewayNodeApi(gatewayName, nodeName, relativeUrl) { if (!relativeUrl) { relativeUrl = ''; } if (!relativeUrl.startsWith('/')) { relativeUrl = '/' + relativeUrl; } if (!nodeName) { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.ArgumentNullError.message; throw new Error(message.format('Net/gatewayNodeApi', 'nodeName')); } return Net.gatewayApi(gatewayName, `/nodes/${nodeName}${relativeUrl}`); } /** * Create /api URL with relativeUrl. * * @param gatewayName The name of gateway. * @param nodeName The name of node. * @param relativeUrl The relative Url. */ static gatewayApi(gatewayName, relativeUrl) { if (!gatewayName) { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.ArgumentNullError.message; throw new Error(message.format('Net/gatewayApi', 'gatewayName')); } if (!relativeUrl) { relativeUrl = ''; } if (!relativeUrl.startsWith('/')) { relativeUrl = '/' + relativeUrl; } gatewayName = gatewayName.toLowerCase(); if (!gatewayName.startsWith('http://') && !gatewayName.startsWith('https://')) { gatewayName = 'https://' + gatewayName; } return `${gatewayName}/api${relativeUrl}`; } /** * Get error message from ajax result or any other error result and optionally includes native error message. * * @param error the error context from Net.ajax. * @param options add additional optional error message: such as native error messages if possible * @return string the error message. */ static getErrorMessage(error, options) { const strings = MsftSme.getStrings().MsftSmeShell.Core; const prefixFormat = strings.Error.PrefixFormat.message; const errorPrefix = options && options.errorPrefix; const xhr = error && error.xhr; const exception = error && error.exception; if (typeof error === 'string') { return errorPrefix ? prefixFormat.format(error) : error; } if (xhr && xhr.response) { const message = Net.parseErrorResponse(xhr.response, options); if (message) { return errorPrefix ? prefixFormat.format(message) : message; } } if (error && error.message) { const errorMessage = errorPrefix ? prefixFormat.format(error.message) : error.message; if (error.details && Array.isArray(error.details)) { // Add details to error message. return this.parseErrorDetails(error.details, errorMessage); } return errorMessage; } if (exception && exception.message) { return errorPrefix ? prefixFormat.format(exception.message) : exception.message; } const statusText = xhr && xhr.statusText; if (statusText) { return errorPrefix ? prefixFormat.format(statusText) : statusText; } throw new Error(strings.Error.NoResponseError.message); } static parseErrorDetails(details, message) { const strings = MsftSme.getStrings().MsftSmeShell.Core; const detailsText = strings.Error.Details.text; const errorMessages = details.map((detail) => { try { const parsedDetail = JSON.parse(detail.message); if (parsedDetail?.error?.message) { return parsedDetail.error.message; } } catch (error) { // The message is not valid JSON return detail.message; } }); // Joining the error messages with newline characters const detailsMessage = `${detailsText}\n${errorMessages.join('\n\n')}`; // Joining the actual error message with details return `${message}\n\n${detailsMessage}`; } /** * Get error message from PowerShell ajax response. * Can be used by a PowerShell batch consumer to get error message in batch response. * * @param response the ajax response. * @return string the error message. */ static getPowerShellErrorMessage(response) { const message = Net.parseErrorResponse(response); if (message) { return message; } const strings = MsftSme.getStrings().MsftSmeShell.Core; throw new Error(strings.Error.NoResponseError.message); } /** * Get error code from ajax result. * * @param error the error context from Net.ajax. * @return string the error code. */ static getErrorCode(error) { const strings = MsftSme.getStrings().MsftSmeShell.Core; const err = error && error.xhr && error.xhr.response && error.xhr.response.error; if (!err) { throw new Error(strings.Error.NoResponseError.message); } if (err.code) { return err.code; } throw new Error(strings.Error.NoCode.message); } /** * Get error message from ajax result excluding error stackTrace * * @param error the error context from Net.ajax. * @return string the error. */ static getErrorMessageWithoutStacktrace(error) { let errorMessage = Net.getErrorMessage(error); if (errorMessage) { const stackTraceIndex = errorMessage.toLowerCase().indexOf('stacktrace'); if (stackTraceIndex > 0) { errorMessage = errorMessage.substring(0, stackTraceIndex); } } return errorMessage; } /** * Translates error code to string * * @param code the error code * @return string the related error string. */ static translateErrorCode(code) { const strings = MsftSme.getStrings().MsftSmeShell.Core; const message = Net.errorCodeMap[code]; if (message) { return strings.ErrorCode.Translated.message.format(message, code); } return strings.ErrorCode.Generic.message.format(code); } /** * Determine if this is an authorization login error. This code never work if it uses NTLM or Kerberos. * * @param error The ajax error object. */ static isUnauthorizedLogin(error) { // new login 401 handling. const forbidden = error?.xhr?.response?.error?.forbidden; return error.status === 401 /* HttpStatusCode.Unauthorized */ && forbidden && forbidden === 'UnauthorizedLogin'; } /** * Determine if this is an authorization error. * * @param error The ajax error object. */ static isUnauthorized(error) { const errorObject = error?.xhr?.response?.error; const forbidden = errorObject?.forbidden; if (forbidden) { // new 403 handling. return error.status === 403 /* HttpStatusCode.Forbidden */ && forbidden === 'Unauthorized'; } else { // legacy 401 handling. (this should be obsolete now) const unauthorized = errorObject?.unauthorized; return error.status === 401 /* HttpStatusCode.Unauthorized */ && !(unauthorized && unauthorized === 'UnauthorizedLogin'); } } /** * Determine if this is an forbidden error. * * @param error The ajax error object. */ static isForbidden(error) { const forbidden = error?.xhr?.response?.error?.forbidden; if (forbidden) { // new forbidden. return error.status === 400 /* HttpStatusCode.BadRequest */ && forbidden === 'Forbidden'; } else { // legacy 403 handling. return error.status === 403 /* HttpStatusCode.Forbidden */; } } /** * Get property from an ErrorExtended error object * * @param error The ErrorExtended error object. * @param sourceName The source of the error. * @param propertyName The property to get from the error object. * @return The value of the property or null if the source doesn't match. */ static getErrorExtendedProperty(error, sourceName, propertyName) { if (error.extendedSource && (error.extendedSource === sourceName || error.extendedSource.includes(sourceName))) { return error?.extended[propertyName]; } return null; } /** * Parse error message from standard ajax error and PowerShell errors. * * @param response the ajax response. * @return string the error message. */ static parseErrorResponse(response, options) { const strings = MsftSme.getStrings().MsftSmeShell.Core; const err = response && response.error; if (err && err.message) { const errorMessage = err.message; if (options && options.addNativeError && err.detailRecord) { return strings.Error.AddNativeErrorCode.message.format(errorMessage, err.detailRecord.nativeErrorCode); } return errorMessage; } const psErrors = response && response.errors; if (psErrors && psErrors.length > 0) { if (psErrors.length === 1) { if (options && options.addNativeError && psErrors[0].detailRecord) { if (options && options.useRemoteExceptionMessage) { return strings.ErrorFormat.Single.Details.message.format(psErrors[0].errorType, psErrors[0].detailRecord.remoteExceptionMessage, psErrors[0].detailRecord.nativeErrorCode); } return strings.ErrorFormat.Single.Details.message.format(psErrors[0].errorType, psErrors[0].message, psErrors[0].detailRecord.nativeErrorCode); } if (options && options.useRemoteExceptionMessage && psErrors[0].detailRecord) { return strings.ErrorFormat.Single.message.format(psErrors[0].errorType, psErrors[0].detailRecord.remoteExceptionMessage); } return strings.ErrorFormat.Single.message.format(psErrors[0].errorType, psErrors[0].message); } let joinedMessage = ''; for (let i = 0; i < psErrors.length; i++) { if (options && options.addNativeError && psErrors[i].detailRecord) { joinedMessage += strings.ErrorFormat.Multiple.Details.message.format(i + 1, psErrors[i].errorType, psErrors[i].message, psErrors[i].detailRecord.nativeErrorCode); } else if (options && options.useRemoteExceptionMessage && psErrors[i].detailRecord) { joinedMessage += strings.ErrorFormat.Multiple.message.format(i + 1, psErrors[i].errorType, psErrors[i].detailRecord.remoteExceptionMessage); } else { joinedMessage += strings.ErrorFormat.Multiple.message.format(i + 1, psErrors[i].errorType, psErrors[i].message); } } return joinedMessage; } if (response && response.exception) { return response.exception; } return null; } static splitByLength(text, length) { const parts = new Array(); if (text === null) { return parts; } const totalLength = text.length; const count = Math.ceil(totalLength / length); if (count < 2) { parts.push(text); return parts; } const lastPart = count - 1; let position = 0; for (let i = 0; i < lastPart; i++, position += length) { parts.push(text.substring(position, position + length)); } parts.push(text.substring(position)); return parts; } } //# sourceMappingURL=net.js.map // SIG // Begin signature block // SIG // MIIoKwYJKoZIhvcNAQcCoIIoHDCCKBgCAQExDzANBglg // SIG // hkgBZQMEAgEFADB3BgorBgEEAYI3AgEEoGkwZzAyBgor // SIG // BgEEAYI3AgEeMCQCAQEEEBDgyQbOONQRoqMAEEvTUJAC // SIG // AQACAQACAQACAQACAQAwMTANBglghkgBZQMEAgEFAAQg // SIG // 4ngYDGhavZNjD3TiQMRcNIU67vpaTjZNJYyzsfeljAyg // SIG // gg12MIIF9DCCA9ygAwIBAgITMwAABARsdAb/VysncgAA // SIG // AAAEBDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV // SIG // UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH // SIG // UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv // SIG // cmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBT // SIG // aWduaW5nIFBDQSAyMDExMB4XDTI0MDkxMjIwMTExNFoX // SIG // DTI1MDkxMTIwMTExNFowdDELMAkGA1UEBhMCVVMxEzAR // SIG // BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v // SIG // bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv // SIG // bjEeMBwGA1UEAxMVTWljcm9zb2Z0IENvcnBvcmF0aW9u // SIG // MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA // SIG // tCg32mOdDA6rBBnZSMwxwXegqiDEUFlvQH9Sxww07hY3 // SIG // w7L52tJxLg0mCZjcszQddI6W4NJYb5E9QM319kyyE0l8 // SIG // EvA/pgcxgljDP8E6XIlgVf6W40ms286Cr0azaA1f7vaJ // SIG // jjNhGsMqOSSSXTZDNnfKs5ENG0bkXeB2q5hrp0qLsm/T // SIG // WO3oFjeROZVHN2tgETswHR3WKTm6QjnXgGNj+V6rSZJO // SIG // /WkTqc8NesAo3Up/KjMwgc0e67x9llZLxRyyMWUBE9co // SIG // T2+pUZqYAUDZ84nR1djnMY3PMDYiA84Gw5JpceeED38O // SIG // 0cEIvKdX8uG8oQa047+evMfDRr94MG9EWwIDAQABo4IB // SIG // czCCAW8wHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYB // SIG // BQUHAwMwHQYDVR0OBBYEFPIboTWxEw1PmVpZS+AzTDwo // SIG // oxFOMEUGA1UdEQQ+MDykOjA4MR4wHAYDVQQLExVNaWNy // SIG // b3NvZnQgQ29ycG9yYXRpb24xFjAUBgNVBAUTDTIzMDAx // SIG // Mis1MDI5MjMwHwYDVR0jBBgwFoAUSG5k5VAF04KqFzc3 // SIG // IrVtqMp1ApUwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDov // SIG // L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWlj // SIG // Q29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNybDBhBggr // SIG // BgEFBQcBAQRVMFMwUQYIKwYBBQUHMAKGRWh0dHA6Ly93 // SIG // d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWlj // SIG // Q29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNydDAMBgNV // SIG // HRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQCI5g/S // SIG // KUFb3wdUHob6Qhnu0Hk0JCkO4925gzI8EqhS+K4umnvS // SIG // BU3acsJ+bJprUiMimA59/5x7WhJ9F9TQYy+aD9AYwMtb // SIG // KsQ/rst+QflfML+Rq8YTAyT/JdkIy7R/1IJUkyIS6srf // SIG // G1AKlX8n6YeAjjEb8MI07wobQp1F1wArgl2B1mpTqHND // SIG // lNqBjfpjySCScWjUHNbIwbDGxiFr93JoEh5AhJqzL+8m // SIG // onaXj7elfsjzIpPnl8NyH2eXjTojYC9a2c4EiX0571Ko // SIG // mhENF3RtR25A7/X7+gk6upuE8tyMy4sBkl2MUSF08U+E // SIG // 2LOVcR8trhYxV1lUi9CdgEU2CxODspdcFwxdT1+G8YNc // SIG // gzHyjx3BNSI4nOZcdSnStUpGhCXbaOIXfvtOSfQX/UwJ // SIG // oruhCugvTnub0Wna6CQiturglCOMyIy/6hu5rMFvqk9A // SIG // ltIJ0fSR5FwljW6PHHDJNbCWrZkaEgIn24M2mG1M/Ppb // SIG // /iF8uRhbgJi5zWxo2nAdyDBqWvpWxYIoee/3yIWpquVY // SIG // cYGhJp/1I1sq/nD4gBVrk1SKX7Do2xAMMO+cFETTNSJq // SIG // fTSSsntTtuBLKRB5mw5qglHKuzapDiiBuD1Zt4QwxA/1 // SIG // kKcyQ5L7uBayG78kxlVNNbyrIOFH3HYmdH0Pv1dIX/Mq // SIG // 7avQpAfIiLpOWwcbjzCCB3owggVioAMCAQICCmEOkNIA // SIG // AAAAAAMwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYT // SIG // AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH // SIG // EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y // SIG // cG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290 // SIG // IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDExMB4XDTEx // SIG // MDcwODIwNTkwOVoXDTI2MDcwODIxMDkwOVowfjELMAkG // SIG // A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO // SIG // BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m // SIG // dCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9zb2Z0 // SIG // IENvZGUgU2lnbmluZyBQQ0EgMjAxMTCCAiIwDQYJKoZI // SIG // hvcNAQEBBQADggIPADCCAgoCggIBAKvw+nIQHC6t2G6q // SIG // ghBNNLrytlghn0IbKmvpWlCquAY4GgRJun/DDB7dN2vG // SIG // EtgL8DjCmQawyDnVARQxQtOJDXlkh36UYCRsr55JnOlo // SIG // XtLfm1OyCizDr9mpK656Ca/XllnKYBoF6WZ26DJSJhIv // SIG // 56sIUM+zRLdd2MQuA3WraPPLbfM6XKEW9Ea64DhkrG5k // SIG // NXimoGMPLdNAk/jj3gcN1Vx5pUkp5w2+oBN3vpQ97/vj // SIG // K1oQH01WKKJ6cuASOrdJXtjt7UORg9l7snuGG9k+sYxd // SIG // 6IlPhBryoS9Z5JA7La4zWMW3Pv4y07MDPbGyr5I4ftKd // SIG // gCz1TlaRITUlwzluZH9TupwPrRkjhMv0ugOGjfdf8NBS // SIG // v4yUh7zAIXQlXxgotswnKDglmDlKNs98sZKuHCOnqWbs // SIG // YR9q4ShJnV+I4iVd0yFLPlLEtVc/JAPw0XpbL9Uj43Bd // SIG // D1FGd7P4AOG8rAKCX9vAFbO9G9RVS+c5oQ/pI0m8GLhE // SIG // fEXkwcNyeuBy5yTfv0aZxe/CHFfbg43sTUkwp6uO3+xb // SIG // n6/83bBm4sGXgXvt1u1L50kppxMopqd9Z4DmimJ4X7Iv // SIG // hNdXnFy/dygo8e1twyiPLI9AN0/B4YVEicQJTMXUpUMv // SIG // dJX3bvh4IFgsE11glZo+TzOE2rCIF96eTvSWsLxGoGyY // SIG // 0uDWiIwLAgMBAAGjggHtMIIB6TAQBgkrBgEEAYI3FQEE // SIG // AwIBADAdBgNVHQ4EFgQUSG5k5VAF04KqFzc3IrVtqMp1 // SIG // ApUwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYD // SIG // VR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j // SIG // BBgwFoAUci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0f // SIG // BFMwUTBPoE2gS4ZJaHR0cDovL2NybC5taWNyb3NvZnQu // SIG // Y29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0 // SIG // MjAxMV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRS // SIG // MFAwTgYIKwYBBQUHMAKGQmh0dHA6Ly93d3cubWljcm9z // SIG // b2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0MjAx // SIG // MV8yMDExXzAzXzIyLmNydDCBnwYDVR0gBIGXMIGUMIGR // SIG // BgkrBgEEAYI3LgMwgYMwPwYIKwYBBQUHAgEWM2h0dHA6 // SIG // Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvZG9jcy9w // SIG // cmltYXJ5Y3BzLmh0bTBABggrBgEFBQcCAjA0HjIgHQBM // SIG // AGUAZwBhAGwAXwBwAG8AbABpAGMAeQBfAHMAdABhAHQA // SIG // ZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEA // SIG // Z/KGpZjgVHkaLtPYdGcimwuWEeFjkplCln3SeQyQwWVf // SIG // Liw++MNy0W2D/r4/6ArKO79HqaPzadtjvyI1pZddZYSQ // SIG // fYtGUFXYDJJ80hpLHPM8QotS0LD9a+M+By4pm+Y9G6XU // SIG // tR13lDni6WTJRD14eiPzE32mkHSDjfTLJgJGKsKKELuk // SIG // qQUMm+1o+mgulaAqPyprWEljHwlpblqYluSD9MCP80Yr // SIG // 3vw70L01724lruWvJ+3Q3fMOr5kol5hNDj0L8giJ1h/D // SIG // Mhji8MUtzluetEk5CsYKwsatruWy2dsViFFFWDgycSca // SIG // f7H0J/jeLDogaZiyWYlobm+nt3TDQAUGpgEqKD6CPxNN // SIG // ZgvAs0314Y9/HG8VfUWnduVAKmWjw11SYobDHWM2l4bf // SIG // 2vP48hahmifhzaWX0O5dY0HjWwechz4GdwbRBrF1HxS+ // SIG // YWG18NzGGwS+30HHDiju3mUv7Jf2oVyW2ADWoUa9WfOX // SIG // pQlLSBCZgB/QACnFsZulP0V3HjXG0qKin3p6IvpIlR+r // SIG // +0cjgPWe+L9rt0uX4ut1eBrs6jeZeRhL/9azI2h15q/6 // SIG // /IvrC4DqaTuv/DDtBEyO3991bWORPdGdVk5Pv4BXIqF4 // SIG // ETIheu9BCrE/+6jMpF3BoYibV3FWTkhFwELJm3ZbCoBI // SIG // a/15n8G9bW1qyVJzEw16UM0xghoNMIIaCQIBATCBlTB+ // SIG // MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv // SIG // bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj // SIG // cm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNy // SIG // b3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExAhMzAAAE // SIG // BGx0Bv9XKydyAAAAAAQEMA0GCWCGSAFlAwQCAQUAoIGu // SIG // MBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisG // SIG // AQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3 // SIG // DQEJBDEiBCAqcbIwMJa6o0UsqqEvDAkmFT/vClhnXShO // SIG // ZAMVKZWN0TBCBgorBgEEAYI3AgEMMTQwMqAUgBIATQBp // SIG // AGMAcgBvAHMAbwBmAHShGoAYaHR0cDovL3d3dy5taWNy // SIG // b3NvZnQuY29tMA0GCSqGSIb3DQEBAQUABIIBAKPxSvkm // SIG // xqRAdpJwPaY39K2HY/cfpnJVUC6gi+41bzWx8zsxlZPk // SIG // Y/CHKRc4DvbjfhOBpRKp7h97E/07MCrYr6ApNgLw6C1l // SIG // zVOKEEMdj097/gb9TZ3KC+eSf2zUHPKm/xXsKPSQPEgs // SIG // NTaV1SwJc0Vu1s1KCpQEMME2CS6PfLApQaew+NrRtIwj // SIG // g9koUrlk0raU+WPpBB4YcBUWN5g0vmOK0IWsi8mMtbOh // SIG // RUosJwUUam40WU48AZZy6HI09IDjQRe9ZiKIgXEEho0q // SIG // XBdgc7WFd1blezNRj6WPP9O7XDCKuPF6Nlf5SJZ6Jcx4 // SIG // ZLYX0kkRIXrB51NKDCbEFWpUlZ6hgheXMIIXkwYKKwYB // SIG // BAGCNwMDATGCF4Mwghd/BgkqhkiG9w0BBwKgghdwMIIX // SIG // bAIBAzEPMA0GCWCGSAFlAwQCAQUAMIIBUgYLKoZIhvcN // SIG // AQkQAQSgggFBBIIBPTCCATkCAQEGCisGAQQBhFkKAwEw // SIG // MTANBglghkgBZQMEAgEFAAQgwez10ESaGNB39VV/Kppg // SIG // b+gHDKvSZe7dGpaAc62tPDQCBmet6zVgiBgTMjAyNTAy // SIG // MjAxNTI4MzIuODA2WjAEgAIB9KCB0aSBzjCByzELMAkG // SIG // A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO // SIG // BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m // SIG // dCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0 // SIG // IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNo // SIG // aWVsZCBUU1MgRVNOOkEwMDAtMDVFMC1EOTQ3MSUwIwYD // SIG // VQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl // SIG // oIIR7TCCByAwggUIoAMCAQICEzMAAAHr4BhstbbvOO0A // SIG // AQAAAeswDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMC // SIG // VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT // SIG // B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw // SIG // b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUt // SIG // U3RhbXAgUENBIDIwMTAwHhcNMjMxMjA2MTg0NTM0WhcN // SIG // MjUwMzA1MTg0NTM0WjCByzELMAkGA1UEBhMCVVMxEzAR // SIG // BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v // SIG // bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv // SIG // bjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3Bl // SIG // cmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNO // SIG // OkEwMDAtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3Nv // SIG // ZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG // SIG // 9w0BAQEFAAOCAg8AMIICCgKCAgEAwRVoIdpW4Fd3iadN // SIG // aKomhQbmGzXO4UippLbydeTawfwwW6FKMPFjzkz8W5+4 // SIG // HJiDhpsCZHfk8hceyjp868Z6Ad4br7/dX2blLoCLCk5w // SIG // L4NgVP53ze2c5/SpNZqbidu0usVAx+KHRYl+dSAnCpeh // SIG // BuHMSoHAwIp4oU/Ma6CVlQEy+6fG2358LHNaYoWZnLyL // SIG // mBp29U2PbZ6XQoVq/RAEbgqN04kRozNi6eKYk9pQ+YZ3 // SIG // d1Whk3qTasmpKZAhldPnCvFbvx5CGXb8vs+RC96I03RS // SIG // y+byfSAKIFn91wLt3e0qRWmqHosdHtaueQA/eGcAz/os // SIG // 6i2nbAUd7c46tkX6wjS/k5ov42pUbaPyem4eHz4RxE5w // SIG // wu/E9cn11EHRrZif7rSPwDcYux1fIAD84nfU2IzD22Kh // SIG // vMucc/oCP0hco/mirRx1pisxFz7bV8wHHsSdRB+8G7ol // SIG // ZN7BKzyvTC4NV2+oTORyFgNIxAGYShMneYR9lzIm82pG // SIG // 6drNhCUFmrEHOAzGhdRLENQs4ApQ2CGBuq1IbnXyO5PC // SIG // /SighLn0WyuZXUWDQKnXa/8kiX7mb9z0t/r7Q+l+qtR+ // SIG // FDpowynY6Ft6rOyUTGZh/X5BZDM2+mEs6+nl9S6GJtz6 // SIG // ztSXmuN0mM5Qd08/ODr7lUlezXInVbTaomXllqVY32r0 // SIG // fiY/yTkCAwEAAaOCAUkwggFFMB0GA1UdDgQWBBR0ngWs // SIG // 1lXMbuKk/TuY09gfqgHq4TAfBgNVHSMEGDAWgBSfpxVd // SIG // AF5iXYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQ // SIG // hk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz // SIG // L2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENB // SIG // JTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwG // SIG // CCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5j // SIG // b20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUt // SIG // U3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNVHRMB // SIG // Af8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4G // SIG // A1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEA // SIG // g3TfL6D3fAvlVmT9/lvO3P0G3W1itLDrfWeJBDlp4Oyp // SIG // oflg9i5zyUySiBGsZ4jnLfcDICfMkMsEfFh4Azr28Kna // SIG // rC1GjODa3q7SOhSPa4Y4XmisTTZwWcx2Sw8JZC/bwhA3 // SIG // vUXNHRklXeQYNwlpJ1d7r1WrteBeeREk1iATWkEvQqaN // SIG // jqc93EYAGFX2ixRmwKzXEb0lr0lG3iNiA6kcQuMQW0Yj // SIG // UPtah1wwj59IRrF3y/spw2Z3An7Mza5YGU9uF4Ib082D // SIG // B3F4qC1WKP9h5MqMOnSO7lCyWysS1/MB4bIsK4lyAwp4 // SIG // y1bBtBOW0fNkIHLHhIcW1NndUVR3ELZFBO1vc8Wamev4 // SIG // z5mqI2YF0Dt9148Th2GFWvwV3CLrvEjMz44wAG7o8E2s // SIG // KWsywb/fey0QdGTmzXJCWMkEKRE0n5Td+o1vs+0f5xsi // SIG // akWdx7WdZV1tX+sxAgHj/vXcup5nAq1XDqm0B1+2a/Fj // SIG // 3IIRyQAA5ZuRMT4ecYtbTUZPouhdmvUqU3kJ2Vz+dMPi // SIG // aE8SEkKu7wYo9p4rQLEi2lXjKqD4vjV5U1DWdjXbWxa+ // SIG // iIq/WSvbn2s9xcX7w2aN+ubyzqM5kDnv2fqbuL2Ocz5r // SIG // TYlSHEJxcuyWTomVQyOWyHcEEWotqrhyiepbVHbItx4z // SIG // Z4nrhO9n0+HlocbZpzeR2AgwggdxMIIFWaADAgECAhMz // SIG // AAAAFcXna54Cm0mZAAAAAAAVMA0GCSqGSIb3DQEBCwUA // SIG // MIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu // SIG // Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV // SIG // TWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylN // SIG // aWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3Jp // SIG // dHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAx // SIG // ODMyMjVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX // SIG // YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD // SIG // VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV // SIG // BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw // SIG // MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA // SIG // 5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1 // SIG // V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeF // SIG // RiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTzxXb1hlDc // SIG // wUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmvHaus // SIG // 9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoPz130 // SIG // /o5Tz9bshVZN7928jaTjkY+yOSxRnOlwaQ3KNi1wjjHI // SIG // NSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3tpK56KTes // SIG // y+uDRedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGp // SIG // F1tnYN74kpEeHT39IM9zfUGaRnXNxF803RKJ1v2lIH1+ // SIG // /NmeRd+2ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fz // SIG // pk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNO // SIG // wTM5TI4CvEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLi // SIG // Mxhy16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5 // SIG // UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9Q // SIG // BXpsxREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6H // SIG // XtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZMBIG // SIG // CSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYE // SIG // FCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSf // SIG // pxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAEVTBTMFEG // SIG // DCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRw // SIG // Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3Mv // SIG // UmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYIKwYBBQUH // SIG // AwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYD // SIG // VR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j // SIG // BBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0f // SIG // BE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQu // SIG // Y29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0 // SIG // XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBK // SIG // BggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQu // SIG // Y29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0w // SIG // Ni0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1Vffwq // SIG // reEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9MTO1 // SIG // OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpT // SIG // Td2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinL // SIG // btg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OOPcbzaN9l // SIG // 9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3+SmJ // SIG // w7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2Fz // SIG // Lixre24/LAl4FOmRsqlb30mjdAy87JGA0j3mSj5mO0+7 // SIG // hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY // SIG // 3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFX // SIG // SVRk2XPXfx5bRAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFU // SIG // a2pFEUep8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz // SIG // /gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/ // SIG // AsGConsXHRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1 // SIG // ZyvgDbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328 // SIG // y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEG // SIG // ahC0HVUzWLOhcGbyoYIDUDCCAjgCAQEwgfmhgdGkgc4w // SIG // gcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n // SIG // dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN // SIG // aWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1p // SIG // Y3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNV // SIG // BAsTHm5TaGllbGQgVFNTIEVTTjpBMDAwLTA1RTAtRDk0 // SIG // NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg // SIG // U2VydmljZaIjCgEBMAcGBSsOAwIaAxUAgAaJdbtcMMGI // SIG // FLVKMDJ6mL27pd6ggYMwgYCkfjB8MQswCQYDVQQGEwJV // SIG // UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH // SIG // UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv // SIG // cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1T // SIG // dGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsFAAIFAOth // SIG // o6MwIhgPMjAyNTAyMjAxMjUwNDNaGA8yMDI1MDIyMTEy // SIG // NTA0M1owdzA9BgorBgEEAYRZCgQBMS8wLTAKAgUA62Gj // SIG // owIBADAKAgEAAgIGhQIB/zAHAgEAAgISljAKAgUA62L1 // SIG // IwIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZ // SIG // CgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqG // SIG // SIb3DQEBCwUAA4IBAQCqmdoVIcQkdywsk3DlsCG8CNkD // SIG // HmucLSQKhujaX4Icn/UCAeCGwMX0gc7+7MvpP4eoAvcT // SIG // m2Eb0Ufp3TbU9RZtqiubFlYv+w0dMJNUI37vTO7+WWO6 // SIG // 1KwAZ5SylTtZv9D5Ptn/jrjxKSvWU9DUdTSyscln1UCZ // SIG // lm6KbsNpaLuUYvnP3yL7cFYgLZ3m8FdLHSC9MnmTsOke // SIG // fhDB7PU42AmyZh7zIYzHHfpAcMRzPZdRE9PPud3OL6Pl // SIG // wT7GF13SdmXlZRx6QZKx9a6NFgOoG3Ww7wCyXkBf01IS // SIG // 1RX3/RZESocEXDpQNCgoUrpIOpXnO5pubrRc0NVbwpTY // SIG // zVNOIbtbMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMC // SIG // VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT // SIG // B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw // SIG // b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUt // SIG // U3RhbXAgUENBIDIwMTACEzMAAAHr4BhstbbvOO0AAQAA // SIG // AeswDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJ // SIG // AzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQg // SIG // RvG48sJd27i7RHjBBZOYR0J1LtNvpEvz+P4oBApUSHAw // SIG // gfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCDOt2u+ // SIG // X2kD4X/EgQ07ZNg0lICG3Ys17M++odSXYSws+DCBmDCB // SIG // gKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo // SIG // aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK // SIG // ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT // SIG // HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMz // SIG // AAAB6+AYbLW27zjtAAEAAAHrMCIEIJh7GNfZ8w9h49KT // SIG // d4HB2/FaX9VTJAqI4Jon3cRbosDVMA0GCSqGSIb3DQEB // SIG // CwUABIICALdZyC0TFfvUMNVWRyIAfachW3LYljNwWYRe // SIG // 1D4y+ZxSgdswA+eryNfjuNhf+Jk3H5RbrDjoi2AAXKfP // SIG // FV4n4dyCDq8nGC6bDyIdVFRVDVpCv8JqgetEX8KGoFSc // SIG // RqXQlVf3itgLtqYMl93lfAI/G7PplukrrmHrAUrjKNdT // SIG // S54/2bvTomFG5Lt2GLPVKhSptAFTV72sMtZArrgpx780 // SIG // hp4HSOtgp4QXRPAwzVGNBoO3zcMyVaA5B9Cb/e76tYB3 // SIG // GcawoTe3EPclbxlBHWWkmAicpH7jFaR2gWIwjO9zdO/o // SIG // c89c4mYHPJ5RObRZsQjvyADgaN4Sp0t4XN55KWfXQXzS // SIG // wknShWoOpcenhgWx3MZpOXQiSQC5oClvVef9KvgNm6f7 // SIG // gZhyVS7u4bSFepsOSWekYNpKNZ6w1A7EYV6yoenQo1lb // SIG // QzTbtrf6HNWXbk0muQqTljfv9XKVMd+OGPy4kO1E4bbo // SIG // Z7ESHBvXWzH36Dc28IJiD3B68i6Xaa8+kKo/jkH8VCgZ // SIG // lflIz2Hha0l6eOEDyEDiPT1OP4a7Rsr22uCKdiTuytiy // SIG // ERTppBIdI3k4AHVSs20Ep8e+jSzuit6z2UBA8rGKoBoF // SIG // ToQ+xpVUelFoeFVtEPodylurdEmVDeztYyiDK+PZpjHQ // SIG // w9NESAa1aDG0lHfgtjcTMCBixWd7Uk/b // SIG // End signature block