UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

846 lines (843 loc) 39.7 kB
import { of, throwError } from 'rxjs'; import { filter, map, take } from 'rxjs/operators'; import { CimStream } from '../data/cim-stream'; import { Http } from '../data/http'; import { Net } from '../data/net'; import { PowerShellStream } from '../data/powershell-stream'; import { Logging } from '../diagnostics/logging'; import { RpcObservablePerformanceClient } from '../rpc/performance/rpc-observable-performance-client'; import { RpcObservablePerformanceConfigClient } from '../rpc/performance/rpc-observable-performance-config-client'; import { RpcObservablePerformanceServer } from '../rpc/performance/rpc-observable-performance-server'; import { PerformanceProfileDataType } from './performance-profile-data-type'; import { PerformanceProfileDatabase } from './performance-profile-database'; /** * Performance measurement class. */ export class PerformanceProfile { static monitorName = 'PerformanceProfile'; static instance; database = null; rpc; rpcObservablePerformanceClient; rpcObservablePerformanceServer; subscription; moduleVersionMap = {}; rpcObservablePerformanceConfigClient; /** * Gets the current PerformanceProfile instance. */ static get current() { if (PerformanceProfile.instance) { return PerformanceProfile.instance; } PerformanceProfile.instance = new PerformanceProfile(); return PerformanceProfile.instance; } static get database() { return PerformanceProfile.current.database; } /** * Record Route navigation performance measurement. */ static logRouteNavigation(source, start, end, url, target, errorMessage) { const data = { source, start, end, errorMessage, type: PerformanceProfileDataType.RouteNavigation, routeNavigation: { url, target } }; PerformanceProfile.current.log(data); } /** * Record Null packet. */ static logNull(source) { const data = { source, start: 0, end: 0, errorMessage: null, type: PerformanceProfileDataType.Null }; PerformanceProfile.current.logAnyway(data); } /** * Record XHR or Fetch performance measurement for PowerShell. */ static logXhrFetchPowerShell(source, start, end, url, method, status, powershell, errorMessage) { const data = { source, start, end, errorMessage, type: PerformanceProfileDataType.XhrFetch, xhrFetch: { url, method, status, powershell } }; PerformanceProfile.current.log(data); } /** * Record XHR or Fetch performance measurement for CIM. */ static logXhrFetchCim(source, start, end, url, method, status, cim, errorMessage) { const data = { source, start, end, errorMessage, type: PerformanceProfileDataType.XhrFetch, xhrFetch: { url, method, status, cim } }; PerformanceProfile.current.log(data); } /** * Record XHR or Fetch performance measurement for Batch. */ static logXhrFetchBatch(source, start, end, url, method, status, batch, errorMessage) { const data = { source, start, end, errorMessage, type: PerformanceProfileDataType.XhrFetch, xhrFetch: { url, method, status, batch } }; PerformanceProfile.current.log(data); } /** * Record XHR or Fetch performance measurement for general. */ static logXhrFetch(source, start, end, url, method, status, errorMessage) { const data = { source, start, end, errorMessage, type: PerformanceProfileDataType.XhrFetch, xhrFetch: { url, method, status } }; PerformanceProfile.current.log(data); } /** * Record WebSocket performance measurement. */ static logWebSocketPowerShell(source, nodeName, command, context, errorMessage) { const data = { source, start: context.progressStart, end: context.progressEnd, errorMessage, type: PerformanceProfileDataType.WebSocket, webSocket: { nodeName, id: context.id, count: context.count, itemCount: context.itemCount, powershell: { command } } }; PerformanceProfile.current.log(data); } /** * Record WebSocket performance measurement. */ static logWebSocketCim(source, nodeName, cim, context, errorMessage) { const data = { source, start: context.progressStart, end: context.progressEnd, errorMessage, type: PerformanceProfileDataType.WebSocket, webSocket: { nodeName, id: context.id, count: context.count, itemCount: context.itemCount, cim } }; PerformanceProfile.current.log(data); } static powershellApi(url, body, response) { const powershell = {}; if (body && body.indexOf('\"properties\"') > 0) { powershell.command = PerformanceProfile.getBetween(body, ',\"command\":\"', '\",\"') || PerformanceProfile.getBetween(body, '\"script\":\"##', '##:'); } powershell.completed = response && response.completed; if (!powershell.completed) { powershell.completed = response && response.properties && response.properties.completed; } powershell.sessionId = response && response.sessionId; if (!powershell.sessionId) { powershell.sessionId = response && response.properties && response.properties.sessionId; if (!powershell.sessionId) { powershell.sessionId = PerformanceProfile.getBetween(url, '/pssessions/', '?'); } } return powershell; } static cimApi(url, body) { if (url.indexOf('/features/cim/query') > 0 || url.indexOf('/services/WinREST/CIM/query') > 0) { try { return JSON.parse(body); } catch { return null; } } const namespaceName = PerformanceProfile.getBetween(url, '/namespaces/', '/classes/'); const className = PerformanceProfile.getBetween(url, '/classes/', '/instances'); return { namespace: namespaceName, className: className }; } static batchApi(body, response) { const delimiter = '\x0d\x0a'; const batch = []; let last = body.indexOf(delimiter); let separator = body.substring(0, last + 2); const bodySegments = body.split(separator); last = response.indexOf(delimiter); separator = response.substring(0, last + 2); const responseSegments = response.split(separator); if (bodySegments.length === responseSegments.length && bodySegments.length > 1) { let batchMethod; let batchUrl; let batchBody; let batchStatus; let batchResponse; for (let i = 1; i < bodySegments.length; i++) { const bodySegment = bodySegments[i]; const responseSegment = responseSegments[i]; const bodySegmentLines = bodySegment.split(delimiter); let emptyLines = 0; for (let j = 0; j < bodySegmentLines.length; j++) { const line = bodySegmentLines[j]; if (line.length > 0) { if (emptyLines === 1 && !batchUrl) { // reached header segment. const query = line.split(' '); batchMethod = query[0]; batchUrl = query[1]; } else if (emptyLines >= 2 && !batchBody) { batchBody = line; } } else { emptyLines++; } } emptyLines = 0; const responseSegmentLines = responseSegment.split(delimiter); for (let j = 0; j < responseSegmentLines.length; j++) { const line = responseSegmentLines[j]; if (line.length > 0) { if (emptyLines === 1 && !batchStatus) { // reached header segment. const query = line.split(' '); batchStatus = Number(query[1]); } else if (emptyLines >= 2 && !batchResponse) { try { batchResponse = JSON.parse(line); } catch { batchResponse = {}; } } } else { emptyLines++; } } const batchItem = { url: batchUrl, status: batchStatus, method: batchMethod }; if (batchUrl.indexOf('/features/powershellApi/') > 0 || batchUrl.indexOf('/services/WinREST/PowerShell/') > 0) { batchItem.powershell = PerformanceProfile.powershellApi(batchUrl, batchBody, batchResponse); } else if (batchUrl.includes('/features/cim/query') || batchUrl.includes('/services/WinREST/CIM/')) { batchItem.cim = PerformanceProfile.cimApi(batchUrl, batchBody); } batch.push(batchItem); } } return batch; } static getBetween(source, begin, end) { let index0 = source.indexOf(begin); if (index0 < 0) { return null; } index0 += begin.length; const index1 = source.indexOf(end, index0); if (index1 < 0) { return null; } return source.substring(index0, index1); } enable(rpc) { MsftSme.setPerformanceProfile(true); this.registerRpc(rpc); } disable(rpc) { MsftSme.setPerformanceProfile(false); this.registerRpc(rpc); } checkPerformanceProfile() { if (!MsftSme.getPerformanceProfile()) { if (this.database) { this.database.close(); this.database = null; } return false; } if (!this.database) { this.database = new PerformanceProfileDatabase(); } return true; } registerRpc(rpc) { if (!this.rpc) { this.rpc = rpc; if (MsftSme.isShell()) { this.subscription = rpc.stateChanged .pipe(filter(active => active), take(1)) .subscribe(() => { this.rpcObservablePerformanceConfigClient = new RpcObservablePerformanceConfigClient(this.rpc); this.rpcObservablePerformanceServer = new RpcObservablePerformanceServer(rpc); this.rpcObservablePerformanceServer.register(request => { if (request.type === PerformanceProfileDataType.Null) { // The packet is null packet and retain only the version data. if (request.sourceVersion === '0.2.0') { // this version can support config command when on/off switch was used. this.moduleVersionMap[request.sourceName] = request.sourceVersion; } return of(null); } if (!this.checkPerformanceProfile()) { return of(null); } return this.database.write(request).pipe(map(() => null)); }); }); } else { this.subscription = rpc.stateChanged .pipe(filter(active => active), take(1)) .subscribe(() => { this.rpcObservablePerformanceClient = new RpcObservablePerformanceClient(rpc); }); } } this.updateMonitors(); } updateMonitors() { const enabled = this.checkPerformanceProfile(); if (this.rpcObservablePerformanceConfigClient) { // enable/disable the performance profile data collection to current modules. // but these must be version 0.2.0. const items = this.rpc.rpcManager.getCurrentRpcOutbound(); if (items) { for (const item of items) { if (this.moduleVersionMap[item.name]) { this.rpcObservablePerformanceConfigClient.config({ enabled }, item).subscribe(); } } } } if (enabled) { this.registerHttp(); this.registerPowerShellStream(); this.registerCimStream(); } else { Http.unregisterMonitors(PerformanceProfile.monitorName); PowerShellStream.unregisterMonitors(PerformanceProfile.monitorName); CimStream.unregisterMonitors(PerformanceProfile.monitorName); } } log(message) { if (!this.checkPerformanceProfile()) { return; } const self = MsftSme.self(); const record = { ...message, ...{ sessionId: self.Init.sessionId, timestamp: Date.now(), moduleName: self.Init.moduleName } }; if (!record.errorMessage) { delete record['errorMessage']; } if (this.rpc && this.rpc.stateActive && this.rpcObservablePerformanceClient) { // send to shell. this.rpcObservablePerformanceClient.log(record).subscribe(); } else { // write to database. this.database.write(record).subscribe(); } } logAnyway(message) { const self = MsftSme.self(); const record = { ...message, ...{ sessionId: self.Init.sessionId, timestamp: Date.now(), moduleName: self.Init.moduleName } }; if (!record.errorMessage) { delete record['errorMessage']; } if (this.rpc && this.rpc.stateActive && this.rpcObservablePerformanceClient) { // send to shell. this.rpcObservablePerformanceClient.log(record).subscribe(); } } registerHttp() { const startPropertyName = '_start_'; Http.registerMonitorSet({ name: PerformanceProfile.monitorName, preMonitor: (request) => { if (!request) { Logging.logWarning('Http', 'Http performance profile measurement error to access the AjaxRequest object.'); return of(request); } request[startPropertyName] = Date.now(); return of(request); }, successMonitor: (response) => { if (!response || !response.request || !response.request.url) { Logging.logWarning('Http', 'Http performance profile measurement error to access the AjaxResponse object.'); return of(response); } const request = response.request; const url = request.url; const method = request.method; const end = Date.now(); const start = request[startPropertyName]; if (url.indexOf('/features/powershellApi/') > 0 || url.indexOf('/services/WinREST/PowerShell/') > 0) { const powershell = PerformanceProfile.powershellApi(url, request.body, response.response); PerformanceProfile.logXhrFetchPowerShell('Http', start, end, url, method, response.status, powershell); } else if (url.includes('/features/cim/') || url.includes('/services/WinREST/CIM')) { const cim = PerformanceProfile.cimApi(url, request.body); PerformanceProfile.logXhrFetchCim('Http', start, end, url, method, response.status, cim); } else if (url.indexOf('/api/batch') > 0) { const batch = PerformanceProfile.batchApi(request.body, response.response); PerformanceProfile.logXhrFetchBatch('Http', start, end, url, method, response.status, batch); } else { PerformanceProfile.logXhrFetch('Http', start, end, url, method, response.status); } return of(response); }, errorMonitor: (error) => { if (!error || !error.response || !error.request || !error.request.url) { Logging.logWarning('Http', 'Http performance profile measurement error to access the AjaxError object.'); return throwError(() => error); } const request = error.request; const url = request.url; const method = request.method; const end = Date.now(); const start = request[startPropertyName]; const message = Net.getErrorMessage(error); if (url.indexOf('features/powershellApi') > 0 || url.indexOf('/services/WinREST/PowerShell/') > 0) { const powershell = PerformanceProfile.powershellApi(url, request.body, error.response); PerformanceProfile.logXhrFetchPowerShell('Http', start, end, url, method, error.status, powershell, message); } else if (url.includes('/features/cim/') || url.includes('/services/WinREST/CIM/')) { const cim = PerformanceProfile.cimApi(url, request.body); PerformanceProfile.logXhrFetchCim('Http', start, end, url, method, error.status, cim, message); } else { PerformanceProfile.logXhrFetch('Http', start, end, url, method, error.status, message); } return throwError(() => error); } }); } registerPowerShellStream() { let masterId = 1; PowerShellStream.registerMonitorSet({ name: PerformanceProfile.monitorName, preMonitor: (nodeName, command, options) => { const start = Date.now(); const id = masterId++; const context = { nodeName, command, options, data: { id, start, progressStart: start, count: 0, itemCount: 0 } }; return of(context); }, successMonitor: (response, context) => { context.data.progressEnd = Date.now(); context.data.count++; context.data.itemCount += (response && response.results && response.results.length || 1); PerformanceProfile.logWebSocketPowerShell('PowerShellStream', context.nodeName, context.command.command, context.data); context.data.progressStart = Date.now(); return of(response); }, errorMonitor: (error, context) => { context.data.progressEnd = Date.now(); PerformanceProfile.logWebSocketPowerShell('PowerShellStream', context.nodeName, context.command.command, context.data, Net.getErrorMessage(error)); return throwError(() => error); } }); } registerCimStream() { let masterId = 1; CimStream.registerMonitorSet({ name: PerformanceProfile.monitorName, preMonitor: (nodeName, requestState, request, format, options) => { const start = Date.now(); const id = masterId++; const context = { nodeName, requestState, request, format, options, data: { id, start, progressStart: start, count: 0, itemCount: 0 } }; return of(context); }, successMonitor: (response, context) => { context.data.progressEnd = Date.now(); context.data.count++; context.data.itemCount += (response && response.results && response.results.length || 1); PerformanceProfile.logWebSocketCim('CimStream', context.nodeName, this.removeCimStreamDetailData(context.request), context.data); context.data.progressStart = Date.now(); return of(response); }, errorMonitor: (error, context) => { context.data.progressEnd = Date.now(); PerformanceProfile.logWebSocketCim('CimStream', context.nodeName, this.removeCimStreamDetailData(context.request), context.data, Net.getErrorMessage(error)); return throwError(() => error); } }); } removeCimStreamDetailData(request) { const skipKeys = ['data', 'keyProperties']; const requestRaw = request; const keys = Object.keys(requestRaw); const trimmedKeys = keys.filter(key => skipKeys.indexOf(key) < 0); if (keys.length !== trimmedKeys.length) { const copy = {}; for (const key of trimmedKeys) { copy[key] = requestRaw[key]; } return copy; } return request; } } //# sourceMappingURL=performance-profile.js.map // SIG // Begin signature block // SIG // MIIoNwYJKoZIhvcNAQcCoIIoKDCCKCQCAQExDzANBglg // SIG // hkgBZQMEAgEFADB3BgorBgEEAYI3AgEEoGkwZzAyBgor // SIG // BgEEAYI3AgEeMCQCAQEEEBDgyQbOONQRoqMAEEvTUJAC // SIG // AQACAQACAQACAQACAQAwMTANBglghkgBZQMEAgEFAAQg // SIG // WKB3p/kv6D5QfJO8CtOLGWUi/mtLt586w68obYvAFGOg // 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 // AYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBAgynJ/hKrHa51 // SIG // Hmml8pliDpsaGQkVZeQqQU2tGdeFzjBCBgorBgEEAYI3 // SIG // AgEMMTQwMqAUgBIATQBpAGMAcgBvAHMAbwBmAHShGoAY // SIG // aHR0cDovL3d3dy5taWNyb3NvZnQuY29tMA0GCSqGSIb3 // SIG // DQEBAQUABIIBAHNY2KSMLPBG3Zb8ZslxyuB+byXoxxGQ // SIG // eSM70tIyRotWlzHQgT6ecGID9tts4BVEwPkRN/4Il3U7 // SIG // OWrrhBv4ic+nUxJHo+jnbaEDyaISUtjv7VIID5C1Jb9X // SIG // Zj8j49k/hO1zHAU+B3L4Fxz2Dq43o9j7hF8UyIqAwYiP // SIG // 7bMQ1UYFH8Od5UImwMLkab91nOVHeo7rX3q5vySwI+ol // SIG // Uc6N//O7bWz2Kx4n53RDnvomPt+rGAAklTI1UpeSGNHW // SIG // 6Pt7uUl1maHrkdy0g7ezWBIdfiwXY7PLDfyoPxcZFjfG // SIG // 6ko8fCMEr/id05vGDi0w1o6qDUeRDkS9GfNqTjteLl6h // SIG // F5ChgheUMIIXkAYKKwYBBAGCNwMDATGCF4Awghd8Bgkq // SIG // hkiG9w0BBwKgghdtMIIXaQIBAzEPMA0GCWCGSAFlAwQC // SIG // AQUAMIIBUgYLKoZIhvcNAQkQAQSgggFBBIIBPTCCATkC // SIG // AQEGCisGAQQBhFkKAwEwMTANBglghkgBZQMEAgEFAAQg // SIG // 0Kf/RtG98rBrvBN843eNm+p/6TWuOXsCguc4yFgaP18C // SIG // Bmet2JkEHRgTMjAyNTAyMjAxNTI4MzUuNTEzWjAEgAIB // 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 // hkiG9w0BCQQxIgQg6HUBk3meE1JRXM6ovDK/PQX/XhiG // SIG // +KbnFnbPvVoi0WAwgfoGCyqGSIb3DQEJEAIvMYHqMIHn // SIG // MIHkMIG9BCAnCeb1an03yIcdtUAQWysqP8XIkCF2qDFl // SIG // C3owBNUKgzCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMw // SIG // EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt // SIG // b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp // SIG // b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w // SIG // IFBDQSAyMDEwAhMzAAAB7OArpILQkVKAAAEAAAHsMCIE // SIG // IJMWfWH4rigb0xVwIT3U52hJl/r0nZiZ9lzyPXRL+C1O // SIG // MA0GCSqGSIb3DQEBCwUABIICAGPa8LNQwidwBMyn+C54 // SIG // g8hvhxXkvrSgcDd1XDJ6QkrjcQhS0vLwfJgyjFsB9Fy8 // SIG // lb1Zu+TAB5AbeVXpm9KFYOMdBQ7tJe9ZNCXLbxBacKH3 // SIG // qYJhuiJcyn8bxF1WhT7h0Ht4uZv06q7tPlJpN+kwbrIe // SIG // OQtMBBF02SdZ4MhBZ87rT4T5pwVZrewEJYXx6RFxsqu7 // SIG // GnYZ5aJE6KYdM9ZlptIswT5NOlZY+faMRsOZdbeFxMI1 // SIG // 9u9psivSOh5VZYk9hsn19eLD43ENaoi98X9ct7zzdM41 // SIG // oUG+bsz89AEYSothg8LUFn4CUJMWZVsd5iAuWq6DeVyw // SIG // hbvutrhJtJwwuw+U+XjKXz9GXdV4b+cgpBHm2+04zA/4 // SIG // C5LhzHJG6XeYxpvt0PGKwoyEnn9ttXFa52arU6qdNe+D // SIG // U5fpNODPNcdBgrxrM6zNBZnjA40uHcb/gxUWeCidVhtz // SIG // 4C2ghsRaenFpqabgxaNQUS1sitOhkM1T4CF7Yfy/ar6p // SIG // Uu5rFqIODiHgCUcO7srVISocOrUY82RKLYlbNXcBeH0i // SIG // zXIsSRCMu23bezlkqatkx7g3okInDxMlIeqFtuW+khOS // SIG // vrm+u4XepfJEsbF9ZQ+6JhW4QA0uVWDtRi5Aycco0RI/ // SIG // Wt2cGFwpvwUAn10KKZi/azjMkHwuirjhtFaMruRBvbPT // SIG // eUOB // SIG // End signature block