UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

858 lines (855 loc) 40.1 kB
import { NativeDeferred } from '../data/native-q'; import { Net } from '../data/net'; import { LogLevel } from '../diagnostics/log-level'; import { Logging } from '../diagnostics/logging'; import { EnvironmentModule } from '../manifest/environment-modules'; import { RpcBase, RpcMessagePacketType, RpcOutboundCommands, RpcType } from './rpc-base'; import { RpcOutbound } from './rpc-outbound'; import { RpcSeekKey, RpcSeekMode } from './seek/rpc-seek-model'; /** * RpcChannel class. * - Both Shell and Module creates one instance to present itself. */ export class RpcChannel extends RpcBase { // Current Rpc mode. rpcMode; // Signature of the gateway running instance. signature; // RpcShell/RpcModule collection. rpcCollection = new Map(); sequence = 0; deferredQueue = new Map(); global = window; inboundHandlers; listenerFunction; webpackInvalid = false; /** * Initiates a new instance of the RpcChannel class. * * @param name the public name of itself. * @param origin the origin url of itself. * @param signature the signature of the gateway running instance. */ constructor(name, origin, signature) { super(null, name, origin, RpcType.Channel); this.signature = signature; if (MsftSme.isShell()) { this.rpcMode = 0 /* RpcMode.Shell */; this.depth = 0; } else { this.rpcMode = 1 /* RpcMode.Module */; this.depth = null; } } /** * Sets the rpc inbound handlers to use when creating for seek command. */ set rpcInboundHandlers(handlers) { this.inboundHandlers = handlers; } /** * Register Inbound/Outbound. * * @param rpcObject the RpcInbound/RpcOutbound class instance. * @param type the type of rpc object. */ registerRpc(rpcObject, type) { if (rpcObject.type !== type) { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcTypeNoMatch.message; throw new Error(message.format('registerRpc')); } this.addToCollection(rpcObject); } /** * Unregister module with subName * * @param name the name of module. * @param subName the subName. * @return RpcBase the rpc object. */ unregisterRpc(name, subName, type) { // unregister it by both origin and name. const rpcObject = this.getFromCollection(name, subName, true); if (rpcObject.type !== type) { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcTypeNoMatch.message; throw new Error(message.format('unregisterRpc')); } if (rpcObject) { this.removeFromCollection(rpcObject); return rpcObject; } else { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcNotFoundModule.message; throw new Error(message.format(name, subName)); } } /** * Get Rpc object by module with subName for Inbound. * * @param name the name of module. * @param subName the subName. * @param type the type of rpc object. * @param exact the matching type forced. * @return RpcBase the rpc object. */ getRpc(name, subName, type, nullOk = false) { const rpcObject = this.getFromCollection(name, subName, true); if (rpcObject && rpcObject.type !== type) { if (nullOk) { return null; } const message = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcTypeNoMatch.message; throw new Error(message.format('getRpc')); } // return null if it cannot find. return rpcObject; } /** * Get all Rpc objects for the specified type. */ getAllRpc(type) { const results = []; this.rpcCollection.forEach((subCollection) => { subCollection.forEach((rpc) => { if (rpc.type === type) { results.push(rpc); } }); }); return results; } /** * Get RpcInbound/RpcOutbound object for module name and module sub name. * If it doesn't configure subName yet, it returns it so the channel set it up. * * @param name the module name. * @param subName the sub name of the iframe object. * @return RpcBase the matched Rpc object. */ getFromCollection(name, subName, exact) { const subCollection = this.rpcCollection.get(name); if (subCollection == null) { return null; } return subCollection.find(value => (!exact && value.subName == null) || value.subName === subName); } removeFromCollection(rpcObject) { const subCollection = this.rpcCollection.get(rpcObject.name); if (subCollection == null) { return null; } const results = MsftSme.remove(subCollection, rpcObject); if (subCollection.length === 0) { // remove the entry if it's empty. this.rpcCollection.delete(rpcObject.name); } if (results && results.length === 1) { return results[0]; } return null; } addToCollection(rpcObject) { let subCollection = this.rpcCollection.get(rpcObject.name); if (subCollection == null) { subCollection = [rpcObject]; this.rpcCollection.set(rpcObject.name, subCollection); } else { subCollection.push(rpcObject); } } /** * Start the message listener. */ start() { this.listenerFunction = (ev) => this.listener(ev); this.global.addEventListener('message', this.listenerFunction); } /** * Stop the message listener. */ stop() { this.global.removeEventListener('message', this.listenerFunction); } /** * Post the message with retry delay. * * @param target the RpcToModule or RpcToShell object. * @param message the message packet. * @param count the retry count. * @param delay the interval milliseconds. * @return Promise<T> the promise object. */ retryPost(target, message, count, delay) { if (target == null || target.window == null) { const message2 = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcTargetWindowNotConfigured.message; throw new Error(message2); } const deferred = new NativeDeferred(); const lastSequence = this.sequence; this.deferredQueue[this.sequence] = deferred; message.srcName = this.name; message.srcSubName = this.subName; message.srcDepth = this.depth; message.destName = target.name; message.destSubName = target.subName; message.signature = this.signature; message.sequence = this.sequence; message.type = RpcMessagePacketType.Request; // post this.sequence++; const header = `Retry ${RpcMessagePacketType[message.type]} "${message.command}" to ${message.destName}!${message.destSubName}`; this.debugLogRpcMessage(message, header); target.window.postMessage(message, target.origin); const timer = setInterval(() => { if (deferred.isPending) { if (--count < 0) { const message2 = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcExpiredRetry.message; clearInterval(timer); deferred.reject(message2.format(message.command)); if (this.deferredQueue[lastSequence]) { delete this.deferredQueue[lastSequence]; } return; } target.window.postMessage(message, target.origin); return; } clearInterval(timer); }, delay); return deferred.promise; } /** * Post the request message. * * @param target the RpcToModule or RpcToShell object. * @param message the message packet. * @param timeout the timeout. (10 seconds at default) * @return Promise<TResult> the promise object. */ post(target, message, timeout) { let ignoreTimeout = false; if (timeout === -1) { ignoreTimeout = true; timeout = null; } timeout = timeout || 10 * 1000; // 10 seconds if (target == null || target.window == null) { const message2 = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcTargetWindowNotConfigured.message; throw new Error(message2); } const deferred = new NativeDeferred(); const lastSequence = this.sequence; this.deferredQueue[this.sequence] = deferred; message.srcName = this.name; message.srcSubName = this.subName; message.srcDepth = this.depth; message.destName = target.name; message.destSubName = target.subName; message.signature = this.signature; message.sequence = this.sequence; message.type = RpcMessagePacketType.Request; // post this.sequence++; const header = `${RpcMessagePacketType[message.type]} "${message.command}" to ${message.destName}!${message.destSubName}`; this.debugLogRpcMessage(message, header); target.window.postMessage(message, target.origin); setTimeout(() => { if (deferred.isPending) { if (ignoreTimeout) { deferred.resolve(); } else { const message2 = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcExpired.message; deferred.reject(message2.format(this.name, this.subName, target.name, target.subName, message.command, message.type)); } } if (this.deferredQueue[lastSequence]) { delete this.deferredQueue[lastSequence]; } }, timeout); return deferred.promise; } /** * Validate the target window if exist by sending null packet. * * @param target the target Rpc object. * @return boolean if false, it remove the target from the list. */ validate(target) { try { target.window.postMessage({ validate: 'validate' }, target.origin); return true; } catch (error) { this.removeFromCollection(target); return false; } } /** * Log the debug message. * @param message the message object. * @param header the header string (used for the log group header). */ debugLog(message, header) { Logging.log({ source: 'rpc', message: message, level: LogLevel.Debug, consoleGroupHeader: header }); } /** * Process and log and rpc message. * @param message the rpc message packet * @param header the header string (used for the log group header). */ debugLogRpcMessage(message, header) { const logMessage = { ...message }; if (message.command === RpcOutboundCommands[RpcOutboundCommands.Init]) { // Why is this hidden? logMessage.data = '(hidden...)'; } this.debugLog(logMessage, header); } /** * The listen handler. * * @param messageEvent the Rpc message event. */ listener(messageEvent) { // ignore any shell hosting messages (don't handle them at all) if (MsftSme.isShell()) { const type = MsftSme.getValue(messageEvent, 'data.type'); if (typeof type === 'string' && type.startsWith('msft-sme-shell-host')) { return; } } // We are operating as an iframe, any message we get, we should format to the parent to handle if (MsftSme.isExtension() && window && window.parent && messageEvent.source === window.self && messageEvent.data && (messageEvent.data.type === 'webpackInvalid' || messageEvent.data.type === 'webpackOk')) { // The rpc channel is an iframe, we need to send a message to the parent for the parent to reload after code change // window.parent references the parent window, postMessage sends a message to the parent // the '*' refers to sending the message to any origin, this can introduce potential security // concerns so we only send messages of type 'webpackInvalid' and 'webpackOk' window.parent.postMessage(messageEvent.data, '*'); } if ( // Extension windows will only trust messages from there parent window (MsftSme.isExtension() && messageEvent.source !== window.parent) // Shell window only trusts extension origins on rpc || (MsftSme.isShell() && !EnvironmentModule.isExtensionOrigin(messageEvent.origin))) { // if we don't trust the origin, then just log a message this.debugLog('RPC listener received message from untrusted sender: {0}'.format(messageEvent)); return; } if (messageEvent.data && messageEvent.data.type) { // Watch for webpack reloads coming from the iframe if (messageEvent.data.type === 'webpackInvalid') { // Webpack is invalid, 1st message this.webpackInvalid = true; } else if (this.webpackInvalid && messageEvent.data.type === 'webpackOk') { // Webpack is okay, 2nd message, we can reload this.webpackInvalid = false; location.reload(); } } // if the message if malformed, ignore it. if (!messageEvent.data || !messageEvent.data.command) { // ignore null event. this.debugLog('RPC listener received malformed message from sender: {0}'.format(messageEvent)); return; } const message = messageEvent.data; const header = `${RpcMessagePacketType[message.type]} "${message.command}" from ${message.srcName}!${message.srcSubName}`; this.debugLogRpcMessage(message, header); if (message.signature !== this.signature) { const message2 = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcSignatureError.message; throw new Error(message2); } // accept shell seek query if (message.destName !== this.name) { const message2 = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcUnexpectedDestination.message; throw new Error(message2.format(message.destName)); } let target = this.getFromCollection(message.srcName, message.srcSubName, false); if (!target) { // unknown request was received. if (message.type === RpcMessagePacketType.Request && message.command === RpcOutboundCommands[RpcOutboundCommands.Ping]) { target = this.getFromCollection('*', '*', true); if (target) { // keep remote window object to respond. // current channel is child, and target is parent. // target could be shell or a parent module. // remove the rpcInbound object once and re-register back again with new name. this.removeFromCollection(target); target.name = message.srcName; target.subName = message.srcSubName; target.window = messageEvent.source; target.origin = messageEvent.origin; target.depth = message.srcDepth; this.subName = message.destSubName; this.depth = message.srcDepth + 1; this.registerRpc(target, RpcType.Inbound); } } } // Seek to create or delete RpcInbound on the shell to access a child call. if (message.command === RpcSeekKey.command && this.name === EnvironmentModule.nameOfShell && message.type === RpcMessagePacketType.Request) { const seekData = message.data; if (seekData.mode === RpcSeekMode.Create) { if (target) { // update window object. target.subName = message.srcSubName; target.window = messageEvent.source; target.depth = message.srcDepth; } else { target = new RpcOutbound(this, message.srcName, messageEvent.origin); target.subName = message.srcSubName; target.window = messageEvent.source; target.depth = message.srcDepth; target.registerAll(this.inboundHandlers); this.registerRpc(target, RpcType.Outbound); } } else if (seekData.mode === RpcSeekMode.Delete && target) { this.removeFromCollection(target); } } if (!target) { // ignore older/unknown response packet. current channel no longer watching it for response, but treat new request as an error. if (message.type === RpcMessagePacketType.Request) { const message2 = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcUnexpectedEvent.message; throw new Error(message2.format(message.srcName, message.srcSubName)); } return; } let deferred; switch (message.type) { case RpcMessagePacketType.Request: // post: processing response/error. target.handle(message.command, message.version, message.srcName, message.srcSubName, message.data).then((data) => { message.data = data; return this.response(target, message); }, error => { let logMessage = ''; let logStack = ''; if (typeof error === 'string') { message.data = error; logMessage = error; } else { message.data = {}; if (error && error.xhr) { const netError = Net.getErrorMessage(error); message.data.message = netError; logMessage = netError; } else if (error.message) { message.data.message = error.message; logMessage = error.message; } if (error.stack) { message.data.stack = error.stack; logStack = error.stack; } } Logging.log({ source: 'RpcChannel', level: LogLevel.Error, message: logMessage, stack: logStack }); // telemetry with predefined view/action name. Logging.trace({ view: 'sme-generic-error', instance: 'rpc-channel', action: 'exceptionLog', data: { stack: '' } }); return this.error(target, message); }); break; case RpcMessagePacketType.Response: // response: received result with success. deferred = this.deferredQueue[message.sequence]; if (!deferred) { if (message.command === RpcOutboundCommands[RpcOutboundCommands.Ping]) { // ping can be sent multiple times and deferred could be settled already. break; } const message2 = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcUnexpectedSequence.message; throw new Error(message2); } delete this.deferredQueue[message.sequence]; deferred.resolve(message.data); break; case RpcMessagePacketType.Error: // error: received result with error. deferred = this.deferredQueue[message.sequence]; if (!deferred) { const message2 = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcUnexpectedErrorSequence.message; throw new Error(message2); } delete this.deferredQueue[message.sequence]; deferred.reject(message.data); break; } } /** * Sending response message. * * @param target the RpcToModule or RpcToShell object. * @param message the Rpc message packet. */ response(target, message) { if (target == null || target.window == null) { const message2 = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcTargetWindowNotConfigured.message; throw new Error(message2); } message.srcName = this.name; message.srcSubName = this.subName; message.srcDepth = this.depth; message.destName = target.name; message.destSubName = target.subName; message.signature = this.signature; message.type = RpcMessagePacketType.Response; // response target.window.postMessage(message, target.origin); } /** * Sending error message. * * @param target the RpcToModule or RpcToShell object. * @param message the Rpc message packet. */ error(target, message) { if (target == null || target.window == null) { const message2 = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcTargetWindowNotConfigured.message; throw new Error(message2); } message.srcName = this.name; message.srcSubName = this.subName; message.srcDepth = this.depth; message.destName = target.name; message.destSubName = target.subName; message.signature = this.signature; message.type = RpcMessagePacketType.Error; // error target.window.postMessage(message, target.origin); } } //# sourceMappingURL=rpc-channel.js.map // SIG // Begin signature block // SIG // MIIoKAYJKoZIhvcNAQcCoIIoGTCCKBUCAQExDzANBglg // SIG // hkgBZQMEAgEFADB3BgorBgEEAYI3AgEEoGkwZzAyBgor // SIG // BgEEAYI3AgEeMCQCAQEEEBDgyQbOONQRoqMAEEvTUJAC // SIG // AQACAQACAQACAQACAQAwMTANBglghkgBZQMEAgEFAAQg // SIG // gMddnM6x+pxDfrPC5ABqaA63Cb9R7CJXLo3ipVhRITmg // 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/15n8G9bW1qyVJzEw16UM0xghoKMIIaBgIBATCBlTB+ // SIG // MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv // SIG // bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj // SIG // cm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNy // SIG // b3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExAhMzAAAE // SIG // BGx0Bv9XKydyAAAAAAQEMA0GCWCGSAFlAwQCAQUAoIGu // SIG // MBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisG // SIG // AQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3 // SIG // DQEJBDEiBCACN6B8iNijpDrGyfqERL4UFjFZvBhThTW4 // SIG // 1tl73i/4WzBCBgorBgEEAYI3AgEMMTQwMqAUgBIATQBp // SIG // AGMAcgBvAHMAbwBmAHShGoAYaHR0cDovL3d3dy5taWNy // SIG // b3NvZnQuY29tMA0GCSqGSIb3DQEBAQUABIIBAA2oTKnp // SIG // gmHPY+ht9odaCEauSgoH0Dawv2xHFiQGhKL4xPwvK+Sb // SIG // XLrXRwUquJEfgiALECox47BtujNYbZHBouB/JSOtWc9O // SIG // rKXIfTZc/YQo5/JaLLU0xIbXoBT4DjSlXt46Xfm3a6ci // SIG // zHu1fGVLZhEk+Zzx/VvxOGhKsKw3b6HY2Z/wj4K0UMw+ // SIG // 079ET/FzTytUH16xh0axQgisjUEmebuJsnbRgoIB3aj6 // SIG // cIpmZsLOJo1ByqNIep9i5p4/cIWyIYFVUDdNmV7RbZ1m // SIG // fWj2heP0xs7Z6AbNkkjo6LPDVyn4JM0wFO3dakJoHbMT // SIG // QYZ+ZIAihp5NNbnt1bRt2NmfbzmhgheUMIIXkAYKKwYB // SIG // BAGCNwMDATGCF4Awghd8BgkqhkiG9w0BBwKgghdtMIIX // SIG // aQIBAzEPMA0GCWCGSAFlAwQCAQUAMIIBUgYLKoZIhvcN // SIG // AQkQAQSgggFBBIIBPTCCATkCAQEGCisGAQQBhFkKAwEw // SIG // MTANBglghkgBZQMEAgEFAAQgoq3Fhu5Sj7Z/rng6euk3 // SIG // OkRra52lr1bvJ3zoCjCgthwCBmet45UxDhgTMjAyNTAy // SIG // MjAxNTI4MzYuMjI1WjAEgAIB9KCB0aSBzjCByzELMAkG // SIG // A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO // SIG // BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m // SIG // dCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0 // SIG // IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNo // SIG // aWVsZCBUU1MgRVNOOjkyMDAtMDVFMC1EOTQ3MSUwIwYD // SIG // VQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl // SIG // oIIR6jCCByAwggUIoAMCAQICEzMAAAHnLo8vkwtPG+kA // SIG // AQAAAecwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMC // SIG // VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT // SIG // B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw // SIG // b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUt // SIG // U3RhbXAgUENBIDIwMTAwHhcNMjMxMjA2MTg0NTE5WhcN // SIG // MjUwMzA1MTg0NTE5WjCByzELMAkGA1UEBhMCVVMxEzAR // SIG // BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v // SIG // bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv // SIG // bjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3Bl // SIG // cmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNO // SIG // OjkyMDAtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3Nv // SIG // ZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG // SIG // 9w0BAQEFAAOCAg8AMIICCgKCAgEAwlefL+CLkOufVzzN // SIG // Q7WljL/fx0VAuZHYhBfPWAT+v0Z+5I6jJGeREnpn+RJY // SIG // uAi7UFUnn0aRdY+0uSyyorDFjhkWi3GlWxk33JiNbzES // SIG // dbczMAjSKAqv78vFh/EHVdQfwG+bCvkPciL8xsOO031z // SIG // xPEZa2rsCv3vp1p8DLdOtGpBGYiSc9VYdS4UmCmoj/Wd // SIG // txGZhhEwlooJCm3LgJ4b4d8qzGvPbgX2nh0GRBxkKnbJ // SIG // DOPBAXFklnaYkkgYgMcoR1JG5J5fTz87Qf0lMc0WY1M1 // SIG // h4PW39ZqmdHCIgFgtBIyuzjYZUHykkR1SyizT6Zd//lC // SIG // +F43NGL3anPPIDi1K//OE/f8Sua/Nrpb0adgPP2q/XBu // SIG // Fu+udLimgMUQJoC+ISoCF+f9GiALG8qiTmujiBkhfWvg // SIG // 315dS6UDzSke/drHBe7Yw+VqsCLon0vWFIhzL0S44ypN // SIG // Ekglf5qVwtAaD5JOWrH8a6yWwrCXjx0jhG5aSc0Zs2j+ // SIG // jjF8EXK2+01xUDrE5CrqpFr72CD71cwuvFDPjLJCz5Xd // SIG // XqnTjjCu0m239rRkmX9/ojsFkDHFlwfYMOYCtwCGCtPF // SIG // pCSbssz6n4rYLm3UQpmK/QlbDTrlvsBw2BoXIiQxdi5K // SIG // 45BVI1HF0iCXfX9rLGIrWfQrqxle+AUHH68Y75NS/I77 // SIG // Te5rpSMCAwEAAaOCAUkwggFFMB0GA1UdDgQWBBTP/uCY // SIG // gJ82OHaRH/2Za4dSu96PWDAfBgNVHSMEGDAWgBSfpxVd // SIG // AF5iXYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQ // SIG // hk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz // SIG // L2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENB // SIG // JTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwG // SIG // CCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5j // SIG // b20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUt // SIG // U3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNVHRMB // SIG // Af8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4G // SIG // A1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEA // SIG // dKHw25PpZVotXAup7H4nuSbadPaOm+gEQqb7Qz6tihT/ // SIG // oYvlDTT+yxnIirnJKlwpgUxSIXwXhksb5OsnKJHUK9/N // SIG // eaRDmmFk5x70NPvISsvOq9ReK3wbuKBweXE8tPE+KIax // SIG // vzmBvwf4DZ89Dper+7v6hI8+PM12emZcShsmcCpimVmg // SIG // Xdg2BMMyqXS5AcbOgOnp1mUdI2PquRXW1eOYIRkyoEq+ // SIG // RAgDpyw+J4ycH4yKtJkWVsA2UKF7SUmlR0rtpR0C92Bx // SIG // BYpLp21EyXzXwQyy+xr/rE5kYg2ZMuTgMaCxtoGk37oh // SIG // W36Zknz3IJeQjlM3zEJ86Sn1+vhZCNEEDb7j6VrA1PLE // SIG // frp4tlZg6O65qia6JuIoYFTXS2jHzVKrwS+WYkitc5mh // SIG // CwSfWvmDoxOaZkmq1ubBm5+4lZBdlvSUCDh+rRlixSUu // SIG // R7N+s2oZKB4fIg/ety3ho2apBbrCmlFu9sjI/8sU3hhA // SIG // zqCK9+ZMF8a9VLvs5Lq9svhbjWNKGY6ac6feQFtZXoT9 // SIG // MWjvqAVdV372grq/weT1QKdsc66LDBFHAMKSaYqPlWHy // SIG // Lnxo+5nl3BkGFgPFJq/CugLqPiZY/CHhUupUryoakKZn // SIG // QcwDBqjzkCrdTsN2V8XoSu7wIopt2YgC5TNCueOpNLGa // SIG // 8XWT4KZs+zvMPYBy7smQEHswggdxMIIFWaADAgECAhMz // 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 // ahC0HVUzWLOhcGbyoYIDTTCCAjUCAQEwgfmhgdGkgc4w // SIG // gcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n // SIG // dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN // SIG // aWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1p // SIG // Y3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNV // SIG // BAsTHm5TaGllbGQgVFNTIEVTTjo5MjAwLTA1RTAtRDk0 // SIG // NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg // SIG // U2VydmljZaIjCgEBMAcGBSsOAwIaAxUAs3IE5xmrEsHv // SIG // 3a7vnD3tTRf78EOggYMwgYCkfjB8MQswCQYDVQQGEwJV // SIG // UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH // SIG // UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv // SIG // cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1T // SIG // dGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsFAAIFAOth // SIG // nAMwIhgPMjAyNTAyMjAxMjE4MTFaGA8yMDI1MDIyMTEy // SIG // MTgxMVowdDA6BgorBgEEAYRZCgQBMSwwKjAKAgUA62Gc // SIG // AwIBADAHAgEAAgISVTAHAgEAAgITLzAKAgUA62LtgwIB // SIG // ADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMC // SIG // oAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3 // SIG // DQEBCwUAA4IBAQB/Go/n5DB53ySFShKauo/5PAMMhslf // SIG // oiTMki8OKjSRACXWD4yBJHquXs9hboyZNcK2yZsQVGBy // SIG // 6PAG+GgLHghfMINGswafHk8cSsyfxz6jqAOmW7Y59uLV // SIG // JL1wTwJZK9rW8Uk/+pxXCtBH/zkCERr8JPYys9AZiMK0 // SIG // +ypgY0a4M7sti62pzUtQihoCQaRGSqvZ5/dmqIb9yuIB // SIG // JKUz3HyxkK9TmkgoJPJC7fIp9/obu1jCzJJiVREDPgpy // SIG // 6ijIj/Tl+pPWZvghugJLjQm1mK21BoM0RdM8AyDJDnwo // SIG // Yj29UhzWX8rMs4S3+eWqMvCC3Jk/PC4m6oOyrixlRhtc // SIG // RacaMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMx // SIG // EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl // SIG // ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh // SIG // dGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3Rh // SIG // bXAgUENBIDIwMTACEzMAAAHnLo8vkwtPG+kAAQAAAecw // SIG // DQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzEN // SIG // BgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgr13C // SIG // M6MOW3PBSIrujBey44tTgOaTUpZqTqiYavSHXbQwgfoG // SIG // CyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCDlNl0NdmqG // SIG // /Q3gxVzPVBR3hF++Bb9AAb0DBu6gudZzrTCBmDCBgKR+ // SIG // MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n // SIG // dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN // SIG // aWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1p // SIG // Y3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB // SIG // 5y6PL5MLTxvpAAEAAAHnMCIEIF2FP3R/vAZxCsgAJaEN // SIG // 0whyGAjsHSLuIPTxdaiAHJKeMA0GCSqGSIb3DQEBCwUA // SIG // BIICALjqkeTXrr6OWEQUXSrbje/XcpDgUMo7lIYyYo2G // SIG // fT5FocpzaV/BtDxVOjndULaD4Oi8N6cVUbv3FXa93jJh // SIG // p9TlGTOsiVF5cS977CuwjyKPTsP0T02khfHgQFQvvWSG // SIG // zh9bogQ98+yq9WmFsOvEf5jOy/u7Dsl7W9fDQGl89Nel // SIG // 9q7QqopyEFt2kyQUEn/YskS+F2jDnTp0E1QZykDHnBDr // SIG // PHD2y3Gy5fq+3yAYxEqfyuVneYpAd2xyqQEW5EmY3Om/ // SIG // TEjZWnQTVUK0zIjbuKRSOwCd6gdv6jGEFcbpMbJGj/tb // SIG // lpYVNVJLtF9IeRkVzpKk674jseFzjV0W7V2ErUMlWq5E // SIG // 1EdEYUkiUEyYZg0SdwH2qCa0bww58Ojh5ApUs46J6TIY // SIG // pKwwaICJC+r+pqFmtdGkS+3PmpRJIaxhvh97C60KU1pp // SIG // On0qMfW/0TBDMRaQLTh3Q9CyrJCzuobV2iOGb2CHU6N4 // SIG // osW1tKb41d32YQYVRcVIHpRDZQknuPt/zgy4rAyWziHw // SIG // MwiHzwRoZPxzv+lmIbKFXkK7lhWHWnsSMQwcORcZDtQk // SIG // 3Q+ENlf7nXF1EXvKBD1US9t8gJ5jDxKvhbV92UjjBPUz // SIG // NaxLMupqjjTGP1v8gBeN3tVZQaCxc4fKB36BznPbaiC4 // SIG // FZa0N9R4JIY2QHt7JmwHVFj/BnZt // SIG // End signature block