@microsoft/windows-admin-center-sdk
Version:
Microsoft - Windows Admin Center Shell
846 lines (843 loc) • 39.7 kB
JavaScript
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