UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

781 lines (778 loc) 36.2 kB
import { Subject } from 'rxjs'; import { CoreEnvironment } from '../data/core-environment'; import { NativeQ } from '../data/native-q'; import { LogLevel } from '../diagnostics/log-level'; import { Logging } from '../diagnostics/logging'; import { SmeWebTelemetry } from '../diagnostics/sme-web-telemetry'; import { RpcBase, RpcInboundCommands, RpcOutboundCommands, RpcType, rpcVersion } from './rpc-base'; import { RpcManager } from './rpc-manager'; import { RpcSeekMode } from './seek/rpc-seek-model'; /** * The Rpc class. */ export class Rpc { // RPC timeout 10 seconds. static rpcTimeout = 10 * 1000; /** * This subject is updated whenever there's new reported data */ rpcSubjects; /** * Deferred response collection. */ deferredCollection = new Map(); /** * Active status of rpc by Observable. */ stateChangedInternal = new Subject(); /** * Active status of rpc. */ stateActiveInternal = false; /** * Inbound module handlers to process when rpc is called. * - called from Module to Shell. */ rpcInboundHandlers = { FailedHandler: (data) => { return this.processNextForSubject(RpcInboundCommands.Failed, data); }, SeekHandler: (data) => { return Promise.resolve({ name: data.sourceName, subName: data.sourceSubName }); } }; /** * Outbound shell handlers to process when rpc is called. * - called from Shell to Module. * - if code reached a handler, module is not ready yet. * set timeout for RPC call. */ rpcOutboundHandlers = { InitHandler: (data) => this.createTimerPromise(RpcOutboundCommands.Init, Rpc.rpcTimeout, { locale: data.locale }), OpenHandler: (rpcOpenData) => this.createTimerPromise(RpcOutboundCommands.Open, Rpc.rpcTimeout, rpcOpenData), ActivateHandler: (data) => this.createTimerPromise(RpcOutboundCommands.Activate, Rpc.rpcTimeout, data), Deactivate2Handler: (data) => this.createTimerPromise(RpcOutboundCommands.Deactivate2, Rpc.rpcTimeout, data), ShutdownHandler: (data) => this.createTimerPromise(RpcOutboundCommands.Shutdown, Rpc.rpcTimeout, data), PingHandler: () => { this.changeActiveState(true); return Promise.resolve({ name: 'pong' }); } }; /** * Rpc manager object. */ rpcManager = new RpcManager(); /** * Initializes a new instance of the Rpc class. * * @param http the Http class instance injected. */ constructor() { this.rpcSubjects = {}; const commands = Object.keys(RpcInboundCommands); commands.forEach((value) => { this.rpcSubjects[RpcInboundCommands[value]] = new Subject(); }); } /** * Gets observable to watch the state change. */ get stateChanged() { this.stateChangedInternal.next(this.stateActiveInternal); return this.stateChangedInternal.asObservable(); } /** * Gets the state of rpc. */ get stateActive() { return this.stateActiveInternal; } /** * Gets whether rpc is running on the shell. */ get isShell() { if (this.rpcManager.rpcChannel == null) { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcNotInitialized.message; throw new Error(message); } return this.rpcManager.rpcChannel.rpcMode === 0 /* RpcMode.Shell */; } /** * Register inbound command handler. * * @param command The command name. * @param handler The command handler. */ registerInboundHandler(command, handler) { const handlerName = RpcBase.commandToHandlerName(command); this.rpcInboundHandlers[handlerName] = handler; this.rpcManager.registerInboundHandler(command, handler); } /** * Register outbound command handler. * * @param command The command name. * @param handler The command handler. */ registerOutboundHandler(command, handler) { const handlerName = RpcBase.commandToHandlerName(command); this.rpcOutboundHandlers[handlerName] = handler; } /** * Initializes Rpc configuration */ init() { this.rpcManager.init(this.rpcInboundHandlers, this.rpcOutboundHandlers); if (this.isShell) { this.changeActiveState(true); } } /*************************************************************** * Section for Shell usage. ***************************************************************/ /** * This updates its value every time there's a reported data from the rpc channel */ moduleSubjects(commandType) { return this.rpcSubjects[RpcInboundCommands[commandType]]; } /** * Connect a module with name and iframe. * - start pinging to iframe to wait for response. * * @param name the name of the module. * @param path the path to open the module the module name. * @param iframe the iframe window object. * @param primary the primary window to affect router url. * @return Promise<string> the promise with subName created for the window. */ moduleConnect(name, path, iframe, primary) { return this.rpcManager.connectRpcOutbound(name, path, iframe, primary); } /** * Init the module. * * @param name the name of module. * @param subName the sub name of rpc channel. * @param entryPointType the entry point type. * @return Promise<void> the promise object of init result. */ moduleInit(name, subName, entryPoint) { const rpc = this.rpcManager.rpcChannel.getRpc(name, subName, RpcType.Outbound); const self = MsftSme.self(); const data = { entryPointType: entryPoint.entryPointType, entryPointName: entryPoint.name, theme: self.Resources.theme, assets: self.Resources.assets, moduleAssets: self.Resources.moduleAssets, locale: self.Resources.localeId, localeRegional: self.Resources.localeRegionalId, lib: self.Resources.lib, sessionId: self.Init.sessionId, modules: self.Environment.modules, accessibilityMode: self.Resources.accessibilityMode, sessionExpiration: self.Init.sessionExpiration, performanceProfile: MsftSme.getPerformanceProfile(), connectivityLevel: self.Init.connectivityLevel, consoleDebug: MsftSme.consoleDebug(), sideLoad: MsftSme.sideLoad(), experiments: MsftSme.experiments(), shellVersion: self.Init.shellVersion, gatewayApiVersion: self.Init.gatewayApiVersion, gatewayPlatform: self.Init.gatewayPlatform }; return rpc.init(data).then(result => { const strings = MsftSme.getStrings().MsftSmeShell.Core.Rpc; // copy the version string of remote module. if (result && result.version) { rpc.version = result.version; Logging.log({ level: LogLevel.Verbose, message: strings.Version.message.format(rpcVersion, name, rpc.version), source: 'rpc.moduleInit' }); } else { const message = strings.MissingVersion.message.format(name); Logging.log({ level: LogLevel.Critical, message, source: 'rpc.moduleInit' }); throw new Error(message); } this.changeActiveState(true); return result; }); } /** * Open the module by specifying the path and parameters. * * @param name the name of module. * @param subName the sub name of rpc channel. * @param path the open path. * @return Promise<RpcOpenResult> the promise object of RpcOpenResult. */ moduleOpen(name, subName, path) { const rpc = this.rpcManager.rpcChannel.getRpc(name, subName, RpcType.Outbound); return rpc.open({ path }).then(result => { this.changeActiveState(true); return result; }); } /** * Activate the module to start receiving data. * * @param name the module name. * @param subName the sub name of rpc channel. * @param primary the primary window to affect router url. * @param url the inner url to open. * @return Promise<void> the promise of activation result. */ moduleActivate(name, subName, primary, url) { const rpc = this.rpcManager.reconnectRpcOutbound(name, subName, primary); return rpc.activate({ url }) .then(data => { this.changeActiveState(true); return data; }); } /** * Deactivate 2 the module to stop receiving data. * * @param name the module name. * @param subName the sub name of rpc channel. * @return Promise<void> the promise of deactivation result. */ moduleDeactivate2(name, subName) { this.changeActiveState(false); const rpc = this.rpcManager.rpcChannel.getRpc(name, subName, RpcType.Outbound); return rpc.deactivate2({}); } /** * Request to shutdown the module. * * @param name the module name. * @param subName the sub name of rpc channel. * @param primary the primary window to affect router url. * @param force the forcible state. * @return Promise<RpcShutdownResult> the promise object of result. */ moduleShutdown(name, subName, primary, force) { const rpc = this.rpcManager.reconnectRpcOutbound(name, subName, primary); return rpc.shutdown({ force: force }); } /** * Remove the module from the rpc channel. * * @param name the module name. * @param subName the sub name of rpc channel. */ moduleRemove(name, subName) { this.rpcManager.removeRpcOutbound(name, subName); } /** * Get module version string. * * @param name the name of module. * @param subName the sub name of rpc channel. * @return string the RPC version of module. */ moduleVersion(name, subName) { const rpc = this.rpcManager.rpcChannel.getRpc(name, subName, RpcType.Outbound); return rpc && rpc.version; } register(command, handler) { if (typeof command === 'string') { const commandName = command; this.rpcManager.rpcInbound.register(commandName, handler); return; } const deferredData = this.deferredCollection[command]; if (deferredData) { delete this.deferredCollection[command]; handler(deferredData.data).then(deferredData.deferred.resolve, deferredData.deferred.reject); return; } if (command === RpcOutboundCommands.Init) { const modifiedHandler = (data) => { // node context is used before passing request to handler. this.changeActiveState(true); const self = MsftSme.self(); self.Init.entryPointType = data.entryPointType; self.Init.entryPointName = data.entryPointName; self.Init.sessionId = data.sessionId; self.Init.sessionExpiration = data.sessionExpiration; self.Init.performanceProfile = data.performanceProfile; self.Init.shellVersion = data.shellVersion; // default is 1.0.0 and Windows which indicate it's running legacy GW. self.Init.gatewayApiVersion = data.gatewayApiVersion ?? '1.0.0', self.Init.gatewayPlatform = data.gatewayPlatform ?? 'Windows'; self.Environment.modules = data.modules; self.Init.connectivityLevel = data.connectivityLevel; self.Resources.lib = data.lib; self.Resources.moduleAssets = data.moduleAssets; if (!MsftSme.isNullOrUndefined(self.Resources.accessibilityMode) && !MsftSme.isNullOrUndefined(data.accessibilityMode) && CoreEnvironment.accessibilityManager) { self.Resources.accessibilityMode = data.accessibilityMode; CoreEnvironment.accessibilityManager.changeAccessibilityMode(self.Resources.accessibilityMode); } // ensure that global environment settings persist across origins if (!MsftSme.isNullOrUndefined(data.consoleDebug) && MsftSme.consoleDebug() !== data.consoleDebug) { MsftSme.consoleDebug(data.consoleDebug); } if (!MsftSme.isNullOrUndefined(data.sideLoad)) { const sideLoadKeys = Object.keys(MsftSme.sideLoad() || {}); const dataSideLoadKeys = Object.keys(data.sideLoad || {}); if (sideLoadKeys.length !== dataSideLoadKeys.length || sideLoadKeys.some(key => !!data.sideLoad[key])) { MsftSme.sideLoadReset(); dataSideLoadKeys.forEach(k => MsftSme.sideLoad(k)); } } if (!MsftSme.isNullOrUndefined(data.experiments)) { const experiments = MsftSme.experiments(); if (experiments.length !== data.experiments.length || experiments.some((v, i) => v !== data.experiments[i])) { MsftSme.experiments(data.experiments); } } if (CoreEnvironment.assetManager && data.theme && data.assets) { CoreEnvironment.assetManager.loadAssets(data.theme, data.assets); } for (const item of data.modules) { // NOTES: the next 'if' block code can be removed only if all extensions adapted newer shell. (after 1.1114.0) if (!self.Init.shellVersion && item.name === 'msft.sme.shell-extensions') { // look for shell version if missing from older MSI/ShellUI. self.Init.shellVersion = item.version; } if (item.name === self.Init.moduleName) { self.Environment.version = item.version || self.Environment.version; } } const localeLoader = CoreEnvironment.moduleLoadLocale({ id: data.localeRegional || data.locale, neutral: data.locale }); const passingData = { locale: data.locale, localeRegional: data.localeRegional, sessionId: data.sessionId }; // update metaTags so sessionId is properly updated in telemetry SmeWebTelemetry.updateFromRpcInit({ 'wac-session-id': data.sessionId, 'wac-extension-version': self.Environment.version }); return localeLoader .then(() => this.seekShell(RpcSeekMode.Create)) .then(() => handler(passingData)) .then(() => ({ version: rpcVersion })); }; this.rpcManager.rpcInbound.register(RpcOutboundCommands[command], modifiedHandler); } else { this.rpcManager.rpcInbound.register(RpcOutboundCommands[command], handler); } } /** * Module report a failure. */ failed(data) { const rpc = this.rpcManager.rpcInbound; return rpc.failed(data); } /** * Seek shell frame. * * @param Promise<any> the promise object. */ seekShell(mode) { return this.rpcManager.seekShell(mode); } /** * Validate existing outbound connection and remove if it doesn't live anymore. * * @return number the count of removed outbound. */ validate() { let count = 0; const collection = this.rpcManager.getCurrentRpcOutbound(); collection.forEach((rpc) => { if (!this.rpcManager.rpcChannel.validate(rpc)) { count++; } }); return count; } /** * Change the active status of rpc. */ changeActiveState(state) { this.stateActiveInternal = state; this.stateChangedInternal.next(state); } /** * Create auto-failed timer promise. * * @param command the outbound command type. * @param timeoutMs the timeout milliseconds. * @param data the data context. * @return Promise<any> the promise. */ createTimerPromise(command, timeoutMs, data) { const deferred = NativeQ.defer(); this.deferredCollection[command] = { deferred: deferred, data: data }; setTimeout(() => { const deferredData = this.deferredCollection[command]; if (deferredData) { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcTimeout.message; deferredData.deferred.reject(message); delete this.deferredCollection[command]; } }, timeoutMs); return deferred.promise; } /** * Create promise that does not timeout. * * @param command the outbound type. * @param data the data context. * @return Promise<any> the promise. */ createPromise(command, data) { const deferred = NativeQ.defer(); this.deferredCollection[command] = { deferred: deferred, data: data }; return deferred.promise; } /** * Process data pushing into next call of subject with deferred data type. * * @param command the inbound command type. * @param data the rpc data came from a module/iframe. * @return Promise the promise which receiver must settle within fixed waiting time (10 seconds) */ processNextForSubject(command, data) { const subject = this.rpcSubjects[RpcInboundCommands[command]]; if (subject.closed) { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcSubjectClosed.message; throw new Error(message.format(RpcInboundCommands[command])); } const deferredData = { data: data, deferred: NativeQ.defer() }; subject.next(deferredData); return deferredData.deferred.promise; } } //# sourceMappingURL=rpc.js.map // SIG // Begin signature block // SIG // MIIoNwYJKoZIhvcNAQcCoIIoKDCCKCQCAQExDzANBglg // SIG // hkgBZQMEAgEFADB3BgorBgEEAYI3AgEEoGkwZzAyBgor // SIG // BgEEAYI3AgEeMCQCAQEEEBDgyQbOONQRoqMAEEvTUJAC // SIG // AQACAQACAQACAQACAQAwMTANBglghkgBZQMEAgEFAAQg // SIG // Vhac0iIHcotHHHimXB0Xrmu1f6a2JfYlJic+NNbszLCg // SIG // gg2FMIIGAzCCA+ugAwIBAgITMwAABAO91ZVdDzsYrQAA // SIG // AAAEAzANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV // SIG // UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH // SIG // UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv // SIG // cmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBT // SIG // aWduaW5nIFBDQSAyMDExMB4XDTI0MDkxMjIwMTExM1oX // SIG // DTI1MDkxMTIwMTExM1owdDELMAkGA1UEBhMCVVMxEzAR // SIG // BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v // SIG // bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv // SIG // bjEeMBwGA1UEAxMVTWljcm9zb2Z0IENvcnBvcmF0aW9u // SIG // MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA // SIG // n3RnXcCDp20WFMoNNzt4s9fV12T5roRJlv+bshDfvJoM // SIG // ZfhyRnixgUfGAbrRlS1St/EcXFXD2MhRkF3CnMYIoeMO // SIG // MuMyYtxr2sC2B5bDRMUMM/r9I4GP2nowUthCWKFIS1RP // SIG // lM0YoVfKKMaH7bJii29sW+waBUulAKN2c+Gn5znaiOxR // SIG // qIu4OL8f9DCHYpME5+Teek3SL95sH5GQhZq7CqTdM0fB // SIG // w/FmLLx98SpBu7v8XapoTz6jJpyNozhcP/59mi/Fu4tT // SIG // 2rI2vD50Vx/0GlR9DNZ2py/iyPU7DG/3p1n1zluuRp3u // SIG // XKjDfVKH7xDbXcMBJid22a3CPbuC2QJLowIDAQABo4IB // SIG // gjCCAX4wHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYB // SIG // BQUHAwMwHQYDVR0OBBYEFOpuKgJKc+OuNYitoqxfHlrE // SIG // gXAZMFQGA1UdEQRNMEukSTBHMS0wKwYDVQQLEyRNaWNy // SIG // b3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQx // SIG // FjAUBgNVBAUTDTIzMDAxMis1MDI5MjYwHwYDVR0jBBgw // SIG // FoAUSG5k5VAF04KqFzc3IrVtqMp1ApUwVAYDVR0fBE0w // SIG // SzBJoEegRYZDaHR0cDovL3d3dy5taWNyb3NvZnQuY29t // SIG // L3BraW9wcy9jcmwvTWljQ29kU2lnUENBMjAxMV8yMDEx // SIG // LTA3LTA4LmNybDBhBggrBgEFBQcBAQRVMFMwUQYIKwYB // SIG // BQUHMAKGRWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w // SIG // a2lvcHMvY2VydHMvTWljQ29kU2lnUENBMjAxMV8yMDEx // SIG // LTA3LTA4LmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3 // SIG // DQEBCwUAA4ICAQBRaP+hOC1+dSKhbqCr1LIvNEMrRiOQ // SIG // EkPc7D6QWtM+/IbrYiXesNeeCZHCMf3+6xASuDYQ+AyB // SIG // TX0YlXSOxGnBLOzgEukBxezbfnhUTTk7YB2/TxMUcuBC // SIG // P45zMM0CVTaJE8btloB6/3wbFrOhvQHCILx41jTd6kUq // SIG // 4bIBHah3NG0Q1H/FCCwHRGTjAbyiwq5n/pCTxLz5XYCu // SIG // 4RTvy/ZJnFXuuwZynowyju90muegCToTOwpHgE6yRcTv // SIG // Ri16LKCr68Ab8p8QINfFvqWoEwJCXn853rlkpp4k7qzw // SIG // lBNiZ71uw2pbzjQzrRtNbCFQAfmoTtsHFD2tmZvQIg1Q // SIG // VkzM/V1KCjHL54ItqKm7Ay4WyvqWK0VIEaTbdMtbMWbF // SIG // zq2hkRfJTNnFr7RJFeVC/k0DNaab+bpwx5FvCUvkJ3z2 // SIG // wfHWVUckZjEOGmP7cecefrF+rHpif/xW4nJUjMUiPsyD // SIG // btY2Hq3VMLgovj+qe0pkJgpYQzPukPm7RNhbabFNFvq+ // SIG // kXWBX/z/pyuo9qLZfTb697Vi7vll5s/DBjPtfMpyfpWG // SIG // 0phVnAI+0mM4gH09LCMJUERZMgu9bbCGVIQR7cT5YhlL // SIG // t+tpSDtC6XtAzq4PJbKZxFjpB5wk+SRJ1gm87olbfEV9 // SIG // SFdO7iL3jWbjgVi1Qs1iYxBmvh4WhLWr48uouzCCB3ow // SIG // ggVioAMCAQICCmEOkNIAAAAAAAMwDQYJKoZIhvcNAQEL // SIG // BQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo // SIG // aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK // SIG // ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMT // SIG // KU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhv // SIG // cml0eSAyMDExMB4XDTExMDcwODIwNTkwOVoXDTI2MDcw // SIG // ODIxMDkwOVowfjELMAkGA1UEBhMCVVMxEzARBgNVBAgT // SIG // Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc // SIG // BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYG // SIG // A1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0Eg // SIG // MjAxMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC // SIG // ggIBAKvw+nIQHC6t2G6qghBNNLrytlghn0IbKmvpWlCq // SIG // uAY4GgRJun/DDB7dN2vGEtgL8DjCmQawyDnVARQxQtOJ // SIG // DXlkh36UYCRsr55JnOloXtLfm1OyCizDr9mpK656Ca/X // SIG // llnKYBoF6WZ26DJSJhIv56sIUM+zRLdd2MQuA3WraPPL // SIG // bfM6XKEW9Ea64DhkrG5kNXimoGMPLdNAk/jj3gcN1Vx5 // SIG // pUkp5w2+oBN3vpQ97/vjK1oQH01WKKJ6cuASOrdJXtjt // SIG // 7UORg9l7snuGG9k+sYxd6IlPhBryoS9Z5JA7La4zWMW3 // SIG // Pv4y07MDPbGyr5I4ftKdgCz1TlaRITUlwzluZH9TupwP // SIG // rRkjhMv0ugOGjfdf8NBSv4yUh7zAIXQlXxgotswnKDgl // SIG // mDlKNs98sZKuHCOnqWbsYR9q4ShJnV+I4iVd0yFLPlLE // SIG // tVc/JAPw0XpbL9Uj43BdD1FGd7P4AOG8rAKCX9vAFbO9 // SIG // G9RVS+c5oQ/pI0m8GLhEfEXkwcNyeuBy5yTfv0aZxe/C // SIG // HFfbg43sTUkwp6uO3+xbn6/83bBm4sGXgXvt1u1L50kp // SIG // pxMopqd9Z4DmimJ4X7IvhNdXnFy/dygo8e1twyiPLI9A // SIG // N0/B4YVEicQJTMXUpUMvdJX3bvh4IFgsE11glZo+TzOE // SIG // 2rCIF96eTvSWsLxGoGyY0uDWiIwLAgMBAAGjggHtMIIB // SIG // 6TAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUSG5k // SIG // 5VAF04KqFzc3IrVtqMp1ApUwGQYJKwYBBAGCNxQCBAwe // SIG // CgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB // SIG // /wQFMAMBAf8wHwYDVR0jBBgwFoAUci06AjGQQ7kUBU7h // SIG // 6qfHMdEjiTQwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDov // SIG // L2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVj // SIG // dHMvTWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNy // SIG // bDBeBggrBgEFBQcBAQRSMFAwTgYIKwYBBQUHMAKGQmh0 // SIG // dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMv // SIG // TWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNydDCB // SIG // nwYDVR0gBIGXMIGUMIGRBgkrBgEEAYI3LgMwgYMwPwYI // SIG // KwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNv // SIG // bS9wa2lvcHMvZG9jcy9wcmltYXJ5Y3BzLmh0bTBABggr // SIG // BgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwAXwBwAG8AbABp // SIG // AGMAeQBfAHMAdABhAHQAZQBtAGUAbgB0AC4gHTANBgkq // SIG // hkiG9w0BAQsFAAOCAgEAZ/KGpZjgVHkaLtPYdGcimwuW // SIG // EeFjkplCln3SeQyQwWVfLiw++MNy0W2D/r4/6ArKO79H // SIG // qaPzadtjvyI1pZddZYSQfYtGUFXYDJJ80hpLHPM8QotS // SIG // 0LD9a+M+By4pm+Y9G6XUtR13lDni6WTJRD14eiPzE32m // SIG // kHSDjfTLJgJGKsKKELukqQUMm+1o+mgulaAqPyprWElj // SIG // HwlpblqYluSD9MCP80Yr3vw70L01724lruWvJ+3Q3fMO // SIG // r5kol5hNDj0L8giJ1h/DMhji8MUtzluetEk5CsYKwsat // SIG // ruWy2dsViFFFWDgycScaf7H0J/jeLDogaZiyWYlobm+n // SIG // t3TDQAUGpgEqKD6CPxNNZgvAs0314Y9/HG8VfUWnduVA // SIG // KmWjw11SYobDHWM2l4bf2vP48hahmifhzaWX0O5dY0Hj // SIG // Wwechz4GdwbRBrF1HxS+YWG18NzGGwS+30HHDiju3mUv // SIG // 7Jf2oVyW2ADWoUa9WfOXpQlLSBCZgB/QACnFsZulP0V3 // SIG // HjXG0qKin3p6IvpIlR+r+0cjgPWe+L9rt0uX4ut1eBrs // SIG // 6jeZeRhL/9azI2h15q/6/IvrC4DqaTuv/DDtBEyO3991 // SIG // bWORPdGdVk5Pv4BXIqF4ETIheu9BCrE/+6jMpF3BoYib // SIG // V3FWTkhFwELJm3ZbCoBIa/15n8G9bW1qyVJzEw16UM0x // SIG // ghoKMIIaBgIBATCBlTB+MQswCQYDVQQGEwJVUzETMBEG // SIG // A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u // SIG // ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u // SIG // MSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5n // SIG // IFBDQSAyMDExAhMzAAAEA73VlV0POxitAAAAAAQDMA0G // SIG // CWCGSAFlAwQCAQUAoIGuMBkGCSqGSIb3DQEJAzEMBgor // SIG // BgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEE // SIG // AYI3AgEVMC8GCSqGSIb3DQEJBDEiBCC1jCecQ26iKv68 // SIG // sDqBKA8xrWcQNo5Di/azbup3I5WO2TBCBgorBgEEAYI3 // SIG // AgEMMTQwMqAUgBIATQBpAGMAcgBvAHMAbwBmAHShGoAY // SIG // aHR0cDovL3d3dy5taWNyb3NvZnQuY29tMA0GCSqGSIb3 // SIG // DQEBAQUABIIBAGuz/8HYZFNdTL2OtLLn2VgDknfuCZuE // SIG // 7PUUkVCVGf7TcDCgbobQW+Rw2eTic+jrZVILzlowtQ+w // SIG // xMv9+h2V/uX2CWEoNVM6gKVgFXLCrlATgUYUSHFCWp+y // SIG // 3jY4ONENItnTIkPlJAq0lEs0f8+fSKZ85gvAoqLea3KS // SIG // vV7HYPe1+h7iWp+rXKh23MbSKMXazzI2KsjYl0ZeRjGV // SIG // 9GfaRnU8DvWVHLRhl5+Ff6XRbCEonlDoG43T9KovWOYm // SIG // v4/2wE/I1w6Qg0R9w9PRr2CX6UJDSNczH4L2iPKqC7Vc // SIG // MBTmt7XZhQN55ze3/jpjowROA7xg/uDZzZeCInMFX1dD // SIG // ZxahgheUMIIXkAYKKwYBBAGCNwMDATGCF4Awghd8Bgkq // SIG // hkiG9w0BBwKgghdtMIIXaQIBAzEPMA0GCWCGSAFlAwQC // SIG // AQUAMIIBUgYLKoZIhvcNAQkQAQSgggFBBIIBPTCCATkC // SIG // AQEGCisGAQQBhFkKAwEwMTANBglghkgBZQMEAgEFAAQg // SIG // 6Kr+gHy/5vXaab9P93lN4J7mYrktdr3oU4oUwSSJV28C // SIG // Bmet2JkE3hgTMjAyNTAyMjAxNTI4NDAuMjY1WjAEgAIB // SIG // 9KCB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgT // SIG // Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc // SIG // BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMG // SIG // A1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9u // SIG // czEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOkE0MDAt // SIG // MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGlt // SIG // ZS1TdGFtcCBTZXJ2aWNloIIR6jCCByAwggUIoAMCAQIC // SIG // EzMAAAHs4CukgtCRUoAAAQAAAewwDQYJKoZIhvcNAQEL // SIG // BQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp // SIG // bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT // SIG // FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMd // SIG // TWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcN // SIG // MjMxMjA2MTg0NTM4WhcNMjUwMzA1MTg0NTM4WjCByzEL // SIG // MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x // SIG // EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv // SIG // c29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9z // SIG // b2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMe // SIG // blNoaWVsZCBUU1MgRVNOOkE0MDAtMDVFMC1EOTQ3MSUw // SIG // IwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2 // SIG // aWNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC // SIG // AgEAsEf0bgk24MVFlZv1XbpdtrsHRGZtCKABbOqCK9/V // SIG // SvyLT/NHJ/vE5rT+u4mmweA5gCifRh+nSRoRDyaWOL0y // SIG // kUjsK0TcVSCqDz3lBd3+FchxHKP7tUFGnZcA9d9jbmQs // SIG // W54ejItpSxu6Q77M2ajBu0tzAotm5Np77RinXgCC/h++ // SIG // 4C+K9NU0lm+67BNiW9T/zemP1tQqg4tfyG9/80all7eM // SIG // 8b3SBnD40uGSskBBd0hGQKuFyI4sqMDx2qjW2cXX9pFj // SIG // v2o3X01PObfd+AlwIp29KPrkPSrWijS1VXDX+UKUuH+v // SIG // zLFzryBbgmDEXSg46Zr6MAHi/tY9u2wsQgaQ0B61pHz8 // SIG // 2af1/m7fQuxOYTz+h1UaKgWEe7tYFH+RhKvua9RwNI2o // SIG // 59EOjr32HJBNB3Tr+ilmvrAJiRuzw702Wnu+4aJs8eiD // SIG // 6oIFaTWbgpO/Un1ZpyrvRefFAJ1OfE6gxxMxrEJzFECr // SIG // LUt845+klNDSxBTQnrZbmipKlg0VSxFm7t9vSBId7alz // SIG // 138ukYf8Am8HvUgiSKKrQXsQaz8kGANl2s9XyvcrE7Md // SIG // JAPVdScFVeOCGvXPjMLQEerKinQIEaP27P17vILmvCw3 // SIG // uilsrve+HvZhlu2TvJ2qwxawE9RFxhw7nsoEir79iu8A // SIG // fJQIDBiY+9wkL6/o6qFsMel3cnkCAwEAAaOCAUkwggFF // SIG // MB0GA1UdDgQWBBT0WtBHZP4r9cIWELFfFIBH+EyFhjAf // SIG // BgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBf // SIG // BgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jv // SIG // c29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBU // SIG // aW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYI // SIG // KwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8v // SIG // d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01p // SIG // Y3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEw // SIG // KDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM // SIG // MAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDANBgkq // SIG // hkiG9w0BAQsFAAOCAgEAkrzEpDEq745Qz2oPAEW9Dhaw // SIG // ELUizA6TdFGNxY7z4cBig664sZp7jH465lY0atbvCIZA // SIG // 7xhf2332xU6/iAJw0noPEwfc3xv+Mm5J7qKZJW3ho27e // SIG // zC8aX4aJQhEchHNtDzGSic/Ur837jtZ+ca6yzi/JtJ5r // SIG // +ZAXL/stQFyeUHC4nJoXtiKd/w+uxHeqD6kCNN5g42Gk // SIG // tTUIQTbbue8Dyl2dRKDU6AZPGwOvN/cNdfW/mvVk6KiL // SIG // JHURqD+cYwyL/pnNLwR4WRpCVb3yIZuAKfM6bQu8VQJc // SIG // tI3jr+XVBjAmIGY76E5oHeOW6gMLp3Zj5Rrq+3pXlmHn // SIG // S0H+7Ny+fqn2mP8RIf/bqNe0pzP4B1UhgM7563hoTqwd // SIG // i7XSqFUnuS22KYoV3LQ3u+omLS/pocVzxKc3Wt2yZYT0 // SIG // zkNyjhGQKVREQaOcpbVozwlpV8cgqZeY4/Z2NJ33dO9W // SIG // 3pp6LvAN61Ga3YCiGrrbB+0hzojnm2RqjbvuttrybWt3 // SIG // gGLAgGsQHAfQYiT5Wu12nfaq02HU+OVZQmE7QUmOKFUb // SIG // HnUgA7/fY7/4mCABstWwsrbmtKP0Kr/Xqyps0Ak1TF2g // SIG // 3NuQ0y3DBia0bmtytMYr3bZ6AXsc1Sa+sl6jPgWtsISF // SIG // UbxnK4gZCl9BSRXlu69vV1/pNHuA5xuogRykI3nOlTcw // SIG // ggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZAAAAAAAV // SIG // MA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzET // SIG // MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk // SIG // bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 // SIG // aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0 // SIG // aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAx // SIG // ODIyMjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYT // SIG // AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH // SIG // EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y // SIG // cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1l // SIG // LVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEF // SIG // AAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7V // SIG // gtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4XYDP/XE/H // SIG // ZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9alKD // SIG // RLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gm // SIG // U3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7uhp7M62AW36M // SIG // EBydUv626GIl3GoPz130/o5Tz9bshVZN7928jaTjkY+y // SIG // OSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoF // SIG // VZhtaDuaRr3tpK56KTesy+uDRedGbsoy1cCGMFxPLOJi // SIG // ss254o2I5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGa // SIG // RnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+Autuqfjbs // SIG // Nkz2K26oElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afo // SIG // mXw/TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9 // SIG // ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZk // SIG // i1ugpoMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y // SIG // 1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReTwDwV // SIG // 2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0C // SIG // AwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEw // SIG // IwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8RjUpzxD/ // SIG // LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtTNRnp // SIG // cjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8G // SIG // CCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j // SIG // b20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYD // SIG // VR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAwe // SIG // CgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB // SIG // /wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9 // SIG // lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDov // SIG // L2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVj // SIG // dHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoG // SIG // CCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDov // SIG // L3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNS // SIG // b29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcN // SIG // AQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pc // SIG // FLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHk // SIG // wo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2LpypglYAA7AF // SIG // vonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0jVOR4 // SIG // U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2 // SIG // EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8DJ6LGYnn8Atq // SIG // gcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmRsqlb30mj // SIG // dAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZM // SIG // cm8Qq3UwxTSwethQ/gpY3UA8x1RtnWN0SCyxTkctwRQE // SIG // cb9k+SS+c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2f // SIG // pCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBM // SIG // drVXVAmxaQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L // SIG // +DvktxW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJ // SIG // C4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU // SIG // 5nR0W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/ // SIG // 2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIDTTCC // SIG // AjUCAQEwgfmhgdGkgc4wgcsxCzAJBgNVBAYTAlVTMRMw // SIG // EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt // SIG // b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp // SIG // b24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9w // SIG // ZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT // SIG // TjpBNDAwLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9z // SIG // b2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsO // SIG // AwIaAxUAjhz7YFXc/RFtIjzS/wV6iaKlTH+ggYMwgYCk // SIG // fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu // SIG // Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV // SIG // TWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N // SIG // aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkq // SIG // hkiG9w0BAQsFAAIFAOthkQQwIhgPMjAyNTAyMjAxMTMx // SIG // MTZaGA8yMDI1MDIyMTExMzExNlowdDA6BgorBgEEAYRZ // SIG // CgQBMSwwKjAKAgUA62GRBAIBADAHAgEAAgISuTAHAgEA // SIG // AgITFzAKAgUA62LihAIBADA2BgorBgEEAYRZCgQCMSgw // SIG // JjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIB // SIG // AAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQAuUY2t4eE7 // SIG // i88PXLaEjJJxs86dP00o71UhvQLqvZc95KCDITUy1cSj // SIG // QCTN7sjQmNZ9dZ4tsvS/JlabGY9rlSvv8JpTcpGLJE5w // SIG // UaEp08HFh33nFn3iZzX0Gp9AcwXGiHqje5HcyN9ddVIZ // SIG // Zre4gluUmrRBAPDN1G40BdBbddVcncwSc1EgStAYTaIV // SIG // EafOXuHveLImjTexBrfIGr2vjS6Jbp87X0YCfF4147nK // SIG // vKe4fKRkDjT2JYIpRSg23+4phwYM7qI6rhnbW5FvZ4FG // SIG // FvjPpH2Rz6uM4p0TNO6V/G56G7tRdm1Js1QwIaeiYlFB // SIG // xLAydmRbO52v30FLvbUim4xTMYIEDTCCBAkCAQEwgZMw // SIG // fDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0 // SIG // b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p // SIG // Y3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWlj // SIG // cm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAHs // SIG // 4CukgtCRUoAAAQAAAewwDQYJYIZIAWUDBAIBBQCgggFK // SIG // MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkq // SIG // hkiG9w0BCQQxIgQghDSh91PmGW1KXosuVrEnb9yXRVgS // SIG // wKZaXDOV/NJiepswgfoGCyqGSIb3DQEJEAIvMYHqMIHn // SIG // MIHkMIG9BCAnCeb1an03yIcdtUAQWysqP8XIkCF2qDFl // SIG // C3owBNUKgzCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMw // SIG // EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt // SIG // b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp // SIG // b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w // SIG // IFBDQSAyMDEwAhMzAAAB7OArpILQkVKAAAEAAAHsMCIE // SIG // IJMWfWH4rigb0xVwIT3U52hJl/r0nZiZ9lzyPXRL+C1O // SIG // MA0GCSqGSIb3DQEBCwUABIICAK+0JW7aXf1II8/7avpv // SIG // Urum4iLPTW2Y7Q/nrxYqNKOSlPuzEqIUJzzporemmYxa // SIG // 0G/kWLV2Mhm1EJD9lBBFd1x/eOGV7C833WYhSvRV9gPJ // SIG // D1X63CXxjNzABkX68XnbEitj0cdX+ACn8Q9/bMBFhfKT // SIG // zoEAjiZlHEp1QTDS+rfXrOSfsB4EmUOrQOBfVBDkdHbm // SIG // ANRrchJqreV5u5tGxs8L5YkkAVfwqhtZt/mrZeLTjOeO // SIG // te911gRAS/mKZ8pQVgk1HoxT5D3G50jCS4/oSvUyHK5x // SIG // hlqHGSzmScpddGN+uMSV6RD4Gx8JCO+Q7Q4zB6iG5d8Z // SIG // z0fRr55qFvuw4498UkrllQGr/CiaWsVkjaAF0huBnmD1 // SIG // IEdk2ZumXCIPtFD9+vAFkOTt2bxghkRN1S9fuDOVpbzw // SIG // AnE8Ph4LSlltWqoTMYw/5atVO0St/0BQB3mtBfIPU4S5 // SIG // T84zzgTLBJpK6ua9ivikiluS0owY1JN5J34oaLRYDJrk // SIG // Oj6t8RV/1EKX2FCIm3aZRn4FHb5j2cIJ5SCPYrntdLjg // SIG // JisHPBmAEEOJTTxBujOWJ/K7EXOrVHt/iDIpgZwQzKoO // SIG // 3R6Dq73usbm4txHB4euWepJid/TYTQcFUx3/bOvnj5Vg // SIG // SDTI564x6tL/JcWowLOdtIGQZbbMpVf/jpsBav6M9ph/ // SIG // BLHJ // SIG // End signature block