@microsoft/windows-admin-center-sdk
Version:
Microsoft - Windows Admin Center Shell
1,169 lines (1,167 loc) • 56.1 kB
JavaScript
import { LogLevel } from '../diagnostics/log-level';
import { Logging } from '../diagnostics/logging';
/**
* The type of entry point.
*/
export var EnvironmentModuleEntryPointType;
(function (EnvironmentModuleEntryPointType) {
EnvironmentModuleEntryPointType["ConnectionProvider"] = "connectionProvider";
EnvironmentModuleEntryPointType["Solution"] = "solution";
EnvironmentModuleEntryPointType["Tool"] = "tool";
EnvironmentModuleEntryPointType["Service"] = "service";
EnvironmentModuleEntryPointType["SettingsForm"] = "settingsForm";
EnvironmentModuleEntryPointType["GroupProvider"] = "groupProvider";
EnvironmentModuleEntryPointType["Worker"] = "worker";
EnvironmentModuleEntryPointType["Dialog"] = "dialog";
EnvironmentModuleEntryPointType["SnapIn"] = "snapIn";
EnvironmentModuleEntryPointType["WacCopilot"] = "wacCopilot";
EnvironmentModuleEntryPointType["WacCopilotAngular"] = "wacCopilotAngular";
})(EnvironmentModuleEntryPointType || (EnvironmentModuleEntryPointType = {}));
/**
* The type of lifetime to implement when creating a worker
*/
export var ExtensionTargetType;
(function (ExtensionTargetType) {
ExtensionTargetType["WorkerTarget"] = "workerTarget";
})(ExtensionTargetType || (ExtensionTargetType = {}));
/**
* The state definition of Tool condition.
*/
export var EnvironmentModuleToolState;
(function (EnvironmentModuleToolState) {
/**
* Tool is available on the connection.
*/
EnvironmentModuleToolState[EnvironmentModuleToolState["Available"] = 0] = "Available";
/**
* Tool is not available because it's not configured properly.
*/
EnvironmentModuleToolState[EnvironmentModuleToolState["NotConfigured"] = 1] = "NotConfigured";
/**
* Tool it not supported on the connection.
*/
EnvironmentModuleToolState[EnvironmentModuleToolState["NotSupported"] = 2] = "NotSupported";
})(EnvironmentModuleToolState || (EnvironmentModuleToolState = {}));
export const defaultEnvironmentConfiguration = {
gateway: {
disabled: false
},
appBar: {
title: {
hide: false
},
solution: {
hide: false,
hideDropdown: false
},
navigation: {
allowHistory: false,
allowRefresh: false,
allowUrlInput: false,
allowHome: false
},
urlField: {
hideSolutionUrl: true
},
rightMenu: {
showScripts: true,
showSettings: true,
showAbout: true,
showWindowControls: false,
showShareLink: false
},
aboutDialog: {
showFeedback: true,
feedbackLink: 'https://go.microsoft.com/fwlink/?linkid=2033442',
showDocumentation: true,
documentationLink: 'https://go.microsoft.com/fwlink/?linkid=2150525',
releaseNotesLink: 'https://aka.ms/honolulucurrent',
seeMoreReleaseDetailsLink: 'https://go.microsoft.com/fwlink/?linkid=2152971',
showLicense: true,
showScriptsUseRights: true,
showLicenseExtensions: true,
showPrivacyStatement: true,
privacyLink: 'https://aka.ms/winserverprivacy',
showSupportPolicy: true,
supportLink: 'https://aka.ms/wac-support-policy',
showThirdPartyNotice: true,
showShortcuts: true,
openLinkWithoutHref: false,
showAccessibilityCompliance: false,
accessibilityComplianceLink: 'https://go.microsoft.com/fwlink/?linkid=2121429',
extensionLicenseLink: 'https://aka.ms/wac-ga-extension-eula',
eulaLicenseLink: 'https://aka.ms/wac-product-ga-eula'
},
overview: {
gatewayStatusUpdateLink: 'settings/updates',
updateLearnMoreLink: 'https://aka.ms/honolulucurrent'
}
},
extensionsAutoUpdate: {
enable: true,
showAlert: true
},
gatewayAutoUpdate: {
enable: true
},
whatsNew: {
showDialog: true
},
tools: {
hide: false
},
connections: {
type: 'standard',
header: {
hide: false
}
},
telemetry: {
sourceLibraryCdnLink: 'https://js.monitor.azure.com/scripts/c/ms.analytics-web-3.0.2.min.js',
// Integrity hash generated via srihash.org
sourceLibraryCdnIntegrityHash: 'sha384-ZCsysyTvHb4xqC4BgJSay4nwlNIGlT1w5t5YQS5htghoD2XEL2b4SrkhRPhtr9GD'
},
settings: {
account: {
show: true
},
personalization: {
show: true
},
diagnostic: {
show: true
},
language: {
show: true
},
notification: {
show: true
},
extension: {
show: true
},
azure: {
show: true
},
access: {
show: true
},
sharedConnections: {
show: true
},
general: {
show: true
},
connectivity: {
show: true
},
updates: {
show: true
},
extensionUpdates: {
show: true
},
performance: {
show: true
},
advanced: {
show: true
},
proxy: {
show: true
}
}
};
/**
* Environment module class.
*/
export class EnvironmentModule {
static logSourceName = 'ManifestLoader';
/**
* Static mapping for connection information.
*/
static connectionMap = null;
/**
* Static mapping for extensionTargetTypes to a map of extensionTargetIds to entry point ids that fulfill that target
*/
static extensionTargetFulfillmentMap;
/**
* Static mapping for friendly url strings to entrypoint ids
*/
static friendlyUrlMap = null;
/**
* The name of shell.
*/
static nameOfShell = 'msft.sme.shell';
/**
* The default signature if missing manifest.
*/
static defaultSignature = 'version 0.0.0';
/**
* The prefix for identifying an sme-icon reference
*/
static smeIconPrefix = 'sme-icon:';
/**
* All entry points from all modules
*/
static allEntryPoints = null;
/**
* All entry points by type
*/
static entryPointsByType = null;
/**
* All entry points by type
*/
static entryPointsById = null;
/**
* All extension targets from all modules
*/
static allExtensionTargets = null;
/**
* All extension targets by type
*/
static extensionTargetsByType = null;
/**
* All extension targets by type
*/
static extensionTargetsById = null;
/**
* All extension targets by type
*/
static extensionOrigins = null;
/**
* schema file information.
*/
$schema;
/**
* name of module.
*/
name;
/**
* display name of module.
*/
displayName;
/**
* description of set of tools.
*/
description;
/**
* keywords of the module.
*/
keywords;
/**
* origin absolute url.
*/
origin;
/**
* target url to open the iframe.
*/
target;
/**
* signature.
*/
signature;
/**
* The version of this module
*/
version;
/**
* icon url, absolute or relative to Shell url.
*/
icon;
/**
* The support JEA endpoint with PowerShell module.
*/
jea;
/**
* extension targets for this extension
* Defines things that can be extended in this module.
*/
extensionTargets;
/**
* entry points to launch the tool.
*/
entryPoints;
/**
* Assets shared by the module
*/
assets;
/**
* localized resources of strings.
*/
resources;
/**
* Schemas provided for use in this manifest
*/
schemas;
/**
* list of all other available modules for shell.
*/
modules;
/**
* Indicates that this module is being sideLoaded
*/
isSideLoaded;
/**
* The Environment configuration
*/
configuration;
/**
* returns true if the provided origin is a known extension origin
*/
static isExtensionOrigin(origin) {
return this.extensionOrigins.has(origin);
}
/**
* Indicates if a given icon reference is an sme-icon or some other form
* @param iconRef the reference to check
*/
static isSmeIconRef(iconRef) {
return (!MsftSme.isNullOrUndefined(iconRef) && iconRef.startsWith(EnvironmentModule.smeIconPrefix));
}
/**
* Gets the icon class from an iconRef or returns null if the iconRef is not an sme-icon reference
* @param iconRef the reference to check
*/
static getSmeIconClassFromRef(iconRef) {
return (!MsftSme.isNullOrUndefined(iconRef) && EnvironmentModule.isSmeIconRef(iconRef))
? iconRef.substring(EnvironmentModule.smeIconPrefix.length) : null;
}
/**
* Gets the icon url from an iconRef or returns null if the iconRef is an sme-icon reference
* @param iconRef the reference to check
*/
static getFormattedIconRefUrl(iconRef) {
return (MsftSme.isNullOrUndefined(iconRef) || EnvironmentModule.isSmeIconRef(iconRef)) ? null : `url(${iconRef})`;
}
/**
* Processes an icon reference to resolve it to either a sme-icon or absolute url
* @param iconRef The icon reference
* @param module the module that the icon belongs to
*/
static processIconReference(iconRef, module) {
// leave icon ref alone if it is an sme-icon, absolute uri, or null/whitespace
if (MsftSme.isNullOrWhiteSpace(iconRef) || EnvironmentModule.isSmeIconRef(iconRef) || MsftSme.isUriAbsolute(iconRef)) {
return iconRef;
}
return this.toAbsolutePath(module, iconRef);
}
/**
* Converts relative module paths into absolute uris
*/
static toAbsolutePath(module, relativePath) {
const pathComponents = [relativePath];
if (module.target && !module.isSideLoaded) {
pathComponents.unshift(module.target);
}
pathComponents.unshift(module.origin);
return MsftSme.pathJoin('/', pathComponents);
}
/**
* Find resource string for the key.
*
* @param resources The resource.
* @param locale The locale.
* @param key The key string.
*/
static findResource(resources, locale, key) {
const prefix = 'resources:strings:';
if (!key.startsWith(prefix)) {
return key;
}
key = key.substring(prefix.length);
const en = resources.first((value) => value.locale === 'default');
const current = resources.first((value) => value.locale === locale);
if (current && current.strings[key]) {
return current.strings[key];
}
else if (en && en.strings[key]) {
return en.strings[key];
}
return key;
}
/**
* Recursively processes manifest resources
*
* @param module the manifest object.
* @param locale the locale string such as 'en'.
* @param obj current object, defaults to the module itself
*/
static processModuleResources(module, locale, obj = module) {
if (!Array.isArray(module.resources)) {
module.resources = [];
}
const keys = Object.keys(obj);
keys.forEach(key => {
if (typeof obj[key] === 'string') {
// first check the string for localized values
obj[key] = EnvironmentModule.findResource(module.resources, locale, obj[key]);
// if the key is 'icon' treat this field as an icon
if (key === 'icon') {
obj[key] = EnvironmentModule.processIconReference(obj[key], module);
}
}
else if (typeof obj[key] === 'object') {
EnvironmentModule.processModuleResources(module, locale, obj[key]);
}
});
}
static getModuleAssetUri(moduleName, resourceName, version) {
const assets = MsftSme.self().Resources.moduleAssets;
if (assets[moduleName] && assets[moduleName][resourceName] && assets[moduleName][resourceName][version]) {
return assets[moduleName][resourceName][version];
}
return null;
}
/**
* Create environment object from the manifest.
*
* @param manifest the manifest object.
* @param locale the locale string such as 'en'.
*/
static createEnvironment(manifest, locale) {
// use local origin automatically.
manifest.origin = MsftSme.getSafeOrigin();
// initialize tracking of known trusted origins
this.extensionOrigins = new Set();
this.extensionOrigins.add(manifest.origin);
// use current time if version is missing so this enforce browser caching if v= option is used.
manifest.version = manifest.version ? manifest.version : Date.now().toString();
// merge manifest configuration with default configuration
manifest.configuration = MsftSme.deepAssign({}, defaultEnvironmentConfiguration, manifest.configuration);
const modules = manifest.modules || [];
// process manifest entry points separately from children modules
if (manifest.name === 'msft.sme.shell') {
const shellExtensionManifest = { ...manifest };
delete shellExtensionManifest.modules;
shellExtensionManifest.name = 'msft.sme.shell-extensions';
shellExtensionManifest.target = '/extensions';
modules.push(shellExtensionManifest);
}
// Initialize Module Assets
MsftSme.self().Resources.moduleAssets = {};
// process Modules
if (modules && modules.length > 0) {
// first process resources, signature, and origin
for (const module of modules) {
// TODO: signature is going to be removed from modules, for now always use default.
module.signature = EnvironmentModule.defaultSignature;
// if the module has no origin, use the global one.
module.origin = module.origin || manifest.origin;
this.extensionOrigins.add(module.origin);
// process module parts
EnvironmentModule.processModuleResources(module, locale);
delete module['resources'];
// add assets to module assets using absolute paths
if (module.assets) {
const moduleAssets = {};
const assetKeys = Object.keys(module.assets);
assetKeys.forEach(key => {
moduleAssets[key] = {};
const versionKeys = Object.keys(module.assets[key]);
versionKeys.forEach(version => {
moduleAssets[key][version] = this.toAbsolutePath(module, module.assets[key][version]);
});
});
MsftSme.self().Resources.moduleAssets[module.name] = moduleAssets;
}
}
// now process extension targets
for (const module of modules) {
EnvironmentModule.processExtensionTargets(module);
}
// finally process entry points
for (const module of modules) {
EnvironmentModule.processEntryPoints(module);
}
// default entry point collections to be sorted alphabetically
const alphaSort = (a, b) => a.displayName ? a.displayName.localeCompareIgnoreCase(b.displayName) : -1;
if (this.allEntryPoints) {
this.allEntryPoints.sort(alphaSort);
}
else {
this.allEntryPoints = [];
}
if (this.entryPointsByType) {
this.entryPointsByType[EnvironmentModuleEntryPointType.Solution].sort(alphaSort);
this.entryPointsByType[EnvironmentModuleEntryPointType.Tool].sort(alphaSort);
}
// TODO: do we want settings alphabetized?
}
return manifest;
}
/**
* Gets the environment module.
*
* @param name the name of module.
* @return EnvironmentModule the environment module.
*/
static checkEnvironmentInitialized() {
if (!MsftSme || !MsftSme.self().Environment) {
const message = MsftSme.getStrings().MsftSmeShell.Core.Error.EnvironmentNotInitialized.message;
throw Error(message);
}
}
/**
* Gets the environment module.
*
* @param name the name of module.
* @return EnvironmentModule the environment module.
*/
static getEnvironmentModule(name) {
const shellEnvironment = MsftSme.self().Environment;
const modules = shellEnvironment && shellEnvironment.modules;
if (modules) {
for (const module of modules) {
if (module.name === name) {
return module;
}
}
}
if (shellEnvironment.name === name) {
return shellEnvironment;
}
return null;
}
/**
* Process extension targets for quick and easy access later
* @param module the modules to process
*/
static processExtensionTargets(module) {
// initialize tracking structures if they have not been
if (!EnvironmentModule.allExtensionTargets) {
EnvironmentModule.allExtensionTargets = [];
EnvironmentModule.extensionTargetsByType = {};
EnvironmentModule.extensionTargetsById = {};
EnvironmentModule.extensionTargetFulfillmentMap = {};
Object.keys(ExtensionTargetType).forEach(key => this.extensionTargetsByType[ExtensionTargetType[key]] = []);
}
// stop if there are no extension targets in this module
if (!module.extensionTargets) {
return;
}
module.extensionTargets.forEach(extensionTarget => {
// ignore invalid types in the manifest
if (!EnvironmentModule.extensionTargetsByType[extensionTarget.extensionTargetType]) {
Logging.log({
source: EnvironmentModule.logSourceName,
level: LogLevel.Warning,
consoleGroupHeader: `Unable to determine extensionTargetType.`,
message: `Entry point "${extensionTarget.name}" in module "${module.displayName} has a extensionTargetType of: ${extensionTarget.extensionTargetType}`
});
return;
}
// save the module information into the extension target
extensionTarget.parentModule = module;
const extensionTargetId = EnvironmentModule.createFormattedExtensionTarget(extensionTarget);
// save the module information into the extension target
extensionTarget.parentModule = module;
// push to data structures
EnvironmentModule.allExtensionTargets.push(extensionTarget);
EnvironmentModule.extensionTargetsByType[extensionTarget.extensionTargetType].push(extensionTarget);
EnvironmentModule.extensionTargetsById[extensionTargetId] = extensionTarget;
// initialize fulfillment map
EnvironmentModule.extensionTargetFulfillmentMap[extensionTargetId] = [];
});
}
/**
* Process Entry points for quick and easy access later
* @param module the modules to process
*/
static processEntryPoints(module) {
// initialize tracking structures if they have not been
if (!EnvironmentModule.allEntryPoints) {
EnvironmentModule.allEntryPoints = [];
EnvironmentModule.entryPointsByType = {};
EnvironmentModule.entryPointsById = {};
Object.keys(EnvironmentModuleEntryPointType).forEach(key => this.entryPointsByType[EnvironmentModuleEntryPointType[key]] = []);
this.friendlyUrlMap = {
connectionTypes: { to: {}, from: {} },
solutions: { to: {}, from: {} },
tools: { to: {}, from: {} },
settingsForms: { to: {}, from: {} }
};
}
if (!module.entryPoints) {
return;
}
module.entryPoints.forEach(entryPoint => {
// ignore invalid types in the manifest
if (!EnvironmentModule.entryPointsByType[entryPoint.entryPointType]) {
Logging.log({
source: EnvironmentModule.logSourceName,
level: LogLevel.Warning,
consoleGroupHeader: `Unable to determine entryPointType.`,
message: `Entry point "${entryPoint.displayName}" in module "${module.displayName} has a entryPointType of: ${entryPoint.entryPointType}`
});
return;
}
// if we have experiment keys, dont process the entry point if any key is not enabled
if (entryPoint.experimentKeys && entryPoint.experimentKeys.some(key => !MsftSme.isExperimentEnabledRaw(key))) {
return;
}
// save the module information into the entry point
entryPoint.parentModule = module;
const entryPointId = EnvironmentModule.createFormattedEntrypoint(entryPoint);
// push to data structures
EnvironmentModule.allEntryPoints.push(entryPoint);
EnvironmentModule.entryPointsByType[entryPoint.entryPointType].push(entryPoint);
EnvironmentModule.entryPointsById[entryPointId] = entryPoint;
// process url mappings
if (entryPoint.urlName) {
switch (entryPoint.entryPointType) {
case EnvironmentModuleEntryPointType.Solution:
this.friendlyUrlMap.solutions.to[entryPointId] = entryPoint.urlName;
this.friendlyUrlMap.solutions.from[entryPoint.urlName] = entryPointId;
break;
case EnvironmentModuleEntryPointType.Tool:
this.friendlyUrlMap.tools.to[entryPointId] = entryPoint.urlName;
this.friendlyUrlMap.tools.from[entryPoint.urlName] = entryPointId;
break;
case EnvironmentModuleEntryPointType.SettingsForm:
this.friendlyUrlMap.settingsForms.to[entryPointId] = entryPoint.urlName;
this.friendlyUrlMap.settingsForms.from[entryPoint.urlName] = entryPointId;
break;
case EnvironmentModuleEntryPointType.ConnectionProvider:
if (entryPoint.connectionTypeUrlName) {
this.friendlyUrlMap.connectionTypes.to[entryPoint.connectionType] = entryPoint.connectionTypeUrlName;
this.friendlyUrlMap.connectionTypes.from[entryPoint.connectionTypeUrlName] = entryPoint.connectionType;
}
}
}
if (entryPoint.entryPointType === EnvironmentModuleEntryPointType.ConnectionProvider && entryPoint.connectionTypeUrlName) {
this.friendlyUrlMap.connectionTypes.to[entryPoint.connectionType] = entryPoint.connectionTypeUrlName;
this.friendlyUrlMap.connectionTypes.from[entryPoint.connectionTypeUrlName] = entryPoint.connectionType;
}
// process extension mappings
if (entryPoint.extends) {
entryPoint.extends.forEach(extender => {
const extensionTarget = EnvironmentModule.getExtensionTargets(target => {
return target.parentModule.name === extender.module
&& target.name === extender.target;
}).first();
if (MsftSme.isNullOrUndefined(extensionTarget)) {
// if we get here, either that target is no longer supported or the target extension is not installed.
return;
}
const extensionTargetId = EnvironmentModule.createFormattedExtensionTarget(extensionTarget);
EnvironmentModule.extensionTargetFulfillmentMap[extensionTargetId].push(entryPointId);
});
}
});
}
/**
* Evaluates all of the modules in the environment and returns a flat list of all of their entry points.
* optionally filtered by the 'filter' function
*
* @param filter the filter to apply to the entry points.
* @return a flat list of all module entry points
*/
static getExtensionTargets(filter) {
return filter ? EnvironmentModule.allExtensionTargets.filter(filter) : EnvironmentModule.allExtensionTargets;
}
/**
* Evaluates all of the modules in the environment and returns a flat list of all of their entry points.
* optionally filtered by the 'filter' function
*
* @param filter the filter to apply to the entry points.
* @return a flat list of all module entry points
*/
static getEntryPoints(filter) {
EnvironmentModule.checkEnvironmentInitialized();
return filter ? EnvironmentModule.allEntryPoints.filter(filter) : EnvironmentModule.allEntryPoints;
}
/**
* Gets the available entry points from all of the modules in the environment, filtered by type.
*
* @param name the name of module.
* @return EnvironmentModule the environment module.
*/
static getEntryPointsByType(entryPointTypes) {
EnvironmentModule.checkEnvironmentInitialized();
return entryPointTypes.mapMany(type => EnvironmentModule.entryPointsByType[type]);
}
/**
* Gets the connection type mapping data.
*
* @return the mapping object.
*/
static fulfillExtensionTarget(extensionTargetId) {
EnvironmentModule.checkEnvironmentInitialized();
return EnvironmentModule.extensionTargetFulfillmentMap[extensionTargetId];
}
/**
* Gets the connection type mapping data.
*
* @return the mapping object.
*/
static getConnectionMap() {
if (!EnvironmentModule.connectionMap) {
EnvironmentModule.connectionMap = EnvironmentModule.createConnectionMap();
}
return EnvironmentModule.connectionMap;
}
/**
* Gets a friendly url segment from a connection type
* @param connectionType the connection type to map.
* @return string friendly url for the connection type or the connection type if no friendly name exists.
*/
static getFriendlyUrlSegmentForConnectionType(connectionType, fallbackToUnfriendlySegment = true) {
return EnvironmentModule.friendlyUrlMap.connectionTypes.to[connectionType] || (fallbackToUnfriendlySegment ? connectionType : null);
}
/**
* Gets a connection type from a friendly url segment
* @param urlSegment the url segment to map
* @return string connection type found using the friendly url segment
*/
static getConnectionTypeFromFriendlyUrlSegment(urlSegment) {
return EnvironmentModule.friendlyUrlMap.connectionTypes.from[urlSegment];
}
/**
* Gets a friendly url segment from an entry point id
* @param urlSegment the url segment.
* @param entryPointType the type of entry point to look for.
* @return string friendly url for the entry point id
*/
static getFriendlyUrlSegmentForEntryPoint(entryPoint, entryPointType, fallbackToUnfriendlySegment = true) {
switch (entryPointType) {
case EnvironmentModuleEntryPointType.Solution:
return EnvironmentModule.friendlyUrlMap.solutions.to[entryPoint] || (fallbackToUnfriendlySegment ? entryPoint : null);
case EnvironmentModuleEntryPointType.Tool:
return EnvironmentModule.friendlyUrlMap.tools.to[entryPoint] || (fallbackToUnfriendlySegment ? entryPoint : null);
case EnvironmentModuleEntryPointType.SettingsForm:
return EnvironmentModule.friendlyUrlMap.settingsForms.to[entryPoint] || (fallbackToUnfriendlySegment ? entryPoint : null);
}
return null;
}
/**
* Gets a friendly url segment for an entry point
* @param urlSegment the url segment.
* @param entryPointType the type of entry point to look for.
* @return string friendly url for the entry point
*/
static getEntryPointFromFriendlyUrlSegment(urlSegment, entryPointType) {
switch (entryPointType) {
case EnvironmentModuleEntryPointType.Solution:
return EnvironmentModule.friendlyUrlMap.solutions.from[urlSegment];
case EnvironmentModuleEntryPointType.Tool:
return EnvironmentModule.friendlyUrlMap.tools.from[urlSegment];
case EnvironmentModuleEntryPointType.SettingsForm:
return EnvironmentModule.friendlyUrlMap.settingsForms.from[urlSegment];
}
return null;
}
/**
* Gets the connection type information.
*
* @param typeName the type name.
* @return EnvironmentConnectionTypeInfo the connection type information.
*/
static getConnectionTypeInfo(typeName) {
return EnvironmentModule.getConnectionMap()[typeName];
}
static createConnectionMap() {
const map = {};
const providers = this.getEntryPointsByType([EnvironmentModuleEntryPointType.ConnectionProvider]);
providers.forEach(provider => {
if (!provider.connectionTypeDefaultSolution) {
const message = MsftSme.getStrings().MsftSmeShell.Core.Error.EnvironmentMissingDefault.message;
throw new Error(message);
}
const solutionEntrypoint = EnvironmentModule.splitFormattedEntrypoint(provider.connectionTypeDefaultSolution);
const solution = this.getEntryPointsByType([EnvironmentModuleEntryPointType.Solution])
.first(ep => ep.parentModule.name === solutionEntrypoint.moduleName && ep.name === solutionEntrypoint.entrypointName);
map[provider.connectionType] = { provider, solution };
if (solution && solution.parentModule && solution.parentModule.name) {
map[solution.parentModule.name] = map[provider.connectionType];
}
});
return map;
}
/**
* splits an entrypoint identifier string into its respective module and entrypoint names
* @param format the formatted entrypoint identifier string
*/
static splitFormattedEntrypoint(format) {
const parts = format.split('!');
return { moduleName: parts[0], entrypointName: parts[1] };
}
/**
* creates a formatted entrypoint identifier string from an entrypoint
* @param entryPoint the entrypoint to create the string from
*/
static createFormattedEntrypoint(entryPoint) {
return EnvironmentModule.createEntrypointId(entryPoint.parentModule.name, entryPoint.name);
}
static createEntrypointId(moduleName, entryPointName) {
return `${moduleName}!${entryPointName}`;
}
/**
* Create a formatted iframe ID used to link iframes and their html element
* Replace . with - because . is not permitted in css selectors required for testing
* @param parentModuleName the name of the parent module of the iframe content
* @param entryPointName the name of the entry point loaded by the iframe
*/
static createFormattedIFrameId(parentModuleName, entryPointName) {
const parentModuleId = MsftSme.replaceAll(parentModuleName, '.', '-');
return '{0}-{1}'.format(parentModuleId, entryPointName);
}
/**
* splits an extension target identifier string into its respective module and extension target names
* @param format the formatted extension target identifier string
*/
static splitFormattedExtensionTarget(format) {
const parts = format.split('!');
return { moduleName: parts[0], extensionTargetName: parts[1] };
}
/**
* creates a formatted extension target identifier string from an extension target
* @param entryPoint the extension target to create the string from
*/
static createFormattedExtensionTarget(extensionTarget) {
return `${extensionTarget.parentModule.name}!${extensionTarget.name}`;
}
/**
* resolves an entrypoint from a formatted entrypoint identifier string
* @param formattedEntrypointIdentifier the formatted entrypoint identifier string
*/
static resolveEntrypoint(formattedEntrypointIdentifier) {
if (!formattedEntrypointIdentifier) {
return null;
}
const parts = EnvironmentModule.splitFormattedEntrypoint(formattedEntrypointIdentifier);
if (!parts.moduleName || !parts.entrypointName) {
return null;
}
const entryPoints = this.getEntryPoints(ep => ep.name === parts.entrypointName && ep.parentModule.name === parts.moduleName);
return entryPoints[0] || null;
}
/**
* Gets the name of current shell or module.
*/
static getModuleName() {
const self = MsftSme.self();
return self.Init.moduleName;
}
/**
* Gets the version of current shell or module.
*/
static getModuleVersion() {
const self = MsftSme.self();
if (self.Environment.version) {
return self.Environment.version;
}
for (const module of self.Environment.modules) {
if (module.name === self.Init.moduleName && module.version) {
self.Environment.version = module.version;
return module.version;
}
}
return '0.0.0';
}
/**
* Compare the shell version with specified version.
* - this function must be called after NavigationService Init was called, otherwise it
* cannot get current shell version and return false.
* - Tag format is expected be like "<Major>.<Minor>.<Patch>-<Tag>.<Tag version>".
* ex) 1.2.3-myTagName.123
*
* @param inputVersion the version to compare.
* @return true if shell has newer version running.
*/
static shellGreaterOrEqual(inputVersion) {
if (MsftSme.isNullOrWhiteSpace(inputVersion)) {
// shell doesn't give version.
Logging.logError('EnvironmentModule.shellGreaterOrEqual', 'version is empty.');
return false;
}
const shellVersion = MsftSme.self().Init.shellVersion;
if (MsftSme.isNullOrWhiteSpace(shellVersion)) {
// shell doesn't give version.
Logging.logError('EnvironmentModule.shellGreaterOrEqual', 'shell version is not available.');
return false;
}
const tagSegments = inputVersion.split("-");
let inputCoreVersion = inputVersion;
let inputTag = "";
let inputTagVersion = 0;
if (tagSegments.length === 2) {
inputCoreVersion = tagSegments[0];
const tag = tagSegments[1].split(".");
inputTag = tag[0];
if (tag.length === 2) {
const tagNumber = Number(tag[1]);
inputTagVersion = isNaN(tagNumber) ? 0 : tagNumber;
}
}
const inputSegments = inputCoreVersion.split('.');
if (inputSegments.length !== 3) {
// shell doesn't give right version format.
Logging.logError('EnvironmentModule.shellGreaterOrEqual', 'version format is not right.');
return false;
}
const shellTagSegments = shellVersion.split("-");
let shellCoreVersion = shellVersion;
let shellTag = "";
let shellTagVersion = 0;
if (shellTagSegments.length === 2) {
shellCoreVersion = shellTagSegments[0];
const tag = shellTagSegments[1].split(".");
shellTag = tag[0];
if (tag.length === 2) {
const tagNumber = Number(tag[1]);
shellTagVersion = isNaN(tagNumber) ? 0 : tagNumber;
}
}
const shellSegments = shellCoreVersion.split('.');
if (shellSegments.length !== 3) {
// shell doesn't give right version format.
Logging.logError('EnvironmentModule.shellGreaterOrEqual', 'shell version is corrupted.');
return false;
}
const inputDigits = inputSegments.map(digit => {
const num = Number(digit);
return isNaN(num) ? 0 : num;
});
const shellDigits = shellSegments.map(digit => {
const num = Number(digit);
return isNaN(num) ? 0 : num;
});
if (shellDigits[0] < inputDigits[0]
|| (shellDigits[0] === inputDigits[0] && shellDigits[1] < inputDigits[1])
|| (shellDigits[0] === inputDigits[0] && shellDigits[1] === inputDigits[1] && shellDigits[2] < inputDigits[2])
|| (shellDigits[0] === inputDigits[0] && shellDigits[1] === inputDigits[1] && shellDigits[2] === inputDigits[2]
&& shellTag !== "" && shellTag.localeCompare(inputTag) < 0)
|| (shellDigits[0] === inputDigits[0] && shellDigits[1] === inputDigits[1] && shellDigits[2] === inputDigits[2]
&& shellTag !== "" && shellTag.localeCompare(inputTag) === 0) && shellTagVersion < inputTagVersion) {
return false;
}
return true;
}
/**
* Check if the gateway uses API set of version 2.0.0.
* @returns true if version 2.0.0
*/
static get isGatewayV200() {
return MsftSme.self().Init.gatewayApiVersion === '2.0.0';
}
/**
* check if the gateway runs on Windows platform.
* @returns true if Windows platform.
*/
static get isGatewayWindows() {
return MsftSme.self().Init.gatewayPlatform === 'Windows';
}
/**
* Check if the gateway runs on Linux platform.
* @returns true if Linux platform.
*/
static get isGatewayLinux() {
return MsftSme.self().Init.gatewayPlatform === 'Linux';
}
}
//# sourceMappingURL=environment-modules.js.map
// SIG // Begin signature block
// SIG // MIIoJgYJKoZIhvcNAQcCoIIoFzCCKBMCAQExDzANBglg
// SIG // hkgBZQMEAgEFADB3BgorBgEEAYI3AgEEoGkwZzAyBgor
// SIG // BgEEAYI3AgEeMCQCAQEEEBDgyQbOONQRoqMAEEvTUJAC
// SIG // AQACAQACAQACAQACAQAwMTANBglghkgBZQMEAgEFAAQg
// SIG // ZUtOdw/8RtLyUeQ70hw+s0fxr6Kgl5t3RQ4MvnPIHQWg
// SIG // gg12MIIF9DCCA9ygAwIBAgITMwAABARsdAb/VysncgAA
// SIG // AAAEBDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV
// SIG // UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
// SIG // UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
// SIG // cmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBT
// SIG // aWduaW5nIFBDQSAyMDExMB4XDTI0MDkxMjIwMTExNFoX
// SIG // DTI1MDkxMTIwMTExNFowdDELMAkGA1UEBhMCVVMxEzAR
// SIG // BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
// SIG // bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
// SIG // bjEeMBwGA1UEAxMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
// SIG // MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
// SIG // tCg32mOdDA6rBBnZSMwxwXegqiDEUFlvQH9Sxww07hY3
// SIG // w7L52tJxLg0mCZjcszQddI6W4NJYb5E9QM319kyyE0l8
// SIG // EvA/pgcxgljDP8E6XIlgVf6W40ms286Cr0azaA1f7vaJ
// SIG // jjNhGsMqOSSSXTZDNnfKs5ENG0bkXeB2q5hrp0qLsm/T
// SIG // WO3oFjeROZVHN2tgETswHR3WKTm6QjnXgGNj+V6rSZJO
// SIG // /WkTqc8NesAo3Up/KjMwgc0e67x9llZLxRyyMWUBE9co
// SIG // T2+pUZqYAUDZ84nR1djnMY3PMDYiA84Gw5JpceeED38O
// SIG // 0cEIvKdX8uG8oQa047+evMfDRr94MG9EWwIDAQABo4IB
// SIG // czCCAW8wHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYB
// SIG // BQUHAwMwHQYDVR0OBBYEFPIboTWxEw1PmVpZS+AzTDwo
// SIG // oxFOMEUGA1UdEQQ+MDykOjA4MR4wHAYDVQQLExVNaWNy
// SIG // b3NvZnQgQ29ycG9yYXRpb24xFjAUBgNVBAUTDTIzMDAx
// SIG // Mis1MDI5MjMwHwYDVR0jBBgwFoAUSG5k5VAF04KqFzc3
// SIG // IrVtqMp1ApUwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDov
// SIG // L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWlj
// SIG // Q29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNybDBhBggr
// SIG // BgEFBQcBAQRVMFMwUQYIKwYBBQUHMAKGRWh0dHA6Ly93
// SIG // d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWlj
// SIG // Q29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNydDAMBgNV
// SIG // HRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQCI5g/S
// SIG // KUFb3wdUHob6Qhnu0Hk0JCkO4925gzI8EqhS+K4umnvS
// SIG // BU3acsJ+bJprUiMimA59/5x7WhJ9F9TQYy+aD9AYwMtb
// SIG // KsQ/rst+QflfML+Rq8YTAyT/JdkIy7R/1IJUkyIS6srf
// SIG // G1AKlX8n6YeAjjEb8MI07wobQp1F1wArgl2B1mpTqHND
// SIG // lNqBjfpjySCScWjUHNbIwbDGxiFr93JoEh5AhJqzL+8m
// SIG // onaXj7elfsjzIpPnl8NyH2eXjTojYC9a2c4EiX0571Ko
// SIG // mhENF3RtR25A7/X7+gk6upuE8tyMy4sBkl2MUSF08U+E
// SIG // 2LOVcR8trhYxV1lUi9CdgEU2CxODspdcFwxdT1+G8YNc
// SIG // gzHyjx3BNSI4nOZcdSnStUpGhCXbaOIXfvtOSfQX/UwJ
// SIG // oruhCugvTnub0Wna6CQiturglCOMyIy/6hu5rMFvqk9A
// SIG // ltIJ0fSR5FwljW6PHHDJNbCWrZkaEgIn24M2mG1M/Ppb
// SIG // /iF8uRhbgJi5zWxo2nAdyDBqWvpWxYIoee/3yIWpquVY
// SIG // cYGhJp/1I1sq/nD4gBVrk1SKX7Do2xAMMO+cFETTNSJq
// SIG // fTSSsntTtuBLKRB5mw5qglHKuzapDiiBuD1Zt4QwxA/1
// SIG // kKcyQ5L7uBayG78kxlVNNbyrIOFH3HYmdH0Pv1dIX/Mq
// SIG // 7avQpAfIiLpOWwcbjzCCB3owggVioAMCAQICCmEOkNIA
// SIG // AAAAAAMwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYT
// SIG // AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
// SIG // EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
// SIG // cG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290
// SIG // IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDExMB4XDTEx
// SIG // MDcwODIwNTkwOVoXDTI2MDcwODIxMDkwOVowfjELMAkG
// SIG // A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO
// SIG // BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
// SIG // dCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9zb2Z0
// SIG // IENvZGUgU2lnbmluZyBQQ0EgMjAxMTCCAiIwDQYJKoZI
// SIG // hvcNAQEBBQADggIPADCCAgoCggIBAKvw+nIQHC6t2G6q
// SIG // ghBNNLrytlghn0IbKmvpWlCquAY4GgRJun/DDB7dN2vG
// SIG // EtgL8DjCmQawyDnVARQxQtOJDXlkh36UYCRsr55JnOlo
// SIG // XtLfm1OyCizDr9mpK656Ca/XllnKYBoF6WZ26DJSJhIv
// SIG // 56sIUM+zRLdd2MQuA3WraPPLbfM6XKEW9Ea64DhkrG5k
// SIG // NXimoGMPLdNAk/jj3gcN1Vx5pUkp5w2+oBN3vpQ97/vj
// SIG // K1oQH01WKKJ6cuASOrdJXtjt7UORg9l7snuGG9k+sYxd
// SIG // 6IlPhBryoS9Z5JA7La4zWMW3Pv4y07MDPbGyr5I4ftKd
// SIG // gCz1TlaRITUlwzluZH9TupwPrRkjhMv0ugOGjfdf8NBS
// SIG // v4yUh7zAIXQlXxgotswnKDglmDlKNs98sZKuHCOnqWbs
// SIG // YR9q4ShJnV+I4iVd0yFLPlLEtVc/JAPw0XpbL9Uj43Bd
// SIG // D1FGd7P4AOG8rAKCX9vAFbO9G9RVS+c5oQ/pI0m8GLhE
// SIG // fEXkwcNyeuBy5yTfv0aZxe/CHFfbg43sTUkwp6uO3+xb
// SIG // n6/83bBm4sGXgXvt1u1L50kppxMopqd9Z4DmimJ4X7Iv
// SIG // hNdXnFy/dygo8e1twyiPLI9AN0/B4YVEicQJTMXUpUMv
// SIG // dJX3bvh4IFgsE11glZo+TzOE2rCIF96eTvSWsLxGoGyY
// SIG // 0uDWiIwLAgMBAAGjggHtMIIB6TAQBgkrBgEEAYI3FQEE
// SIG // AwIBADAdBgNVHQ4EFgQUSG5k5VAF04KqFzc3IrVtqMp1
// SIG // ApUwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYD
// SIG // VR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
// SIG // BBgwFoAUci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0f
// SIG // BFMwUTBPoE2gS4ZJaHR0cDovL2NybC5taWNyb3NvZnQu
// SIG // Y29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0
// SIG // MjAxMV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRS
// SIG // MFAwTgYIKwYBBQUHMAKGQmh0dHA6Ly93d3cubWljcm9z
// SIG // b2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0MjAx
// SIG // MV8yMDExXzAzXzIyLmNydDCBnwYDVR0gBIGXMIGUMIGR
// SIG // BgkrBgEEAYI3LgMwgYMwPwYIKwYBBQUHAgEWM2h0dHA6
// SIG // Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvZG9jcy9w
// SIG // cmltYXJ5Y3BzLmh0bTBABggrBgEFBQcCAjA0HjIgHQBM
// SIG // AGUAZwBhAGwAXwBwAG8AbABpAGMAeQBfAHMAdABhAHQA
// SIG // ZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEA
// SIG // Z/KGpZjgVHkaLtPYdGcimwuWEeFjkplCln3SeQyQwWVf
// SIG // Liw++MNy0W2D/r4/6ArKO79HqaPzadtjvyI1pZddZYSQ
// SIG // fYtGUFXYDJJ80hpLHPM8QotS0LD9a+M+By4pm+Y9G6XU
// SIG // tR13lDni6WTJRD14eiPzE32mkHSDjfTLJgJGKsKKELuk
// SIG // qQUMm+1o+mgulaAqPyprWEljHwlpblqYluSD9MCP80Yr
// SIG // 3vw70L01724lruWvJ+3Q3fMOr5kol5hNDj0L8giJ1h/D
// SIG // Mhji8MUtzluetEk5CsYKwsatruWy2dsViFFFWDgycSca
// SIG // f7H0J/jeLDogaZiyWYlobm+nt3TDQAUGpgEqKD6CPxNN
// SIG // ZgvAs0314Y9/HG8VfUWnduVAKmWjw11SYobDHWM2l4bf
// SIG // 2vP48hahmifhzaWX0O5dY0HjWwechz4GdwbRBrF1HxS+
// SIG // YWG18NzGGwS+30HHDiju3mUv7Jf2oVyW2ADWoUa9WfOX
// SIG // pQlLSBCZgB/QACnFsZulP0V3HjXG0qKin3p6IvpIlR+r
// SIG // +0cjgPWe+L9rt0uX4ut1eBrs6jeZeRhL/9azI2h15q/6
// SIG // /IvrC4DqaTuv/DDtBEyO3991bWORPdGdVk5Pv4BXIqF4
// SIG // ETIheu9BCrE/+6jMpF3BoYibV3FWTkhFwELJm3ZbCoBI
// SIG // a/15n8G9bW1qyVJzEw16UM0xghoIMIIaBAIBATCBlTB+
// SIG // MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
// SIG // bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj
// SIG // cm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNy
// SIG // b3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExAhMzAAAE
// SIG // BGx0Bv9XKydyAAAAAAQEMA0GCWCGSAFlAwQCAQUAoIGu
// SIG // MBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisG
// SIG // AQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3
// SIG // DQEJBDEiBCB1jdOJ3WPeLlP4qSxU3nFKMHU9bCqhWqgs
// SIG // 1mL89khmQDBCBgorBgEEAYI3AgEMMTQwMqAUgBIATQBp
// SIG // AGMAcgBvAHMAbwBmAHShGoAYaHR0cDovL3d3dy5taWNy
// SIG // b3NvZnQuY29tMA0GCSqGSIb3DQEBAQUABIIBAA05Ceki
// SIG // CGVXWnT/LMUnXjiFkJXFjQkgsAY0AxPh3Pl4NyKBXdrE
// SIG // Wbnq1of3ZsjkRDCyKE1TBehTEnQzNNfUwrsZ5cqOFdmg
// SIG // dtlhdPBNzh7yao1czjyCJvhCWiiC8rII+Ir50F1dU1/l
// SIG // RM0rJlNvC/Jh5nG7RS+0CrMsA8IhVzGLxY6TokqXPiCb
// SIG // KQAGtOu0QJG1AaJ5h++ZhQs7uu8mBnK/GzhIO237wsom
// SIG // NOchJAbBDjdpnOq4LWC7MdiJM9PcqhHb0PK/fCiiau5q
// SIG // H5axR8vYvWjMRIV5QfpGgmuKPsyksupk7TGPG/7WhYZc
// SIG // XnXCVFTE/hoiUU0S/pp9x4xOoVqhgheSMIIXjgYKKwYB
// SIG // BAGCNwMDATGCF34wghd6BgkqhkiG9w0BBwKgghdrMIIX
// SIG // ZwIBAzEPMA0GCWCGSAFlAwQCAQUAMIIBUAYLKoZIhvcN
// SIG // AQkQAQSgggE/BIIBOzCCATcCAQEGCisGAQQBhFkKAwEw
// SIG // MTANBglghkgBZQMEAgEFAAQgMa5p8kaYGj5HZkgPG4x1
// SIG // zc6E5oZod+jK2JK2BwJT+90CBmet86n9nBgRMjAyNTAy
// SIG // MjAxNTI4MzguNlowBIACAfSggdGkgc4wgcsxCzAJBgNV
// SIG // BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
// SIG // VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
// SIG // Q29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBB
// SIG // bWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGll
// SIG // bGQgVFNTIEVTTjo4RDAwLTA1RTAtRDk0NzElMCMGA1UE
// SIG // AxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCC
// SIG // EeowggcgMIIFCKADAgECAhMzAAAB88UKQ64DzB0xAAEA
// SIG // AAHzMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVT
// SIG // MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
// SIG // ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y
// SIG // YXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0
// SIG // YW1wIFBDQSAyMDEwMB4XDTIzMTIwNjE4NDYwMloXDTI1
// SIG // MDMwNTE4NDYwMlowgcsxCzAJBgNVBAYTAlVTMRMwEQYD
// SIG // VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
// SIG // MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
// SIG // JTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJh
// SIG // dGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo4
// SIG // RDAwLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0
// SIG // IFRpbWUtU3RhbXAgU2VydmljZTCCAiIwDQYJKoZIhvcN
// SIG // AQEBBQADggIPADCCAgoCggIBAP6fptrhK4H2JI7lYyFu
// SIG // eCpgBv7Pch/M2lkhZL+yB9eGUtiYaexS2sZfc5VyD7yS
// SIG // sl2LG41Qw7tkA6oJmxdSM7PzNyfVpQPkPavY+HNUqMe2
// SIG // K9YaAaPjHnCpZ7VCi/e8zPxYewqx9p0iVaN8EydUpWiY
// SIG // 7JtDv7aNzhp/OPZclBBKYT2NBGgGiAPCaplqR5icjHQS
// SIG // Y665w+vrvhPr9hpM+IhiUZ/5dXa7qhAcCQwbnrFg9CKS
// SIG // K1COM1YcAN8GpsERqqmlqy3GlE1ziJ3ZLXFVDFxAZeOc
// SIG // CB55Vts9sCgQuFvD7PdV61HC4QUlHNPqFtYSC/P0sxg9
// SIG // JuKgcvzD5mJajfG7DdHt8myp7umqyePC+eI/ux8TW61+
// SIG // LuTQ1Bkym+I6z//bf0fp4Dog5W0XzDrqKkTvURitxI2s
// SIG // 4aVObm6qr6zI7W51k54ozTFjvbw1wYMWqeO4U9sQSbr5
// SIG // 61kp+1T2PEsJLOpc5U7N2oDw7ldrcTjWPezsyVMXhDsF
// SIG // itCZunGqFO9+4iVjAjYDN47c6K9x7MnAGPYVCBOJUdpy
// SIG // 8xAOBIDsTm/K1qTT4wsGbQBxbgg96vwDiA4YP2hKmubI
// SIG // C7UnrAWQGt/ZKOf6J42roXHS1aPwimDe5C9y6DfuNJp0
// SIG // XqrWtQRqg8hqNkIZWT6jnCfqu35zB0nf1ERTjdpYLCfQ
// SIG // L5fHAgMBAAGjggFJMIIBRTAdBgNVHQ4EFgQUw2QV9qUR
// SIG // UQyMDcCmhTH2oOsNCiQwHwYDVR0jBBgwFoAUn6cVXQBe
// SIG // Yl2D9OXSZacbUzUZ6XIwXwYDVR0fBFgwVjBUoFKgUIZO
// SIG // aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j
// SIG // cmwvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUy
// SIG // MDIwMTAoMSkuY3JsMGwGCCsGAQUFBwEBBGAwXjBcBggr
// SIG // BgEFBQcwAoZQaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
// SIG // L3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBUaW1lLVN0
// SIG // YW1wJTIwUENBJTIwMjAxMCgxKS5jcnQwDAYDVR0TAQH/
// SIG // BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAOBgNV
// SIG // HQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQELBQADggIBAN/E
// SIG // HI/80f7v29zeWI7hzudcz9QoVwCbnDrUXFHE/EJdFeWI
// SIG // 2NnuwOo0/QPNRMFT21LkOqSpFKIhXXmPurx7p6WDz9wP
// SIG // du/Sxbgaj0AwviWEDkwGDfDMp2KF8nQT8cipwdfXWbC1
// SIG // ulOILayABSHv45mdv1PAkTulsQE8lBTHG4KJLn+vSzZB
// SIG // WKkGaL/wwRbZ4iLiYn68cjkMJoAaihPgDXn/ug2P3PLN
// SIG // EAFNQgI02tLX0p+vIQ3l2HmSo4bhCBxr3DovsIv5K65N
// SIG // mLRJnxmrrmIraFDwgwA5XF7AKkPiVkvo0OxU1LAE1c5S
// SIG // WzE4A7cbTA1P5wG6D8cPjcHsTah1V+zofYRgJnFRLWuB
// SIG // F4Z3a6pDGBDbCsy5NvnKQ76p37ieFp//1I3eB62ia1Cf
// SIG // kjOF8KStpPUqdkXxMjfJ7Vnemd6vQKf+nXkfvA3AOQEC
// SIG // Jn7aLP01QR5gt8wab28SsNUENEyMawT8eqpjtBNJO0O9
// SIG // Tv7NnBE8aOJhhQVdP5WCR90eIWkrDjZeybQx8vlo5rfU
// SIG // XIIzXv+k9MgpNGIqwMXfvRLAjBkCNXOIP/1CEQUG72mi
// SIG // MVQs5m/O4vmJIQkhyqilUDB1s12uhmLYc3yd8OPMlrwI
// SIG // xORB5J9CxCkqvzc6EGYTcwXazPyCp7eWhzTkNbwk29nf
// SIG // bwmmzcskIAu3StA8lic7MIIHcTCCBVmgAwIBAgITMwAA
// SIG // ABXF52ueAptJmQAAAAAAFTANBgkqhkiG9w0BAQsFADCB
// SIG // iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
// SIG // b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p
// SIG // Y3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWlj
// SIG // cm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
// SIG // IDIwMTAwHhcNMjEwOTMwM