UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

899 lines (896 loc) 42.1 kB
import { filter, take } from 'rxjs/operators'; import { Http } from '../data/http'; import { Net } from '../data/net'; import { RpcLogClient } from '../rpc/log/rpc-log-client'; import { RpcLogSubjectServer } from '../rpc/log/rpc-log-subject-server'; import { RpcTelemetryClient } from '../rpc/telemetry/rpc-telemetry-client'; import { RpcTelemetrySubjectServer } from '../rpc/telemetry/rpc-telemetry-subject-server'; import { LogLevel } from './log-level'; import { LoggingConstants } from './logging-constants'; import { TelemetryControlType } from './telemetry-control-type'; /** * Logging class. * @dynamic */ export class Logging { static logMaxRecordLength = 20; static logMaxWaitTimeMs = 30000; static telemetryMaxRecordLength = 100; static telemetryMaxWaitTimeMs = 60000; static testMode = 'test'; static instance; static errorLogHeaderStyle = 'font-weight: bold; color: #E81123;'; static warnLogHeaderStyle = 'font-weight: bold; color: #FF8C00;'; static successLogHeaderStyle = 'font-weight: bold; color: ##288928;'; static infoLogHeaderStyle = 'font-weight: bold; color: #0078D7;'; static verboseLogHeaderStyle = 'color: #999'; logSubjectServer; telemetrySubjectServer; gateway; http; rpc; logSet; telemetrySet; thresholdOfLogLevel = LogLevel.Informational; verboseTelemetry = false; /** * Log a logging event. * * @param record the log record to send the gateway. * @return Promise<any> settle to resolve if buffered. */ static log(record) { return Logging.current.logInternal(record); } /** * Log a critical logging event. * * @param source The record originator of event within a module. * @param message The message of event. * @param params The parameters object which will be serialized. * @return Promise<any> settle to resolve if buffered. */ static logCritical(source, message, params) { return Logging.current.logInternal({ level: LogLevel.Critical, source, message, params: params }); } /** * Log an error logging event. * * @param source The record originator of event within a module. * @param message The message of event. * @param params The parameters object which will be serialized. * @return Promise<any> settle to resolve if buffered. */ static logError(source, message, params) { return Logging.current.logInternal({ level: LogLevel.Error, source, message, params: params }); } /** * Log a warning logging event. * * @param source The record originator of event within a module. * @param message The message of event. * @param params The parameters object which will be serialized. * @return Promise<any> settle to resolve if buffered. */ static logWarning(source, message, params) { return Logging.current.logInternal({ level: LogLevel.Warning, source, message, params: params }); } /** * Log a success logging event. * * @param source The record originator of event within a module. * @param message The message of event. * @param params The parameters object which will be serialized. * @return Promise<any> settle to resolve if buffered. */ static logSuccess(source, message, params) { return Logging.current.logInternal({ level: LogLevel.Success, source, message, params: params }); } /** * Log a informational logging event. * * @param source The record originator of event within a module. * @param message The message of event. * @param params The parameters object which will be serialized. * @return Promise<any> settle to resolve if buffered. */ static logInformational(source, message, params) { return Logging.current.logInternal({ level: LogLevel.Informational, source, message, params: params }); } /** * Log a verbose logging event. * * @param source The record originator of event within a module. * @param message The message of event. * @param params The parameters object which will be serialized. * @return Promise<any> settle to resolve if buffered. */ static logVerbose(source, message, params) { return Logging.current.logInternal({ level: LogLevel.Verbose, source, message, params: params }); } /** * Log a debug logging event. * * @param source The record originator of event within a module. * @param message The message of event. * @param params The parameters object which will be serialized. * @return Promise<any> settle to resolve if buffered. */ static logDebug(source, message, params) { return Logging.current.logInternal({ level: LogLevel.Debug, source, message, params: params }); } /** * Trace a telemetry event. * * @param record the telemetry record to send the gateway. * @return Promise<any> settle to resolve if buffered. */ static trace(record) { return Logging.current.telemetryInternal(record); } /** * Trace a user action telemetry event. * * @param data additional data. * @return Promise<any> settle to resolve if buffered. */ static traceUserAction(data) { return Logging.trace({ view: LoggingConstants.views.smeUIControl, instance: LoggingConstants.empty, action: LoggingConstants.actions.click, data: data }); } /** * Trace a telemetry event for a button click. * * @param controlName Describes which control was used. * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button. * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness. * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName) * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type) * @return Promise<any> settle to resolve if buffered. */ static traceButton(controlName, controlId, nodeName, nodeType) { return Logging.traceButtonClick(TelemetryControlType.Button, controlName, controlId, nodeName, nodeType); } /** * Trace a telemetry event for a action pane button click. * * @param controlName Describes which control was used. * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button. * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness. * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName) * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type) * @return Promise<any> settle to resolve if buffered. */ static traceActionPaneButton(controlName, controlId, nodeName, nodeType) { return Logging.traceButtonClick(TelemetryControlType.ActionPaneButton, controlName, controlId, nodeName, nodeType); } /** * Trace a telemetry event for a action bar button click. * * @param controlName Describes which control was used. * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button. * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness. * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName) * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type) * @return Promise<any> settle to resolve if buffered. */ static traceActionBarButton(controlName, controlId, nodeName, nodeType) { return Logging.traceButtonClick(TelemetryControlType.ActionBarButton, controlName, controlId, nodeName, nodeType); } /** * Trace a telemetry event on a sme control. * * @param controlName Describes which control was used. * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button. * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness. * @param additionalData Additional key value pairs that can be sent to telemetry. * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName) * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type) * @return Promise<any> settle to resolve if buffered. */ static traceControl(controlType, controlName, controlId, additionalData, nodeName, nodeType) { let data = {}; if (additionalData) { data = additionalData; } data[controlType] = controlType; data[controlName] = controlName; data[controlId] = controlId; const nodeId = Logging.getFormattedNodeId(nodeName, nodeType); if (nodeId) { data[LoggingConstants.dataFields.nodeId] = nodeId; } return Logging.traceUserAction(data); } /** * Trace a telemetry event on click of an external link. * * @param controlName Describes which control was used. * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button. * @param url External link that was clicked. * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness. * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName) * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type) * @return Promise<any> settle to resolve if buffered. */ static traceExternalLink(controlName, url, controlId, nodeName, nodeType) { const data = { controlType: TelemetryControlType.ExternalLink, controlName: controlName, controlId: controlId, url: url }; const nodeId = Logging.getFormattedNodeId(nodeName, nodeType); if (nodeId) { data[LoggingConstants.dataFields.nodeId] = nodeId; } return Logging.traceUserAction(data); } /** * Trace a telemetry event on click of an internal link. * * @param controlName Describes which control was used. * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button. * @param route rpc route. * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness. * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName) * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type) * @return Promise<any> settle to resolve if buffered. */ static traceInternalLink(controlName, route, controlId, nodeName, nodeType) { const data = { controlType: TelemetryControlType.InternalLink, controlName: controlName, controlId: controlId, route: route }; const nodeId = Logging.getFormattedNodeId(nodeName, nodeType); if (nodeId) { data[LoggingConstants.dataFields.nodeId] = nodeId; } return Logging.traceUserAction(data); } /** * Trace a telemetry event when an async task returns. * * @param eventLocation UI location of the event being recorded. * ex) createVmForm, RegisterAadDialog, stopServiceConfirmationDialog... * @param eventLabel Description of what event is being logged. * ex) 'Registered with Azure', 'Added a connection', 'Failed Azure backup' * @param result Result of event. * @param additionalData Additional key value pairs that can be sent to telemetry. * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName) * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type) * @return Promise<any> settle to resolve if buffered. */ static traceAsyncResult(eventLocation, eventLabel, result, additionalData, nodeName, nodeType) { let data = {}; if (additionalData) { data = additionalData; } data[LoggingConstants.dataFields.eventLocation] = eventLocation; data[LoggingConstants.dataFields.eventLabel] = eventLabel; data[LoggingConstants.dataFields.result] = result; const nodeId = Logging.getFormattedNodeId(nodeName, nodeType); if (nodeId) { data[LoggingConstants.dataFields.nodeId] = nodeId; } return Logging.traceUserAction(data); } /** * Log a raw object into the console at debug level of mode. */ static debug(object) { if (Logging.current.consoleLogLevel >= LogLevel.Debug) { console.log(object); } } /** * Configure logging mode. * * @param thresholdOfLogLevel the log level for gateway. * @param verboseTelemetry if true, optional telemerty will be collected. */ static configureLog(thresholdOfLogLevel, verboseTelemetry) { Logging.current.thresholdOfLogLevel = thresholdOfLogLevel; Logging.current.verboseTelemetry = verboseTelemetry; } /** * Wrapper method for tracing a telemetry event for a button click. * * @param controlType Type of button that is being recorded * @param controlName Describes which control was used. * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button. * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness. * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName) * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type) * @return Promise<any> settle to resolve if buffered. */ static traceButtonClick(controlType, controlName, controlId, nodeName, nodeType) { const data = { controlType: controlType, controlName: controlName, controlId: controlId }; const nodeId = Logging.getFormattedNodeId(nodeName, nodeType); if (nodeId) { data[LoggingConstants.dataFields.nodeId] = nodeId; } return Logging.traceUserAction(data); } /** * Format node information for telemetry * * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName) * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type) * @return string */ static getFormattedNodeId(nodeName, nodeType) { if (nodeType && nodeName) { return nodeType + '!' + nodeName; } else { return null; } } /** * Gets the level of current logging. */ get consoleLogLevel() { const global = window; return (global.MsftSme && global.MsftSme.Init && global.MsftSme.Init.logLevel) || LogLevel.Warning; } /** * Gets the session Id of shell. */ get sessionId() { const global = window; return global.MsftSme && global.MsftSme.Init && global.MsftSme.Init.sessionId || Logging.testMode; } /** * Gets the name of current shell or module. */ get nameOfModule() { const global = window; return global.MsftSme && global.MsftSme.Init && global.MsftSme.Init.moduleName || Logging.testMode; } /** * Initializes a new instance of the Logging class. */ constructor() { this.http = new Http(); this.logSet = { maxWaitTimeMs: Logging.logMaxWaitTimeMs, maxRecordLength: Logging.logMaxRecordLength, api: '/log' }; this.telemetrySet = { maxWaitTimeMs: Logging.telemetryMaxWaitTimeMs, maxRecordLength: Logging.telemetryMaxRecordLength, api: '/telemetry' }; } /** * Gets the current logging instance. */ static get current() { if (Logging.instance) { return Logging.instance; } Logging.instance = new Logging(); return Logging.instance; } /** * Flush the regular log set, immediately submitting the logs to the gateway */ static flushLogs() { Logging.current.flush(Logging.current.logSet); } /** * Flush the telemetry log set, immediately submitting the logs to the gateway */ static flushTelemetry() { Logging.current.flush(Logging.current.telemetrySet); } /** * Register Rpc object to logging instance. * * @param rpc the rpc instance. */ registerRpc(rpc, gateway) { this.rpc = rpc; this.gateway = gateway; // start subscribing once after the rpc is ready on the shell. this.rpc.stateChanged .pipe(filter(active => active), take(1)) .subscribe(() => { if (this.rpc.isShell) { this.logSubjectServer = new RpcLogSubjectServer(this.rpc); this.logSet.rpcSubscription = this.logSubjectServer.subject .subscribe(data => { this.logGateway(this.logSet, data.data); data.deferred.resolve(); }); this.telemetrySubjectServer = new RpcTelemetrySubjectServer(this.rpc); this.telemetrySet.rpcSubscription = this.telemetrySubjectServer.subject .subscribe(data => { this.logGateway(this.telemetrySet, data.data); data.deferred.resolve(); }); } }); } /** * Dispose the set of rpc forwarding pipes. */ dispose() { this.disposeSet(this.logSet); this.disposeSet(this.telemetrySet); } /** * Log a record. * * @param record the log record. * @return Promise<any> the promise object. */ logInternal(record) { const now = new Date(); if (record.level <= this.consoleLogLevel) { let headerStyle = Logging.verboseLogHeaderStyle; if (record.level <= LogLevel.Error) { headerStyle = Logging.errorLogHeaderStyle; } else if (record.level <= LogLevel.Warning) { headerStyle = Logging.warnLogHeaderStyle; } else if (record.level <= LogLevel.Success) { headerStyle = Logging.successLogHeaderStyle; } else if (record.level <= LogLevel.Informational) { headerStyle = Logging.infoLogHeaderStyle; } const logSeparator = '--'; const customHeader = record.consoleGroupHeader ? ` ${logSeparator} ${record.consoleGroupHeader}` : ''; if (MsftSme.isEdge() || MsftSme.isInternetExplorer()) { // Microsoft Edge and IE don't support styles in group headers. so remove if running on Microsoft Edge // Since there is no color support, also log the severity console.groupCollapsed(`${LogLevel[record.level]} ${logSeparator} ${this.nameOfModule} ${logSeparator} ${record.source}${customHeader}`); } else { console.groupCollapsed(`%c${this.nameOfModule} ${logSeparator} ${record.source}${customHeader}`, headerStyle); } console.log(`logLevel: ${LogLevel[record.level]}`); console.log(`timestamp: ${now.toISOString()}`); if (record.message) { if (MsftSme.isObject(record.message)) { console.log('message:'); console.log({ ...record.message }); } else { console.log(`message: ${record.message}`); } } if (record.params) { console.group('params'); console.log({ ...record.params }); console.groupEnd(); } if (record.localParams) { console.group('params'); console.log({ ...record.localParams }); console.groupEnd(); delete record['localParams']; } if (record.stack) { console.group('stack'); console.log(record.stack); console.groupEnd(); } console.groupEnd(); } if (record.level <= this.thresholdOfLogLevel && this.sessionId !== Logging.testMode) { if (MsftSme.isObject(record.message)) { // ensure message is a string. record.message = JSON.stringify(record.message); } const rpcRecord = { ...record, ...{ sessionId: this.sessionId, timestamp: now.getTime(), sourceName: this.nameOfModule } }; if (this.rpc && this.rpc.stateActive && !this.rpc.isShell) { return RpcLogClient.log(this.rpc, rpcRecord); } this.logGateway(this.logSet, rpcRecord); } return Promise.resolve(); } /** * Log a telemerty record. * * @param record the telemetry record. * @return Promise<any> the promise object. */ telemetryInternal(record) { if (((!this.verboseTelemetry && !record.optional) || this.verboseTelemetry) && this.sessionId !== Logging.testMode) { const rpcRecord = { ...record, ...{ sessionId: this.sessionId, timestamp: Date.now(), sourceName: this.nameOfModule } }; if (this.rpc && this.rpc.stateActive && !this.rpc.isShell) { return RpcTelemetryClient.telemetry(this.rpc, rpcRecord); } this.logGateway(this.telemetrySet, rpcRecord); } return Promise.resolve(); } /** * Dispose the set. * * @param set the logger set. */ disposeSet(set) { if (set.rpcSubscription) { set.rpcSubscription.unsubscribe(); set.rpcSubscription = null; } } /** * Log to the gateway. * * @param set the logger set. * @param data the record data. */ logGateway(set, data) { if (set.timer == null) { set.buffer = []; set.timer = setTimeout(() => this.submitRecords(set), set.maxWaitTimeMs); } set.buffer.push(data); if (set.buffer.length >= set.maxRecordLength) { clearTimeout(set.timer); this.submitRecords(set); set.timer = setTimeout(() => this.submitRecords(set), set.maxWaitTimeMs); } } /** * Flush a log set, immediately submitting the logs to the gateway */ flush(set) { if (set && set.buffer && set.buffer.length > 0) { this.submitRecords(set); } } /** * Submit records to the gateway. */ submitRecords(set) { // Disabled gateway can't log anything in gateway. if (set.buffer.length > 0 && this.gateway && !this.gateway.disabled) { this.gateway.post(set.api, set.buffer, { maxRetryCount: 0 }).subscribe({ error: error => { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.LoggingUnableSubmit.message; console.error(message.format(Net.getErrorMessage(error))); } }); } set.timer = null; set.buffer = []; } } //# sourceMappingURL=logging.js.map // SIG // Begin signature block // SIG // MIIoNwYJKoZIhvcNAQcCoIIoKDCCKCQCAQExDzANBglg // SIG // hkgBZQMEAgEFADB3BgorBgEEAYI3AgEEoGkwZzAyBgor // SIG // BgEEAYI3AgEeMCQCAQEEEBDgyQbOONQRoqMAEEvTUJAC // SIG // AQACAQACAQACAQACAQAwMTANBglghkgBZQMEAgEFAAQg // SIG // M487nwVsJwQXU58G6WwhM82lgppyLSqWy5bhMHtegbCg // 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 // AYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBkmKDvLui5kpoQ // SIG // ShqD1l1YNX0o1EpeOHCIqRONRtaTITBCBgorBgEEAYI3 // SIG // AgEMMTQwMqAUgBIATQBpAGMAcgBvAHMAbwBmAHShGoAY // SIG // aHR0cDovL3d3dy5taWNyb3NvZnQuY29tMA0GCSqGSIb3 // SIG // DQEBAQUABIIBABLgpPIQLue0EOytJVnKA/cG/Pw0eCnj // SIG // yyvUZRlJsDhdpGnLOe5dQYGg5hXKSbOrO8y5T+rDbDJV // SIG // 4UKjc2O1a7VATvWxyzeZN1J8hXC8l4BzhhTZLVu6O2dJ // SIG // TYc6nS+tkh7TpDTQZEaqqeVboHhkCajQnseFuPX/QhvX // SIG // 91m640jHGE3kg89DRzRM24KA3sK+rq5D8+pclg1A/E4/ // SIG // jnxS73YailltYQ4BmMuoOOV0DWO+70RO5AnkYQlbF5rE // SIG // PSg9or1gy+TyVB7BP1Wnd7u9MSqQa3nlggKRsoN5WsXL // SIG // VgFj/wcpW9FATG3rp1A7o9mlnYl417A+ZN0QC/PI4o9F // SIG // OiShgheUMIIXkAYKKwYBBAGCNwMDATGCF4Awghd8Bgkq // SIG // hkiG9w0BBwKgghdtMIIXaQIBAzEPMA0GCWCGSAFlAwQC // SIG // AQUAMIIBUgYLKoZIhvcNAQkQAQSgggFBBIIBPTCCATkC // SIG // AQEGCisGAQQBhFkKAwEwMTANBglghkgBZQMEAgEFAAQg // SIG // hHOQjKfqf9MmeYlA5OIegougmkXCLvmVMXAHV7Bj3GMC // SIG // BmeuJGuZOBgTMjAyNTAyMjAxNTI4MzkuOTUzWjAEgAIB // SIG // 9KCB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgT // SIG // Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc // SIG // BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMG // SIG // A1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9u // SIG // czEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjk2MDAt // SIG // MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGlt // SIG // ZS1TdGFtcCBTZXJ2aWNloIIR6jCCByAwggUIoAMCAQIC // SIG // EzMAAAHviT9WoVjMqNoAAQAAAe8wDQYJKoZIhvcNAQEL // SIG // BQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp // SIG // bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT // SIG // FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMd // SIG // TWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcN // SIG // MjMxMjA2MTg0NTQ4WhcNMjUwMzA1MTg0NTQ4WjCByzEL // SIG // MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x // SIG // EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv // SIG // c29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9z // SIG // b2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMe // SIG // blNoaWVsZCBUU1MgRVNOOjk2MDAtMDVFMC1EOTQ3MSUw // SIG // IwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2 // SIG // aWNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC // SIG // AgEAowtY4p8M4B8ITmpGaste6BOASASrJuZF+A1JggVi // SIG // NJRVaRIiuZmdioefbKC+J7OdqYRTEGBhuZMqQoqbp4MD // SIG // /TaG+FRlROmqDKOYWfTcrV0eWUYG/WfDUehJiyiAkYQ+ // SIG // LKIzzIP0ZxkU3HX+/02L8jNdIy45i8ihHoDB37yMD5jP // SIG // gD+4c0C3xMQ3agidruuBneV5Z6xTpLuVPYyzipNcu9HP // SIG // k8LdOP0S6q7r9Xxj/C5mJrR76weE3AbAA10pnBY4dFYE // SIG // JF+M1xcKpyBvK4GPsw6iWEDWT/DtWKOJEnJB0+N1wtKD // SIG // ONMntvvZf602IgxTN55WXto4bTpBgjuhqok6edMSPSE6 // SIG // SV4tLxHpPAHo0+DyjBDtmz8VOt6et7mW43TeS/pYCHAj // SIG // TAjSNEiKKUuIGlUeEsvyKA79bw1qXviNvPysvI1k3nnd // SIG // Dtx8TyTGal+EAdyOg58Gax4ip+qBN/LYAUwggCrxKGDk // SIG // 4O69pRdCLm7f9/lT7yrUwlG2TxThvI2bfaugBaHZb0J7 // SIG // YqJWCGLakqy8lwECJVxoWeIDXL+Hb9WAIpZ21gPQrJ2I // SIG // fjihBa/+MODOvZSPsmqGdy/7f1H16U//snO4UvxaJXJq // SIG // xhSUwWJUuJxNXLim5cGf1Dhtuki4QzjVlxmQyjCSjed6 // SIG // Di0kpOJXUdB5bG0+IXi5VpThJSUCAwEAAaOCAUkwggFF // SIG // MB0GA1UdDgQWBBTtTFqihcKwm7a8PT/AOt2wFUicyzAf // SIG // BgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBf // SIG // BgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jv // SIG // c29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBU // SIG // aW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYI // SIG // KwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8v // SIG // d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01p // SIG // Y3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEw // SIG // KDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM // SIG // MAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDANBgkq // SIG // hkiG9w0BAQsFAAOCAgEAGBmWt2gg7nW5PRFXZD/MXEBm // SIG // biACD0cfStQgO7kcwbfNHwtGlpLmGIUDLxxyUR1KG0jO // SIG // FMN8ze3xxDfIYWgQ2/TUWhpxVnbR8ZifXjM+iaZ+ioiM // SIG // ovVOToO0Ak2TJde59sOHnXaub7ZOK0Vjlb6YgwRiQESo // SIG // l1gfbtosdFh9hDBRh6oyIY1lF4T4EeAujShTVx71r13n // SIG // Cdll6yZ770BlwHzSRhEyWRqUeNZ1Dd4o34gkoxQ8Wphj // SIG // 7MuYmLvdOB7/brkl2HeZtCcX9ljSUl5DxpTYaztu6T8Y // SIG // E9ddZsgEetUt0toXOe9szfcqCRDmxPfFcuShDN2V+d3C // SIG // 3nzfNRdQvaf3ACpBOrvVeq8spf6koMbtVKnjmQrRv4mh // SIG // 0ijKMTOzKuEjBbD0//InjncApWKXMNAo2XuSgcdsS2uA // SIG // dZ3hYm/CfP4EqLIzHRd5x4sh8dWHnWQ7cUkoHoHibItH // SIG // 21IHc7FTCWL6lcOdlqkDbtBkQu/Wbla3lFSnQiZlDARw // SIG // aU6elRaKS9CX+Eq4IPs0Q/YsG3Pbma5/vPaHaSJ2852K // SIG // 5zyh4jtuqntXpDcJf3e66NiLT/5YIc9A6A+5BBnopCiV // SIG // h3baO3lSaCYZK1HGp07lB9PIPjWMBukvj4wUgfzcjRem // SIG // x2v8UfnHgGIXI8dIgYr/dDJ9CYhn5wNv4S4+Xr4U3AIw // 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 // Tjo5NjAwLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9z // SIG // b2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsO // SIG // AwIaAxUAS3CPNYMW3mtRMdphW18e3JPtIP+ggYMwgYCk // SIG // fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu // SIG // Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV // SIG // TWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N // SIG // aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkq // SIG // hkiG9w0BAQsFAAIFAOthNCEwIhgPMjAyNTAyMjAwNDU0 // SIG // NTdaGA8yMDI1MDIyMTA0NTQ1N1owdDA6BgorBgEEAYRZ // SIG // CgQBMSwwKjAKAgUA62E0IQIBADAHAgEAAgIZHTAHAgEA // SIG // AgIiMTAKAgUA62KFoQIBADA2BgorBgEEAYRZCgQCMSgw // SIG // JjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIB // SIG // AAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQCh0tRfygN1 // SIG // 97uMosyihIbypYP3Rn1LersJkthkKTw8FgRHDz/Xb6Lf // SIG // MUuR3wlXqsnKFCthLh/EzrZ+Ojao+t/cZ/E+egYRpxze // SIG // BBM/+BLmoYA24USUgPR9nWHYpx+efue//fboWjW36vli // SIG // 6mVJryc2/NiUtqGttRVRPBSSmqEJULVmvU+DsXoW0msa // SIG // UV7s+4+wwJfaJV9LBejiGUG5JgNjfsy7T8pv+cq1lcjQ // SIG // VHG6wTpcO8Eb1O2avA2ioO18rgbik9+PI3Ik31jfOJ40 // SIG // dUH3FaxVxn6YPnb7qCy7q3WwEf+tTOEp0pf1mwNITaoA // SIG // Ht8e/eCQ6hPFcQpuuIHC8htDMYIEDTCCBAkCAQEwgZMw // SIG // fDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0 // SIG // b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p // SIG // Y3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWlj // SIG // cm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAHv // SIG // iT9WoVjMqNoAAQAAAe8wDQYJYIZIAWUDBAIBBQCgggFK // SIG // MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkq // SIG // hkiG9w0BCQQxIgQgA1QstsvdHZnN5L65sE5F1w02W1kA // SIG // TEh7TCvIWXxnxC0wgfoGCyqGSIb3DQEJEAIvMYHqMIHn // SIG // MIHkMIG9BCDwYShFuBaN8FM9PTUMdmtA23HbF/I6LzOS // SIG // 4sx5p8l/ozCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMw // SIG // EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt // SIG // b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp // SIG // b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w // SIG // IFBDQSAyMDEwAhMzAAAB74k/VqFYzKjaAAEAAAHvMCIE // SIG // IFbk9jFTorFlI4xM2so4TTtuOU/RVAajDSD7CajID8VZ // SIG // MA0GCSqGSIb3DQEBCwUABIICACQvdZ1kdm00uJaLdaPm // SIG // Yq7RKvwP57Qkq0pBnwlC8Otwt01QbU0ymFZR8njw0fqS // SIG // vYJ0cDflpvhxA9g612LNO85heCWUPJlOSKDTyqTniKcw // SIG // aYhTqw1jQnionEq7/SWS9pTApIDH5RZvo3PK03BMfbdP // SIG // 0w5XxDi/OfaNJ0ifYHOtAl8+sFKzOdf3kWU7B/x2ZmW1 // SIG // 7aARex7w0EcI1Nh7gZDZZ4AGr8dllFS8CX2oxrsGa7EZ // SIG // SfaO+kDwaRBZ7YwaOMLOYITRWcFPzswa6LBisdI/SCat // SIG // aU4mTSP8LcPZ2tBjKCz/LlhGgOpNOvMt0ExRzHT2gpG2 // SIG // qYkQ0ejcLVO3iF4xKv7BgfWB6cPnPnHoTFiOEKHKQ/xG // SIG // hHYEjTvZ4a+T01yHhEnyuBE3YfUzymI3rfvfrPrCdB4/ // SIG // M+gv1/8D68ItRluDKtbaGnHW1uvgZW5jsdjeN+Bi3CG1 // SIG // 9rSLFL2pmtWo4+qIPL5aLXezNsjlrzq4fIgXRXIdsEJy // SIG // DKS2ekSkc8vKvxEcN0VeXwm6uwMVBj1cT1efQXAzdlsp // SIG // bet83iL3mnJ+eA4lUnP6l8S0dbQU115AGA5pM68J8sAm // SIG // PCjxbNXx14kiSeKzGXfaxzl+bKphX1rma0tKLf+hjLGo // SIG // 2+dlTv12zVKK3uM3zZqITTQlOv0uaJFft/zqzVBAO2jt // SIG // FnWQ // SIG // End signature block