{"version":3,"file":"index-L2mxvfn5.js","sources":["../../../src/resources/icons/default.svg","../../../src/app/classes/utilities/MemoryCachingHelpers.ts","../../../src/app/classes/exceptions/Exception.ts","../../../src/app/classes/exceptions/EnvironmentNotSelectedException.ts","../../../src/components/controls/native/TextField/ControlManifest.Input.xml","../../../src/components/controls/native/MultilineText/ControlManifest.Input.xml","../../../src/components/controls/native/Url/ControlManifest.Input.xml","../../../src/components/controls/native/DateTime/ControlManifest.Input.xml","../../../src/components/controls/native/Lookup/ControlManifest.Input.xml","../../../src/components/controls/native/Lookup/localization/translations.1029.resx","../../../src/components/controls/native/Lookup/localization/translations.1033.resx","../../../src/components/controls/native/View/ControlManifest.Input.xml","../../../src/components/controls/native/View/localization/translations.1029.resx","../../../src/components/controls/native/View/localization/translations.1033.resx","../../../src/components/controls/native/View/img/view_empty.svg","../../../src/components/controls/native/OptionSet/ControlManifest.Input.xml","../../../src/components/controls/native/MultiSelectOptionSet/ControlManifest.Input.xml","../../../src/components/controls/native/Form/ControlManifest.Input.xml","../../../src/components/controls/native/Form/localization/translations.1029.resx","../../../src/components/controls/native/Form/localization/translations.1033.resx","../../../src/components/controls/native/Decimal/ControlManifest.Input.xml","../../../src/components/controls/native/WholeNumber/ControlManifest.Input.xml","../../../src/components/controls/native/Email/ControlManifest.Input.xml","../../../src/components/controls/native/TwoOptions/ControlManifest.Input.xml","../../../src/components/controls/native/Currency/ControlManifest.Input.xml","../../../src/components/controls/native/Label/ControlManifest.Input.xml","../../../src/components/controls/native/WebPage/ControlManifest.Input.xml","../../../src/components/controls/native/Duration/ControlManifest.Input.xml","../../../src/components/controls/native/Duration/localization/translations.1029.resx","../../../src/components/controls/native/Duration/localization/translations.1033.resx","../../../src/components/controls/native/File/ControlManifest.Input.xml","../../../src/components/controls/native/File/localization/translations.1029.resx","../../../src/components/controls/native/File/localization/translations.1033.resx","../../../src/app/Constants.tsx","../../../src/app/classes/mappers/ManifestMapper.ts","../../../src/app/classes/loaders/ScriptLoader.ts","../../../src/app/classes/loaders/PlatformLibraryLoader.ts","../../../src/components/controls/native/TextField/index.ts","../../../src/components/controls/native/DateTime/index.ts","../../../src/components/controls/native/Lookup/index.ts","../../../src/providers/TelemetryProvider/TelemetryService.tsx","../../../src/app/classes/Authentication.ts","../../../src/app/classes/models/UserSettings.ts","../../../src/app/classes/definitions/UserSettingsDefinition.ts","../../../src/localization/helpers.ts","../../../src/app/classes/definitions/EntityDefinition.ts","../../../src/components/lists/DetailsList/Style.ts","../../../src/components/lists/DetailsList/index.tsx","../../../src/components/controls/native/Form/interfaces/enums.ts","../../../src/components/loadings/Loading/Constants.tsx","../../../src/components/loadings/Loading/Styles.tsx","../../../src/components/loadings/Loading/index.tsx","../../../src/components/controls/native/Form/components/Tabs/Functions.tsx","../../../src/components/navigation/commandbars/TabCommandBar/index.tsx","../../../src/components/controls/native/Form/components/Tabs/index.tsx","../../../src/app/classes/configuration/AppComponents.ts","../../../src/app/classes/definitions/FormDefinition.ts","../../../src/app/classes/mappers/FormMapper.ts","../../../src/components/controls/native/Form/components/Cell/index.tsx","../../../src/app/classes/definitions/OptionSetDefinition.ts","../../../src/app/classes/mappers/SiteMapMapper.ts","../../../src/app/classes/utilities/ThemeDesigner.ts","../../../src/app/classes/models/Theme.ts","../../../src/app/classes/models/Website.ts","../../../src/app/classes/definitions/WebsiteDefinition.ts","../../../src/app/classes/definitions/ThemeDefinition.ts","../../../src/app/classes/models/SiteMap.ts","../../../src/app/classes/definitions/SitemapDefinition.ts","../../../src/providers/HistoryProvider/State.ts","../../../src/providers/HistoryProvider/HistoryManager.ts","../../../src/providers/HistoryProvider/Page.ts","../../../src/components/dialogs/NavigationPromptDialog/index.tsx","../../../src/components/loadings/MainLoading/index.tsx","../../../src/providers/HistoryProvider/HistoryProvider.tsx","../../../src/ComponentFramework/interfaces/DataType.ts","../../../src/Xrm/XrmFormType.ts","../../../src/app/classes/BotProtection.ts","../../../src/app/classes/utilities/NumberParser.ts","../../../src/ComponentFramework/PropertyClasses/WebApi.ts","../../../src/components/loadings/FormLoading/FormLoading.tsx","../../../src/components/controls/DatasetControl/interfaces.ts","../../../src/app/classes/definitions/RibbonDefinition/RibbonButtonOverrider.ts","../../../src/app/classes/definitions/RibbonDefinition/index.ts","../../../src/app/classes/utilities/IFrameFactory.ts","../../../src/app/classes/models/Ribbon/Ribbon.ts","../../../src/app/classes/models/Ribbon/FormRibbon.ts","../../../src/components/controls/native/Form/Form.tsx","../../../src/components/controls/useControlState.ts","../../../src/components/controls/FieldControl/index.tsx","../../../src/app/classes/definitions/ViewDefinition.ts","../../../src/app/classes/definitions/TransactionCurrencyDefinition.ts","../../../src/components/controls/DatasetControl/Grid.ts","../../../src/components/controls/DatasetControl/ViewSelector/useViewSwitcher.ts","../../../src/components/controls/DatasetControl/QuickFind/useQuickFind.ts","../../../src/components/controls/DatasetControl/QuickFind/QuickFindComponent.tsx","../../../src/components/controls/DatasetControl/EditColumnsPanel/EditColumnsPanel.tsx","../../../src/components/controls/DatasetControl/QueryBuilder/QueryBuilder.ts","../../../src/components/controls/DatasetControl/QueryBuilder/useQueryBuilder.ts","../../../src/components/controls/DatasetControl/QueryBuilder/QueryBuilderPanel.tsx","../../../src/components/controls/DatasetControl/ViewSelector/ViewSelector.ts","../../../src/components/controls/DatasetControl/QuickFind/QuickFind.ts","../../../src/components/controls/DatasetControl/GridContext.ts","../../../src/app/classes/models/Ribbon/DatasetRibbon.ts","../../../src/components/controls/DatasetControl/DatasetControl.ts","../../../src/components/dialogs/Dialog/Constants.tsx","../../../src/components/dialogs/Dialog/Styles.tsx","../../../src/components/dialogs/Dialog/index.tsx","../../../src/components/controls/DatasetControl/ViewManager/ViewManager.ts","../../../src/components/controls/DatasetControl/ViewManager/ViewManagerDialog/styles.ts","../../../src/components/controls/DatasetControl/ViewManager/ViewManagerDialog/ViewManagerDialog.tsx","../../../src/components/controls/DatasetControl/DatasetControlRenderer.tsx","../../../src/components/controls/index.tsx","../../../src/ComponentFramework/NestedPcfWrapper.tsx","../../../src/app/interfaces/entitydefinition.ts","../../../src/Xrm/GetEntityMetadataResponse.ts","../../../src/ComponentFramework/Implementation.ts","../../../src/ComponentFramework/PropertyClasses/Mode.ts","../../../src/ComponentFramework/PropertyClasses/Navigation.ts","../../../src/ComponentFramework/PropertyClasses/Context.ts","../../../src/pages/Layout/components/Navbar/components/PcfNavbarWrapper.tsx","../../../src/components/navigation/ribbon/useRibbon.tsx","../../../src/components/navigation/ribbon/RibbonController.tsx","../../../src/components/loadings/ViewLoading/index.tsx","../../../src/components/controls/native/View/components/ItemColumn/components/CommandBarWrapper/index.tsx","../../../src/components/controls/native/View/components/ItemColumn/index.tsx","../../../src/components/controls/native/View/components/GroupHeader/GroupHeader.base.tsx","../../../src/components/controls/native/View/components/GroupHeader/GroupHeader.ts","../../../src/components/controls/native/View/components/filtering/configuration.ts","../../../src/components/controls/native/View/components/filtering/FilterCallout.tsx","../../../src/components/controls/native/View/components/View/View.tsx","../../../src/components/controls/native/View/index.ts","../../../src/components/controls/native/OptionSet/index.ts","../../../src/components/controls/native/MultiSelectOptionSet/index.ts","../../../src/components/controls/native/Form/index.ts","../../../src/components/controls/native/TwoOptions/index.ts","../../../src/components/controls/native/Decimal/index.ts","../../../src/components/controls/native/Label/index.ts","../../../src/components/controls/native/WebPage/LiquidService.ts","../../../src/components/controls/native/WebPage/index.ts","../../../src/components/controls/native/Duration/index.ts","../../../src/components/controls/native/File/components/MessageBar.tsx","../../../src/components/controls/native/File/components/FileComponent.tsx","../../../src/components/controls/native/File/index.ts","../../../src/app/classes/loaders/ControlLoader.ts","../../../src/Xrm/WebApi/index.ts","../../../src/app/classes/RingProvider.ts","../../../src/components/navigation/panels/Panel/index.tsx","../../../src/app/Functions.tsx","../../../src/app/classes/MultitenantProvider.ts","../../../src/app/classes/configuration/SpaConfiguration.ts","../../../src/app/classes/definitions/MetadataApi.ts","../../../src/app/classes/loaders/IconLoader.ts","../../../src/app/classes/configuration/AppModule.ts","../../../src/components/utilities/BotProtectionVerification/index.tsx","../../../src/components/dialogs/ErrorDialog/Styles.tsx","../../../src/components/dialogs/ErrorDialog/index.tsx","../../../src/components/dialogs/EnvironmentSelectionDialog/index.tsx","../../../src/app/hooks/useDebounce.ts","../../../src/components/utilities/DevKit/menus/EntityMenu/index.tsx","../../../src/components/dialogs/AppSwitcherDialog/index.tsx","../../../src/components/utilities/DevKit/index.tsx","../../../src/app/classes/models/Manifest.ts","../../../src/app/classes/definitions/ManifestDefinition.ts","../../../src/components/dialogs/ConfirmationDialog/Styles.tsx","../../../src/components/dialogs/ConfirmationDialog/index.tsx","../../../src/components/dialogs/AlertDialog/Styles.tsx","../../../src/components/dialogs/AlertDialog/index.tsx","../../../src/providers/AppProvider/index.tsx","../../../src/pages/Home/index.tsx","../../../src/pages/Layout/components/GlobalNotification/index.tsx","../../../src/pages/Layout/components/Notifications/index.tsx","../../../src/pages/Control/Form/index.tsx","../../../src/components/dialogs/FormDialog/Styles.tsx","../../../src/components/dialogs/FormDialog/index.tsx","../../../src/pages/Control/index.tsx","../../../src/pages/Layout/components/Footer/Styles.tsx","../../../src/pages/Layout/components/Footer/index.tsx","../../../src/pages/Layout/components/Navbar/components/AppPanel/index.tsx","../../../src/pages/Layout/components/Navbar/index.tsx","../../../src/pages/Layout/components/PageNavigation/components/HorizontalPageNavigation/index.tsx","../../../src/pages/Layout/components/PageNavigation/components/VerticalPageNavigation/InstallPrompt/useInstallPrompt.ts","../../../src/pages/Layout/components/PageNavigation/components/VerticalPageNavigation/InstallPrompt/Taskbar/Taskbar.tsx","../../../src/pages/Layout/components/PageNavigation/components/VerticalPageNavigation/InstallPrompt/InstallationDialog/EditShortcutNameDialog/EditShortcutNameDialog.tsx","../../../src/pages/Layout/components/PageNavigation/components/VerticalPageNavigation/InstallPrompt/InstallationDialog/InstallationDialog.tsx","../../../src/pages/Layout/components/PageNavigation/components/VerticalPageNavigation/InstallPrompt/useInstalationDialog.ts","../../../src/pages/Layout/components/PageNavigation/components/VerticalPageNavigation/InstallPrompt/InstallPrompt.tsx","../../../src/pages/Layout/components/PageNavigation/components/VerticalPageNavigation/index.tsx","../../../src/components/navigation/panels/LookupPanel/index.tsx","../../../src/components/loadings/VerticalNavigationLoading/VerticalNavigationLoading.tsx","../../../src/components/loadings/HorizontalNavigationLoading/HorizontalNavigationLoading.tsx","../../../src/pages/Layout/useLayoutStyles.ts","../../../src/app/classes/models/Ribbon/AppRibbon.ts","../../../src/pages/Layout/index.tsx","../../../src/components/navigation/buttons/BackButton.tsx","../../../src/pages/Search/styles.ts","../../../src/pages/Search/index.tsx","../../../src/app/index.tsx","../../../src/pages/Registration.tsx","../../../src/pages/Login.tsx","../../../src/pages/Admin.tsx","../../../src/providers/TelemetryProvider/index.tsx","../../../src/index.tsx"],"sourcesContent":["export default \"data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='utf-8'?%3e%3c!--%20Generator:%20Adobe%20Illustrator%2020.1.0,%20SVG%20Export%20Plug-In%20.%20SVG%20Version:%206.00%20Build%200)%20--%3e%3csvg%20version='1.1'%20id='Layer_1'%20xmlns='http://www.w3.org/2000/svg'%20xmlns:xlink='http://www.w3.org/1999/xlink'%20x='0px'%20y='0px'%20viewBox='0%200%2064%2064'%20style='enable-background:new%200%200%2064%2064;'%20xml:space='preserve'%3e%3cg%3e%3cpath%20d='M10.7,42.7c-1.5,0-2.9-0.3-4.2-0.8c-1.3-0.6-2.4-1.3-3.4-2.3c-1-1-1.7-2.1-2.3-3.4C0.3,34.9,0,33.5,0,32%20c0-1.5,0.3-2.9,0.9-4.2c0.6-1.3,1.3-2.4,2.3-3.4c1-1,2.1-1.7,3.4-2.3c1.3-0.6,2.7-0.8,4.2-0.8v-16h16V12c0,0.7,0.1,1.4,0.4,2.1%20c0.3,0.7,0.7,1.2,1.1,1.7c0.5,0.5,1.1,0.9,1.7,1.1c0.7,0.3,1.3,0.4,2.1,0.4c0.8,0,1.4-0.1,2.1-0.4c0.6-0.3,1.2-0.7,1.7-1.1%20c0.5-0.5,0.9-1,1.1-1.7c0.3-0.6,0.4-1.3,0.4-2.1V5.3h15.9v16c1.5,0,2.9,0.3,4.3,0.8c1.3,0.5,2.4,1.3,3.4,2.2%20c0.9,0.9,1.7,2.1,2.2,3.4c0.5,1.3,0.8,2.7,0.8,4.3c0,1.5-0.3,2.9-0.8,4.3c-0.5,1.3-1.3,2.4-2.2,3.4c-0.9,0.9-2.1,1.7-3.4,2.2%20c-1.3,0.5-2.7,0.8-4.3,0.8v16H37.4V52c0-0.8-0.1-1.4-0.4-2.1c-0.3-0.6-0.7-1.2-1.1-1.7c-0.5-0.5-1.1-0.9-1.7-1.1%20c-0.6-0.3-1.3-0.4-2.1-0.4c-0.7,0-1.4,0.1-2.1,0.4c-0.7,0.3-1.2,0.7-1.7,1.1c-0.5,0.5-0.9,1.1-1.1,1.7c-0.3,0.7-0.4,1.3-0.4,2.1%20v6.7h-16V42.7z%20M10.7,26.7c-0.7,0-1.4,0.1-2.1,0.4c-0.7,0.3-1.2,0.7-1.7,1.1c-0.5,0.5-0.9,1.1-1.1,1.7c-0.3,0.7-0.4,1.3-0.4,2.1%20c0,0.7,0.1,1.4,0.4,2.1c0.3,0.7,0.7,1.2,1.1,1.7c0.5,0.5,1.1,0.9,1.7,1.1c0.7,0.3,1.3,0.4,2.1,0.4h5.4v16h5.3V52%20c0-1.5,0.3-2.9,0.8-4.2c0.6-1.3,1.3-2.4,2.3-3.4c1-1,2.1-1.7,3.4-2.3c1.3-0.6,2.7-0.8,4.2-0.8c1.5,0,2.9,0.3,4.2,0.8%20c1.3,0.6,2.4,1.3,3.4,2.3c1,1,1.7,2.1,2.3,3.4c0.6,1.3,0.8,2.7,0.8,4.2v1.3H48v-16h5.6c0.8,0,1.4-0.1,2.1-0.4%20c0.6-0.3,1.2-0.7,1.6-1.1c0.4-0.5,0.8-1.1,1-1.7c0.3-0.7,0.4-1.3,0.4-2.1c0-0.7-0.1-1.4-0.4-2.1c-0.3-0.7-0.6-1.2-1-1.7%20c-0.4-0.5-1-0.9-1.6-1.1c-0.6-0.3-1.3-0.4-2.1-0.4H48v-16h-5.3V12c0,1.5-0.3,2.9-0.8,4.2c-0.6,1.3-1.3,2.4-2.3,3.4%20c-1,1-2.1,1.7-3.4,2.3c-1.3,0.6-2.7,0.8-4.2,0.8c-1.5,0-2.9-0.3-4.2-0.8c-1.3-0.6-2.4-1.3-3.4-2.3c-1-1-1.7-2.1-2.3-3.4%20c-0.6-1.3-0.8-2.7-0.8-4.2v-1.3h-5.3v16H10.7z'/%3e%3c/g%3e%3c/svg%3e\"","import cloneDeep from \"lodash/cloneDeep\";\r\n\r\nexport interface IPromiseCache {\r\n [key: string]: Promise;\r\n}\r\n\r\nexport const cachedWrapper = async (key: string, func: () => Promise, cache: IPromiseCache): Promise => {\r\n if (!cache[key]) {\r\n cache[key] = func();\r\n }\r\n\r\n const definition = await cache[key];\r\n\r\n // XMLDocument (for example ribbon) doesn't support deep copy, so we just return it as is\r\n if (definition instanceof XMLDocument) {\r\n return definition;\r\n }\r\n\r\n // We clone the object because if someone touches it when passed by reference, the cache would become dirty\r\n return cloneDeep(definition);\r\n};","export class Exception extends Error {\r\n constructor(msg: string, innerException?: Exception | Error) {\r\n super(msg);\r\n // Set the prototype explicitly.\r\n Object.setPrototypeOf(this, Exception.prototype);\r\n\r\n if (innerException) {\r\n if(innerException instanceof Exception) {\r\n this.InnerException = innerException;\r\n }\r\n else {\r\n this.InnerException = new Exception(innerException.message);\r\n }\r\n }\r\n }\r\n\r\n public InnerException: Exception;\r\n public GetInnerMostException(): Exception {\r\n if (this.InnerException) {\r\n return this.InnerException.GetInnerMostException();\r\n }\r\n return this;\r\n }\r\n\r\n public Print(): string {\r\n let output = this.message;\r\n if (this.InnerException) {\r\n output += \"\\r\\n\\r\\nInner Exception>> \" + this.InnerException.Print();\r\n }\r\n return output;\r\n }\r\n}","import { Exception } from \"./Exception\";\r\n\r\nexport class EnvironmentNotSelectedException extends Exception {\r\n constructor(msg: string) {\r\n super(msg);\r\n // Set the prototype explicitly.\r\n Object.setPrototypeOf(this, EnvironmentNotSelectedException.prototype);\r\n }\r\n}","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9IlRleHRGaWVsZCIgdmVyc2lvbj0iMC4wLjEiDQogICAgZGlzcGxheS1uYW1lLWtleT0iVEFMWElTLlBDRi5Qb3J0YWwuVGV4dEZpZWxkIiBkZXNjcmlwdGlvbi1rZXk9IiIgY29udHJvbC10eXBlPSJzdGFuZGFyZCI+DQogICAgPHByb3BlcnR5IG5hbWU9InZhbHVlIiBkaXNwbGF5LW5hbWUta2V5PSJWYWx1ZSIgZGVzY3JpcHRpb24ta2V5PSIiIG9mLXR5cGU9IlNpbmdsZUxpbmUuVGV4dCINCiAgICAgIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9ImVuYWJsZURlbGV0ZUJ1dHRvbiIgZGlzcGxheS1uYW1lLWtleT0iRW5hYmxlIERlbGV0ZSBCdXR0b24iDQogICAgICBkZXNjcmlwdGlvbi1rZXk9IkVuYWJsZSBEZWxldGUgQnV0dG9uIiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJpbnB1dCINCiAgICAgIHJlcXVpcmVkPSJmYWxzZSIgLz4NCiAgICA8cHJvcGVydHkgbmFtZT0iZW5hYmxlQ29weUJ1dHRvbiIgZGlzcGxheS1uYW1lLWtleT0iRW5hYmxlIENvcHkgQnV0dG9uIg0KICAgICAgZGVzY3JpcHRpb24ta2V5PSJFbmFibGUgQ29weSBCdXR0b24iIG9mLXR5cGU9IlNpbmdsZUxpbmUuVGV4dCIgdXNhZ2U9ImlucHV0IiByZXF1aXJlZD0iZmFsc2UiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9IkVuYWJsZVR5cGVTdWZmaXgiIGRpc3BsYXktbmFtZS1rZXk9IkVuYWJsZSBUeXBlIFN1ZmZpeCIgZGVzY3JpcHRpb24ta2V5PSIiDQogICAgICB1c2FnZT0iaW5wdXQiIG9mLXR5cGU9IkVudW0iIHJlcXVpcmVkPSJmYWxzZSI+DQogICAgICA8dmFsdWUgbmFtZT0iWWVzIiBkaXNwbGF5LW5hbWUta2V5PSJDQ19FbmFibGVfVHlwZV9TdWZmaXgiDQogICAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRW5hYmxlX1R5cGVfU3VmZml4Ij50cnVlPC92YWx1ZT4NCiAgICAgIDx2YWx1ZSBuYW1lPSJObyIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRGlzYWJsZV9UeXBlX1N1ZmZpeCINCiAgICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19EaXNhYmxlX1R5cGVfU3VmZml4X0Rlc2MiDQogICAgICAgIGRlZmF1bHQ9InRydWUiPmZhbHNlPC92YWx1ZT4NCiAgICA8L3Byb3BlcnR5Pg0KICAgIDwhLS0gaXNDb250cm9sRGlzYWJsZSBzZXRzIHJlYWQtb25seSBzdGF0ZSB3aGVyZSBGb3JjZURpc2FibGVkIHNldHMgZGlzYWJsZWQgc3RhdGUgb2YgdGhlDQogICAgY29udHJvbCAtLT4NCiAgICA8cHJvcGVydHkgbmFtZT0iRm9yY2VEaXNhYmxlIiBkaXNwbGF5LW5hbWUta2V5PSJDQ19Gb3JjZURpc2FibGVfQ29udHJvbCINCiAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRm9yY2VEaXNhYmxlX0NvbnRyb2wiIHVzYWdlPSJpbnB1dCIgb2YtdHlwZT0iRW51bSIgcmVxdWlyZWQ9ImZhbHNlIj4NCiAgICAgIDx2YWx1ZSBuYW1lPSJUcnVlIiBkaXNwbGF5LW5hbWUta2V5PSJDQ19EaXNhYmxlZF9Db250cm9sIg0KICAgICAgICBkZXNjcmlwdGlvbi1rZXk9IkNDX0Rpc2FibGVkX0NvbnRyb2xfRGVzYyI+dHJ1ZTwvdmFsdWU+DQogICAgICA8dmFsdWUgbmFtZT0iRmFsc2UiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0VuYWJsZV9Db250cm9sIg0KICAgICAgICBkZXNjcmlwdGlvbi1rZXk9IkNDX0VuYWJsZV9Db250cm9sX0Rlc2MiIGRlZmF1bHQ9InRydWUiPmZhbHNlPC92YWx1ZT4NCiAgICA8L3Byb3BlcnR5Pg0KICAgIDxyZXNvdXJjZXM+DQogICAgICA8Y29kZSBwYXRoPSJpbmRleC50cyIgb3JkZXI9IjEiIC8+DQogICAgPC9yZXNvdXJjZXM+DQogIDwvY29udHJvbD4NCjwvbWFuaWZlc3Q+\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9Ik11bHRpbGluZVRleHQiIHZlcnNpb249IjAuMC4xIg0KICAgIGRpc3BsYXktbmFtZS1rZXk9IlRBTFhJUy5QQ0YuUG9ydGFsLk11bHRpbGluZVRleHQiIGRlc2NyaXB0aW9uLWtleT0iIiBjb250cm9sLXR5cGU9InN0YW5kYXJkIj4NCiAgICA8cHJvcGVydHkgbmFtZT0idmFsdWUiIGRpc3BsYXktbmFtZS1rZXk9IlZhbHVlIiBkZXNjcmlwdGlvbi1rZXk9IiIgb2YtdHlwZT0iTXVsdGlwbGUiDQogICAgICB1c2FnZT0iYm91bmQiIHJlcXVpcmVkPSJ0cnVlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJlbmFibGVEZWxldGVCdXR0b24iIGRpc3BsYXktbmFtZS1rZXk9IkVuYWJsZSBEZWxldGUgQnV0dG9uIg0KICAgICAgZGVzY3JpcHRpb24ta2V5PSJFbmFibGUgRGVsZXRlIEJ1dHRvbiIgb2YtdHlwZT0iU2luZ2xlTGluZS5UZXh0IiB1c2FnZT0iaW5wdXQiDQogICAgICByZXF1aXJlZD0iZmFsc2UiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9ImVuYWJsZUNvcHlCdXR0b24iIGRpc3BsYXktbmFtZS1rZXk9IkVuYWJsZSBDb3B5IEJ1dHRvbiINCiAgICAgIGRlc2NyaXB0aW9uLWtleT0iRW5hYmxlIENvcHkgQnV0dG9uIiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJpbnB1dCIgcmVxdWlyZWQ9ImZhbHNlIiAvPg0KICAgIDxyZXNvdXJjZXM+DQogICAgICA8Y29kZSBwYXRoPSJpbmRleC50cyIgb3JkZXI9IjEiIC8+DQogICAgPC9yZXNvdXJjZXM+DQogIDwvY29udHJvbD4NCjwvbWFuaWZlc3Q+\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9IlRleHRGaWVsZCIgdmVyc2lvbj0iMC4wLjEiDQogICAgZGlzcGxheS1uYW1lLWtleT0iVEFMWElTLlBDRi5Qb3J0YWwuVGV4dEZpZWxkIiBkZXNjcmlwdGlvbi1rZXk9IiIgY29udHJvbC10eXBlPSJzdGFuZGFyZCI+DQogICAgPHByb3BlcnR5IG5hbWU9InZhbHVlIiBkaXNwbGF5LW5hbWUta2V5PSJWYWx1ZSIgZGVzY3JpcHRpb24ta2V5PSIiIG9mLXR5cGU9IlNpbmdsZUxpbmUuVVJMIg0KICAgICAgdXNhZ2U9ImJvdW5kIiByZXF1aXJlZD0idHJ1ZSIgLz4NCiAgICA8cHJvcGVydHkgbmFtZT0iZW5hYmxlRGVsZXRlQnV0dG9uIiBkaXNwbGF5LW5hbWUta2V5PSJFbmFibGUgRGVsZXRlIEJ1dHRvbiINCiAgICAgIGRlc2NyaXB0aW9uLWtleT0iRW5hYmxlIERlbGV0ZSBCdXR0b24iIG9mLXR5cGU9IlNpbmdsZUxpbmUuVGV4dCIgdXNhZ2U9ImlucHV0Ig0KICAgICAgcmVxdWlyZWQ9ImZhbHNlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJlbmFibGVDb3B5QnV0dG9uIiBkaXNwbGF5LW5hbWUta2V5PSJFbmFibGUgQ29weSBCdXR0b24iDQogICAgICBkZXNjcmlwdGlvbi1rZXk9IkVuYWJsZSBDb3B5IEJ1dHRvbiIgb2YtdHlwZT0iU2luZ2xlTGluZS5UZXh0IiB1c2FnZT0iaW5wdXQiIHJlcXVpcmVkPSJmYWxzZSIgLz4NCiAgICA8cHJvcGVydHkgbmFtZT0iRW5hYmxlVHlwZVN1ZmZpeCIgZGlzcGxheS1uYW1lLWtleT0iRW5hYmxlIFR5cGUgU3VmZml4IiBkZXNjcmlwdGlvbi1rZXk9IiINCiAgICAgIHVzYWdlPSJpbnB1dCIgb2YtdHlwZT0iRW51bSIgcmVxdWlyZWQ9ImZhbHNlIj4NCiAgICAgIDx2YWx1ZSBuYW1lPSJZZXMiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0VuYWJsZV9UeXBlX1N1ZmZpeCINCiAgICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19FbmFibGVfVHlwZV9TdWZmaXgiPnRydWU8L3ZhbHVlPg0KICAgICAgPHZhbHVlIG5hbWU9Ik5vIiBkaXNwbGF5LW5hbWUta2V5PSJDQ19EaXNhYmxlX1R5cGVfU3VmZml4Ig0KICAgICAgICBkZXNjcmlwdGlvbi1rZXk9IkNDX0Rpc2FibGVfVHlwZV9TdWZmaXhfRGVzYyINCiAgICAgICAgZGVmYXVsdD0idHJ1ZSI+ZmFsc2U8L3ZhbHVlPg0KICAgIDwvcHJvcGVydHk+DQogICAgPCEtLSBpc0NvbnRyb2xEaXNhYmxlIHNldHMgcmVhZC1vbmx5IHN0YXRlIHdoZXJlIEZvcmNlRGlzYWJsZWQgc2V0cyBkaXNhYmxlZCBzdGF0ZSBvZiB0aGUNCiAgICBjb250cm9sIC0tPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJGb3JjZURpc2FibGUiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0ZvcmNlRGlzYWJsZV9Db250cm9sIg0KICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19Gb3JjZURpc2FibGVfQ29udHJvbCIgdXNhZ2U9ImlucHV0IiBvZi10eXBlPSJFbnVtIiByZXF1aXJlZD0iZmFsc2UiPg0KICAgICAgPHZhbHVlIG5hbWU9IlRydWUiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0Rpc2FibGVkX0NvbnRyb2wiDQogICAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRGlzYWJsZWRfQ29udHJvbF9EZXNjIj50cnVlPC92YWx1ZT4NCiAgICAgIDx2YWx1ZSBuYW1lPSJGYWxzZSIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRW5hYmxlX0NvbnRyb2wiDQogICAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRW5hYmxlX0NvbnRyb2xfRGVzYyIgZGVmYXVsdD0idHJ1ZSI+ZmFsc2U8L3ZhbHVlPg0KICAgIDwvcHJvcGVydHk+DQogICAgPHJlc291cmNlcz4NCiAgICAgIDxjb2RlIHBhdGg9ImluZGV4LnRzIiBvcmRlcj0iMSIgLz4NCiAgICA8L3Jlc291cmNlcz4NCiAgPC9jb250cm9sPg0KPC9tYW5pZmVzdD4=\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9IkRhdGVUaW1lIiB2ZXJzaW9uPSIwLjAuMSINCiAgICBkaXNwbGF5LW5hbWUta2V5PSJUQUxYSVMuUENGLlBvcnRhbC5EYXRlVGltZSIgZGVzY3JpcHRpb24ta2V5PSIiIGNvbnRyb2wtdHlwZT0ic3RhbmRhcmQiPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJ2YWx1ZSIgZGlzcGxheS1uYW1lLWtleT0iVmFsdWUiIGRlc2NyaXB0aW9uLWtleT0iIiBvZi10eXBlPSJEYXRlVGltZSINCiAgICAgIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9ImVuYWJsZURlbGV0ZUJ1dHRvbiIgZGlzcGxheS1uYW1lLWtleT0iRW5hYmxlIERlbGV0ZSBCdXR0b24iDQogICAgICBkZXNjcmlwdGlvbi1rZXk9IkVuYWJsZSBEZWxldGUgQnV0dG9uIiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJpbnB1dCINCiAgICAgIHJlcXVpcmVkPSJmYWxzZSIgLz4NCiAgICA8cHJvcGVydHkgbmFtZT0iSGlkZU1vbnRoU2VsZWN0aW9uIiBkaXNwbGF5LW5hbWUta2V5PSJIaWRlIE1vbnRoIFNlbGVjdGlvbiIgZGVzY3JpcHRpb24ta2V5PSIiDQogICAgICBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJpbnB1dCIgcmVxdWlyZWQ9ImZhbHNlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJoaWRlRGF5U2VsZWN0aW9uIiBkaXNwbGF5LW5hbWUta2V5PSJIaWRlIERheSBTZWxlY3Rpb24iIGRlc2NyaXB0aW9uLWtleT0iIg0KICAgICAgb2YtdHlwZT0iU2luZ2xlTGluZS5UZXh0IiB1c2FnZT0iaW5wdXQiIHJlcXVpcmVkPSJmYWxzZSIgLz4NCiAgICA8cHJvcGVydHkgbmFtZT0iUmVzdHJpY3RlZERheXNPZldlZWsiDQogICAgICBkaXNwbGF5LW5hbWUta2V5PSJFeGNsdWRlIERheXMgb2YgdGhlIFdlZWsgQXJyYXkgKDAgPSBTdW5kYXksLi4uNiA9IFNhdHVyZGF5KSwgZXhhbXBsZTogWzAsIDEsIDJdIHdpbGwgZGlzYWJsZSBhbGwgU3VuZGF5cywgTW9uZGF5cyBhbmQgVHVlc2RheXMiDQogICAgICBkZXNjcmlwdGlvbi1rZXk9IiIgb2YtdHlwZT0iU2luZ2xlTGluZS5UZXh0IiB1c2FnZT0iaW5wdXQiIHJlcXVpcmVkPSJmYWxzZSIgLz4NCiAgICA8cHJvcGVydHkgbmFtZT0iUmVzdHJpY3RlZERhdGVzIg0KICAgICAgZGlzcGxheS1uYW1lLWtleT0iRXhjbHVkZSBEYXlzIEFycmF5LCBleGFtcGxlOiBbMjAxOS0wMS0xMCcsIDIwMTktMDEtMTFdIg0KICAgICAgZGVzY3JpcHRpb24ta2V5PSIiIG9mLXR5cGU9IlNpbmdsZUxpbmUuVGV4dCIgdXNhZ2U9ImlucHV0IiByZXF1aXJlZD0iZmFsc2UiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9IkZvcm1hdCIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRm9ybWF0IiBkZXNjcmlwdGlvbi1rZXk9IkNDX0Zvcm1hdF9EZXNjIg0KICAgICAgdXNhZ2U9ImlucHV0IiBvZi10eXBlPSJFbnVtIiByZXF1aXJlZD0iZmFsc2UiIGhpZGRlbj0idHJ1ZSI+DQogICAgICA8dmFsdWUgbmFtZT0iRGF0ZSBBbmQgVGltZSIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRGF0ZVRpbWUiIGRlc2NyaXB0aW9uLWtleT0iQ0NfRGF0ZVRpbWVfRGVzYyI+DQogICAgICAgIERhdGVBbmRUaW1lPC92YWx1ZT4NCiAgICAgIDx2YWx1ZSBuYW1lPSJEYXRlIE9ubHkiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0RhdGVPbmx5IiBkZXNjcmlwdGlvbi1rZXk9IkNDX0RhdGVPbmx5X0Rlc2MiDQogICAgICAgIGRlZmF1bHQ9InRydWUiPkRhdGU8L3ZhbHVlPg0KICAgIDwvcHJvcGVydHk+DQogICAgPHR5cGUtZ3JvdXAgbmFtZT0iRGF0ZVRpbWUiPg0KICAgICAgPHR5cGU+RGF0ZUFuZFRpbWUuRGF0ZUFuZFRpbWU8L3R5cGU+DQogICAgICA8dHlwZT5EYXRlQW5kVGltZS5EYXRlT25seTwvdHlwZT4NCiAgICA8L3R5cGUtZ3JvdXA+DQogICAgPCEtLSBpc0NvbnRyb2xEaXNhYmxlZCBzZXRzIHJlYWQtb25seSBzdGF0ZSB3aGVyZSBGb3JjZURpc2FibGUgc2V0cyBkaXNhYmxlZCBzdGF0ZSBvZiB0aGUNCiAgICBjb250cm9sIC0tPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJGb3JjZURpc2FibGUiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0ZvcmNlRGlzYWJsZV9Db250cm9sIg0KICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19Gb3JjZURpc2FibGVfQ29udHJvbCIgdXNhZ2U9ImlucHV0IiBvZi10eXBlPSJFbnVtIiByZXF1aXJlZD0iZmFsc2UiPg0KICAgICAgPHZhbHVlIG5hbWU9IlRydWUiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0Rpc2FibGVkX0NvbnRyb2wiDQogICAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRGlzYWJsZWRfQ29udHJvbF9EZXNjIj50cnVlPC92YWx1ZT4NCiAgICAgIDx2YWx1ZSBuYW1lPSJGYWxzZSIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRW5hYmxlX0NvbnRyb2wiDQogICAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRW5hYmxlX0NvbnRyb2xfRGVzYyIgZGVmYXVsdD0idHJ1ZSI+ZmFsc2U8L3ZhbHVlPg0KICAgIDwvcHJvcGVydHk+DQogICAgPHJlc291cmNlcz4NCiAgICAgIDxjb2RlIHBhdGg9ImluZGV4LnRzIiBvcmRlcj0iMSIgLz4NCiAgICA8L3Jlc291cmNlcz4NCiAgPC9jb250cm9sPg0KPC9tYW5pZmVzdD4=\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9Ikxvb2t1cCIgdmVyc2lvbj0iMC4wLjEiDQogICAgZGlzcGxheS1uYW1lLWtleT0iVEFMWElTLlBDRi5Qb3J0YWwuU2ltcGxlTG9va3VwIiBkZXNjcmlwdGlvbi1rZXk9IiIgY29udHJvbC10eXBlPSJzdGFuZGFyZCI+DQogICAgPHByb3BlcnR5IG5hbWU9InZhbHVlIiBkaXNwbGF5LW5hbWUta2V5PSJWYWx1ZSIgZGVzY3JpcHRpb24ta2V5PSIiIG9mLXR5cGU9Ikxvb2t1cC5TaW1wbGUiDQogICAgICB1c2FnZT0iYm91bmQiIHJlcXVpcmVkPSJ0cnVlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJJc0lubGluZU5ld0VuYWJsZWQiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0xvb2t1cF9Jc0lubGluZU5ld0VuYWJsZWQiDQogICAgICBkZXNjcmlwdGlvbi1rZXk9IkNDX0dyaWRfSXNJbmxpbmVOZXdFbmFibGVkX0Rlc2MiIHVzYWdlPSJpbnB1dCIgb2YtdHlwZT0iU2luZ2xlTGluZS5UZXh0Ig0KICAgICAgcmVxdWlyZWQ9ImZhbHNlIiBoaWRkZW49ImZhbHNlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJNdWx0aXBsZUVuYWJsZWQiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0xvb2t1cF9Jc0lubGluZU5ld0VuYWJsZWQiDQogICAgICBkZXNjcmlwdGlvbi1rZXk9IkNDX0dyaWRfSXNJbmxpbmVOZXdFbmFibGVkX0Rlc2MiIHVzYWdlPSJpbnB1dCIgb2YtdHlwZT0iU2luZ2xlTGluZS5UZXh0Ig0KICAgICAgcmVxdWlyZWQ9ImZhbHNlIiBoaWRkZW49ImZhbHNlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJFbmFibGVOYXZpZ2F0aW9uIiBkaXNwbGF5LW5hbWUta2V5PSJDQ19FbmFibGVfTmF2aWdhdGlvbiINCiAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRW5hYmxlX05hdmlnYXRpb24iIHVzYWdlPSJpbnB1dCIgb2YtdHlwZT0iRW51bSIgcmVxdWlyZWQ9ImZhbHNlIj4NCiAgICAgIDx2YWx1ZSBuYW1lPSJUcnVlIiBkaXNwbGF5LW5hbWUta2V5PSJDQ19FbmFibGVfTmF2aWdhdGlvbiINCiAgICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19FbmFibGVfTmF2aWdhdGlvbiIgZGVmYXVsdD0idHJ1ZSI+dHJ1ZTwvdmFsdWU+DQogICAgICA8dmFsdWUgbmFtZT0iRmFsc2UiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0Rpc2FibGVfTmF2aWdhdGlvbiINCiAgICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19EaXNhYmxlX05hdmlnYXRpb25fRGVzYyI+ZmFsc2U8L3ZhbHVlPg0KICAgIDwvcHJvcGVydHk+DQogICAgPCEtLSBpc0NvbnRyb2xEaXNhYmxlZCBzZXRzIHJlYWQtb25seSBzdGF0ZSB3aGVyZSBGb3JjZURpc2FibGUgc2V0cyBkaXNhYmxlZCBzdGF0ZSBvZiB0aGUNCiAgICBjb250cm9sIC0tPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJGb3JjZURpc2FibGUiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0ZvcmNlRGlzYWJsZV9Db250cm9sIg0KICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19Gb3JjZURpc2FibGVfQ29udHJvbCIgdXNhZ2U9ImlucHV0IiBvZi10eXBlPSJFbnVtIiByZXF1aXJlZD0iZmFsc2UiPg0KICAgICAgPHZhbHVlIG5hbWU9IlRydWUiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0Rpc2FibGVkX0NvbnRyb2wiDQogICAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRGlzYWJsZWRfQ29udHJvbF9EZXNjIj50cnVlPC92YWx1ZT4NCiAgICAgIDx2YWx1ZSBuYW1lPSJGYWxzZSIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRW5hYmxlX0NvbnRyb2wiDQogICAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRW5hYmxlX0NvbnRyb2xfRGVzYyIgZGVmYXVsdD0idHJ1ZSI+ZmFsc2U8L3ZhbHVlPg0KICAgIDwvcHJvcGVydHk+DQogICAgPHJlc291cmNlcz4NCiAgICAgIDxjb2RlIHBhdGg9ImluZGV4LnRzIiBvcmRlcj0iMSIgLz4NCiAgICA8L3Jlc291cmNlcz4NCiAgPC9jb250cm9sPg0KPC9tYW5pZmVzdD4=\"","export default \"data:application/octet-stream;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxyb290Pg0KICAgIDx4c2Q6c2NoZW1hIGlkPSJyb290Ig0KICAgICAgICB4bWxucz0iIg0KICAgICAgICB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIg0KICAgICAgICB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSI+DQogICAgICAgIDx4c2Q6aW1wb3J0IG5hbWVzcGFjZT0iaHR0cDovL3d3dy53My5vcmcvWE1MLzE5OTgvbmFtZXNwYWNlIiAvPg0KICAgIDwveHNkOnNjaGVtYT4NCiAgICA8cmVzaGVhZGVyIG5hbWU9InJlc21pbWV0eXBlIj4NCiAgICAgICAgPHZhbHVlPnRleHQvbWljcm9zb2Z0LXJlc3g8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0idmVyc2lvbiI+DQogICAgICAgIDx2YWx1ZT4yLjA8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0icmVhZGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlUmVhZGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLA0KICAgICAgICAgICAgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5PC92YWx1ZT4NCiAgICA8L3Jlc2hlYWRlcj4NCiAgICA8cmVzaGVhZGVyIG5hbWU9IndyaXRlciI+DQogICAgICAgIDx2YWx1ZT5TeXN0ZW0uUmVzb3VyY2VzLlJlc1hSZXNvdXJjZVdyaXRlciwgU3lzdGVtLldpbmRvd3MuRm9ybXMsIFZlcnNpb249NC4wLjAuMCwNCiAgICAgICAgICAgIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OTwvdmFsdWU+DQogICAgPC9yZXNoZWFkZXI+DQogICAgPGRhdGEgbmFtZT0ic2VhcmNoIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPlZ5aGxlZGVqdGU8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9Im5ld1JlY29yZCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5Ob3bDvSB6w6F6bmFtPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJzZWFyY2hpbmciIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+SGxlZMOhbS4uLjwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0ibm9SZWNvcmRzRm91bmQiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+TmVieWx5IG5hbGV6ZW55IMW+w6FkbsOpIHrDoXpuYW15PC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJyZXN1bHRzRnJvbSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5Ww71zbGVka3kgejo8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9Im5vTmFtZSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT4oQmV6IG7DoXp2dSk8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KPC9yb290Pg==\"","export default \"data:application/octet-stream;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxyb290Pg0KICAgIDx4c2Q6c2NoZW1hIGlkPSJyb290Ig0KICAgICAgICB4bWxucz0iIg0KICAgICAgICB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIg0KICAgICAgICB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSI+DQogICAgICAgIDx4c2Q6aW1wb3J0IG5hbWVzcGFjZT0iaHR0cDovL3d3dy53My5vcmcvWE1MLzE5OTgvbmFtZXNwYWNlIiAvPg0KICAgIDwveHNkOnNjaGVtYT4NCiAgICA8cmVzaGVhZGVyIG5hbWU9InJlc21pbWV0eXBlIj4NCiAgICAgICAgPHZhbHVlPnRleHQvbWljcm9zb2Z0LXJlc3g8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0idmVyc2lvbiI+DQogICAgICAgIDx2YWx1ZT4yLjA8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0icmVhZGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlUmVhZGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLA0KICAgICAgICAgICAgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5PC92YWx1ZT4NCiAgICA8L3Jlc2hlYWRlcj4NCiAgICA8cmVzaGVhZGVyIG5hbWU9IndyaXRlciI+DQogICAgICAgIDx2YWx1ZT5TeXN0ZW0uUmVzb3VyY2VzLlJlc1hSZXNvdXJjZVdyaXRlciwgU3lzdGVtLldpbmRvd3MuRm9ybXMsIFZlcnNpb249NC4wLjAuMCwNCiAgICAgICAgICAgIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OTwvdmFsdWU+DQogICAgPC9yZXNoZWFkZXI+DQogICAgPGRhdGEgbmFtZT0ic2VhcmNoIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPlNlYXJjaDwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0ibmV3UmVjb3JkIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPk5ldyByZWNvcmQ8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9InNlYXJjaGluZyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5TZWFyY2hpbmcuLi48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9Im5vUmVjb3Jkc0ZvdW5kIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPk5vIHJlY29yZHMgZm91bmQ8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9InJlc3VsdHNGcm9tIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPlJlc3VsdHMgZnJvbTo8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9Im5vTmFtZSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT4oTm8gTmFtZSk8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KPC9yb290Pg==\"","export default \"__VITE_ASSET__BrJZU1jV__\"","export default \"__VITE_ASSET__CuAgP_92__\"","export default \"__VITE_ASSET___NKqjAw6__\"","export default \"__VITE_ASSET__EELnJZcE__\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9Ik9wdGlvblNldCIgdmVyc2lvbj0iMC4wLjEiDQogICAgZGlzcGxheS1uYW1lLWtleT0iVEFMWElTLlBDRi5Qb3J0YWwuT3B0aW9uU2V0IiBkZXNjcmlwdGlvbi1rZXk9IiIgY29udHJvbC10eXBlPSJzdGFuZGFyZCI+DQogICAgPHByb3BlcnR5IG5hbWU9InZhbHVlIiBkaXNwbGF5LW5hbWUta2V5PSJWYWx1ZSIgZGVzY3JpcHRpb24ta2V5PSIiIG9mLXR5cGU9Ik9wdGlvblNldCINCiAgICAgIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9ImRlbGV0ZUJ1dHRvbiIgZGlzcGxheS1uYW1lLWtleT0iRGVsZXRlIEJ1dHRvbiIgZGVzY3JpcHRpb24ta2V5PSJEZWxldGUgQnV0dG9uIg0KICAgICAgb2YtdHlwZT0iU2luZ2xlTGluZS5UZXh0IiB1c2FnZT0iaW5wdXQiIHJlcXVpcmVkPSJmYWxzZSIgLz4NCiAgICA8cHJvcGVydHkgbmFtZT0iRW5hYmxlT3B0aW9uU2V0Q29sb3JzIiBkaXNwbGF5LW5hbWUta2V5PSJFbmFibGUgT3B0aW9uU2V0IGNvbG9ycyINCiAgICAgIGRlc2NyaXB0aW9uLWtleT0iIg0KICAgICAgb2YtdHlwZT0iRW51bSIgdXNhZ2U9ImlucHV0Ij4NCiAgICAgIDx2YWx1ZSBuYW1lPSJZZXMiIGRpc3BsYXktbmFtZS1rZXk9IlllcyIgZGVzY3JpcHRpb24ta2V5PSIiPnRydWU8L3ZhbHVlPg0KICAgICAgPHZhbHVlIG5hbWU9Ik5vIiBkZWZhdWx0PSJ0cnVlIiBkaXNwbGF5LW5hbWUta2V5PSJObyIgZGVzY3JpcHRpb24ta2V5PSIiPmZhbHNlPC92YWx1ZT4NCiAgICA8L3Byb3BlcnR5Pg0KICAgIDxyZXNvdXJjZXM+DQogICAgICA8Y29kZSBwYXRoPSJpbmRleC50cyIgb3JkZXI9IjEiIC8+DQogICAgPC9yZXNvdXJjZXM+DQogIDwvY29udHJvbD4NCjwvbWFuaWZlc3Q+\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9Ik11bHRpU2VsZWN0T3B0aW9uU2V0IiB2ZXJzaW9uPSIwLjAuMSINCiAgICBkaXNwbGF5LW5hbWUta2V5PSJUQUxYSVMuUENGLlBvcnRhbC5NdWx0aVNlbGVjdE9wdGlvblNldCIgZGVzY3JpcHRpb24ta2V5PSIiDQogICAgY29udHJvbC10eXBlPSJzdGFuZGFyZCI+DQogICAgPHByb3BlcnR5IG5hbWU9InZhbHVlIiBkaXNwbGF5LW5hbWUta2V5PSJWYWx1ZSIgZGVzY3JpcHRpb24ta2V5PSIiDQogICAgICBvZi10eXBlPSJNdWx0aVNlbGVjdE9wdGlvblNldCIgdXNhZ2U9ImJvdW5kIiByZXF1aXJlZD0idHJ1ZSIgLz4NCiAgICA8cmVzb3VyY2VzPg0KICAgICAgPGNvZGUgcGF0aD0iaW5kZXgudHMiIG9yZGVyPSIxIiAvPg0KICAgIDwvcmVzb3VyY2VzPg0KICA8L2NvbnRyb2w+DQo8L21hbmlmZXN0Pg==\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9IkZvcm0iIHZlcnNpb249IjAuMC4xIiBkaXNwbGF5LW5hbWUta2V5PSJUQUxYSVMuUENGLlBvcnRhbC5Gb3JtIiBkZXNjcmlwdGlvbi1rZXk9IiIgY29udHJvbC10eXBlPSJzdGFuZGFyZCI+DQogICAgPCEtLSBVc2VkIGZvciBuZXN0ZWQgZm9ybXMgLS0+DQogICAgPHByb3BlcnR5IG5hbWU9InZhbHVlIiBkaXNwbGF5LW5hbWUta2V5PSJWYWx1ZSIgZGVzY3JpcHRpb24ta2V5PSIiIG9mLXR5cGU9Ikxvb2t1cC5TaW1wbGUiIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9ImZhbHNlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJRdWlja0Zvcm1zIiByZXF1aXJlZD0idHJ1ZSIgZGlzcGxheS1uYW1lLWtleT0iZm9ybXNfbmFtZSIgdXNhZ2U9ImlucHV0IiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIC8+DQogICAgPCEtLSBVc2VkIGZvciBtYWluIGZvcm1zIC0tPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJlbnRpdHlOYW1lIiBkaXNwbGF5LW5hbWUta2V5PSJFbnRpdHkgbmFtZSIgZGVzY3JpcHRpb24ta2V5PSIiIG9mLXR5cGU9IlNpbmdsZUxpbmUuVGV4dCIgdXNhZ2U9ImJvdW5kIiByZXF1aXJlZD0iZmFsc2UiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9ImVudGl0eUlkIiBkaXNwbGF5LW5hbWUta2V5PSJFbnRpdHkgSUQiIGRlc2NyaXB0aW9uLWtleT0iIiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9ImZhbHNlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJmb3JtSWQiIGRpc3BsYXktbmFtZS1rZXk9IkZvcm0gSUQiIGRlc2NyaXB0aW9uLWtleT0iIiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9ImZhbHNlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJleHRyYVFzIiBkaXNwbGF5LW5hbWUta2V5PSJFeHRyYSBxdWVyeSBzdHJpbmciIGRlc2NyaXB0aW9uLWtleT0iIiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9ImZhbHNlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJmb3JtVW5pcXVlTmFtZSIgZGlzcGxheS1uYW1lLWtleT0iRm9ybSBVbmlxdWUgTmFtZSIgZGVzY3JpcHRpb24ta2V5PSIiIG9mLXR5cGU9IlNpbmdsZUxpbmUuVGV4dCIgdXNhZ2U9ImJvdW5kIiByZXF1aXJlZD0iZmFsc2UiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9ImlzUXVpY2tDcmVhdGUiIGRpc3BsYXktbmFtZS1rZXk9IkZvcm0gVW5pcXVlIE5hbWUiIGRlc2NyaXB0aW9uLWtleT0iIiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9ImZhbHNlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJpc0RpYWxvZyIgZGlzcGxheS1uYW1lLWtleT0iSXMgb3BlbmVkIGluIERpYWxvZyIgZGVzY3JpcHRpb24ta2V5PSIiIG9mLXR5cGU9IlNpbmdsZUxpbmUuVGV4dCIgdXNhZ2U9ImJvdW5kIiByZXF1aXJlZD0iZmFsc2UiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9ImlzTmF2YmFyTG9hZGVkIiBkaXNwbGF5LW5hbWUta2V5PSJGb3JtIFVuaXF1ZSBOYW1lIiBkZXNjcmlwdGlvbi1rZXk9IiIgb2YtdHlwZT0iU2luZ2xlTGluZS5UZXh0IiB1c2FnZT0iYm91bmQiIHJlcXVpcmVkPSJmYWxzZSIgLz4NCiAgICA8cHJvcGVydHkgbmFtZT0iRGlzcGxheUNvbW1hbmRiYXIiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0VuYWJsZV9SaWJib24iIGRlc2NyaXB0aW9uLWtleT0iQ0NfRW5hYmxlX1JpYmJvbl9EZXNjIiB1c2FnZT0iaW5wdXQiIG9mLXR5cGU9IkVudW0iIHJlcXVpcmVkPSJmYWxzZSI+DQogICAgICA8dmFsdWUgbmFtZT0iWWVzIiBkaXNwbGF5LW5hbWUta2V5PSJDQ19FbmFibGVfUmliYm9uIiBkZXNjcmlwdGlvbi1rZXk9IkNDX0VuYWJsZV9SaWJib25fRGVzYyI+eWVzPC92YWx1ZT4NCiAgICAgIDx2YWx1ZSBuYW1lPSJObyIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRGlzYWJsZV9SaWJib24iIGRlc2NyaXB0aW9uLWtleT0iQ0NfRGlzYWJsZV9SaWJib25fRGVzYyIgZGVmYXVsdD0idHJ1ZSI+bm88L3ZhbHVlPg0KICAgIDwvcHJvcGVydHk+DQogICAgPHJlc291cmNlcz4NCiAgICAgIDxjb2RlIHBhdGg9ImluZGV4LnRzIiBvcmRlcj0iMSIgLz4NCiAgICA8L3Jlc291cmNlcz4NCiAgPC9jb250cm9sPg0KPC9tYW5pZmVzdD4=\"","export default \"data:application/octet-stream;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxyb290Pg0KICAgIDx4c2Q6c2NoZW1hIGlkPSJyb290Ig0KICAgICAgICB4bWxucz0iIg0KICAgICAgICB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIg0KICAgICAgICB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSI+DQogICAgICAgIDx4c2Q6aW1wb3J0IG5hbWVzcGFjZT0iaHR0cDovL3d3dy53My5vcmcvWE1MLzE5OTgvbmFtZXNwYWNlIiAvPg0KICAgIDwveHNkOnNjaGVtYT4NCiAgICA8cmVzaGVhZGVyIG5hbWU9InJlc21pbWV0eXBlIj4NCiAgICAgICAgPHZhbHVlPnRleHQvbWljcm9zb2Z0LXJlc3g8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0idmVyc2lvbiI+DQogICAgICAgIDx2YWx1ZT4yLjA8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0icmVhZGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlUmVhZGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0id3JpdGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlV3JpdGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxkYXRhIG5hbWU9InNhdmluZyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5Va2zDoWTDoW7DrTwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0iZmFpbGVkVG9TYXZlIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPk5lcG92ZWRsbyBzZSBuw6FtIHVsb8W+aXQgZGF0YSwgemt1c3RlIHRvIHpub3Z1LCBwxZnDrXBhZG7EmyBrb250YWt0dWp0ZSBwb2Rwb3J1LjwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0ic2F2ZSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5VbG/Fvml0PC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJzYXZlZCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5VbG/FvmVubzwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0ic2F2aW5nIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPlVrbMOhZMOhbsOtPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJzYXZlQW5kQ2xvc2UiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+VWxvxb5pdCBhIHphdsWZw610PC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJzYXZpbmdDaGFuZ2VzIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPlVrbMOhZMOhbSB6bcSbbnkuLi48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9ImNyZWF0aW5nUmVjb3JkIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPlZ5dHbDocWZw61tIHrDoXpuYW0uLi48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9ImNyZWF0ZSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5WeXR2b8WZaXQ8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9ImNsb3NlIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPlphdsWZw610PC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJtaXNzaW5nUmVxdWlyZWQiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+TmVsemUgdWxvxb5pdCBmb3JtdWzDocWZLCBqZWxpa2/FviBuxJtrdGVyw6EgcG9sZSBuZWpzb3Ugc3Byw6F2bsSbIHZ5cGxuxJtuYS48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9InNhdmluZ0Vycm9yIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPkNoeWJhIHDFmWkgdWtsw6Fkw6Fuw60gZm9ybXVsw6HFmWUuPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJzZWxlY3RSZWNvcmQiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+UHJvIHpvYnJhemVuw60gZGV0YWlsdSB2eWJlcnRlIHrDoXpuYW0uPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJyZWNvcmRJbmFjdGl2ZU5vdGlmaWNhdGlvbiIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5KZW4gcHJvIMSNdGVuw60g4oCTIHN0YXYgdG9ob3RvIHrDoXpuYW11OjwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0iMHg4MDA0NDMzMSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5CeWxhIHDFmWVrcm/EjWVuYSBtYXhpbcOhbG7DrSBkw6lsa2EgcG9sZS48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9IjB4ODAxNTRCNTAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+TmVtw6F0ZSBvcHLDoXZuxJtuw60gcHJvIHrDoXBpcyBkbyBkYXRhYsOhemUuIFBva3VkIG9wcsOhdm7Em27DrSB2ecW+YWR1amV0ZSwga29udGFrdHVqdGUgcHJvc8OtbSBzcHLDoXZjZS48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9ImR1cGxpY2F0ZUFsdGVybmF0ZUtleSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5aw6F6bmFtIG5lbHplIHVsb8W+aXQsIG5lYm/FpSBuZW7DrSB6YXJ1xI1lbmEgamVobyB1bmlrw6F0bm9zdC48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KPC9yb290Pg==\"","export default \"data:application/octet-stream;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxyb290Pg0KICAgIDx4c2Q6c2NoZW1hIGlkPSJyb290Ig0KICAgICAgICB4bWxucz0iIg0KICAgICAgICB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIg0KICAgICAgICB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSI+DQogICAgICAgIDx4c2Q6aW1wb3J0IG5hbWVzcGFjZT0iaHR0cDovL3d3dy53My5vcmcvWE1MLzE5OTgvbmFtZXNwYWNlIiAvPg0KICAgIDwveHNkOnNjaGVtYT4NCiAgICA8cmVzaGVhZGVyIG5hbWU9InJlc21pbWV0eXBlIj4NCiAgICAgICAgPHZhbHVlPnRleHQvbWljcm9zb2Z0LXJlc3g8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0idmVyc2lvbiI+DQogICAgICAgIDx2YWx1ZT4yLjA8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0icmVhZGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlUmVhZGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0id3JpdGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlV3JpdGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxkYXRhIG5hbWU9InNhdmluZyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5TYXZpbmc8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9ImZhaWxlZFRvU2F2ZSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5OZXBvdmVkbG8gc2UgbsOhbSB1bG/Fvml0IGRhdGEsIHprdXN0ZSB0byB6bm92dSwgcMWZw61wYWRuxJsga29udGFrdHVqdGUgcG9kcG9ydS48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9InNhdmUiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+U2F2ZTwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0ic2F2ZWQiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+U2F2ZWQ8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9InNhdmVBbmRDbG9zZSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5TYXZlIGFuZCBjbG9zZTwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0ic2F2aW5nQ2hhbmdlcyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5TYXZpbmcgY2hhbmdlcy4uLjwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0iY3JlYXRpbmdSZWNvcmQiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+Q3JlYXRpbmcgcmVjb3JkLi4uPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJjcmVhdGUiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+Q3JlYXRlPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJjbG9zZSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5DbG9zZTwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0ibWlzc2luZ1JlcXVpcmVkIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPkNhbm5vdCBzYXZlIHRoZSBmb3JtIGJlY2F1c2Ugbm90IGFsbCByZXF1aXJlZCBmaWVsZHMgYXJlIGZpbGxlZCBpbjwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0ic2F2aW5nRXJyb3IiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+RXJyb3Igd2hpbGUgc2F2aW5nIHRoZSByZWNvcmQ8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9InNlbGVjdFJlY29yZCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5TZWxlY3QgYSByZWNvcmQgdG8gdmlldyB0aGUgZm9ybS48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9InJlY29yZEluYWN0aXZlTm90aWZpY2F0aW9uIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPlJlYWQtb25seSBUaGlzIHJlY29yZCdzIHN0YXR1czo8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9IjB4ODAwNDQzMzEiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+RXJyb3Igd2hpbGUgc2F2aW5nIHRoZSByZWNvcmQuIE1heGltdW0gZmllbGQgbGVuZ3RoIGhhcyBiZWVuIGV4Y2VlZGVkLjwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0iMHg4MDE1NEI1MCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5Zb3UgZG8gbm90IGhhdmUgcGVybWlzc2lvbiB0byB3cml0ZSB0byB0aGUgZGF0YWJhc2UuIElmIHlvdSByZXF1aXJlIHRoaXMgcGVybWlzc2lvbiwgcGxlYXNlIGNvbnRhY3QgdGhlIGFkbWluaXN0cmF0b3IuPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJkdXBsaWNhdGVBbHRlcm5hdGVLZXkiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+UmVjb3JkIGNhbm5vdCBiZSBzYXZlZCBiZWNhdXNlIGl0cyB1bmlxdWVuZXNzIGlzIG5vdCBndWFyYW50ZWVkLjwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQo8L3Jvb3Q+\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9IkRlY2ltYWwiIHZlcnNpb249IjAuMC4xIg0KICAgIGRpc3BsYXktbmFtZS1rZXk9IlRBTFhJUy5QQ0YuUG9ydGFsLkRlY2ltYWwiIGRlc2NyaXB0aW9uLWtleT0iIiBjb250cm9sLXR5cGU9InN0YW5kYXJkIj4NCiAgICA8cHJvcGVydHkgbmFtZT0idmFsdWUiIGRpc3BsYXktbmFtZS1rZXk9IlZhbHVlIiBkZXNjcmlwdGlvbi1rZXk9IiIgb2YtdHlwZT0iRGVjaW1hbCINCiAgICAgIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9ImVuYWJsZURlbGV0ZUJ1dHRvbiIgZGlzcGxheS1uYW1lLWtleT0iRW5hYmxlIERlbGV0ZSBCdXR0b24iDQogICAgICBkZXNjcmlwdGlvbi1rZXk9IkVuYWJsZSBEZWxldGUgQnV0dG9uIiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJpbnB1dCINCiAgICAgIHJlcXVpcmVkPSJmYWxzZSIgLz4NCiAgICA8cHJvcGVydHkgbmFtZT0iZW5hYmxlQ29weUJ1dHRvbiIgZGlzcGxheS1uYW1lLWtleT0iRW5hYmxlIENvcHkgQnV0dG9uIg0KICAgICAgZGVzY3JpcHRpb24ta2V5PSJFbmFibGUgQ29weSBCdXR0b24iIG9mLXR5cGU9IlNpbmdsZUxpbmUuVGV4dCIgdXNhZ2U9ImlucHV0IiByZXF1aXJlZD0iZmFsc2UiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9IkVuYWJsZVNwaW5CdXR0b24iIGRpc3BsYXktbmFtZS1rZXk9IkVuYWJsZSBTcGluIEJ1dHRvbiINCiAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRW5hYmxlX0JvcmRlciIgdXNhZ2U9ImlucHV0IiBvZi10eXBlPSJFbnVtIiByZXF1aXJlZD0iZmFsc2UiPg0KICAgICAgPHZhbHVlIG5hbWU9IlllcyIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRW5hYmxlX0JvcmRlciINCiAgICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19FbmFibGVfQm9yZGVyIj50cnVlPC92YWx1ZT4NCiAgICAgIDx2YWx1ZSBuYW1lPSJObyIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRGlzYWJsZV9Cb3JkZXIiIGRlc2NyaXB0aW9uLWtleT0iQ0NfRGlzYWJsZV9Cb3JkZXJfRGVzYyINCiAgICAgICAgZGVmYXVsdD0idHJ1ZSI+ZmFsc2U8L3ZhbHVlPg0KICAgIDwvcHJvcGVydHk+DQogICAgPCEtLSBpc0NvbnRyb2xEaXNhYmxlZCBzZXRzIHJlYWQtb25seSBzdGF0ZSB3aGVyZSBGb3JjZURpc2FibGUgc2V0cyBkaXNhYmxlZCBzdGF0ZSBvZiB0aGUNCiAgICBjb250cm9sIC0tPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJGb3JjZURpc2FibGUiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0ZvcmNlRGlzYWJsZV9Db250cm9sIg0KICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19Gb3JjZURpc2FibGVfQ29udHJvbCIgdXNhZ2U9ImlucHV0IiBvZi10eXBlPSJFbnVtIiByZXF1aXJlZD0iZmFsc2UiPg0KICAgICAgPHZhbHVlIG5hbWU9IlRydWUiIGRpc3BsYXktbmFtZS1rZXk9IkNDX0Rpc2FibGVkX0NvbnRyb2wiDQogICAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRGlzYWJsZWRfQ29udHJvbF9EZXNjIj50cnVlPC92YWx1ZT4NCiAgICAgIDx2YWx1ZSBuYW1lPSJGYWxzZSIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRW5hYmxlX0NvbnRyb2wiDQogICAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRW5hYmxlX0NvbnRyb2xfRGVzYyIgZGVmYXVsdD0idHJ1ZSI+ZmFsc2U8L3ZhbHVlPg0KICAgIDwvcHJvcGVydHk+DQogICAgPHJlc291cmNlcz4NCiAgICAgIDxjb2RlIHBhdGg9ImluZGV4LnRzIiBvcmRlcj0iMSIgLz4NCiAgICA8L3Jlc291cmNlcz4NCiAgPC9jb250cm9sPg0KPC9tYW5pZmVzdD4=\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgICA8Y29udHJvbCBuYW1lc3BhY2U9IlRBTFhJUy5QQ0YuUG9ydGFsIiBjb25zdHJ1Y3Rvcj0iQ3VycmVuY3kiIHZlcnNpb249IjAuMC4xIg0KICAgICAgICBkaXNwbGF5LW5hbWUta2V5PSJUQUxYSVMuUENGLlBvcnRhbC5DdXJyZW5jeSIgZGVzY3JpcHRpb24ta2V5PSIiIGNvbnRyb2wtdHlwZT0ic3RhbmRhcmQiPg0KICAgICAgICA8cHJvcGVydHkgbmFtZT0idmFsdWUiIGRpc3BsYXktbmFtZS1rZXk9IlZhbHVlIiBkZXNjcmlwdGlvbi1rZXk9IiIgb2YtdHlwZT0iV2hvbGUuTm9uZSINCiAgICAgICAgICAgIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgICAgIDxwcm9wZXJ0eSBuYW1lPSJlbmFibGVEZWxldGVCdXR0b24iIGRpc3BsYXktbmFtZS1rZXk9IkVuYWJsZSBEZWxldGUgQnV0dG9uIg0KICAgICAgICAgICAgZGVzY3JpcHRpb24ta2V5PSJFbmFibGUgRGVsZXRlIEJ1dHRvbiIgb2YtdHlwZT0iU2luZ2xlTGluZS5UZXh0IiB1c2FnZT0iaW5wdXQiDQogICAgICAgICAgICByZXF1aXJlZD0iZmFsc2UiIC8+DQogICAgICAgIDxwcm9wZXJ0eSBuYW1lPSJlbmFibGVDb3B5QnV0dG9uIiBkaXNwbGF5LW5hbWUta2V5PSJFbmFibGUgQ29weSBCdXR0b24iDQogICAgICAgICAgICBkZXNjcmlwdGlvbi1rZXk9IkVuYWJsZSBDb3B5IEJ1dHRvbiIgb2YtdHlwZT0iU2luZ2xlTGluZS5UZXh0IiB1c2FnZT0iaW5wdXQiDQogICAgICAgICAgICByZXF1aXJlZD0iZmFsc2UiIC8+DQogICAgICAgIDxwcm9wZXJ0eSBuYW1lPSJFbmFibGVTcGluQnV0dG9uIiBkaXNwbGF5LW5hbWUta2V5PSJFbmFibGUgU3BpbiBCdXR0b24iDQogICAgICAgICAgICBkZXNjcmlwdGlvbi1rZXk9IkNDX0VuYWJsZV9TcGluX2J1dHRvbiIgdXNhZ2U9ImlucHV0IiBvZi10eXBlPSJFbnVtIiByZXF1aXJlZD0iZmFsc2UiPg0KICAgICAgICAgICAgPHZhbHVlIG5hbWU9IlllcyIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRW5hYmxlX0JvcmRlciINCiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbi1rZXk9IkNDX0VuYWJsZV9TcGluX0J1dHRvbiI+dHJ1ZTwvdmFsdWU+DQogICAgICAgICAgICA8dmFsdWUgbmFtZT0iTm8iIGRpc3BsYXktbmFtZS1rZXk9IkNDX0Rpc2FibGVfU3Bpbl9CdXR0b24iDQogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19EaXNhYmxlX1NwaW5fQnV0dG9uIg0KICAgICAgICAgICAgICAgIGRlZmF1bHQ9InRydWUiPmZhbHNlPC92YWx1ZT4NCiAgICAgICAgPC9wcm9wZXJ0eT4NCiAgICAgICAgPHJlc291cmNlcz4NCiAgICAgICAgICAgIDxjb2RlIHBhdGg9ImluZGV4LnRzIiBvcmRlcj0iMSIgLz4NCiAgICAgICAgPC9yZXNvdXJjZXM+DQogICAgPC9jb250cm9sPg0KPC9tYW5pZmVzdD4=\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9IlRleHRGaWVsZCIgdmVyc2lvbj0iMC4wLjEiDQogICAgZGlzcGxheS1uYW1lLWtleT0iVEFMWElTLlBDRi5Qb3J0YWwuVGV4dEZpZWxkIiBkZXNjcmlwdGlvbi1rZXk9IiIgY29udHJvbC10eXBlPSJzdGFuZGFyZCI+DQogICAgPHByb3BlcnR5IG5hbWU9InZhbHVlIiBkaXNwbGF5LW5hbWUta2V5PSJWYWx1ZSIgZGVzY3JpcHRpb24ta2V5PSIiIG9mLXR5cGU9IlNpbmdsZUxpbmUuRW1haWwiDQogICAgICB1c2FnZT0iYm91bmQiIHJlcXVpcmVkPSJ0cnVlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJlbmFibGVEZWxldGVCdXR0b24iIGRpc3BsYXktbmFtZS1rZXk9IkVuYWJsZSBEZWxldGUgQnV0dG9uIg0KICAgICAgZGVzY3JpcHRpb24ta2V5PSJFbmFibGUgRGVsZXRlIEJ1dHRvbiIgb2YtdHlwZT0iU2luZ2xlTGluZS5UZXh0IiB1c2FnZT0iaW5wdXQiDQogICAgICByZXF1aXJlZD0iZmFsc2UiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9ImVuYWJsZUNvcHlCdXR0b24iIGRpc3BsYXktbmFtZS1rZXk9IkVuYWJsZSBDb3B5IEJ1dHRvbiINCiAgICAgIGRlc2NyaXB0aW9uLWtleT0iRW5hYmxlIENvcHkgQnV0dG9uIiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJpbnB1dCIgcmVxdWlyZWQ9ImZhbHNlIiAvPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJFbmFibGVUeXBlU3VmZml4IiBkaXNwbGF5LW5hbWUta2V5PSJFbmFibGUgVHlwZSBTdWZmaXgiIGRlc2NyaXB0aW9uLWtleT0iIg0KICAgICAgdXNhZ2U9ImlucHV0IiBvZi10eXBlPSJFbnVtIiByZXF1aXJlZD0iZmFsc2UiPg0KICAgICAgPHZhbHVlIG5hbWU9IlllcyIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRW5hYmxlX1R5cGVfU3VmZml4Ig0KICAgICAgICBkZXNjcmlwdGlvbi1rZXk9IkNDX0VuYWJsZV9UeXBlX1N1ZmZpeCI+dHJ1ZTwvdmFsdWU+DQogICAgICA8dmFsdWUgbmFtZT0iTm8iIGRpc3BsYXktbmFtZS1rZXk9IkNDX0Rpc2FibGVfVHlwZV9TdWZmaXgiDQogICAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRGlzYWJsZV9UeXBlX1N1ZmZpeF9EZXNjIg0KICAgICAgICBkZWZhdWx0PSJ0cnVlIj5mYWxzZTwvdmFsdWU+DQogICAgPC9wcm9wZXJ0eT4NCiAgICA8IS0tIGlzQ29udHJvbERpc2FibGUgc2V0cyByZWFkLW9ubHkgc3RhdGUgd2hlcmUgRm9yY2VEaXNhYmxlZCBzZXRzIGRpc2FibGVkIHN0YXRlIG9mIHRoZQ0KICAgIGNvbnRyb2wgLS0+DQogICAgPHByb3BlcnR5IG5hbWU9IkZvcmNlRGlzYWJsZSIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRm9yY2VEaXNhYmxlX0NvbnRyb2wiDQogICAgICBkZXNjcmlwdGlvbi1rZXk9IkNDX0ZvcmNlRGlzYWJsZV9Db250cm9sIiB1c2FnZT0iaW5wdXQiIG9mLXR5cGU9IkVudW0iIHJlcXVpcmVkPSJmYWxzZSI+DQogICAgICA8dmFsdWUgbmFtZT0iVHJ1ZSIgZGlzcGxheS1uYW1lLWtleT0iQ0NfRGlzYWJsZWRfQ29udHJvbCINCiAgICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19EaXNhYmxlZF9Db250cm9sX0Rlc2MiPnRydWU8L3ZhbHVlPg0KICAgICAgPHZhbHVlIG5hbWU9IkZhbHNlIiBkaXNwbGF5LW5hbWUta2V5PSJDQ19FbmFibGVfQ29udHJvbCINCiAgICAgICAgZGVzY3JpcHRpb24ta2V5PSJDQ19FbmFibGVfQ29udHJvbF9EZXNjIiBkZWZhdWx0PSJ0cnVlIj5mYWxzZTwvdmFsdWU+DQogICAgPC9wcm9wZXJ0eT4NCiAgICA8cmVzb3VyY2VzPg0KICAgICAgPGNvZGUgcGF0aD0iaW5kZXgudHMiIG9yZGVyPSIxIiAvPg0KICAgIDwvcmVzb3VyY2VzPg0KICA8L2NvbnRyb2w+DQo8L21hbmlmZXN0Pg==\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+DQo8bWFuaWZlc3Q+DQogIDxjb250cm9sIG5hbWVzcGFjZT0iVEFMWElTLlBDRi5Qb3J0YWwiIGNvbnN0cnVjdG9yPSJUd29PcHRpb25zIiB2ZXJzaW9uPSIwLjAuMSIgZGlzcGxheS1uYW1lLWtleT0iVEFMWElTLlBDRi5Qb3J0YWwuVGV4dEZpZWxkIiBkZXNjcmlwdGlvbi1rZXk9IiIgY29udHJvbC10eXBlPSJzdGFuZGFyZCI+DQogICAgPHByb3BlcnR5IG5hbWU9InZhbHVlIiBkaXNwbGF5LW5hbWUta2V5PSJWYWx1ZSIgZGVzY3JpcHRpb24ta2V5PSIiIG9mLXR5cGU9IlR3b09wdGlvbnMiIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgPHJlc291cmNlcz4NCiAgICAgIDxjb2RlIHBhdGg9ImluZGV4LnRzIiBvcmRlcj0iMSIvPg0KICAgIDwvcmVzb3VyY2VzPg0KICA8L2NvbnRyb2w+DQo8L21hbmlmZXN0Pg==\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9IkN1cnJlbmN5IiB2ZXJzaW9uPSIwLjAuMSINCiAgICBkaXNwbGF5LW5hbWUta2V5PSJUQUxYSVMuUENGLlBvcnRhbC5DdXJyZW5jeSIgZGVzY3JpcHRpb24ta2V5PSIiIGNvbnRyb2wtdHlwZT0ic3RhbmRhcmQiPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJ2YWx1ZSIgZGlzcGxheS1uYW1lLWtleT0iVmFsdWUiIGRlc2NyaXB0aW9uLWtleT0iIiBvZi10eXBlPSJDdXJyZW5jeSINCiAgICAgIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9ImVuYWJsZURlbGV0ZUJ1dHRvbiIgZGlzcGxheS1uYW1lLWtleT0iRW5hYmxlIERlbGV0ZSBCdXR0b24iDQogICAgICBkZXNjcmlwdGlvbi1rZXk9IkVuYWJsZSBEZWxldGUgQnV0dG9uIiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJpbnB1dCINCiAgICAgIHJlcXVpcmVkPSJmYWxzZSIgLz4NCiAgICA8cHJvcGVydHkgbmFtZT0iZW5hYmxlQ29weUJ1dHRvbiIgZGlzcGxheS1uYW1lLWtleT0iRW5hYmxlIENvcHkgQnV0dG9uIg0KICAgICAgZGVzY3JpcHRpb24ta2V5PSJFbmFibGUgQ29weSBCdXR0b24iIG9mLXR5cGU9IlNpbmdsZUxpbmUuVGV4dCIgdXNhZ2U9ImlucHV0IiByZXF1aXJlZD0iZmFsc2UiIC8+DQogICAgPHByb3BlcnR5IG5hbWU9IkVuYWJsZVNwaW5CdXR0b24iIGRpc3BsYXktbmFtZS1rZXk9IkVuYWJsZSBTcGluIEJ1dHRvbiINCiAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRW5hYmxlX1NwaW5fYnV0dG9uIiB1c2FnZT0iaW5wdXQiIG9mLXR5cGU9IkVudW0iIHJlcXVpcmVkPSJmYWxzZSI+DQogICAgICA8dmFsdWUgbmFtZT0iWWVzIiBkaXNwbGF5LW5hbWUta2V5PSJDQ19FbmFibGVfQm9yZGVyIg0KICAgICAgICBkZXNjcmlwdGlvbi1rZXk9IkNDX0VuYWJsZV9TcGluX0J1dHRvbiI+dHJ1ZTwvdmFsdWU+DQogICAgICA8dmFsdWUgbmFtZT0iTm8iIGRpc3BsYXktbmFtZS1rZXk9IkNDX0Rpc2FibGVfU3Bpbl9CdXR0b24iDQogICAgICAgIGRlc2NyaXB0aW9uLWtleT0iQ0NfRGlzYWJsZV9TcGluX0J1dHRvbiINCiAgICAgICAgZGVmYXVsdD0idHJ1ZSI+ZmFsc2U8L3ZhbHVlPg0KICAgIDwvcHJvcGVydHk+DQogICAgPHJlc291cmNlcz4NCiAgICAgIDxjb2RlIHBhdGg9ImluZGV4LnRzIiBvcmRlcj0iMSIgLz4NCiAgICA8L3Jlc291cmNlcz4NCiAgPC9jb250cm9sPg0KPC9tYW5pZmVzdD4=\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLkxhYmVsIiBjb25zdHJ1Y3Rvcj0iTGFiZWwiIHZlcnNpb249IjAuMC4xIiBkaXNwbGF5LW5hbWUta2V5PSJUQUxYSVMuUENGLlBvcnRhbC5MYWJlbCIgZGVzY3JpcHRpb24ta2V5PSIiIGNvbnRyb2wtdHlwZT0ic3RhbmRhcmQiPg0KICAgIDxwcm9wZXJ0eSBuYW1lPSJ2YWx1ZSIgZGlzcGxheS1uYW1lLWtleT0iVmFsdWUiIGRlc2NyaXB0aW9uLWtleT0iIiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgPHJlc291cmNlcz4NCiAgICAgIDxjb2RlIHBhdGg9ImluZGV4LnRzIiBvcmRlcj0iMSIgLz4NCiAgICA8L3Jlc291cmNlcz4NCiAgPC9jb250cm9sPg0KPC9tYW5pZmVzdD4=\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGIiBjb25zdHJ1Y3Rvcj0iV2ViUGFnZSIgdmVyc2lvbj0iMC4wLjEiIGRpc3BsYXktbmFtZS1rZXk9IldlYlBhZ2UiIGRlc2NyaXB0aW9uLWtleT0iV2ViUGFnZSBkZXNjcmlwdGlvbiIgY29udHJvbC10eXBlPSJzdGFuZGFyZCI+DQogICAgPCEtLWV4dGVybmFsLXNlcnZpY2UtdXNhZ2Ugbm9kZSBkZWNsYXJlcyB3aGV0aGVyIHRoaXMgM3JkIHBhcnR5IFBDRiBjb250cm9sIGlzIHVzaW5nIGV4dGVybmFsIHNlcnZpY2Ugb3Igbm90LCBpZiB5ZXMsIHRoaXMgY29udHJvbCB3aWxsIGJlIGNvbnNpZGVyZWQgYXMgcHJlbWl1bSBhbmQgcGxlYXNlIGFsc28gYWRkIHRoZSBleHRlcm5hbCBkb21haW4gaXQgaXMgdXNpbmcuDQogICAgSWYgaXQgaXMgbm90IHVzaW5nIGFueSBleHRlcm5hbCBzZXJ2aWNlLCBwbGVhc2Ugc2V0IHRoZSBlbmFibGVkPSJmYWxzZSIgYW5kIERPIE5PVCBhZGQgYW55IGRvbWFpbiBiZWxvdy4gVGhlICJlbmFibGVkIiB3aWxsIGJlIGZhbHNlIGJ5IGRlZmF1bHQuDQogICAgRXhhbXBsZTE6DQogICAgICA8ZXh0ZXJuYWwtc2VydmljZS11c2FnZSBlbmFibGVkPSJ0cnVlIj4NCiAgICAgICAgPGRvbWFpbj53d3cuTWljcm9zb2Z0LmNvbTwvZG9tYWluPg0KICAgICAgPC9leHRlcm5hbC1zZXJ2aWNlLXVzYWdlPg0KICAgIEV4YW1wbGUyOg0KICAgICAgPGV4dGVybmFsLXNlcnZpY2UtdXNhZ2UgZW5hYmxlZD0iZmFsc2UiPg0KICAgICAgPC9leHRlcm5hbC1zZXJ2aWNlLXVzYWdlPg0KICAgIC0tPg0KICAgIDxleHRlcm5hbC1zZXJ2aWNlLXVzYWdlIGVuYWJsZWQ9ImZhbHNlIj4NCiAgICAgIDwhLS1VTkNPTU1FTlQgVE8gQUREIEVYVEVSTkFMIERPTUFJTlMNCiAgICAgIDxkb21haW4+PC9kb21haW4+DQogICAgICA8ZG9tYWluPjwvZG9tYWluPg0KICAgICAgLS0+DQogICAgPC9leHRlcm5hbC1zZXJ2aWNlLXVzYWdlPg0KICAgIDwhLS0gcHJvcGVydHkgbm9kZSBpZGVudGlmaWVzIGEgc3BlY2lmaWMsIGNvbmZpZ3VyYWJsZSBwaWVjZSBvZiBkYXRhIHRoYXQgdGhlIGNvbnRyb2wgZXhwZWN0cyBmcm9tIENEUyAtLT4NCiAgICA8cHJvcGVydHkgbmFtZT0ic2FtcGxlUHJvcGVydHkiIGRpc3BsYXktbmFtZS1rZXk9IlByb3BlcnR5X0Rpc3BsYXlfS2V5IiBkZXNjcmlwdGlvbi1rZXk9IlByb3BlcnR5X0Rlc2NfS2V5IiBvZi10eXBlPSJTaW5nbGVMaW5lLlRleHQiIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgPCEtLQ0KICAgICAgUHJvcGVydHkgbm9kZSdzIG9mLXR5cGUgYXR0cmlidXRlIGNhbiBiZSBvZi10eXBlLWdyb3VwIGF0dHJpYnV0ZS4NCiAgICAgIEV4YW1wbGU6DQogICAgICA8dHlwZS1ncm91cCBuYW1lPSJudW1iZXJzIj4NCiAgICAgICAgPHR5cGU+V2hvbGUuTm9uZTwvdHlwZT4NCiAgICAgICAgPHR5cGU+Q3VycmVuY3k8L3R5cGU+DQogICAgICAgIDx0eXBlPkZQPC90eXBlPg0KICAgICAgICA8dHlwZT5EZWNpbWFsPC90eXBlPg0KICAgICAgPC90eXBlLWdyb3VwPg0KICAgICAgPHByb3BlcnR5IG5hbWU9InNhbXBsZVByb3BlcnR5IiBkaXNwbGF5LW5hbWUta2V5PSJQcm9wZXJ0eV9EaXNwbGF5X0tleSIgZGVzY3JpcHRpb24ta2V5PSJQcm9wZXJ0eV9EZXNjX0tleSIgb2YtdHlwZS1ncm91cD0ibnVtYmVycyIgdXNhZ2U9ImJvdW5kIiByZXF1aXJlZD0idHJ1ZSIgLz4NCiAgICAtLT4NCiAgICA8cmVzb3VyY2VzPg0KICAgICAgPGNvZGUgcGF0aD0iaW5kZXgudHMiIG9yZGVyPSIxIiAvPg0KICAgICAgPCEtLSBVTkNPTU1FTlQgVE8gQUREIE1PUkUgUkVTT1VSQ0VTDQogICAgICA8Y3NzIHBhdGg9ImNzcy9XZWJQYWdlLmNzcyIgb3JkZXI9IjEiIC8+DQogICAgICA8cmVzeCBwYXRoPSJzdHJpbmdzL1dlYlBhZ2UuMTAzMy5yZXN4IiB2ZXJzaW9uPSIxLjAuMCIgLz4NCiAgICAgIC0tPg0KICAgIDwvcmVzb3VyY2VzPg0KICAgIDwhLS0gVU5DT01NRU5UIFRPIEVOQUJMRSBUSEUgU1BFQ0lGSUVEIEFQSQ0KICAgIDxmZWF0dXJlLXVzYWdlPg0KICAgICAgPHVzZXMtZmVhdHVyZSBuYW1lPSJEZXZpY2UuY2FwdHVyZUF1ZGlvIiByZXF1aXJlZD0idHJ1ZSIgLz4NCiAgICAgIDx1c2VzLWZlYXR1cmUgbmFtZT0iRGV2aWNlLmNhcHR1cmVJbWFnZSIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgICA8dXNlcy1mZWF0dXJlIG5hbWU9IkRldmljZS5jYXB0dXJlVmlkZW8iIHJlcXVpcmVkPSJ0cnVlIiAvPg0KICAgICAgPHVzZXMtZmVhdHVyZSBuYW1lPSJEZXZpY2UuZ2V0QmFyY29kZVZhbHVlIiByZXF1aXJlZD0idHJ1ZSIgLz4NCiAgICAgIDx1c2VzLWZlYXR1cmUgbmFtZT0iRGV2aWNlLmdldEN1cnJlbnRQb3NpdGlvbiIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgICA8dXNlcy1mZWF0dXJlIG5hbWU9IkRldmljZS5waWNrRmlsZSIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgICA8dXNlcy1mZWF0dXJlIG5hbWU9IlV0aWxpdHkiIHJlcXVpcmVkPSJ0cnVlIiAvPg0KICAgICAgPHVzZXMtZmVhdHVyZSBuYW1lPSJXZWJBUEkiIHJlcXVpcmVkPSJ0cnVlIiAvPg0KICAgIDwvZmVhdHVyZS11c2FnZT4NCiAgICAtLT4NCiAgPC9jb250cm9sPg0KPC9tYW5pZmVzdD4=\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxtYW5pZmVzdD4NCiAgPGNvbnRyb2wgbmFtZXNwYWNlPSJUQUxYSVMuUENGLlBvcnRhbCIgY29uc3RydWN0b3I9IkR1cmF0aW9uIiB2ZXJzaW9uPSIwLjAuMSIgZGlzcGxheS1uYW1lLWtleT0iVEFMWElTLlBDRi5Qb3J0YWwuRHVyYXRpb24iIGRlc2NyaXB0aW9uLWtleT0iIiBjb250cm9sLXR5cGU9InN0YW5kYXJkIj4NCiAgICA8cHJvcGVydHkgbmFtZT0idmFsdWUiIGRpc3BsYXktbmFtZS1rZXk9IlZhbHVlIiBkZXNjcmlwdGlvbi1rZXk9IiIgb2YtdHlwZT0iV2hvbGUuRHVyYXRpb24iIHVzYWdlPSJib3VuZCIgcmVxdWlyZWQ9InRydWUiIC8+DQogICAgPHJlc291cmNlcz4NCiAgICAgIDxjb2RlIHBhdGg9ImluZGV4LnRzIiBvcmRlcj0iMSIgLz4NCiAgICA8L3Jlc291cmNlcz4NCiAgPC9jb250cm9sPg0KPC9tYW5pZmVzdD4=\"","export default \"data:application/octet-stream;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxyb290Pg0KICAgIDx4c2Q6c2NoZW1hIGlkPSJyb290Ig0KICAgICAgICB4bWxucz0iIg0KICAgICAgICB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIg0KICAgICAgICB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSI+DQogICAgICAgIDx4c2Q6aW1wb3J0IG5hbWVzcGFjZT0iaHR0cDovL3d3dy53My5vcmcvWE1MLzE5OTgvbmFtZXNwYWNlIiAvPg0KICAgIDwveHNkOnNjaGVtYT4NCiAgICA8cmVzaGVhZGVyIG5hbWU9InJlc21pbWV0eXBlIj4NCiAgICAgICAgPHZhbHVlPnRleHQvbWljcm9zb2Z0LXJlc3g8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0idmVyc2lvbiI+DQogICAgICAgIDx2YWx1ZT4yLjA8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0icmVhZGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlUmVhZGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0id3JpdGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlV3JpdGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxkYXRhIG5hbWU9ImZvcm1hdE1pbnV0ZXMiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+bWludXRhLG1pbnV0eSxtaW51dHksbWludXQsbWluLG08L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9ImZvcm1hdEhvdXJzIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPmhvZGluYSxob2RpbnksaG9kaW55LGhvZGluLGgsaG9kPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJmb3JtYXREYXlzIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPmRlbixkbmUsZG55LGRuw60sZCxkbsWvPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJkdXJhdGlvbkVycm9yTWVzc2FnZSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5Ew6lsa2EgdHJ2w6Fuw606IETDqWxrYSBtdXPDrSB6YWTDoW5hIHYgbsOhc2xlZHVqw61jw61tIGZvcm3DoXR1OiB4IG1pbnV0LCB4IGhvZGluLCBuZWJvIHggZG7DrS4gSG9kaW55IGEgZG55IG1vaG91IGLDvXQgemFkw6FueSBzIGRlc2V0aW5ub3UgxI3DoXJrb3UsIG5hcMWZw61rbGFkLCB4LnggaG9kaW4sIG5lYm8geC54IGRuw60uPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJkdXJhdGlvbkxpbWl0RXJyb3JNZXNzYWdlIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPkRvYmEgdHJ2w6Fuw606IFphZGVqdGUgcG/EjWV0IG1pbnV0IG1lemkgMCBhIDIgMTQ3IDQ4MyA2NDcuPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCjwvcm9vdD4=\"","export default \"data:application/octet-stream;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxyb290Pg0KICAgIDx4c2Q6c2NoZW1hIGlkPSJyb290Ig0KICAgICAgICB4bWxucz0iIg0KICAgICAgICB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIg0KICAgICAgICB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSI+DQogICAgICAgIDx4c2Q6aW1wb3J0IG5hbWVzcGFjZT0iaHR0cDovL3d3dy53My5vcmcvWE1MLzE5OTgvbmFtZXNwYWNlIiAvPg0KICAgIDwveHNkOnNjaGVtYT4NCiAgICA8cmVzaGVhZGVyIG5hbWU9InJlc21pbWV0eXBlIj4NCiAgICAgICAgPHZhbHVlPnRleHQvbWljcm9zb2Z0LXJlc3g8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0idmVyc2lvbiI+DQogICAgICAgIDx2YWx1ZT4yLjA8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0icmVhZGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlUmVhZGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0id3JpdGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlV3JpdGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxkYXRhIG5hbWU9ImZvcm1hdE1pbnV0ZXMiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+bWludXRlLG1pbnV0ZXMsbSxtaW48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9ImZvcm1hdEhvdXJzIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPmhvdXIsaG91cnMsaDwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0iZm9ybWF0RGF5cyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5kYXksZGF5cyxkPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJkdXJhdGlvbkVycm9yTWVzc2FnZSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5EdXJhdGlvbjogVGhlIGR1cmF0aW9uIG11c3QgYmUgZW50ZXJlZCBpbiB0aGUgZm9sbG93aW5nIGZvcm1hdDogeCBtaW51dGVzLCB4IGhvdXJzIG9yIHggZGF5cy4gSG91cnMgYW5kIGRheXMgY2FuIGFsc28gYmUgZW50ZXJlZCB1c2luZyBkZWNpbWFscywgZm9yIGV4YW1wbGUsIHgueCBob3VycyBvciB4LnggZGF5cy48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9ImR1cmF0aW9uTGltaXRFcnJvck1lc3NhZ2UiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+RHVyYXRpb246IEVudGVyIGEgbnVtYmVyIGJldHdlZW4gMCBhbmQgMiwxNDcsNDgzLDY0Ny48L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KPC9yb290Pg==\"","export default \"data:text/xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+DQo8bWFuaWZlc3Q+DQogIDxjb250cm9sIG5hbWVzcGFjZT0iVEFMWElTLlBDRi5Qb3J0YWwiIGNvbnN0cnVjdG9yPSJGaWxlQ29udHJvbCIgdmVyc2lvbj0iMC4wLjEiIGRpc3BsYXktbmFtZS1rZXk9IlRBTFhJUy5QQ0YuUG9ydGFsLkZpbGUiIGRlc2NyaXB0aW9uLWtleT0iIiBjb250cm9sLXR5cGU9InN0YW5kYXJkIj4NCiAgICA8cHJvcGVydHkgbmFtZT0idmFsdWUiIGRpc3BsYXktbmFtZS1rZXk9IlZhbHVlIiBkZXNjcmlwdGlvbi1rZXk9IiIgb2YtdHlwZT0iRmlsZSIgdXNhZ2U9ImJvdW5kIiByZXF1aXJlZD0idHJ1ZSIgLz4NCiAgICA8cmVzb3VyY2VzPg0KICAgICAgPGNvZGUgcGF0aD0iaW5kZXgudHMiIG9yZGVyPSIxIi8+DQogICAgPC9yZXNvdXJjZXM+DQogIDwvY29udHJvbD4NCjwvbWFuaWZlc3Q+\"","export default \"data:application/octet-stream;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxyb290Pg0KICAgIDx4c2Q6c2NoZW1hIGlkPSJyb290Ig0KICAgICAgICB4bWxucz0iIg0KICAgICAgICB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIg0KICAgICAgICB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSI+DQogICAgICAgIDx4c2Q6aW1wb3J0IG5hbWVzcGFjZT0iaHR0cDovL3d3dy53My5vcmcvWE1MLzE5OTgvbmFtZXNwYWNlIiAvPg0KICAgIDwveHNkOnNjaGVtYT4NCiAgICA8cmVzaGVhZGVyIG5hbWU9InJlc21pbWV0eXBlIj4NCiAgICAgICAgPHZhbHVlPnRleHQvbWljcm9zb2Z0LXJlc3g8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0idmVyc2lvbiI+DQogICAgICAgIDx2YWx1ZT4yLjA8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0icmVhZGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlUmVhZGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0id3JpdGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlV3JpdGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxkYXRhIG5hbWU9InNhdmVSZWNvcmQiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+TmVqcHJ2ZSB1bG/FvnRlIHrDoXpuYW0uIFBvdMOpIG3Fr8W+ZXRlIG5haHLDoXQgc291Ym9yLjwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0idXBsb2FkQnV0dG9uVGV4dCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5OYWhyw6F0IHNvdWJvcjwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0iZGVsZXRlRmlsZSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5PcHJhdmR1IGNoY2V0ZSBzb3Vib3Igc21hemF0PzwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0idXBsb2FkSW5Qcm9ncmVzcyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5Qcm9iw61ow6EgbmFocsOhbsOtPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCiAgICA8ZGF0YSBuYW1lPSJkZWxldGVJblByb2dyZXNzIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgPHZhbHVlPnByb2LDrWjDoSBzbWF6w6Fuw608L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KPC9yb290Pg==\"","export default \"data:application/octet-stream;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxyb290Pg0KICAgIDx4c2Q6c2NoZW1hIGlkPSJyb290Ig0KICAgICAgICB4bWxucz0iIg0KICAgICAgICB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIg0KICAgICAgICB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSI+DQogICAgICAgIDx4c2Q6aW1wb3J0IG5hbWVzcGFjZT0iaHR0cDovL3d3dy53My5vcmcvWE1MLzE5OTgvbmFtZXNwYWNlIiAvPg0KICAgIDwveHNkOnNjaGVtYT4NCiAgICA8cmVzaGVhZGVyIG5hbWU9InJlc21pbWV0eXBlIj4NCiAgICAgICAgPHZhbHVlPnRleHQvbWljcm9zb2Z0LXJlc3g8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0idmVyc2lvbiI+DQogICAgICAgIDx2YWx1ZT4yLjA8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0icmVhZGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlUmVhZGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxyZXNoZWFkZXIgbmFtZT0id3JpdGVyIj4NCiAgICAgICAgPHZhbHVlPlN5c3RlbS5SZXNvdXJjZXMuUmVzWFJlc291cmNlV3JpdGVyLCBTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODk8L3ZhbHVlPg0KICAgIDwvcmVzaGVhZGVyPg0KICAgIDxkYXRhIG5hbWU9InNhdmVSZWNvcmQiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+VGhpcyByZWNvcmQgaGFzbid0IGJlZW4gY3JlYXRlZCB5ZXQuIFRvIGVuYWJsZSBmaWxlIHVwbG9hZCwgY3JlYXRlIHRoaXMgcmVjb3JkLjwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0idXBsb2FkQnV0dG9uVGV4dCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5VcGxvYWQgZmlsZTwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0iZGVsZXRlRmlsZSIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5BcmUgeW91IHN1cmUgeW91IHdhbnQgdG8gZGVsZXRlIHRoZSBmaWxlPzwvdmFsdWU+DQogICAgICAgIDxjb21tZW50PjwvY29tbWVudD4NCiAgICA8L2RhdGE+DQogICAgPGRhdGEgbmFtZT0idXBsb2FkSW5Qcm9ncmVzcyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQogICAgICAgIDx2YWx1ZT5VcGxvYWQgaW4gcHJvZ3Jlc3M8L3ZhbHVlPg0KICAgICAgICA8Y29tbWVudD48L2NvbW1lbnQ+DQogICAgPC9kYXRhPg0KICAgIDxkYXRhIG5hbWU9ImRlbGV0ZUluUHJvZ3Jlc3MiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KICAgICAgICA8dmFsdWU+RGVsZXRlIGluIHByb2dyZXNzPC92YWx1ZT4NCiAgICAgICAgPGNvbW1lbnQ+PC9jb21tZW50Pg0KICAgIDwvZGF0YT4NCjwvcm9vdD4=\"","export const DomParser = new DOMParser();\r\nexport const FRONTEND_VERSION = import.meta.env.VITE_BUILD_VERSION;\r\nexport const APPLICATION_RIBBON_ENTITY_NAME = '_talxis_application_ribbon';\r\nexport const DEFAULT_BODY_MAIN_BACKGROUND_COLOR = '#faf9f8';\r\nexport const SCRIPT_ISOLATION = false;","import { Manifest } from \"@controls/interfaces/manifest\";\r\nimport { DataType } from \"@ComponentFramework/interfaces/DataType\";\r\nimport { DomParser } from \"../../Constants\";\r\n\r\nconst _parseDatasets = (datasetCollection: HTMLCollectionOf): Manifest.DataSet[] => {\r\n const properties: Manifest.DataSet[] = [];\r\n for (const property of datasetCollection) {\r\n properties.push({\r\n name: property.getAttribute('name'),\r\n cdsOptions: property.getAttribute('cds-data-set-options'),\r\n });\r\n }\r\n return properties;\r\n};\r\n\r\nconst _parseProperties = (propertyCollection: HTMLCollectionOf): Manifest.Property[] => {\r\n const properties: Manifest.Property[] = [];\r\n for (const property of propertyCollection) {\r\n properties.push({\r\n name: property.getAttribute('name'),\r\n // TODO: We need to handle mapping of type groups\r\n ofType: property.getAttribute('of-type') as DataType,\r\n ofTypeGroup: property.getAttribute('of-type-group'),\r\n\r\n usage: property.getAttribute('usage') as (\"bound\" | \"input\")\r\n });\r\n }\r\n return properties;\r\n};\r\n\r\nconst _parseCode = (codeElement: Element): Manifest.Code => {\r\n const code: Manifest.Code = {\r\n path: `/controls/${codeElement.getAttribute('path')}`,\r\n order: codeElement.getAttribute('order')\r\n };\r\n return code;\r\n};\r\nconst _parseLibraries = (libraryElements?: HTMLCollectionOf): Manifest.Library[] => {\r\n if (!libraryElements) {\r\n return [];\r\n }\r\n return [...libraryElements].map(x => {\r\n const lib: Manifest.Library = {\r\n name: (x.parentElement.getAttribute('name')),\r\n library_version: (x.parentElement.getAttribute('version')),\r\n path: x.getAttribute('path'),\r\n version: x.getAttribute('version')\r\n };\r\n return lib;\r\n });\r\n};\r\nconst _parsePlatformLibraries = (libararyElements?: HTMLCollectionOf): Manifest.PlatformLibrary[] => {\r\n if (!libararyElements) {\r\n return undefined;\r\n }\r\n return [...libararyElements].map(x => {\r\n const lib: Manifest.PlatformLibrary = {\r\n name: x.getAttribute('name'),\r\n version: x.getAttribute('version')\r\n };\r\n return lib;\r\n });\r\n};\r\nconst _parseCss = (cssElements?: HTMLCollectionOf): Manifest.CSS[] => {\r\n if (!cssElements) {\r\n return [];\r\n }\r\n return [...cssElements].map(x => {\r\n return {\r\n path: x.getAttribute('path'),\r\n order: x.getAttribute('order')\r\n };\r\n });\r\n};\r\n\r\nconst _parseImg = (imgElements: NodeListOf): Manifest.Img[] => {\r\n return [...imgElements].map(x => {\r\n return {\r\n path: x.getAttribute('path'),\r\n };\r\n });\r\n};\r\n\r\nconst _parseResx = (resxElements?: HTMLCollectionOf): Manifest.Resx[] => {\r\n if (!resxElements) {\r\n return undefined;\r\n }\r\n return [...resxElements].map(x => {\r\n return {\r\n path: x.getAttribute('path')\r\n };\r\n });\r\n};\r\n\r\nconst _parseResources = (resourceElement: Element): Manifest.Resources => {\r\n const resources: Manifest.Resources = {\r\n code: _parseCode(resourceElement.getElementsByTagName('code')[0]),\r\n platformLibraries: _parsePlatformLibraries(resourceElement.getElementsByTagName('platform-library')),\r\n libraries: _parseLibraries(resourceElement.getElementsByTagName('packaged_library')),\r\n css: _parseCss(resourceElement.getElementsByTagName('css')),\r\n resx: _parseResx(resourceElement.getElementsByTagName('resx')),\r\n img: _parseImg(resourceElement.querySelectorAll('img'))\r\n };\r\n return resources;\r\n};\r\n\r\nconst _parseControl = (controlElement: Element): Manifest.Control => {\r\n const control: Manifest.Control = {\r\n namespace: controlElement.getAttribute('namespace'),\r\n constructor: controlElement.getAttribute('constructor'),\r\n properties: _parseProperties(controlElement.getElementsByTagName('property')),\r\n datasets: _parseDatasets(controlElement.getElementsByTagName('data-set')),\r\n resources: _parseResources(controlElement.getElementsByTagName('resources')[0]),\r\n typeGroups: _parseTypeGroups(controlElement),\r\n controlType: controlElement.getAttribute('control-type')\r\n };\r\n return control;\r\n};\r\nconst _parseTypeGroups = (controlElement: Element): Manifest.TypeGroup[] => {\r\n const typeGroups = controlElement.querySelectorAll('type-group');\r\n const result: Manifest.TypeGroup[] = [];\r\n for (const typeGroup of typeGroups) {\r\n result.push({\r\n name: typeGroup.getAttribute('name'),\r\n types: (() => {\r\n const result: string[] = [];\r\n const types = typeGroup.querySelectorAll('type');\r\n for (const type of types) {\r\n result.push(type.innerHTML);\r\n }\r\n return result;\r\n })()\r\n });\r\n }\r\n return result;\r\n};\r\nexport class ManifestMapper {\r\n public static map(manifestXml: string): Manifest.Control {\r\n const xmlDoc = DomParser.parseFromString(manifestXml, \"text/xml\");\r\n const manifest = _parseControl(xmlDoc.getElementsByTagName('control')[0]);\r\n return manifest;\r\n }\r\n}","import { IWebResource } from \"../../interfaces/IWebResource\";\r\nimport { metadataRetrieveMultiple, getWebResourceUrl } from \"@definitions/MetadataApi\";\r\nimport { DomParser } from \"../../Constants\";\r\nimport { IPromiseCache, cachedWrapper } from \"@utilities/MemoryCachingHelpers\";\r\n\r\nexport class ScriptLoader {\r\n private static _script: IPromiseCache = {};\r\n private static _libraryWithDependencies: IPromiseCache = {};\r\n private static _libraryDepdencies: IPromiseCache = {};\r\n private static _resx: IPromiseCache<{ [key: string]: string }> = {};\r\n\r\n static loadAsync(name: string, url: string, targetDocument?: HTMLIFrameElement): Promise {\r\n let cache = this._script;\r\n if (targetDocument) {\r\n if (!targetDocument.contentWindow._cachedScripts) {\r\n targetDocument.contentWindow._cachedScripts = {};\r\n }\r\n cache = targetDocument.contentWindow._cachedScripts;\r\n }\r\n\r\n return cachedWrapper(name, () => new Promise((resolve, reject) => {\r\n const script: HTMLScriptElement = document.createElement(\"script\");\r\n script.async = true;\r\n\r\n if (!url.startsWith('/') && !url.startsWith('http')) {\r\n //TODO: Scripts should be loaded from metadata service.\r\n // script.src = `data:text/javascript;base64,${url}`\r\n script.innerHTML = this._b64DecodeUnicode(url);\r\n resolve(true);\r\n }\r\n else {\r\n script.src = url;\r\n }\r\n\r\n script.onload = () => {\r\n resolve(true);\r\n };\r\n script.onerror = () => {\r\n reject(new Error(`Unable to load script ${name} from ${url}!`));\r\n };\r\n\r\n if (targetDocument) {\r\n targetDocument.contentWindow.document.head?.appendChild(script);\r\n }\r\n else {\r\n document.body.appendChild(script);\r\n }\r\n\r\n console.log(`Loading remote webresource ${name} to the DOM.`, targetDocument);\r\n }), cache);\r\n }\r\n\r\n private static async _getDependencies(libraryName: string): Promise {\r\n return cachedWrapper(libraryName, () => new Promise(async (resolve, reject) => {\r\n const dependencies: string[] = [];\r\n\r\n const webResourceDefinitions = await metadataRetrieveMultiple(`v9.1/webresourceset?$select=dependencyxml&$filter=name eq '${libraryName}' and webresourcetype eq 3`);\r\n\r\n if (webResourceDefinitions?.entities && webResourceDefinitions.entities.length === 1) {\r\n const webResourceDefinition = webResourceDefinitions.entities[0];\r\n\r\n if (webResourceDefinition.dependencyxml) {\r\n const dependencyXmlDoc = DomParser.parseFromString(webResourceDefinition.dependencyxml, \"text/xml\");\r\n const libraries = dependencyXmlDoc.querySelectorAll('Library');\r\n\r\n for (const libDependency of libraries) {\r\n const libDependencyName = libDependency.getAttribute('name');\r\n dependencies.push(libDependencyName);\r\n }\r\n }\r\n resolve(dependencies);\r\n }\r\n else {\r\n reject(`Web Resource Library ${libraryName} could not be loaded! Check if it is available in the system.`);\r\n }\r\n }), this._libraryDepdencies);\r\n }\r\n\r\n static async loadWebResourceLibraryAndDependencies(libraryName: string, targetDocument?: HTMLIFrameElement): Promise {\r\n const webResource: IWebResource = {\r\n translations: {}\r\n };\r\n const name = targetDocument ? `${targetDocument.getAttribute('id')}: ${libraryName}` : libraryName;\r\n\r\n let cache = this._libraryWithDependencies;\r\n if (targetDocument) {\r\n if (!targetDocument.contentWindow._cachedWebResources) {\r\n targetDocument.contentWindow._cachedWebResources = {};\r\n }\r\n cache = targetDocument.contentWindow._cachedWebResources;\r\n }\r\n\r\n return cachedWrapper(name, () => new Promise(async (resolve, reject) => {\r\n try {\r\n const dependencies = await ScriptLoader._getDependencies(libraryName);\r\n for (const dependency of dependencies) {\r\n if (dependency.endsWith(\".resx\")) {\r\n const resxNameWithLanguageId = dependency.substr(0, dependency.indexOf(\".resx\"));\r\n\r\n if (resxNameWithLanguageId.endsWith(`${window.Xrm.Utility.getGlobalContext().userSettings.languageId}`)) {\r\n const resxName = dependency.substr(0, resxNameWithLanguageId.lastIndexOf(\".\"));\r\n const resx = await this._fetchResxAsync(dependency);\r\n webResource.translations[resxName] = resx;\r\n }\r\n } else {\r\n const nestedWebResource = await this.loadWebResourceLibraryAndDependencies(dependency, targetDocument);\r\n webResource.translations = { ...webResource.translations, ...nestedWebResource.translations };\r\n }\r\n }\r\n\r\n window.TALXIS.Portal.WebResouces = { ...window.TALXIS.Portal.WebResouces, ...webResource.translations };\r\n await this.loadAsync(libraryName, getWebResourceUrl(`webresources/${libraryName}`), targetDocument);\r\n resolve(webResource);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n }), cache);\r\n }\r\n\r\n private static async _fetchResxAsync(name: string): Promise<{ [key: string]: string }> {\r\n return cachedWrapper(name, () => new Promise(async (resolve, reject) => {\r\n const response = await metadataRetrieveMultiple(`v9.1/webresourceset?$select=contentjson&$filter=webresourcetype eq 12 and name eq '${name}'`);\r\n resolve(JSON.parse(response.entities[0][\"contentjson\"]));\r\n }), this._resx);\r\n }\r\n\r\n public static _b64DecodeUnicode(str: string): string {\r\n return decodeURIComponent(atob(str).split('').map(function (c) {\r\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);\r\n }).join(''));\r\n }\r\n}","import { ScriptLoader } from \"./ScriptLoader\";\r\n\r\n// TODO: Thse files should be served locally, but since we are not encouraging to use platform libraries, we can just fallback to the remote ones\r\n\r\nexport const loadReact = async () => {\r\n // This has to be loaded in proper order\r\n await ScriptLoader.loadAsync(\"react_17\", \"https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js\");\r\n await ScriptLoader.loadAsync(\"react-dom_17\", \"https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js\");\r\n};\r\nexport const loadFluentUiV8 = async () => {\r\n await ScriptLoader.loadAsync(\"fluentui_v8\", \"https://cdnjs.cloudflare.com/ajax/libs/fluentui-react/8.29.0/fluentui-react.min.js\");\r\n // @ts-ignore - Fluent V8 only populates window.FluentUIReact, but we need it also in FluentUIReactv8290 for compatibility with PCF\r\n window.FluentUIReactv8290 = window.FluentUIReact;\r\n};\r\nexport const loadFluentUiV9 = async () => {\r\n throw new Error(\"FluentUI V9 is not supported yet!\");\r\n\r\n await ScriptLoader.loadAsync(\"fluentui_v9\", \"/static/libraries/fluentui-react_9.19.1.js\");\r\n // @ts-ignore - Fluent V9 only populates window.FluentUIReactV9, but we need it also in FluentUIReactv940 for compatibility with PCF\r\n window.FluentUIReactv940 = window.FluentUIReactV9;\r\n};","import React from 'react';\r\nimport ReactDOM from \"react-dom\";\r\nimport { TextField as TextFieldComponent } from \"@talxis/base-controls\";\r\nimport { ITextField } from \"@talxis/base-controls\";\r\n\r\ninterface IInputs {\r\n value: ComponentFramework.PropertyTypes.StringProperty;\r\n enableDeleteButton?: ComponentFramework.PropertyTypes.StringProperty;\r\n enableCopyButton?: ComponentFramework.PropertyTypes.StringProperty;\r\n EnableTypeSuffix?: ComponentFramework.PropertyTypes.EnumProperty<\"true\" | \"false\">;\r\n ForceDisable?: ComponentFramework.PropertyTypes.StringProperty;\r\n}\r\ninterface IOutputs {\r\n value?: string;\r\n}\r\n\r\nexport class TextField implements ComponentFramework.StandardControl {\r\n private _notifyOutputChanged: () => void;\r\n private _container: HTMLDivElement;\r\n private _outputs: IOutputs = {};\r\n constructor() { }\r\n\r\n public init(context: ComponentFramework.Context, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container: HTMLDivElement) {\r\n this._notifyOutputChanged = notifyOutputChanged;\r\n this._container = container;\r\n }\r\n public updateView(context: ComponentFramework.Context): void {\r\n ReactDOM.render(React.createElement(TextFieldComponent, {\r\n context: context,\r\n parameters: {\r\n value: context.parameters.value,\r\n EnableDeleteButton: {\r\n raw: context.parameters.enableDeleteButton?.raw === 'true'\r\n },\r\n EnableCopyButton: {\r\n raw: context.parameters.enableCopyButton?.raw === 'true'\r\n },\r\n ForceDisable: {\r\n raw: context.parameters.ForceDisable?.raw === 'true'\r\n },\r\n EnableTypeSuffix: {\r\n raw: context.parameters.EnableTypeSuffix?.raw === 'false' ? false : true\r\n },\r\n },\r\n onNotifyOutputChanged: (outputs) => {\r\n this._outputs = outputs;\r\n this._notifyOutputChanged();\r\n }\r\n } as ITextField), this._container);\r\n }\r\n\r\n public getOutputs(): IOutputs {\r\n return this._outputs;\r\n }\r\n\r\n public destroy(): void {\r\n ReactDOM.unmountComponentAtNode(this._container);\r\n }\r\n}","import React from 'react';\r\nimport ReactDOM from \"react-dom\";\r\nimport { DateTime as DateTimeComponent } from \"@talxis/base-controls\";\r\nimport { IDateTime } from \"@talxis/base-controls\";\r\n\r\ninterface IInputs {\r\n value: ComponentFramework.PropertyTypes.DateTimeProperty;\r\n enableDeleteButton?: ComponentFramework.PropertyTypes.StringProperty;\r\n HideMonthSelection?: ComponentFramework.PropertyTypes.StringProperty;\r\n hideDaySelection?: ComponentFramework.PropertyTypes.StringProperty;\r\n RestrictedDaysOfWeek?: ComponentFramework.PropertyTypes.StringProperty;\r\n RestrictedDates?: ComponentFramework.PropertyTypes.StringProperty;\r\n ForceDisable?: ComponentFramework.PropertyTypes.StringProperty;\r\n}\r\ninterface IOutputs {\r\n value?: Date;\r\n}\r\n\r\nexport class DateTime implements ComponentFramework.StandardControl {\r\n private _notifyOutputChanged: () => void;\r\n private _container: HTMLDivElement;\r\n private _outputs: IOutputs = {};\r\n\r\n constructor() { }\r\n\r\n public init(context: ComponentFramework.Context, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container: HTMLDivElement) {\r\n this._notifyOutputChanged = notifyOutputChanged;\r\n this._container = container;\r\n }\r\n public updateView(context: ComponentFramework.Context): void {\r\n ReactDOM.render(React.createElement(DateTimeComponent, {\r\n context: context,\r\n parameters: {\r\n value: context.parameters.value,\r\n EnableDeleteButton: {\r\n raw: true\r\n },\r\n ForceDisable: {\r\n raw: context.parameters.ForceDisable?.raw === 'true'\r\n },\r\n EnableDayPicker: {\r\n raw: context.parameters.hideDaySelection?.raw === 'true' ? false : true\r\n },\r\n EnableMonthPicker: {\r\n raw: context.parameters.HideMonthSelection?.raw === 'true' ? false : true\r\n },\r\n RestrictedDaysOfWeek: {\r\n raw: context.parameters.RestrictedDaysOfWeek?.raw\r\n },\r\n RestrictedDates: {\r\n raw: context.parameters.RestrictedDates?.raw\r\n }\r\n },\r\n onNotifyOutputChanged: (outputs) => {\r\n this._outputs = outputs;\r\n this._notifyOutputChanged();\r\n }\r\n } as IDateTime), this._container);\r\n }\r\n\r\n public getOutputs(): IOutputs {\r\n return this._outputs;\r\n }\r\n\r\n public destroy(): void {\r\n ReactDOM.unmountComponentAtNode(this._container);\r\n }\r\n}","import React from 'react';\r\nimport ReactDOM from \"react-dom\";\r\nimport { ILookup } from \"@talxis/base-controls\";\r\nimport { Lookup as LookupComponent } from \"@talxis/base-controls\";\r\n\r\ninterface IInputs {\r\n value: ComponentFramework.PropertyTypes.LookupProperty;\r\n IsInlineNewEnabled?: ComponentFramework.PropertyTypes.StringProperty;\r\n MultipleEnabled?: ComponentFramework.PropertyTypes.StringProperty;\r\n EnableNavigation: ComponentFramework.PropertyTypes.StringProperty;\r\n ForceDisable?: ComponentFramework.PropertyTypes.StringProperty;\r\n}\r\ninterface IOutputs {\r\n value?: ComponentFramework.LookupValue[];\r\n}\r\n\r\nexport class Lookup implements ComponentFramework.StandardControl {\r\n private _notifyOutputChanged: () => void;\r\n private _container: HTMLDivElement;\r\n private _outputs: IOutputs = {};\r\n\r\n constructor() { }\r\n\r\n public init(context: ComponentFramework.Context, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container: HTMLDivElement) {\r\n this._notifyOutputChanged = notifyOutputChanged;\r\n this._container = container;\r\n }\r\n public updateView(context: ComponentFramework.Context): void {\r\n ReactDOM.render(React.createElement(LookupComponent, {\r\n context: context,\r\n parameters: {\r\n value: context.parameters.value,\r\n EnableNavigation: {\r\n raw: context.parameters.EnableNavigation?.raw === 'false' ? false : true\r\n },\r\n IsInlineNewEnabled: {\r\n raw: context.parameters.IsInlineNewEnabled?.raw === 'true'\r\n },\r\n MultipleEnabled: {\r\n raw: context.parameters.MultipleEnabled?.raw === 'true'\r\n },\r\n ForceDisable: {\r\n raw: context.parameters.ForceDisable?.raw === 'true'\r\n }\r\n\r\n },\r\n onNotifyOutputChanged: (outputs: any) => {\r\n this._outputs = outputs;\r\n this._notifyOutputChanged();\r\n }\r\n } as any), this._container);\r\n }\r\n\r\n public getOutputs(): IOutputs {\r\n return this._outputs;\r\n }\r\n\r\n public destroy(): void {\r\n ReactDOM.unmountComponentAtNode(this._container);\r\n }\r\n}","import { ApplicationInsights, DistributedTracingModes } from '@microsoft/applicationinsights-web';\r\nimport { ReactPlugin } from '@microsoft/applicationinsights-react-js';\r\nimport { FRONTEND_VERSION } from '@app/Constants';\r\n\r\nlet reactPlugin: ReactPlugin = null;\r\nlet appInsights: ApplicationInsights = null;\r\n\r\nlet AI_DEBUG = false;\r\n\r\n/**\r\n * Create the App Insights Telemetry Service\r\n * @return {{reactPlugin: ReactPlugin, appInsights: Object, initialize: Function}} - Object\r\n */\r\nconst createTelemetryService = () => {\r\n\r\n /**\r\n * Initialize the Application Insights class\r\n * @param {string} connectionString - Application Insights Connection string\r\n * @param {Object} browserHistory - client's browser history, supplied by the withRouter HOC\r\n * @return {void}\r\n */\r\n const initialize = (connectionString: string, browserHistory: History, appId: string) => {\r\n if (!browserHistory) {\r\n throw new Error('Could not initialize Telemetry Service');\r\n }\r\n if (!connectionString) {\r\n throw new Error('Connection string not provided in ./src/telemetry-provider.jsx');\r\n }\r\n\r\n // let debugPlugin = null;\r\n // let debugPluginInstance = null;\r\n // if (AI_DEBUG) {\r\n // // Run `npm i @microsoft/applicationinsights-debugplugin-js`\r\n // debugPlugin = require(\"@microsoft/applicationinsights-debugplugin-js\").DebugPlugin;\r\n // debugPluginInstance = new debugPlugin();\r\n // }\r\n\r\n reactPlugin = new ReactPlugin();\r\n\r\n appInsights = new ApplicationInsights({\r\n config: {\r\n appId: appId,\r\n connectionString: connectionString,\r\n maxBatchInterval: 10000, //Batch telemetry every 10 seconds\r\n disableFetchTracking: false,\r\n enableCorsCorrelation: true,\r\n enableRequestHeaderTracking: true,\r\n enableResponseHeaderTracking: true,\r\n distributedTracingMode: DistributedTracingModes.AI_AND_W3C,\r\n correlationHeaderExcludedDomains: [\r\n '*.smartsuppchat.com',\r\n '*.smartsuppcdn.com',\r\n // Exclusion for CORS for https://www.cloudflare.com/cdn-cgi/trace\r\n 'www.cloudflare.com',\r\n // Exclusion for PCFs\r\n 'maps.googleapis.com'\r\n ],\r\n extensions: [\r\n // ...(AI_DEBUG === true ? [debugPluginInstance] : []),\r\n reactPlugin\r\n ],\r\n extensionConfig: {\r\n // ...(AI_DEBUG === true && {\r\n // [debugPlugin.identifier]: {\r\n // trackers: [\r\n // 'trackEvent',\r\n // 'trackPageView',\r\n // 'trackPageViewPerformance',\r\n // 'trackException',\r\n // 'trackTrace',\r\n // 'trackMetric',\r\n // 'trackDependencyData',\r\n // 'throwInternal', // called when a message is logged internally\r\n // 'logInternalMessage', // called when a message is logged internally\r\n // 'triggerSend', // called when data is queued to be sent to the server\r\n // '_sender', // called when data is sent to the server\r\n // ]\r\n // }\r\n // }),\r\n [reactPlugin.identifier]: {\r\n history: browserHistory\r\n }\r\n }\r\n }\r\n });\r\n\r\n appInsights.loadAppInsights();\r\n\r\n appInsights.context.application.ver = FRONTEND_VERSION;\r\n\r\n appInsights.addTelemetryInitializer((item) => {\r\n // Filter out ResizeObserver loop errors as per - https://github.com/microsoft/ApplicationInsights-JS/issues/1300\r\n if (item.name.includes(\"Exception\") || item.name.includes(\"exception\")) {\r\n if (item.data.message.includes(\"ResizeObserver loop limit exceeded\") === true) {\r\n return false;\r\n }\r\n }\r\n });\r\n };\r\n\r\n return { reactPlugin, appInsights, initialize };\r\n};\r\n\r\nexport const ai = createTelemetryService();\r\nexport const getAppInsights = () => appInsights;","import * as Msal from '@azure/msal-browser';\r\nimport { CommonSilentFlowRequest } from '@azure/msal-common';\r\nimport { StringDict } from '@azure/msal-common';\r\nimport { User } from '../interfaces/general';\r\nimport { SpaConfiguration } from '@configuration/SpaConfiguration';\r\nimport { MultitenantProvider } from './MultitenantProvider';\r\nimport { getClient, getUserProvisioningEndpointOverrideHeader } from '../Functions';\r\nimport { getAppInsights } from '@providers/TelemetryProvider/TelemetryService';\r\nimport { ClientAuthError } from '@azure/msal-browser';\r\n\r\nexport enum AuthenticationSource {\r\n B2B = \"b2b\",\r\n B2C = \"b2c\",\r\n TokenInQuery = \"tokenInQuery\",\r\n Anonymous = \"anonymous\"\r\n}\r\n\r\nexport class Authentication {\r\n private static _msalInstance: Msal.PublicClientApplication;\r\n private static _user: User = null;\r\n private static _msalUser: Msal.AccountInfo = null;\r\n private static _tokenPromise: Promise;\r\n private static _authenticationSource: AuthenticationSource = AuthenticationSource.Anonymous;\r\n private static _authenticationSourceSet: boolean = false;\r\n private static _loginRequest: Msal.RedirectRequest = {\r\n scopes: [\"openid\", \"profile\"]\r\n };\r\n private static readonly _redirectUrl: string = \"https://client.talxis.com/shared/sso.html\";\r\n public static getUser(): User {\r\n return this._user;\r\n }\r\n public static isAuthenticated(): boolean {\r\n return this._user !== null;\r\n }\r\n // state property is not supported in BaseAuthRequest or SilentRequest, but it is used internally and we need to pass it for iframe token pickup to work\r\n private static async _getTokenRequest(): Promise & { state: string }> {\r\n return {\r\n scopes: SpaConfiguration.get().apiScopes,\r\n state: this._createState(window.location.href),\r\n account: this._msalUser,\r\n forceRefresh: false\r\n };\r\n }\r\n private static _setAppInsightsUserContext(): void {\r\n const ai = getAppInsights();\r\n if (ai && this._user) {\r\n ai.setAuthenticatedUserContext(this._user.accessPrincipalId, null, true);\r\n }\r\n }\r\n private static _clearAppInsightsUserContext(): void {\r\n const ai = getAppInsights();\r\n if (ai) {\r\n ai.clearAuthenticatedUserContext();\r\n }\r\n }\r\n private static _filterAccounts(accounts: Msal.AccountInfo[]): Msal.AccountInfo[] {\r\n const spaConfiguration = SpaConfiguration.get();\r\n const environment = new URL(spaConfiguration.authority);\r\n const allowedEnvironments = [environment.hostname];\r\n if (environment.hostname === \"login.microsoftonline.com\") {\r\n allowedEnvironments.push(\"login.windows.net\");\r\n }\r\n let matchPolicy = false;\r\n if (this._isB2c()) {\r\n matchPolicy = true;\r\n }\r\n return accounts.filter(account => {\r\n return (\r\n allowedEnvironments.includes(account.environment) &&\r\n (!matchPolicy || account.idTokenClaims[\"tfp\"] == spaConfiguration.b2cLoginPolicy)\r\n );\r\n });\r\n }\r\n public static async trySilentLoginAsync(): Promise {\r\n await this._getMsalInstanceAsync();\r\n\r\n let tokenResponse = await this._msalInstance.handleRedirectPromise();\r\n // We are returning from authorization server, run the proper login pipeline\r\n if (tokenResponse) {\r\n return this.loginAsync();\r\n }\r\n let accounts = this._filterAccounts(this._msalInstance.getAllAccounts());\r\n let token: Msal.AuthenticationResult;\r\n\r\n if (isTokenInQuery()) {\r\n this._authenticationSource = AuthenticationSource.TokenInQuery;\r\n\r\n if (accounts.length > 0) {\r\n await Xrm.Navigation.openAlertDialog({\r\n title: \"Multiple sign-in sessions detected!\",\r\n text: \"You are currently signed-in with an account, however a token has been provided explicitly in the URL. If you proceed further, the token in the URL will be used.\",\r\n confirmButtonLabel: \"OK\"\r\n });\r\n }\r\n\r\n try {\r\n this._user = await this._callWhoAmI();\r\n }\r\n catch (error) {\r\n // TODO: Display gracefully error coming from whoami endpoint\r\n throw error;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n if (accounts.length === 1) {\r\n try {\r\n token = await this._msalInstance.acquireTokenSilent({\r\n ...await this._getTokenRequest(),\r\n account: accounts[0]\r\n });\r\n }\r\n catch (err) {\r\n }\r\n }\r\n else if (accounts.length > 1) {\r\n // Attempt to match one of many accounts to the current authority\r\n let foundAccount = false;\r\n const spaConfiguration = SpaConfiguration.get();\r\n const environment = new URL(spaConfiguration.authority);\r\n for (const account of accounts) {\r\n if (account.environment === environment.hostname) {\r\n try {\r\n token = await this._msalInstance.acquireTokenSilent({\r\n ...await this._getTokenRequest(),\r\n account: account\r\n });\r\n accounts = [account];\r\n foundAccount = true;\r\n break;\r\n }\r\n catch (err) {\r\n }\r\n }\r\n }\r\n if (!foundAccount) {\r\n // If there are multiple accounts, log all the accounts out locally (clear cache)\r\n for (const account of accounts) {\r\n try {\r\n await this._msalInstance.logoutRedirect({\r\n onRedirectNavigate: (url) => {\r\n return false;\r\n },\r\n account: account\r\n });\r\n } catch (error) {\r\n if (error instanceof ClientAuthError) {\r\n // Mitigation for https://github.com/AzureAD/microsoft-authentication-library-for-android/issues/1779 where `tid` doesn't return from B2C when not using custom policy\r\n if (error.errorCode === \"no_account_found\") {\r\n console.warn(\"No account found in cache, skipping logout attempt.\", account, error);\r\n continue;\r\n }\r\n }\r\n throw error;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (token) {\r\n this._msalUser = accounts[0];\r\n\r\n try {\r\n this._user = await this._callWhoAmI(this._msalUser);\r\n } catch (error) {\r\n console.error(error);\r\n return false;\r\n }\r\n\r\n Authentication._setAppInsightsUserContext();\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n public static async loginAsync(popup?: boolean): Promise {\r\n if (popup) {\r\n throw new Error('Popup login is currently not supported!');\r\n }\r\n await this._getMsalInstanceAsync();\r\n let tokenResponse = await this._msalInstance.handleRedirectPromise();\r\n const accounts = this._filterAccounts(this._msalInstance.getAllAccounts());\r\n let token: Msal.AuthenticationResult;\r\n // Check if we can successfully obtain a token\r\n if (accounts.length === 1) {\r\n this._msalUser = accounts[0];\r\n try {\r\n token = await this._msalInstance.acquireTokenSilent({\r\n ...await this._getTokenRequest(),\r\n account: accounts[0]\r\n });\r\n }\r\n catch (err) {\r\n }\r\n }\r\n else if (accounts.length > 1) {\r\n // If there are multiple accounts, log all the accounts out locally (clear cache)\r\n for (const account of accounts) {\r\n try {\r\n await this._msalInstance.logoutRedirect({\r\n onRedirectNavigate: (url) => {\r\n return false;\r\n },\r\n account: account\r\n });\r\n } catch (error) {\r\n if (error instanceof ClientAuthError) {\r\n // Mitigation for https://github.com/AzureAD/microsoft-authentication-library-for-android/issues/1779 where `tid` doesn't return from B2C when not using custom policy\r\n if (error.errorCode === \"no_account_found\") {\r\n console.warn(\"No account found in cache, skipping logout attempt.\", account, error);\r\n continue;\r\n }\r\n }\r\n throw error;\r\n }\r\n }\r\n }\r\n if (!tokenResponse && !token) {\r\n const result = await this._handleLogin({ ...this._loginRequest, state: this._createState(window.location.href) });\r\n if (!result) return false;\r\n\r\n tokenResponse = result;\r\n }\r\n if (tokenResponse) {\r\n let originalUrl = this._getState(tokenResponse.state ?? \"\");\r\n if (originalUrl && originalUrl != \"\" && originalUrl != window.location.href) {\r\n window.location.replace(originalUrl);\r\n }\r\n else {\r\n if (!this._msalUser) this._msalUser = tokenResponse.account;\r\n\r\n try {\r\n this._user = await this._callWhoAmI(this._msalUser);\r\n } catch (error) {\r\n console.error(error);\r\n throw error;\r\n }\r\n Authentication._setAppInsightsUserContext();\r\n }\r\n return true;\r\n }\r\n else if (token) {\r\n this._msalUser = accounts[0];\r\n\r\n try {\r\n this._user = await this._callWhoAmI(this._msalUser);\r\n } catch (error) {\r\n console.error(error);\r\n await this._handleLogin({ ...this._loginRequest, state: this._createState(window.location.href) });\r\n return false;\r\n }\r\n\r\n Authentication._setAppInsightsUserContext();\r\n return true;\r\n }\r\n };\r\n /**\r\n * Internal force login handle - either redirect, attempt silent SSO or create a pop-up\r\n */\r\n private static async _handleLogin(request?: Msal.RedirectRequest): Promise {\r\n if (getClient() !== \"Outlook\") {\r\n window.TALXIS.Portal.Context?.SetLoading(true);\r\n await this._msalInstance.loginRedirect(request);\r\n return null;\r\n }\r\n else {\r\n // TODO: This should be UPN, however EXO returns primary email address, in case it is different, we will need to go with pop-up since the SSO will fail\r\n // @ts-ignore - Office types are not resolved for some reason\r\n const username = Office.context.mailbox.userProfile.emailAddress;\r\n try {\r\n const result = await this._msalInstance.ssoSilent({ ...request, loginHint: username });\r\n return result;\r\n }\r\n catch (err) {\r\n console.error(\"Failed to obtain token via ssoSilent!\", err);\r\n // TODO: Attempt to login via pop-up\r\n throw err;\r\n }\r\n }\r\n }\r\n public static async loginRedirect(extraQueryParameters?: StringDict, redirectStartPage?: string, domainHint?: string, authority?: string): Promise {\r\n await this._getMsalInstanceAsync();\r\n\r\n const tokenResponse = await this._msalInstance.handleRedirectPromise();\r\n\r\n if (tokenResponse) {\r\n let originalUrl = this._getState(tokenResponse.state ?? \"\");\r\n if (originalUrl && originalUrl != \"\" && originalUrl != window.location.href) {\r\n window.location.replace(originalUrl);\r\n }\r\n }\r\n else {\r\n const request: Msal.RedirectRequest = {\r\n ...this._loginRequest,\r\n state: this._createState(redirectStartPage ? redirectStartPage : null),\r\n extraQueryParameters: extraQueryParameters,\r\n authority: authority,\r\n account: this._msalUser\r\n };\r\n\r\n if (domainHint) {\r\n request.domainHint = domainHint;\r\n }\r\n\r\n return this._msalInstance.loginRedirect(request);\r\n }\r\n };\r\n public static async getAuthorizationHeader(requireToken: boolean = false): Promise {\r\n const request: RequestInit = {\r\n headers: {\r\n ...((this.isAuthenticated() || requireToken) && { 'Authorization': `Bearer ${await this._getTokenAsync()}` })\r\n }\r\n };\r\n return request;\r\n }\r\n public static async logout(): Promise {\r\n if (this.getAuthenticationSource() === AuthenticationSource.TokenInQuery) {\r\n window.location.replace(window.location.origin + window.location.pathname + window.location.search);\r\n }\r\n else if ([AuthenticationSource.B2B, AuthenticationSource.B2C].includes(this.getAuthenticationSource())) {\r\n this._clearAppInsightsUserContext();\r\n await this._msalInstance.logoutRedirect({\r\n account: this._msalUser\r\n });\r\n }\r\n }\r\n public static async profileEditRedirect(): Promise {\r\n if (this.getAuthenticationSource() === AuthenticationSource.TokenInQuery) {\r\n await Xrm.Navigation.openAlertDialog({\r\n title: \"Profile edit is not available\",\r\n text: \"You are currently signed-in with a token provided explicitly in the URL. Profile edit is not available in this mode.\",\r\n confirmButtonLabel: \"OK\"\r\n });\r\n }\r\n else if ([AuthenticationSource.B2B, AuthenticationSource.B2C].includes(this.getAuthenticationSource())) {\r\n await this._getMsalInstanceAsync();\r\n if (this._filterAccounts(this._msalInstance.getAllAccounts()).length === 1) {\r\n if (this._isB2c()) {\r\n const spaConfiguration = SpaConfiguration.get();\r\n this._msalInstance.loginRedirect({\r\n ...this._loginRequest,\r\n state: this._createState(window.location.href),\r\n authority: spaConfiguration.authority + spaConfiguration.b2cProfileEditPolicy,\r\n account: this._msalUser\r\n });\r\n }\r\n else {\r\n window.open(\"https://myaccount.microsoft.com\", \"_blank\");\r\n }\r\n }\r\n }\r\n\r\n await Xrm.Navigation.openAlertDialog({\r\n title: \"Profile edit is not available\",\r\n text: \"You are not currently signed-in. Profile edit is not available in this mode.\",\r\n confirmButtonLabel: \"OK\"\r\n });\r\n }\r\n public static async isProfileEditRedirectAvailable(): Promise {\r\n if ([AuthenticationSource.B2B, AuthenticationSource.B2C].includes(this.getAuthenticationSource())) {\r\n await this._getMsalInstanceAsync();\r\n if (this._filterAccounts(this._msalInstance.getAllAccounts()).length === 1) {\r\n if (this._isB2c()) {\r\n const spaConfiguration = SpaConfiguration.get();\r\n if (spaConfiguration.b2cProfileEditPolicy && spaConfiguration.b2cProfileEditPolicy !== \"\") {\r\n return true;\r\n }\r\n else {\r\n return false;\r\n }\r\n }\r\n else {\r\n return true;\r\n }\r\n }\r\n }\r\n else {\r\n return false;\r\n }\r\n }\r\n public static async passwordChangeRedirect(): Promise {\r\n if (this.getAuthenticationSource() === AuthenticationSource.TokenInQuery) {\r\n await Xrm.Navigation.openAlertDialog({\r\n title: \"Password change is not available\",\r\n text: \"You are currently signed-in with a token provided explicitly in the URL. Password change is not available in this mode.\",\r\n confirmButtonLabel: \"OK\"\r\n });\r\n return;\r\n }\r\n else if ([AuthenticationSource.B2B, AuthenticationSource.B2C].includes(this.getAuthenticationSource())) {\r\n await this._getMsalInstanceAsync();\r\n if (this._filterAccounts(this._msalInstance.getAllAccounts()).length === 1) {\r\n if (this._isB2c()) {\r\n const spaConfiguration = SpaConfiguration.get();\r\n this._msalInstance.loginRedirect({\r\n ...this._loginRequest,\r\n prompt: \"login\",\r\n state: this._createState(window.location.href),\r\n authority: spaConfiguration.authority + spaConfiguration.b2cPasswordChangePolicy,\r\n account: this._msalUser\r\n });\r\n\r\n }\r\n else {\r\n window.open(\"https://account.activedirectory.windowsazure.com/ChangePassword.aspx\", \"_blank\");\r\n }\r\n }\r\n }\r\n else {\r\n await Xrm.Navigation.openAlertDialog({\r\n title: \"Password change is not available\",\r\n text: \"You are not currently signed-in. Password change is not available in this mode.\",\r\n confirmButtonLabel: \"OK\"\r\n });\r\n }\r\n }\r\n private static _getMsalInstanceAsync(): void {\r\n if (this._msalInstance) return;\r\n\r\n const spaConfiguration = SpaConfiguration.get();\r\n const msalLogging = localStorage.getItem('msalLogging') === \"true\";\r\n const msalConfig: Msal.Configuration = {\r\n auth: {\r\n clientId: spaConfiguration.clientId,\r\n authority: spaConfiguration.authority + (this._isB2c() ? spaConfiguration.b2cLoginPolicy : \"\"),\r\n redirectUri: this._redirectUrl,\r\n knownAuthorities: [spaConfiguration.authority],\r\n },\r\n cache: {\r\n cacheLocation: \"localStorage\",\r\n storeAuthStateInCookie: false\r\n },\r\n system: {\r\n // https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-logging-js\r\n ...msalLogging && {\r\n loggerOptions: {\r\n logLevel: Msal.LogLevel.Trace,\r\n loggerCallback: (level, message, containsPii) => {\r\n // if (containsPii) {\r\n // return;\r\n // }\r\n switch (level) {\r\n case Msal.LogLevel.Error:\r\n console.error(message);\r\n return;\r\n case Msal.LogLevel.Info:\r\n console.info(message);\r\n return;\r\n case Msal.LogLevel.Verbose:\r\n case Msal.LogLevel.Trace:\r\n console.debug(message);\r\n return;\r\n case Msal.LogLevel.Warning:\r\n console.warn(message);\r\n return;\r\n }\r\n },\r\n piiLoggingEnabled: true\r\n }\r\n }\r\n }\r\n };\r\n this._msalInstance = new Msal.PublicClientApplication(msalConfig);\r\n }\r\n private static async _getTokenAsync(): Promise {\r\n try {\r\n if (isTokenInQuery()) {\r\n return getTokenFromQuery();\r\n }\r\n else {\r\n const response = await this._msalInstance.acquireTokenSilent(await this._getTokenRequest());\r\n return response.accessToken;\r\n }\r\n }\r\n catch (err) {\r\n console.error(\"Failed to obtain token silently!\", err);\r\n if (!this._tokenPromise) {\r\n this._tokenPromise = new Promise(async (resolve) => {\r\n window.TALXIS.Portal.Translations.getLocalizedString('');\r\n await Xrm.Navigation.openAlertDialog({\r\n text: window.TALXIS.Portal.Translations.getLocalizedString('@app/classes/Authentication/SessionExpiredDialogText'),\r\n title: window.TALXIS.Portal.Translations.getLocalizedString('@app/classes/Authentication/SessionExpiredDialogTitle'),\r\n confirmButtonLabel: window.TALXIS.Portal.Translations.getLocalizedString('@app/classes/Authentication/SessionExpiredDialogButton')\r\n });\r\n const authenticationResult = await this._msalInstance.loginPopup({\r\n scopes: SpaConfiguration.get().apiScopes,\r\n state: this._createPopupState(window.location.href),\r\n\r\n });\r\n resolve(authenticationResult.accessToken);\r\n return;\r\n });\r\n }\r\n const result = await this._tokenPromise;\r\n this._tokenPromise = null;\r\n return result;\r\n }\r\n }\r\n private static _isB2c(): boolean {\r\n const spaConfiguration = SpaConfiguration.get();\r\n if (spaConfiguration.b2cLoginPolicy) {\r\n return true;\r\n }\r\n else {\r\n return false;\r\n }\r\n }\r\n private static _createState(customData: any): string {\r\n const state: IPortalState = {\r\n __ssoRedirectUrl: `${window.location.protocol}//${window.location.host}`,\r\n __customData: customData\r\n };\r\n return btoa(JSON.stringify(state));\r\n }\r\n private static _getState(state: string): any {\r\n try {\r\n return (JSON.parse(atob(state)) as IPortalState).__customData;\r\n }\r\n catch (e) {\r\n console.warn(\"Failed to parse and deserialize incoming state\", state);\r\n return null;\r\n }\r\n }\r\n private static _createPopupState(customData: any): string {\r\n const state: IPortalState = {\r\n __ssoRedirectUrl: `${window.location.protocol}//${window.location.host}/sso/sso.html`,\r\n __customData: customData\r\n };\r\n return btoa(JSON.stringify(state));\r\n }\r\n\r\n public static getAuthenticationSource(): AuthenticationSource {\r\n // TODO: If user logs in during an anonymous session, we should handle this change, but probably via refresh to reload every dependency (like pickers)\r\n if (!this._authenticationSourceSet) {\r\n if (isTokenInQuery()) {\r\n this._authenticationSource = AuthenticationSource.TokenInQuery;\r\n }\r\n else if (this._user && this._msalUser) {\r\n if (this._isB2c()) {\r\n this._authenticationSource = AuthenticationSource.B2C;\r\n }\r\n else {\r\n this._authenticationSource = AuthenticationSource.B2B;\r\n }\r\n }\r\n else {\r\n this._authenticationSource = AuthenticationSource.Anonymous;\r\n }\r\n this._authenticationSourceSet = true;\r\n }\r\n\r\n return this._authenticationSource;\r\n }\r\n\r\n private static async _callWhoAmI(msalUser?: Msal.AccountInfo): Promise {\r\n let response = await fetch(SpaConfiguration.get().edsApi + '/v9.1/whoami', {\r\n headers: {\r\n ...MultitenantProvider.getFetchHeader().headers,\r\n ...(await this.getAuthorizationHeader(true)).headers,\r\n ...getUserProvisioningEndpointOverrideHeader().headers\r\n }\r\n });\r\n\r\n if (!response.ok) {\r\n const contentType = response.headers.get(\"content-type\");\r\n let errorMessage = response.statusText;\r\n if (contentType && contentType.indexOf(\"application/json\") !== -1) {\r\n const errorDetails = await response.json();\r\n errorMessage = errorDetails?.message ?? errorMessage;\r\n }\r\n else {\r\n errorMessage = await response.text();\r\n }\r\n throw new Error(`Authentication error! ${response.status}: ${response.statusText}\\n\\n${errorMessage}`);\r\n }\r\n\r\n var responseContent = await response.json();\r\n const user: User = {\r\n accessPrincipalId: responseContent.accessPrincipalId,\r\n userPrincipalName: responseContent.userPrincipalName,\r\n displayName: responseContent.displayName\r\n };\r\n\r\n return user;\r\n }\r\n};\r\n\r\nexport const requireAuthentication = async (): Promise => {\r\n if (Authentication.isAuthenticated()) {\r\n return false;\r\n }\r\n else {\r\n return Authentication.loginAsync();\r\n }\r\n};\r\n\r\nconst TOKEN_QUERY_PARAM = \"token\";\r\nconst isTokenInQuery = (): boolean => {\r\n const searchParams = new URLSearchParams(window.location.hash.substring(1));\r\n return searchParams.has(TOKEN_QUERY_PARAM);\r\n};\r\nconst getTokenFromQuery = (): string => {\r\n const searchParams = new URLSearchParams(window.location.hash.substring(1));\r\n return searchParams.get(TOKEN_QUERY_PARAM);\r\n};\r\n\r\ninterface IPortalState {\r\n __ssoRedirectUrl: string;\r\n __customData: any;\r\n}","import { DEFAULT_LANGUAGE } from \"@src/localization/helpers\";\r\nimport lcid from \"lcid\";\r\nimport { NUMBER_OF_RECORDS_PER_VIEW_PAGE } from \"../definitions/UserSettingsDefinition\";\r\nimport { DateFormattingInfo, Formatting, NumberFormattingInfo } from \"@talxis/client-libraries\";\r\n\r\ninterface IAccessPrincipalDetails {\r\n id: string;\r\n username?: string;\r\n languageId?: number;\r\n pagingLimit?: number;\r\n settingsId?: string\r\n}\r\n\r\nconst DEFAULT_RECORDS_PER_VIEW_PAGE = 100;\r\n\r\nexport class UserSettings implements ComponentFramework.UserSettings {\r\n public readonly dateFormattingInfo: DateFormattingInfo;\r\n public readonly locale: string;\r\n public readonly isRTL: boolean;\r\n public readonly languageId: number;\r\n public readonly numberFormattingInfo: NumberFormattingInfo;\r\n //is part of globalContext UserSettings in Power Apps\r\n public readonly formatInfoCultureName: string;\r\n public readonly securityRoles: string[];\r\n public readonly userId: string;\r\n public readonly userName: string;\r\n private _pagingLimit: number;\r\n private _accessPrincipalSettingsId?: string;\r\n\r\n constructor(accessPrincipalDetails?: IAccessPrincipalDetails) {\r\n this.userId = accessPrincipalDetails?.id ?? null;\r\n this.userName = accessPrincipalDetails?.username ?? null;\r\n this._pagingLimit = accessPrincipalDetails?.pagingLimit ?? DEFAULT_RECORDS_PER_VIEW_PAGE;\r\n this._accessPrincipalSettingsId = accessPrincipalDetails?.settingsId;\r\n this.locale = this._getLocale(accessPrincipalDetails?.languageId);\r\n this.formatInfoCultureName = this.locale;\r\n this.languageId = this._getLanguageId(accessPrincipalDetails?.languageId);\r\n this.numberFormattingInfo = Formatting.Get(this.locale).numberFormattingInfo;\r\n this.dateFormattingInfo = Formatting.Get(this.locale).dateFormattingInfo;\r\n }\r\n\r\n public getTimeZoneOffsetMinutes(date?: Date): number {\r\n throw new Error(\"Method not implemented.\");\r\n }\r\n /**\r\n * Returns local browser's timezone offset in miliseconds\r\n */\r\n public getLocalTimeZoneOffset(): number {\r\n return (new Date()).getTimezoneOffset() * 60000;\r\n }\r\n\r\n public async setPagingLimit(pageSize: number) {\r\n const optionSetValue = NUMBER_OF_RECORDS_PER_VIEW_PAGE.find(x => x.value == pageSize)?.id;\r\n if (!optionSetValue || !this._accessPrincipalSettingsId) {\r\n return;\r\n }\r\n this._pagingLimit = pageSize;\r\n return window.Xrm.WebApi.updateRecord('talxis_accessprincipalsettings', this._accessPrincipalSettingsId, {\r\n talxis_numberofrecordsperviewpagetypecode: optionSetValue\r\n });\r\n }\r\n\r\n public get pagingLimit() {\r\n return this._pagingLimit;\r\n }\r\n /**\r\n * Returns current user's timezone offset in miliseconds from talxis_accessprincipalsettings in future\r\n */\r\n public getConfiguredUserTimeZoneOffset(): number {\r\n return (new Date()).getTimezoneOffset() * 60000;\r\n }\r\n private _getLanguageId(languageId?: number) {\r\n return languageId ?? lcid.to(this._getLocale().replace('-', '_'));\r\n }\r\n private _getLocale(languageId?: number) {\r\n if (languageId) {\r\n return lcid.from(languageId).replace('_', '-');\r\n }\r\n const browserLocale = navigator.languages[0];\r\n const browserLocaleLCID = lcid.to(browserLocale.replace('-', '_'));\r\n //if the browser LCID has portal translations, use it\r\n if (window.TALXIS.Portal.Translations._builtinTranslations?.[browserLocaleLCID]) {\r\n return browserLocale;\r\n }\r\n return lcid.from(DEFAULT_LANGUAGE).replace('_', '-');\r\n }\r\n}","import { Authentication } from \"../Authentication\";\r\nimport { UserSettings } from \"../models/UserSettings\";\r\n\r\nexport const NUMBER_OF_RECORDS_PER_VIEW_PAGE = [\r\n { id: 742070000, value: 25 },\r\n { id: 742070001, value: 50 },\r\n { id: 742070002, value: 100 },\r\n { id: 742070003, value: 250 }\r\n];\r\n\r\nexport class UserSettingsDefinition {\r\n private static _userSettings: UserSettings;\r\n public static async load(accessPrincipalId?: string): Promise {\r\n if (this._userSettings) {\r\n return this._userSettings;\r\n }\r\n if (!accessPrincipalId) {\r\n this._userSettings = new UserSettings();\r\n }\r\n else {\r\n try {\r\n const retrievedUserSettings = await Xrm.WebApi.retrieveRecord(\"talxis_accessprincipal\", accessPrincipalId, \"?$select=talxis_accessprincipalid&$expand=talxis_accessprincipalsettingsid($select=talxis_language,talxis_numberofrecordsperviewpagetypecode),talxis_contactid($select=emailaddress1)\");\r\n this._userSettings = new UserSettings({\r\n id: accessPrincipalId,\r\n settingsId: retrievedUserSettings?.['talxis_accessprincipalsettingsid']?.['talxis_accessprincipalsettingsid'],\r\n username: Authentication.getUser().displayName,\r\n languageId: retrievedUserSettings?.['talxis_accessprincipalsettingsid']?.['talxis_language'],\r\n pagingLimit: NUMBER_OF_RECORDS_PER_VIEW_PAGE.find(x => x.id === retrievedUserSettings?.['talxis_accessprincipalsettingsid']?.['talxis_numberofrecordsperviewpagetypecode'])?.value\r\n });\r\n }\r\n catch (ex) {\r\n console.warn(\"UserSettings\", \"Unable to retrieve user settings, falling back to built-in defaults!\", ex);\r\n this._userSettings = new UserSettings({\r\n id: accessPrincipalId,\r\n username: Authentication.getUser()?.displayName\r\n });\r\n }\r\n }\r\n return this._userSettings;\r\n }\r\n\r\n public static getUserSettings() {\r\n if (!this._userSettings) {\r\n throw new Error('User definition has not been loaded. Have you called UserSettingsDefinition.load()?');\r\n }\r\n return this._userSettings;\r\n }\r\n}","import { UserSettingsDefinition } from \"@src/app/classes/definitions/UserSettingsDefinition\";\r\n\r\nexport interface ILocalizedLabel {\r\n LanguageCode: number;\r\n Label: string;\r\n}\r\n\r\nexport const DEFAULT_LANGUAGE = 1029;\r\nexport const FALLBACK_LANGUAGE = 1033;\r\n\r\n// TODO: This should be merged with TALXIX.Portal.Localization user language retrieval\r\nexport const LocalizeLabel = (localizedLabels: ILocalizedLabel[]): string | null => {\r\n if (!localizedLabels) return null;\r\n // TODO: This should also come from Xrm.Utility.getGlobalContext().userSettings.languageId but it is not initialized yet\r\n const userLanguage = UserSettingsDefinition.getUserSettings()?.languageId ?? DEFAULT_LANGUAGE;\r\n let label = localizedLabels.find(x => x.LanguageCode == userLanguage);\r\n\r\n if (!label) {\r\n label = localizedLabels.find(x => x.LanguageCode == FALLBACK_LANGUAGE);\r\n }\r\n if (!label) {\r\n label = localizedLabels[0];\r\n }\r\n\r\n return label?.Label;\r\n};\r\n\r\nexport const getLocalizedString = (path: string): string => {\r\n return window.TALXIS.Portal.Translations.getLocalizedString(path);\r\n};","import { EntityDefinition as IEntityDefinition, ISimpleEntityDefinition, LocalizedLabel } from '../../interfaces/entitydefinition';\r\nimport { Exception } from '../exceptions/Exception';\r\nimport { sendMetadataGetRequest } from './MetadataApi';\r\nimport { IPromiseCache, cachedWrapper } from '@utilities/MemoryCachingHelpers';\r\nimport { IODataResponse } from '../../interfaces/general';\r\nimport { LocalizeLabel } from '@src/localization/helpers';\r\n\r\nexport class EntityDefinition {\r\n private static _entityDefinition: IPromiseCache = {};\r\n\r\n static async preloadAsync(metadataIds: string[]): Promise {\r\n console.groupCollapsed(\"Entity Definitions Preload\");\r\n if (!metadataIds || metadataIds.length === 0) {\r\n console.log(\"No entities to preload\");\r\n console.groupEnd();\r\n return;\r\n }\r\n const timeStart = performance.now();\r\n console.log(`Preloading entity definitions for:`, metadataIds);\r\n\r\n const entities: IEntityDefinition[] = [];\r\n\r\n // Querying EntityDefinitions has limit of 25 entities per request\r\n const chunkSize = 25;\r\n for (let i = 0; i < metadataIds.length; i += chunkSize) {\r\n const chunk = metadataIds.slice(i, i + chunkSize);\r\n const response = await sendMetadataGetRequest(`v9.1/EntityDefinitions?$filter=${chunk.map(x => `MetadataId eq '${x}'`).join(' or ')}&$select=LogicalName,DisplayCollectionName,PrimaryNameAttribute,PrimaryIdAttribute,PrimaryImageAttribute,SchemaName,EntitySetName,Description,DisplayName,MetadataId,IsQuickCreateEnabled,IsActivity,IsValidForAdvancedFind&$expand=Attributes,OneToManyRelationships($select=SchemaName,RelationshipType,IsValidForAdvancedFind,ReferencedAttribute,ReferencedEntity,ReferencingAttribute,ReferencingEntity,ReferencedEntityNavigationPropertyName,ReferencingEntityNavigationPropertyName),ManyToOneRelationships($select=SchemaName,RelationshipType,IsValidForAdvancedFind,ReferencedAttribute,ReferencedEntity,ReferencingAttribute,ReferencingEntity,ReferencedEntityNavigationPropertyName,ReferencingEntityNavigationPropertyName),ManyToManyRelationships($select=SchemaName,RelationshipType,IsValidForAdvancedFind,Entity1LogicalName,Entity1IntersectAttribute,Entity1NavigationPropertyName,Entity2LogicalName,Entity2IntersectAttribute,Entity2NavigationPropertyName,IntersectEntityName)`);\r\n if (!response.ok) {\r\n throw new Exception('Unable to preload entity definitions!', new Exception(await response.text()));\r\n }\r\n const entityDefinitions: IODataResponse = await response.json();\r\n entities.push(...entityDefinitions.value);\r\n }\r\n\r\n const entityLogicalNames: string[] = [];\r\n\r\n for (const entity of entities) {\r\n entityLogicalNames.push(entity.LogicalName);\r\n this._entityDefinition[entity.LogicalName] = new Promise(async (resolve) => {\r\n resolve(entity);\r\n });\r\n }\r\n\r\n console.log(`Preloading entity definitions took:`, performance.now() - timeStart);\r\n console.groupEnd();\r\n\r\n return entityLogicalNames;\r\n }\r\n\r\n static async getAsync(): Promise;\r\n static async getAsync(entityName: string): Promise;\r\n static async getAsync(entityName?: string): Promise {\r\n if (entityName === undefined) entityName = '*ALL*';\r\n return cachedWrapper(entityName, () => new Promise(async (resolve, reject) => {\r\n try {\r\n if (entityName === '*ALL*') {\r\n const response = await sendMetadataGetRequest(`v9.1/EntityDefinitions?$select=LogicalName,DisplayName,MetadataId`);\r\n if (!response.ok) {\r\n throw new Error(`Entities could not be fetched!`);\r\n }\r\n\r\n const simpleEntitiesDefinitions = (await response.json()).value;\r\n resolve(simpleEntitiesDefinitions.map((def: any) => ({\r\n ...def,\r\n DisplayName: LocalizeLabel(def.DisplayName.LocalizedLabels as LocalizedLabel[]),\r\n })));\r\n return;\r\n }\r\n\r\n const response = await sendMetadataGetRequest(`v9.1/EntityDefinitions(LogicalName='${entityName}')?$select=LogicalName,DisplayCollectionName,PrimaryNameAttribute,PrimaryIdAttribute,PrimaryImageAttribute,SchemaName,EntitySetName,Description,DisplayName,MetadataId,IsQuickCreateEnabled,IsActivity,IsValidForAdvancedFind&$expand=Attributes,OneToManyRelationships($select=SchemaName,RelationshipType,IsValidForAdvancedFind,ReferencedAttribute,ReferencedEntity,ReferencingAttribute,ReferencingEntity,ReferencedEntityNavigationPropertyName,ReferencingEntityNavigationPropertyName),ManyToOneRelationships($select=SchemaName,RelationshipType,IsValidForAdvancedFind,ReferencedAttribute,ReferencedEntity,ReferencingAttribute,ReferencingEntity,ReferencedEntityNavigationPropertyName,ReferencingEntityNavigationPropertyName),ManyToManyRelationships($select=SchemaName,RelationshipType,IsValidForAdvancedFind,Entity1LogicalName,Entity1IntersectAttribute,Entity1NavigationPropertyName,Entity2LogicalName,Entity2IntersectAttribute,Entity2NavigationPropertyName,IntersectEntityName)`);\r\n if (!response.ok) {\r\n throw new Error(`Entity ${entityName} could not be fetched!`);\r\n }\r\n const entityDefinition: IEntityDefinition = await response.json();\r\n resolve(entityDefinition);\r\n }\r\n catch (error) {\r\n reject(error);\r\n }\r\n }), this._entityDefinition);\r\n }\r\n}","import { getTheme, mergeStyles } from \"@fluentui/react/lib/Styling\";\r\n\r\nexport const getDetailsListStyles = (): string => {\r\n const theme = getTheme();\r\n return mergeStyles({\r\n '.ms-DetailsRow': {\r\n minHeight: 49,\r\n width: '100%',\r\n '.ms-DetailsRow-cell': {\r\n display: 'flex',\r\n alignItems: 'center',\r\n '.ms-CommandBar-primaryCommand': {\r\n display: 'none'\r\n },\r\n '.ms-CommandBar-secondaryCommand': {\r\n justifyContent: 'flex-end',\r\n width: '100%',\r\n minWidth: 'max-content'\r\n },\r\n },\r\n '.ms-DetailsRow-cell > div:first-child': {\r\n width: '100%'\r\n },\r\n '.ms-DetailsRow-check': {\r\n width: '48px !important'\r\n },\r\n '.ms-CommandBar, .ms-Button--commandBar': {\r\n backgroundColor: 'transparent'\r\n },\r\n '.ms-Button--commandBar:hover': {\r\n backgroundColor: theme.semanticColors.buttonBackgroundPressed,\r\n }\r\n }\r\n });\r\n};","import React from 'react';\r\nimport { DetailsList as DetailsListBase, IDetailsListProps } from '@fluentui/react';\r\nimport { getDetailsListStyles } from './Style';\r\nexport const DetailsList: React.FC = (props) => {\r\n return (\r\n \r\n );\r\n};","export enum FormControlType {\r\n Field = \"field\",\r\n DataSet = \"dataset\",\r\n Button = \"button\"\r\n}\r\n\r\nexport enum ParticipationTypeMasktoType {\r\n \"from\" = 1,\r\n \"to\" = 2,\r\n \"cc\" = 3,\r\n \"bcc\" = 4,\r\n \"requiredattendees\" = 5,\r\n \"optionalattendees\" = 6,\r\n \"organizer\" = 7,\r\n \"resources\" = 10,\r\n \"customers\" = 11,\r\n \"partners\" = 12\r\n}","import { ISpinnerProps } from \"@fluentui/react/lib/Spinner\";\r\n\r\nexport const defaultProps: ISpinnerProps = {\r\n className: ''\r\n};","import { mergeStyles, getTheme } from \"@fluentui/react/lib/Styling\";\r\n\r\nexport const getRootStyles = (): string => {\r\n const theme = getTheme();\r\n const rootStyles = mergeStyles({\r\n selectors: {\r\n '.ms-Spinner-circle': {\r\n borderColor: `${theme.palette.themePrimary} ${theme.palette.neutralLight} ${theme.palette.neutralLight}`\r\n },\r\n }\r\n });\r\n return rootStyles;\r\n};","import React from 'react';\r\nimport { defaultProps } from './Constants';\r\nimport { getRootStyles } from './Styles';\r\nimport { Spinner } from '@talxis/react-components';\r\nimport { ISpinnerProps } from '@fluentui/react';\r\n\r\nconst Loading: React.FC = (props) => {\r\n return (\r\n \r\n );\r\n};\r\nexport default Loading;\r\nLoading.defaultProps = defaultProps;","import { ICommandBarItemProps } from '@fluentui/react/lib/CommandBar';\r\nimport { ITabsProps } from './interfaces';\r\nexport const getTabCommandBarItems = (props: ITabsProps, isMobile: boolean): ICommandBarItemProps[] => {\r\n const tabItems: ICommandBarItemProps[] = [];\r\n\r\n for (const tab of props.tabs) {\r\n if (tab.showLabel && tab.visible && (!isMobile || tab.availableForPhone)) {\r\n const tabItem: ICommandBarItemProps = {\r\n key: tab.id,\r\n text: tab.label,\r\n iconProps: {\r\n iconName: tab.iconName\r\n },\r\n 'data-id': `tablist-${tab.name}`,\r\n onClick: () => props.onTabChange(tab)\r\n };\r\n tabItems.push(tabItem);\r\n }\r\n }\r\n return tabItems;\r\n};\r\n","import * as React from 'react';\r\nimport './css/styles.css';\r\nimport { ICommandBarItemProps, ICommandBarProps } from '@fluentui/react/lib/components/CommandBar/CommandBar.types';\r\nimport { getTheme, ITheme, mergeStyles } from '@fluentui/react/lib/Styling';\r\nimport { useState } from 'react';\r\nimport { cloneDeep } from 'lodash';\r\nimport { ThemeDefinition } from '@src/app/classes/definitions/ThemeDefinition';\r\nimport { IButtonProps, CommandBarButton, Icon, IRenderFunction } from '@fluentui/react';\r\nimport { CommandBar } from '@talxis/react-components';\r\nexport interface ITabCommandBarProps extends ICommandBarProps {\r\n selectedKey?: string;\r\n theme?: ITheme;\r\n}\r\n\r\nconst TabCommandBar: React.FC = (props) => {\r\n const [itemsState, setItemsState] = useState(props.items);\r\n const theme = props.theme ?? getTheme();\r\n const getThemedStyles = (): string => {\r\n return mergeStyles({\r\n '[data-selected-top-level=\"true\"]::after': {\r\n borderBottom: `3px solid ${theme.palette.themePrimary}`,\r\n position: 'relative',\r\n zIndex: 2,\r\n top: -2\r\n\r\n },\r\n ':global([data-selected=\"true\"] .ms-ContextualMenu-itemText)': {\r\n fontWeight: 600\r\n }\r\n });\r\n };\r\n\r\n const setActiveItem = () => {\r\n const items = cloneDeep(props.items);\r\n for (const item of items) {\r\n if (markCurrentItem(item)) {\r\n item[\"data-selected-top-level\"] = true;\r\n break;\r\n }\r\n }\r\n setItemsState(items);\r\n };\r\n const markCurrentItem = (item: ICommandBarItemProps): ICommandBarItemProps => {\r\n if (item.key === props.selectedKey) {\r\n item['data-selected'] = true;\r\n return item;\r\n }\r\n const childItems = item.sectionProps?.items ?? item.subMenuProps?.items;\r\n if (childItems) {\r\n for (const childItem of childItems) {\r\n const markedItem = markCurrentItem(childItem);\r\n if (markedItem) {\r\n return markedItem;\r\n }\r\n }\r\n }\r\n };\r\n React.useEffect(() => {\r\n if (props.items.length > 0) {\r\n setActiveItem();\r\n }\r\n }, [props.items, props.selectedKey]);\r\n\r\n const iconRender: IRenderFunction = buttonProps => {\r\n return buttonProps.iconProps?.imageProps?.src ? (\r\n \r\n ) : ();\r\n };\r\n\r\n const IconButtonWrapper: React.FunctionComponent = buttonProps => {\r\n return ();\r\n };\r\n\r\n return (\r\n \r\n );\r\n};\r\nexport default TabCommandBar;\r\n","import React, { useEffect, useState, useContext } from 'react';\r\nimport { ITabsProps } from './interfaces';\r\nimport { getTabCommandBarItems } from './Functions';\r\nimport { ICommandBarItemProps } from '@fluentui/react/lib/components/CommandBar/CommandBar.types';\r\nimport { IFormContext } from '../../interfaces/IFormContext';\r\nimport { FormContext } from '../../Form';\r\nimport TabCommandBar from '../../../../../navigation/commandbars/TabCommandBar';\r\nimport { mergeStyles, useTheme } from '@fluentui/react';\r\n\r\nconst Tabs: React.FC = (props) => {\r\n const [items, setItems] = useState([]);\r\n const [currentTabId, setCurrentTabId] = useState(null);\r\n const formContext: IFormContext = useContext(FormContext);\r\n\r\n const getTabStyles = () => {\r\n return mergeStyles({\r\n '.ms-CommandBar-primaryCommand > .ms-OverflowSet-item:first-child .ms-Button--commandBar': {\r\n marginLeft: 0\r\n },\r\n });\r\n };\r\n\r\n const showTabs = () => {\r\n //hide the tabs if there is only one tab with the name 'Tab'\r\n //MS hides this tab by default, so we hide it as well for consistency\r\n\r\n if (items.length == 1 && items[0].text === 'Tab') {\r\n return false;\r\n }\r\n if (items.length > 0) {\r\n return true;\r\n }\r\n return false;\r\n };\r\n\r\n useEffect(() => {\r\n const items = getTabCommandBarItems(props, formContext.isMobile);\r\n setItems(items);\r\n if (props.currentTab) setCurrentTabId(props.currentTab.id);\r\n }, [props]);\r\n\r\n return (\r\n <>\r\n {showTabs() &&\r\n \r\n }\r\n \r\n );\r\n};\r\nexport default Tabs;","import { CurrentAppComponents, AppComponent as IAppComponent } from '../../interfaces/appcomponent';\r\nimport { AppModule } from './AppModule';\r\nimport { Component, Descriptor } from '../../interfaces/appmodule';\r\nimport { EntityDefinition } from '@definitions/EntityDefinition';\r\nimport { metadataRetrieveMultiple } from '@definitions/MetadataApi';\r\n\r\nexport class AppComponents {\r\n private static _appComponents: IAppComponent[];\r\n public static async loadAsync(): Promise {\r\n if (!this._appComponents) {\r\n const appModule = AppModule.get();\r\n\r\n const descriptor: Descriptor = JSON.parse(appModule.descriptor);\r\n\r\n const appComponents: IAppComponent[] = [];\r\n const limitComponentsPerFetch = 50;\r\n\r\n // For unmanaged app modules, we can use the descriptor straight away since it is returned in the correct order, for managed, we need to resolve order ourselves\r\n if (!appModule.ismanaged) {\r\n console.info(\"No managed configuration found for app module, using values from descriptor.\");\r\n\r\n const entityMetadataIds: string[] = [];\r\n\r\n for (const appComponent of descriptor.appInfo.Components) {\r\n if (appComponent.Type === 1) {\r\n entityMetadataIds.push(appComponent.Id);\r\n }\r\n else {\r\n appComponents.push({\r\n componenttype: appComponent.Type,\r\n objectid: appComponent.Id,\r\n appmodulecomponentid: null,\r\n });\r\n }\r\n }\r\n const entities = await EntityDefinition.preloadAsync(entityMetadataIds);\r\n\r\n for (const entity of entities) {\r\n const definition = await EntityDefinition.getAsync(entity);\r\n appComponents.push({\r\n componenttype: 1,\r\n objectid: definition.MetadataId,\r\n appmodulecomponentid: null,\r\n componentlogicalname: definition.LogicalName\r\n });\r\n }\r\n }\r\n else {\r\n // SiteMap is always first\r\n const sitemap = descriptor.appInfo.Components.find(x => x.Type === 62);\r\n appComponents.unshift({\r\n appmodulecomponentid: null,\r\n componenttype: sitemap.Type,\r\n objectid: sitemap.Id\r\n });\r\n\r\n const entityComponents = descriptor.appInfo.Components.filter(x => x.Type === 1);\r\n const formComponents = descriptor.appInfo.Components.filter(x => x.Type === 60);\r\n const viewComponents = descriptor.appInfo.Components.filter(x => x.Type === 26);\r\n\r\n if (entityComponents.length > 0) {\r\n let views: Xrm.RetrieveMultipleResult = { entities: [], nextLink: null };\r\n let forms: Xrm.RetrieveMultipleResult = { entities: [], nextLink: null };\r\n\r\n let formReq: Promise = null;\r\n let viewReq: Promise = null;\r\n\r\n if (formComponents.length > 0) {\r\n formReq = this._retrieveMultipleSystemForms(formComponents, limitComponentsPerFetch);\r\n }\r\n if (viewComponents.length > 0) {\r\n viewReq = this._retrieveMultipleSavedQueries(viewComponents, limitComponentsPerFetch);\r\n }\r\n\r\n const entities = await EntityDefinition.preloadAsync(entityComponents.map(x => x.Id));\r\n\r\n if (formReq !== null) forms = await formReq;\r\n if (viewReq !== null) views = await viewReq;\r\n\r\n for (const entity of entities) {\r\n const definition = await EntityDefinition.getAsync(entity);\r\n appComponents.push({\r\n componenttype: 1,\r\n objectid: definition.MetadataId,\r\n appmodulecomponentid: null,\r\n componentlogicalname: definition.LogicalName\r\n });\r\n for (const form of forms.entities.filter(x => x.objecttypecode === definition.LogicalName)) {\r\n appComponents.push({\r\n componenttype: 60,\r\n objectid: form[\"formid\"],\r\n appmodulecomponentid: null\r\n });\r\n }\r\n for (const view of views.entities.filter(x => x.returnedtypecode === definition.LogicalName)) {\r\n appComponents.push({\r\n componenttype: 26,\r\n objectid: view[\"savedqueryid\"],\r\n appmodulecomponentid: null\r\n });\r\n }\r\n }\r\n }\r\n\r\n }\r\n\r\n this._appComponents = appComponents;\r\n }\r\n }\r\n public static get(): IAppComponent[] {\r\n if (!this._appComponents) {\r\n throw new Error(\"AppComponents is unitialized!\");\r\n }\r\n return this._appComponents;\r\n }\r\n public static async filterAppComponents(entityName: string, componentType: number): Promise {\r\n const appComponents = this.get();\r\n const entityDefinition = await EntityDefinition.getAsync(entityName);\r\n const filteredAppComponents = appComponents.filter(x => x.componenttype === 1 || x.componenttype === componentType);\r\n const componentIds: string[] = [];\r\n const entityIndex = filteredAppComponents.findIndex(x => x.componenttype === 1 && x.objectid === entityDefinition.MetadataId);\r\n if (entityIndex !== -1) {\r\n for (let i = entityIndex + 1; i < filteredAppComponents.length; i++) {\r\n if (filteredAppComponents[i].componenttype === componentType) {\r\n componentIds.push(filteredAppComponents[i].objectid);\r\n }\r\n else if (filteredAppComponents[i].componenttype === 1) {\r\n break;\r\n }\r\n }\r\n }\r\n return componentIds;\r\n }\r\n\r\n public static getCurrentAppComponents(): CurrentAppComponents {\r\n return {\r\n entities: AppComponents.get()\r\n .filter(({ componenttype }) => componenttype === 1)\r\n .map(({ objectid, componentlogicalname }) => ({\r\n Id: objectid,\r\n LogicalName: componentlogicalname,\r\n })),\r\n };\r\n };\r\n\r\n private static async _retrieveMultipleSystemForms(components: Component[], limitPerFetch: number): Promise {\r\n const reqArray = [];\r\n const reqSteps = Math.ceil(components.length / limitPerFetch);\r\n for (let i = 0; i < reqSteps; i++) {\r\n const sliceStart = i * limitPerFetch;\r\n const sliceEnd = (i + 1) * limitPerFetch;\r\n const componentSlice = components.slice(sliceStart, sliceEnd);\r\n\r\n const reqStep = metadataRetrieveMultiple(`v9.1/systemforms?$select=formid,objecttypecode&$filter=${componentSlice.map(x => `formid eq ${x.Id}`).join(\" or \")}`);\r\n reqArray.push(reqStep);\r\n }\r\n\r\n const reqResult = this._combineRetrieveMultipleResults(await Promise.all(reqArray));\r\n\r\n return reqResult;\r\n }\r\n\r\n private static async _retrieveMultipleSavedQueries(components: any[], limitPerFetch: number): Promise {\r\n const reqArray = [];\r\n const reqSteps = Math.ceil(components.length / limitPerFetch);\r\n for (let i = 0; i < reqSteps; i++) {\r\n const sliceStart = i * limitPerFetch;\r\n const sliceEnd = (i + 1) * limitPerFetch;\r\n const componentSlice = components.slice(sliceStart, sliceEnd);\r\n\r\n const reqStep = metadataRetrieveMultiple(`v9.1/savedqueries?$select=savedqueryid,returnedtypecode&$filter=${componentSlice.map(x => `savedqueryid eq ${x.Id}`).join(\" or \")}`);\r\n reqArray.push(reqStep);\r\n }\r\n\r\n const reqResult = this._combineRetrieveMultipleResults(await Promise.all(reqArray));\r\n\r\n return reqResult;\r\n }\r\n\r\n private static _combineRetrieveMultipleResults(results: Xrm.RetrieveMultipleResult[]): Xrm.RetrieveMultipleResult {\r\n const combinedResult: Xrm.RetrieveMultipleResult = {\r\n entities: [],\r\n ...results[0]\r\n };\r\n for (const result of results) {\r\n combinedResult.entities = combinedResult.entities.concat(result.entities);\r\n };\r\n return combinedResult;\r\n };\r\n};","import { DomParser } from '../../Constants';\r\nimport { AppComponents } from '@configuration/AppComponents';\r\nimport { ILocalizedLabel, LocalizeLabel } from '@localization/helpers';\r\nimport { IPromiseCache, cachedWrapper } from '@utilities/MemoryCachingHelpers';\r\nimport { metadataRetrieveMultiple, sendMetadataGetRequest } from './MetadataApi';\r\nimport { sanitizeGuid } from '../../Functions';\r\n\r\nexport enum FormType {\r\n Main = 2,\r\n Dialog = 8,\r\n QuickCreate = 7\r\n}\r\nexport enum ErrorType {\r\n MissingEntityName,\r\n MissingQuickCreateForm,\r\n MissingDefaultForm\r\n}\r\nexport class FormDefinition {\r\n private static _formDefinitionCache: IPromiseCache = {};\r\n private static _defaultQuickCreateDefinitionCache: IPromiseCache = {};\r\n private static _defaultEntityFormCache: IPromiseCache = {};\r\n private static _entityFormIdNameCache: {\r\n [entityName: string]: Promise<{\r\n formid: string,\r\n name: string\r\n }[]>\r\n } = {};\r\n\r\n public Id: string;\r\n public Type: FormType;\r\n public FormXml: Document;\r\n public Labels: { [key: string]: ILocalizedLabel[] };\r\n\r\n /**\r\n * This method performs a lookup for form ID if it is not know and caches results.\r\n * Use one of parameters to identify the form you want to retrieve\r\n * @param entityName If you don't know a specific form you can use a defaut form for an entity\r\n * @param formId Use this parameter when you know ID of the form you want\r\n * @param formUniqueName Form names are usually used when opening dialogs from the cluent SDK\r\n * @returns \r\n */\r\n static async getAsync(entityName?: string, formId?: string, formUniqueName?: string): Promise {\r\n if (formId) {\r\n formId = sanitizeGuid(formId);\r\n }\r\n if (!entityName && !formId && !formUniqueName) {\r\n throw Error(\"You need to specify an entity name, form ID or form unique name!\");\r\n }\r\n else if (entityName && !formId && !formUniqueName) {\r\n formId = await this.getEntityDefaultFormId(entityName);\r\n }\r\n\r\n return cachedWrapper(formId ?? formUniqueName, () => new Promise(async (resolve, reject) => {\r\n if (!formId && !formUniqueName && entityName) { // Get a default form ID\r\n formId = await this.getEntityDefaultFormId(entityName);\r\n }\r\n else if (formUniqueName) {\r\n const formQueryResponse = (await metadataRetrieveMultiple(`v9.1/systemforms?$select=formid&$filter=uniquename eq '${formUniqueName}'`))?.entities;\r\n if (formQueryResponse && formQueryResponse.length === 1) {\r\n formId = formQueryResponse[0]?.[\"formid\"];\r\n }\r\n else {\r\n throw Error(`Form with unique name ${formUniqueName} was not found in metadata!`);\r\n }\r\n }\r\n\r\n resolve(await this._getFormDefinitionAsync(formId));\r\n }), this._formDefinitionCache);\r\n }\r\n\r\n static async getDefaultQuickCreateAsync(entityName?: string): Promise {\r\n if (!entityName) {\r\n throw { code: ErrorType.MissingEntityName, message: \"You need to specify an entity name!\" };\r\n }\r\n\r\n return cachedWrapper(entityName, () => new Promise(async (resolve, reject) => {\r\n const formIds = await AppComponents.filterAppComponents(entityName, 60);\r\n let filter = `type eq 7 and objecttypecode eq '${entityName}' and contains(formxml, 'Order=\"1\"')`;\r\n if (formIds.length > 0) {\r\n filter += ` and (${formIds.map(x => `formid eq ${x}`).join(' or ')})`;\r\n }\r\n // $top to make sure we only get a single response, multiple Order=\"1\" quick creates can return when set via XML manually\r\n const formQueryResponse = (await metadataRetrieveMultiple(`v9.1/systemforms?$filter=${filter}&$select=formid&$top=1`))?.entities;\r\n let formId = null;\r\n if (formQueryResponse && formQueryResponse.length === 1) {\r\n formId = formQueryResponse[0]?.[\"formid\"];\r\n }\r\n else {\r\n reject({ code: ErrorType.MissingQuickCreateForm, message: `Default quick create form for entity ${entityName} was not found in metadata!` });\r\n }\r\n\r\n resolve(await this._getFormDefinitionAsync(formId));\r\n }), this._defaultQuickCreateDefinitionCache);\r\n }\r\n\r\n private static async _getFormDefinitionAsync(formId: string): Promise {\r\n const [formXml, labels, type] = await this._getFormXmlAsync(formId);\r\n\r\n return {\r\n Id: formId,\r\n FormXml: formXml,\r\n Type: type,\r\n Labels: labels ?? {}\r\n };\r\n }\r\n\r\n private static async _getFormXmlAsync(formId: string): Promise<[Document, { [key: string]: ILocalizedLabel[] }, FormType]> {\r\n const response = await sendMetadataGetRequest(`v9.1/systemforms(${formId})?$select=formxml,type`);\r\n const formData = await response.json();\r\n return [DomParser.parseFromString(formData['formxml'], \"text/xml\"), formData[\"__labels\"], formData[\"type\"]];\r\n }\r\n public static async getEntityDefaultFormId(entityName: string): Promise {\r\n return cachedWrapper(entityName, () => new Promise(async (resolve, reject) => {\r\n const formIds = await AppComponents.filterAppComponents(entityName, 60);\r\n let filter = `?$select=name,formid&$filter=objecttypecode eq '${entityName}'`;\r\n if (formIds.length > 0) {\r\n filter = `?$select=name,formid&$filter=(${formIds.map(x => `formid eq ${x}`).join(' or ')})`;\r\n }\r\n filter += ` and type eq 2`;\r\n\r\n const form = await metadataRetrieveMultiple(`v9.1/systemforms${filter}`);\r\n if (form.entities.length > 0) {\r\n resolve(form.entities[0][\"formid\"]);\r\n return;\r\n }\r\n reject({ code: ErrorType.MissingDefaultForm, message: `Unable to find default form for entity ${entityName}` });\r\n }), this._defaultEntityFormCache);\r\n }\r\n public static async getFormNamesAndIds(entityName: string, formType?: FormType): Promise<{ formid: string; name: string }[]> {\r\n let cacheKey = entityName;\r\n if (formType) {\r\n cacheKey += `_${formType}`;\r\n }\r\n return cachedWrapper(cacheKey, () => new Promise(async (resolve) => {\r\n const formIds = await AppComponents.filterAppComponents(entityName, 60);\r\n let filter = `?$select=name,formid&$filter=objecttypecode eq '${entityName}'`;\r\n if (formIds.length > 0) {\r\n filter = `?$select=name,formid&$filter=(${formIds.map(x => `formid eq ${x}`).join(' or ')})`;\r\n }\r\n if (formType) {\r\n filter += ` and type eq ${formType}`;\r\n }\r\n const result = await metadataRetrieveMultiple(`v9.1/systemforms${filter}`);\r\n const forms: { formid: string; name: string }[] = result.entities.map(entity => {\r\n return {\r\n formid: entity.formid,\r\n name: LocalizeLabel(entity[\"__labels\"]?.[\"name\"]) ?? entity.name\r\n };\r\n });\r\n resolve(forms);\r\n }), this._entityFormIdNameCache);\r\n }\r\n}","import { FormDefinition, FormType } from '@definitions/FormDefinition';\r\nimport { Form } from \"@controls/native/Form/interfaces/form\";\r\nimport { FormControlType } from \"@controls/native/Form/interfaces/enums\";\r\nimport { ControlLoader } from \"@loaders/ControlLoader\";\r\nimport { LocalizeLabel, ILocalizedLabel } from \"@localization/helpers\";\r\nimport { EntityDefinition } from \"@definitions/EntityDefinition\";\r\nimport { sanitizeGuid } from \"../../Functions\";\r\n\r\nexport class FormMapper {\r\n private _entityName: string;\r\n private _controlDescriptions: Form.ControlDescription[] = [];\r\n private _formId?: string;\r\n private _formUniqueName?: string;\r\n private _labels: { [key: string]: ILocalizedLabel[] };\r\n\r\n constructor(entityName: string, formId?: string, formUniqueName?: string) {\r\n this._entityName = entityName;\r\n this._formId = formId;\r\n this._formUniqueName = formUniqueName;\r\n }\r\n public getForm = async (): Promise => {\r\n const formDefinition = await FormDefinition.getAsync(this._entityName, this._formId, this._formUniqueName);\r\n this._labels = formDefinition.Labels;\r\n this._controlDescriptions = this._parseControlDescriptions(formDefinition.FormXml.getElementsByTagName('controlDescription'));\r\n\r\n const isTitleElement = formDefinition.FormXml.getElementsByTagName('IsTitle')?.[0];\r\n const formHeader = isTitleElement?.parentElement?.parentElement?.parentElement;\r\n const formHeaderId = formHeader?.getAttribute('id');\r\n const formEvents = await this._parseEvents(formDefinition.FormXml.getElementsByTagName('event'));\r\n const form: Form.Root = {\r\n id: formDefinition.Id, // We may not know form ID from constructor\r\n formXml: formDefinition.FormXml,\r\n libraries: await this._parseLibraries(formDefinition.FormXml.getElementsByTagName('Library')),\r\n header: await this._parseHeader(formDefinition.FormXml.querySelector('header'), formEvents, formDefinition),\r\n tabs: await this._parseTabs(formDefinition.FormXml.getElementsByTagName('tab'), formEvents, formDefinition.Type),\r\n events: formEvents,\r\n type: formDefinition.Type,\r\n title: (formDefinition.Type === FormType.Dialog) ? this._getLabel((isTitleElement?.innerHTML === \"true\") ? formHeader : null, this._labels[sanitizeGuid(formHeaderId)]) : null\r\n };\r\n return form;\r\n };\r\n\r\n private _parseHeader = async (headerElement: Element, formEvents: Form.Event[], formDefinition: FormDefinition): Promise => {\r\n if (!headerElement) {\r\n return null;\r\n }\r\n return {\r\n id: headerElement.getAttribute('id'),\r\n showImage: formDefinition.FormXml.getElementsByTagName('form')?.[0].getAttribute('showImage') === 'true',\r\n rows: await this._parseRows(headerElement.getElementsByTagName('row'), formEvents)\r\n };\r\n };\r\n\r\n private _parseLibraries = async (libraryCollection: HTMLCollectionOf): Promise => {\r\n const libraries: Form.Library[] = [];\r\n\r\n for (const library of libraryCollection) {\r\n libraries.push({\r\n name: library.getAttribute(\"name\"),\r\n });\r\n }\r\n\r\n return libraries;\r\n };\r\n\r\n private _parseEvents = async (eventCollection: HTMLCollectionOf): Promise => {\r\n const events: Form.Event[] = [];\r\n\r\n for (const event of eventCollection) {\r\n events.push({\r\n name: event.getAttribute(\"name\"),\r\n handlers: await this._parseEventHandlers(event.getElementsByTagName(\"Handler\")),\r\n attribute: event.getAttribute(\"attribute\"),\r\n control: event.getAttribute(\"control\")\r\n });\r\n }\r\n\r\n return events;\r\n };\r\n\r\n private _parseEventHandlers = async (handlerCollection: HTMLCollectionOf): Promise => {\r\n const handlers: Form.Handler[] = [];\r\n\r\n for (const handler of handlerCollection) {\r\n const libraryName = handler.getAttribute(\"libraryName\");\r\n\r\n handlers.push({\r\n functionName: handler.getAttribute(\"functionName\"),\r\n libraryName: libraryName,\r\n handlerUniqueId: handler.getAttribute(\"handlerUniqueId\"),\r\n enabled: handler.getAttribute(\"enabled\") === \"true\" ? true : false,\r\n parameters: handler.getAttribute(\"parameters\"),\r\n passExecutionContext: handler.getAttribute(\"passExecutionContext\") === \"true\" ? true : false\r\n });\r\n }\r\n\r\n return handlers;\r\n };\r\n\r\n private _parseControlDescriptions = (controlDescriptionsCollection: HTMLCollectionOf): Form.ControlDescription[] => {\r\n const controlDescriptions: Form.ControlDescription[] = [];\r\n\r\n for (const controlDescription of controlDescriptionsCollection) {\r\n controlDescriptions.push({\r\n forControl: controlDescription.getAttribute('forControl'),\r\n customControls: this._parseCustomControls(controlDescription.querySelectorAll('customControl'))\r\n });\r\n }\r\n\r\n return controlDescriptions;\r\n };\r\n\r\n private _parseTabs = async (tabsCollection: HTMLCollectionOf, formEvents: Form.Event[], formType: FormType): Promise => {\r\n const tabs: Form.Tab[] = [];\r\n for (const tab of tabsCollection) {\r\n const matchingLabels = this._labels[sanitizeGuid(tab.getAttribute(\"labelid\") ?? tab.getAttribute(\"id\"))];\r\n let label = this._getLabel(tab, matchingLabels);\r\n if (label === null) label = '';\r\n\r\n const labelMatches = [...label.matchAll(/#(.*)#(.*)/g)];\r\n const labelMatchResult: string[] = labelMatches.length === 1 ? labelMatches[0] : [];\r\n const iconName = labelMatchResult.length > 2 ? labelMatchResult[1] : null;\r\n label = labelMatchResult.length > 2 ? labelMatchResult[2] : label;\r\n\r\n tabs.push({\r\n id: tab.getAttribute('id'),\r\n name: tab.getAttribute('name'),\r\n showLabel: this._showLabel(tab),\r\n label: label,\r\n columns: await this._parseColumns(tab.getElementsByTagName('column'), formEvents),\r\n iconName: iconName,\r\n visible: this._visible(tab),\r\n availableForPhone: this._availableForPhone(tab),\r\n contentType: tab.getAttribute('contenttype') as 'cardSections' | 'singleComponent' ?? 'cardSections',\r\n tabFooter: (formType === FormType.Dialog) ? (await this._parseSections(tab.getElementsByTagName('tabfooter'), formEvents))?.[0] : null\r\n });\r\n }\r\n return tabs;\r\n };\r\n private _parseCustomControls = (customControlsCollection: NodeListOf) => {\r\n const customControls: Form.CustomControl[] = [];\r\n\r\n for (const customControl of customControlsCollection) {\r\n customControls.push({\r\n name: customControl.getAttribute('name'),\r\n bindingParameters: this._parseCustomControlBindings(customControl.getAttribute('name'), customControl.getElementsByTagName('parameters')[0]),\r\n formFactor: customControl.getAttribute('formFactor')\r\n });\r\n }\r\n return customControls;\r\n };\r\n\r\n private _parseCustomControlBindings = (controlName: string, parametersElement: Element): Form.ControlBindings => {\r\n const bindings: Form.ControlBindings = {};\r\n if (parametersElement) {\r\n for (const parameter of parametersElement.children) {\r\n const isStatic = parameter.getAttribute(\"static\") === \"true\" ? true : false;\r\n let value = isStatic ? parameter.textContent : parameter.innerHTML;\r\n if (parameter.hasChildNodes() && parameter.getElementsByTagName(\"BindAttribute\")?.[0]) {\r\n value = parameter.getElementsByTagName(\"BindAttribute\")?.[0]?.textContent;;\r\n }\r\n bindings[parameter.tagName] = {\r\n isStatic: isStatic,\r\n type: parameter.getAttribute(\"type\"),\r\n value: value,\r\n extraParameters: parameter.hasChildNodes() ? parameter.innerHTML : undefined\r\n };\r\n }\r\n }\r\n\r\n return bindings;\r\n };\r\n\r\n private _parseColumns = async (columnsCollection: HTMLCollectionOf, formEvents: Form.Event[]): Promise => {\r\n const columns: Form.Column[] = [];\r\n for (const column of columnsCollection) {\r\n columns.push({\r\n // Columns don't appear to have an ID defined\r\n id: window.self.crypto.randomUUID(),\r\n width: column.getAttribute('width'),\r\n sections: await this._parseSections(column.getElementsByTagName('section'), formEvents)\r\n });\r\n }\r\n return columns;\r\n };\r\n\r\n private _parseSections = async (sectionsCollection: HTMLCollectionOf, formEvents: Form.Event[]): Promise => {\r\n const sections: Form.Section[] = [];\r\n for (const section of sectionsCollection) {\r\n const matchingLabels = this._labels[sanitizeGuid(section.getAttribute(\"labelid\") ?? section.getAttribute(\"id\"))];\r\n sections.push({\r\n id: section.getAttribute(\"id\"),\r\n showLabel: this._showLabel(section),\r\n numOfColumns: section.getAttribute(\"columns\")?.length || 1,\r\n label: this._getLabel(section, matchingLabels),\r\n rows: await this._parseRows(section.getElementsByTagName('row'), formEvents),\r\n visible: this._visible(section),\r\n availableForPhone: this._availableForPhone(section),\r\n name: section.getAttribute(\"name\"),\r\n celllabelposition: section.getAttribute('celllabelposition') as 'Top' | 'Left' ?? 'Left'\r\n });\r\n }\r\n return sections;\r\n };\r\n\r\n private _parseRows = async (rowsCollection: HTMLCollectionOf, formEvents: Form.Event[]): Promise => {\r\n const rows: Form.Row[] = [];\r\n for (const formRow of rowsCollection) {\r\n const row: Form.Row = {\r\n // Rows don't appear to have an ID defined\r\n id: window.self.crypto.randomUUID(),\r\n cells: []\r\n };\r\n\r\n for (const cell of formRow.getElementsByTagName('cell')) {\r\n row.cells.push(await this._parseCell(cell, formEvents));\r\n }\r\n\r\n if (row.cells.length > 0) {\r\n rows.push(row);\r\n }\r\n }\r\n return rows;\r\n };\r\n\r\n private _parseCell = async (cellElement?: Element, formEvents?: Form.Event[]): Promise => {\r\n if (!cellElement) {\r\n return null;\r\n }\r\n const _control = cellElement.getElementsByTagName('control')[0];\r\n let matchingLabels = this._labels[sanitizeGuid(cellElement.getAttribute(\"labelid\") ?? cellElement.getAttribute(\"id\"))];\r\n if (!matchingLabels && this._entityName) {\r\n const entityDefinition = await EntityDefinition.getAsync(this._entityName);\r\n matchingLabels = entityDefinition.Attributes.find(x => x.LogicalName === _control?.getAttribute(\"datafieldname\"))?.DisplayName?.LocalizedLabels;\r\n }\r\n const cell: Form.Cell = {\r\n id: cellElement.getAttribute(\"id\"),\r\n showLabel: this._showLabel(cellElement),\r\n label: this._getLabel(cellElement, matchingLabels),\r\n colspan: cellElement.getAttribute(\"colspan\"),\r\n rowspan: cellElement.getAttribute(\"rowspan\"),\r\n control: await this._parseControl(_control, formEvents, this._visible(cellElement)),\r\n visible: this._visible(cellElement),\r\n auto: cellElement.getAttribute('auto') === 'true' ? true : false,\r\n availableForPhone: this._availableForPhone(cellElement)\r\n };\r\n return cell;\r\n };\r\n\r\n private _visible = (element: Element): boolean => {\r\n const _visible = element.getAttribute('visible');\r\n const _userspacer = element.getAttribute('userspacer');\r\n if (_visible === 'false' || _userspacer === 'true') {\r\n return false;\r\n }\r\n return true;\r\n };\r\n private _availableForPhone = (element: Element): boolean => {\r\n const _afp = element.getAttribute('availableforphone');\r\n if (_afp === 'false') {\r\n return false;\r\n }\r\n return true;\r\n };\r\n\r\n private _parseControl = async (controlElement: Element, formEvents: Form.Event[], visible: boolean = true): Promise => {\r\n if (!controlElement) {\r\n return null;\r\n }\r\n const controlId = controlElement.getAttribute('id');\r\n const controlUniqueId = controlElement.getAttribute('uniqueid');\r\n let controlName = this._getControlName(controlElement);\r\n const isCustomControl = !controlName.startsWith('{');\r\n let controlType: FormControlType = FormControlType.Field;\r\n const indicationOfSubgrid = controlElement.getAttribute('indicationOfSubgrid');\r\n if (indicationOfSubgrid === \"true\") {\r\n controlType = FormControlType.DataSet;\r\n }\r\n const controlNameUpper = controlName.toUpperCase();\r\n // Full map reference: https://dev.azure.com/thenetworg/INT0015/_wiki/wikis/INT0015.wiki/4083/Control-Map\r\n // Control with type customcontrol (classid = f9a8a302-114e-466a-b582-6771b2ae0d92) is resolved with _getControlName above\r\n if (controlNameUpper === \"{4273EDBD-AC1D-40D3-9FB2-095C621B552D}\" || // SingleLine.Text\r\n controlNameUpper === \"{0D2C745A-E5A8-4C8F-BA63-C6D3BB604660}\" || // Floating Point Number\r\n false) {\r\n controlName = \"TALXIS.PCF.Portal.TextField\";\r\n }\r\n else if (controlNameUpper === '{ADA2203E-B4CD-49BE-9DDF-234642B43B52}') {\r\n controlName = \"TALXIS.PCF.Portal.Email\";\r\n }\r\n else if (controlNameUpper === '{71716B6C-711E-476C-8AB8-5D11542BFB47}') {\r\n controlName = \"TALXIS.PCF.Portal.Url\";\r\n }\r\n else if (controlNameUpper === \"{E0DECE4B-6FC8-4A8F-A065-082708572369}\") { // MultipleLinesOfText\r\n controlName = \"TALXIS.PCF.Portal.MultilineText\";\r\n }\r\n else if (controlNameUpper === \"{5B773807-9FB2-42DB-97C3-7A91EFF8ADFF}\") { // DateTime\r\n controlName = \"TALXIS.PCF.Portal.DateTime\";\r\n }\r\n else if (controlNameUpper === \"{C3EFE0C3-0EC6-42BE-8349-CBD9079DFD8E}\") { // Decimal\r\n controlName = \"TALXIS.PCF.Portal.Decimal\";\r\n }\r\n else if (controlNameUpper === \"{C6D124CA-7EDA-4A60-AEA9-7FB8D318B68F}\") { // WholeNumber\r\n controlName = \"TALXIS.PCF.Portal.WholeNumber\";\r\n }\r\n else if (controlNameUpper === \"{533B9E00-756B-4312-95A0-DC888637AC78}\") { // Currency\r\n controlName = \"TALXIS.PCF.Portal.Currency\";\r\n }\r\n else if (controlNameUpper == \"{B0C6723A-8503-4FD7-BB28-C8A06AC933C2}\" || // Boolean\r\n controlNameUpper === \"{67FAC785-CD58-4F9F-ABB3-4B7DDC6ED5ED}\" // TwoOptions\r\n ) {\r\n controlName = \"TALXIS.PCF.Portal.TwoOptions\";\r\n }\r\n else if (controlNameUpper === \"{270BD3DB-D9AF-4782-9025-509E298DEC0A}\" || // Lookup \r\n controlNameUpper === \"{CBFB742C-14E7-4A17-96BB-1A13F7F64AA2}\" || // PartyList\r\n controlNameUpper === \"{F3015350-44A2-4AA0-97B5-00166532B5E9}\" // Regarding\r\n ) {\r\n controlName = \"TALXIS.PCF.Portal.SimpleLookup\";\r\n }\r\n else if (controlNameUpper === \"{E7A81278-8635-4D9E-8D4D-59480B391C5B}\") { // View\r\n controlName = \"TALXIS.PCF.Portal.View\";\r\n controlType = FormControlType.DataSet;\r\n }\r\n // This handles an edge case caused by solution import bug: https://dev.azure.com/thenetworg/INT0015/_workitems/edit/22596/\r\n else if (controlNameUpper === \"{F9A8A302-114E-466A-B582-6771B2AE0D92}\" && controlType === FormControlType.DataSet &&\r\n controlNameUpper === controlElement.getAttribute('classid').toUpperCase()\r\n ) {\r\n controlName = \"TALXIS.PCF.Portal.View\";\r\n }\r\n else if (controlNameUpper === \"{3EF39988-22BB-4F0B-BBBE-64B5A3748AEE}\") { // Option Set\r\n controlName = \"TALXIS.PCF.Portal.OptionSet\";\r\n }\r\n else if (controlNameUpper === \"{4AA28AB7-9C13-4F57-A73D-AD894D048B5F}\") { // MultiSelectOptionSet\r\n controlName = \"TALXIS.PCF.Portal.MultiSelectOptionSet\";\r\n }\r\n else if (controlNameUpper === \"{39354E4A-5015-4D74-8031-EA9EB73A1322}\") { // Label\r\n controlName = \"TALXIS.PCF.Portal.Label\";\r\n }\r\n else if (controlNameUpper === \"{00AD73DA-BD4D-49C6-88A8-2F4F4CAD4A20}\") { // Dialog Button\r\n controlName = \"TALXIS.PCF.Portal.Button\";\r\n controlType = FormControlType.Button;\r\n }\r\n else if (controlNameUpper === \"{AA987274-CE4E-4271-A803-66164311A958}\") { // Duration\r\n controlName = \"TALXIS.PCF.Portal.Duration\";\r\n }\r\n else if (controlNameUpper === \"{0A7FF475-B016-4687-9CE5-042BFDBD6519}\") { // File\r\n controlName = \"TALXIS.PCF.Portal.File\";\r\n }\r\n else if (controlNameUpper === \"MSCRMCONTROLS.MODELFORM.MODELFORMCONTROL\") {\r\n controlName = \"TALXIS.PCF.Portal.Form\";\r\n }\r\n else if (controlNameUpper === \"MSCRMCONTROLS.GRID.GRIDCONTROL\") {\r\n controlName = \"TALXIS.PCF.Portal.View\";\r\n }\r\n // Unsupported controls\r\n else if (controlNameUpper === \"{7C624A0B-F59E-493D-9583-638D34759266}\" || // Timezone\r\n controlNameUpper === \"{06375649-C143-495E-A496-C962E5B4488E}\" || // Notes\r\n controlNameUpper === \"{671A9387-CA5A-4D1E-8AB7-06E39DDCF6B5}\" || // Language\r\n (controlNameUpper.startsWith(\"{\") && controlNameUpper.endsWith(\"}\")) || // All other unmatched native controls\r\n false\r\n ) {\r\n console.warn(`Found unsupported control! Name: ${controlName}, datafieldname: ${controlElement.getAttribute('datafieldname')}`);\r\n controlName = null;\r\n }\r\n\r\n let dataFieldName: string;\r\n switch (controlType) {\r\n case FormControlType.Field:\r\n dataFieldName = controlElement.getAttribute('datafieldname');\r\n if (!dataFieldName) {\r\n // When we are in dialog, we treat `id` field as `datafieldname` for default value output\r\n dataFieldName = controlElement.getAttribute('id');\r\n }\r\n break;\r\n }\r\n\r\n const isUnbound = controlElement.getAttribute('isunbound') === \"true\";\r\n const isRequired = controlElement.getAttribute('isrequired') === \"true\";\r\n const control: Form.Control = {\r\n name: controlName,\r\n type: controlType,\r\n xrmType: this._getControlXrmType(controlElement.getAttribute('classid'), isCustomControl ? controlName : null, indicationOfSubgrid === 'true'),\r\n classId: controlElement.getAttribute('classid'),\r\n id: controlElement.getAttribute('id'),\r\n disabled: controlElement.getAttribute('disabled') === 'true' ? true : false,\r\n // Visible comes from cell since it is primarily manipulated on the control level\r\n visible: visible,\r\n isRequired: isRequired,\r\n isUnbound: isUnbound,\r\n datafieldname: dataFieldName,\r\n bindings: this._parseControlBindings(dataFieldName, controlElement.getElementsByTagName('parameters')[0], controlName, controlUniqueId, controlId, isUnbound, isRequired, controlNameUpper),\r\n onClickEventHandlers: formEvents.filter(x => x.attribute === controlElement.getAttribute('id') && x.name === \"onclick\")?.[0]?.handlers,\r\n // Fix rendering for unsupported control types\r\n definition: controlName !== null ? await ControlLoader.getAsync(controlName) : null\r\n };\r\n\r\n return control;\r\n };\r\n //TODO: return types in Xrm do not always correspond to what gets returned in Power Apps\r\n //for example, multiselectoptionset is not specified in types (https://learn.microsoft.com/en-us/power-apps/developer/model-driven-apps/clientapi/reference/controls/getcontroltype)\r\n //but Power Apps returns it\r\n private _getControlXrmType(classId: string, customControlName?: string, isSubgrid?: boolean): Xrm.Controls.ControlType {\r\n if (customControlName) {\r\n //@ts-ignore - we need to update typings\r\n return `${isSubgrid ? 'customsubgrid' : 'customcontrol'}:${customControlName}`;\r\n }\r\n switch (classId.toUpperCase()) {\r\n case \"{270BD3DB-D9AF-4782-9025-509E298DEC0A}\": // Lookup \r\n case \"{CBFB742C-14E7-4A17-96BB-1A13F7F64AA2}\": // PartyList\r\n case \"{F3015350-44A2-4AA0-97B5-00166532B5E9}\": // Regarding\r\n return \"lookup\";\r\n\r\n case \"{E7A81278-8635-4D9E-8D4D-59480B391C5B}\":\r\n case \"{F9A8A302-114E-466A-B582-6771B2AE0D92}\": // View\r\n return \"subgrid\";\r\n\r\n case \"{3EF39988-22BB-4F0B-BBBE-64B5A3748AEE}\": // Option Set\r\n return \"optionset\";\r\n case \"{4AA28AB7-9C13-4F57-A73D-AD894D048B5F}\": // MultiSelectOptionSet\r\n //@ts-ignore - not part of types \r\n return \"multiselectoptionset\";\r\n\r\n case \"MSCRMCONTROLS.MODELFORM.MODELFORMCONTROL\":\r\n //@ts-ignore - missing in types\r\n return \"formcomponent\";\r\n default:\r\n return \"standard\";\r\n }\r\n };\r\n\r\n private _parseControlBindings = (datafieldname: string, parametersElement: Element, controlName: string, uniqueId: string, controlId: string, isUnbound: boolean, isRequired: boolean, classId: string): Form.ControlBindings => {\r\n const controlDescriptions = this._controlDescriptions.find(x => x.forControl === uniqueId)?.customControls?.filter(x => x.formFactor === \"0\" || x.formFactor === \"1\");\r\n let controlDescriptionBindings: Form.ControlBindings = {};\r\n for (const controlDescription of controlDescriptions ?? []) {\r\n // TODO: Add isRequired true to first bound field\r\n controlDescriptionBindings = { ...controlDescriptionBindings, ...controlDescription.bindingParameters };\r\n }\r\n\r\n // TODO: Primary (binding) field is the first field set to \"bound\" in PCF manifest, which we don't know here yet, so we just use the first non-static field\r\n const primaryBoundField = Object.entries(controlDescriptionBindings).find(x => x[1].isStatic === false);\r\n if (primaryBoundField) {\r\n controlDescriptionBindings[primaryBoundField[0]].isRequired = isRequired;\r\n }\r\n\r\n const formControlInlineBindings: Form.ControlBindings = {};\r\n if (parametersElement) {\r\n for (const parameter of parametersElement.children) {\r\n formControlInlineBindings[parameter.tagName] = {\r\n isStatic: true,\r\n value: parameter.hasChildNodes() ? parameter.innerHTML : parameter.textContent,\r\n };\r\n }\r\n }\r\n\r\n // This is fallback for native controls which have no bindings explicitly specified in the form\r\n if (Object.entries({ ...controlDescriptionBindings, ...formControlInlineBindings }).length === 0 ||\r\n // Handles unbound controls like those on Dialogs, especially OptionSet\r\n (isUnbound && !Object.keys({ ...controlDescriptionBindings, ...formControlInlineBindings }).includes(\"value\")) ||\r\n (!isUnbound && Object.entries({ ...controlDescriptionBindings, ...formControlInlineBindings }).find(x => x[1].isStatic === false) !== null) ||\r\n // Set proper lookup value when we are a bound form control for lookup to work correctly.\r\n (controlName === \"TALXIS.PCF.Portal.Form\" && Object.keys({ ...controlDescriptionBindings, ...formControlInlineBindings }).includes(\"value\")) ||\r\n (controlName === \"TALXIS.PCF.Portal.SimpleLookup\" && !Object.keys({ ...controlDescriptionBindings, ...formControlInlineBindings }).includes(\"value\"))\r\n ) {\r\n // TODO: This should come dynamically from manifest (which we don't have at this time yet)\r\n const property = \"value\";\r\n // Prevent conflict with other hard set values - primarily for Form Control\r\n if (controlDescriptionBindings && controlDescriptionBindings[property]) delete controlDescriptionBindings[property];\r\n if (datafieldname != null) {\r\n // If control is Party List and is not \"from\", set MultipleEnabled to true\r\n if (classId === \"{CBFB742C-14E7-4A17-96BB-1A13F7F64AA2}\" && datafieldname !== \"from\") {\r\n formControlInlineBindings[\"MultipleEnabled\"] = {\r\n isStatic: true,\r\n value: \"true\",\r\n isRequired: isRequired\r\n };\r\n }\r\n formControlInlineBindings[property] = {\r\n isStatic: false,\r\n value: datafieldname,\r\n isRequired: isRequired\r\n };\r\n }\r\n else {\r\n // In dialogs controls don't have datafieldname specified but use their ID as a virtual attribute on the form\r\n formControlInlineBindings[property] = {\r\n isStatic: false,\r\n value: controlId,\r\n isRequired: isRequired\r\n };\r\n }\r\n }\r\n\r\n return { ...controlDescriptionBindings, ...formControlInlineBindings };\r\n };\r\n\r\n private _getLabel = (element: Element, localizedLabels?: ILocalizedLabel[]): string => {\r\n if (!element || !this._showLabel(element)) {\r\n // TODO: This should be handled on the future PCF label level\r\n return null;\r\n }\r\n\r\n if (localizedLabels && localizedLabels.length > 0) {\r\n return LocalizeLabel(localizedLabels);\r\n }\r\n\r\n const labelsWrap = element.getElementsByTagName('labels')[0];\r\n if (!labelsWrap) {\r\n throw new Error('No labels were set for this object. Either add them or set showlabel parameter to false.');\r\n }\r\n\r\n const labels: ILocalizedLabel[] = [];\r\n for (const label of labelsWrap.getElementsByTagName('label')) {\r\n labels.push({\r\n Label: label.getAttribute('description'),\r\n LanguageCode: parseInt(label.getAttribute('languagecode'))\r\n });\r\n }\r\n\r\n if (labels.length === 0) {\r\n throw new Error('No labels were set for this object. Either add them or set showlabel parameter to false.');\r\n }\r\n\r\n return LocalizeLabel(labels) ?? \"Unknown\";\r\n };\r\n\r\n private _getControlName = (element: Element): string => {\r\n let name;\r\n const uniqueId = element.getAttribute('uniqueid');\r\n if (uniqueId) {\r\n const controlDescription = this._controlDescriptions.filter(x => x.forControl === uniqueId)[0];\r\n if (controlDescription) {\r\n name = controlDescription.customControls.filter(customControl => customControl.name != undefined)[0]?.name;\r\n if (name) {\r\n const parts = name.split(\"_\");\r\n if (parts[1]) {\r\n name = parts[1];\r\n }\r\n }\r\n }\r\n }\r\n if (!name) {\r\n name = element.getAttribute('classid');\r\n }\r\n return name;\r\n };\r\n\r\n private _showLabel = (element: Element): boolean => {\r\n const _showLabel = element.getAttribute('showlabel');\r\n if (_showLabel === 'false') {\r\n return false;\r\n }\r\n return true;\r\n };\r\n private _decode = (escapedStr: string): string => {\r\n const txt = document.createElement(\"textarea\");\r\n txt.innerHTML = escapedStr;\r\n return txt.value;\r\n };\r\n}","import React, { useContext, useRef } from 'react';\r\nimport { Control } from '../../../../';\r\nimport { IFormContext } from '../../interfaces/IFormContext';\r\nimport { FormContext } from '../../Form';\r\nimport { Form } from \"../../interfaces/form\";\r\nimport { Icon, Label, mergeStyles, useTheme } from '@fluentui/react';\r\nimport { getRequiredLevel } from '@ComponentFramework/PropertyClasses/Context';\r\nimport { FormControlType } from '../../interfaces/enums';\r\n\r\nexport interface ICellProps {\r\n cell: Form.Cell;\r\n index?: number;\r\n tabContentType?: 'cardSections' | 'singleComponent',\r\n formContext?: IFormContext;\r\n theme?: ComponentFramework.FluentDesignState;\r\n onFormUpdated: (arg: { formContext: Xrm.FormContext }) => void;\r\n};\r\n\r\nexport const Cell: React.FC = (props) => {\r\n const formContext: IFormContext = props.formContext ?? useContext(FormContext);\r\n const theme = useTheme();\r\n const cell = props.cell;\r\n const control = props.cell.control;\r\n const ref = useRef(null);\r\n let dataIdClass = \"fieldControl_container\";\r\n const lockIconClassName = 'TALXIS__form__cell__lockIcon';\r\n const requiredLevel = getRequiredLevel(formContext.attributeConfiguration[control?.datafieldname], control?.isRequired);\r\n if (cell?.control?.classId.toLowerCase() === \"{4273edbd-ac1d-40d3-9fb2-095c621b552d}\") {\r\n dataIdClass = \"fieldControl-text-box-container\";\r\n }\r\n const labelVisible = () => {\r\n if (props.tabContentType === 'singleComponent' && props.index === 0) {\r\n return false;\r\n }\r\n if (cell?.label && cell?.showLabel && cell?.control && cell?.control?.bindings?.EnableViewPicker?.value !== 'true' && cell?.control?.name !== 'TALXIS.PCF.Portal.Label') {\r\n return true;\r\n }\r\n return false;\r\n };\r\n const shouldDisplay = () => {\r\n if (((control && (control.visible ?? true)) || (!cell.control && (cell?.visible ?? true))) && (!formContext.isMobile || (cell?.availableForPhone ?? true))) {\r\n return true;\r\n }\r\n return false;\r\n };\r\n const isMultipleOrSubgrid = () => {\r\n const bindingTypeGroup = cell?.control?.definition?.manifest.properties[0]?.ofTypeGroup;\r\n if (cell?.control?.definition?.manifest.properties[0]?.ofType === 'Multiple') {\r\n return true;\r\n }\r\n if (bindingTypeGroup && cell?.control?.definition?.manifest.typeGroups.find(typeGroup => typeGroup.name === bindingTypeGroup && typeGroup.types.includes('Multiple')))\r\n if (cell?.control?.definition?.manifest.typeGroups.find(typeGroup => typeGroup.types.includes('Multiple'))) {\r\n return true;\r\n }\r\n if (cell.control?.name === 'TALXIS.PCF.Portal.View') {\r\n return true;\r\n }\r\n return false;\r\n };\r\n if (props.tabContentType === 'singleComponent' && props.index !== 0) {\r\n return <>;\r\n }\r\n const getRowEnd = (): string | undefined => {\r\n if (!cell.rowspan || cell.rowspan === '1') {\r\n return undefined;\r\n }\r\n return `span ${parseInt(cell.rowspan) * 3}`;\r\n };\r\n return (\r\n //In dialogs controls may not be defined for label placeholders and in that case labels should be displayed\r\n <>\r\n
div>label>[data-icon-name^=\"Lock\"]': {\r\n visibility: control?.disabled ? 'visible' : 'hidden'\r\n }\r\n\r\n })}`}>\r\n {/* //we always need to render the top level cell element even if it's not visible\r\n //if we do not, the layout with spacers might get broken as we do not seperate between rows\r\n //in HTML (to allow rowspan for elements), if the cells disappears the spacers might appear in different row which break the layout */}\r\n {shouldDisplay() &&\r\n
\r\n {labelVisible() &&\r\n <>\r\n \r\n \r\n }\r\n {cell?.control &&\r\n
\r\n \r\n
\r\n }\r\n
\r\n }\r\n
\r\n \r\n );\r\n};\r\nexport default Cell;","import { OptionSet, IOptionSetDefinition } from '../../interfaces/optionset';\r\nimport { GlobalOptionSet, ITwoOptionsDefinition } from '../../interfaces/twooptions';\r\nimport { MultiSelectOptionSet, IMultiSelectOptionSetDefinition } from '../../interfaces/multiselectoptionset';\r\nimport { IODataResponse } from '../../interfaces/general';\r\nimport { sendMetadataGetRequest } from './MetadataApi';\r\nimport { IPromiseCache, cachedWrapper } from '@utilities/MemoryCachingHelpers';\r\n\r\nexport class OptionSetDefinition {\r\n private static _optionSetDefinition: IPromiseCache> = {};\r\n private static _globalOptionSetDefinition: IPromiseCache = {};\r\n private static _twoOptionsDefinition: IPromiseCache> = {};\r\n private static _globalTwoOptionsDefinition: IPromiseCache = {};\r\n private static _multiSelectOptionSetDefinition: IPromiseCache> = {};\r\n private static _globalMultiSelectOptionSetDefinition: IPromiseCache = {};\r\n\r\n static async getAsync(entityName: string): Promise> {\r\n return cachedWrapper(entityName, () => new Promise>(async (resolve) => {\r\n const optionSetsDefinition = this._getOptionSetsAsync(entityName);\r\n const statusOptionSetsDefinition = this._getStatusOptionSetsAsync(entityName);\r\n const stateOptionSetsDefinition = this._getStateOptionSetsAsync(entityName);\r\n const multiselectOptionSetsDefinition = this.getMultiSelectOptionSetAsync(entityName);\r\n const twoOptionsOptionSetsDefinition = this.getTwoOptionsAsync(entityName);\r\n\r\n const [optionSets, statusOptionSets, stateOptionSets, multiselectOptionSets, twoOptionsOptionSets] = await Promise.all([optionSetsDefinition, statusOptionSetsDefinition, stateOptionSetsDefinition, multiselectOptionSetsDefinition, twoOptionsOptionSetsDefinition]);\r\n\r\n const twoOptionsTransformed = twoOptionsOptionSets.value.map((twoOptionsOptionSet) => {\r\n const transformed: IOptionSetDefinition = {\r\n DefaultFormValue: twoOptionsOptionSet.DefaultValue ? 1 : 0,\r\n LogicalName: twoOptionsOptionSet.LogicalName,\r\n RequiredLevel: twoOptionsOptionSet.RequiredLevel,\r\n OptionSet: {\r\n IsGlobal: twoOptionsOptionSet.OptionSet.IsGlobal,\r\n Description: twoOptionsOptionSet.OptionSet.Description,\r\n DisplayName: twoOptionsOptionSet.OptionSet.DisplayName,\r\n ExternalTypeName: twoOptionsOptionSet.OptionSet.ExternalTypeName,\r\n IsCustomOptionSet: twoOptionsOptionSet.OptionSet.IsCustomOptionSet,\r\n Name: twoOptionsOptionSet.OptionSet.Name,\r\n OptionSetType: twoOptionsOptionSet.OptionSet.OptionSetType,\r\n Options: []\r\n },\r\n };\r\n if (twoOptionsOptionSet.OptionSet.TrueOption == null || twoOptionsOptionSet.OptionSet.FalseOption == null) {\r\n console.warn(`Two Options OptionSet ${twoOptionsOptionSet.LogicalName}, is missing True or False Option!`);\r\n }\r\n else {\r\n transformed.OptionSet.Options = [{\r\n Color: twoOptionsOptionSet.OptionSet.TrueOption.Color,\r\n Description: twoOptionsOptionSet.OptionSet.TrueOption.Description,\r\n Label: twoOptionsOptionSet.OptionSet.TrueOption.Label,\r\n Value: twoOptionsOptionSet.OptionSet.TrueOption.Value,\r\n ExternalValue: twoOptionsOptionSet.OptionSet.TrueOption.ExternalValue,\r\n ParentValues: twoOptionsOptionSet.OptionSet.TrueOption.ParentValues,\r\n }, {\r\n Color: twoOptionsOptionSet.OptionSet.FalseOption.Color,\r\n Description: twoOptionsOptionSet.OptionSet.FalseOption.Description,\r\n Label: twoOptionsOptionSet.OptionSet.FalseOption.Label,\r\n Value: twoOptionsOptionSet.OptionSet.FalseOption.Value,\r\n ExternalValue: twoOptionsOptionSet.OptionSet.FalseOption.ExternalValue,\r\n ParentValues: twoOptionsOptionSet.OptionSet.FalseOption.ParentValues,\r\n }];\r\n }\r\n return transformed;\r\n });\r\n\r\n resolve({\r\n value: [...optionSets.value, ...statusOptionSets.value, ...stateOptionSets.value, ...multiselectOptionSets.value, ...twoOptionsTransformed]\r\n });\r\n }), this._optionSetDefinition);\r\n }\r\n static async getTwoOptionsAsync(entityName: string): Promise> {\r\n return cachedWrapper(entityName, () => this._getTwoOptionsAsync(entityName), this._twoOptionsDefinition);\r\n }\r\n static async getGlobalTwoOptionsAsync(optionsetName: string): Promise {\r\n return cachedWrapper(optionsetName, () => this._getGlobalOptionSetsAsync(optionsetName) as unknown as Promise, this._globalTwoOptionsDefinition);\r\n }\r\n static async getGlobalAsync(optionsetName: string): Promise {\r\n return cachedWrapper(optionsetName, () => this._getGlobalOptionSetsAsync(optionsetName), this._globalOptionSetDefinition);\r\n }\r\n static async getGlobalMultiSelectOptionSetAsync(optionsetName: string): Promise {\r\n return cachedWrapper(optionsetName, () => this._getGlobalMultiSelectOptionSetAsync(optionsetName), this._globalMultiSelectOptionSetDefinition);\r\n }\r\n static async getMultiSelectOptionSetAsync(entityName: string): Promise> {\r\n return cachedWrapper(entityName, () => this._getMultiSelectOptionSetAsync(entityName), this._multiSelectOptionSetDefinition);\r\n }\r\n\r\n private static async _getTwoOptionsAsync(entityName: string): Promise> {\r\n const response = await sendMetadataGetRequest(`v9.1/EntityDefinitions(LogicalName='${entityName}')/Attributes/Microsoft.Dynamics.CRM.BooleanAttributeMetadata?$select=LogicalName,RequiredLevel,DefaultValue&$expand=OptionSet,GlobalOptionSet`);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch option sets for ${entityName} Entity!`);\r\n }\r\n\r\n const optionSetsDefinition: IODataResponse = await response.json();\r\n return optionSetsDefinition;\r\n }\r\n\r\n private static async _getOptionSetsAsync(entityName: string): Promise> {\r\n const response = await sendMetadataGetRequest(`v9.1/EntityDefinitions(LogicalName='${entityName}')/Attributes/Microsoft.Dynamics.CRM.PicklistAttributeMetadata?$select=LogicalName,RequiredLevel&$expand=OptionSet,GlobalOptionSet`);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch option sets for ${entityName} Entity!`);\r\n }\r\n\r\n const optionSetsDefinition: IODataResponse = await response.json();\r\n return optionSetsDefinition;\r\n }\r\n private static async _getStatusOptionSetsAsync(entityName: string): Promise> {\r\n const response = await sendMetadataGetRequest(`v9.1/EntityDefinitions(LogicalName='${entityName}')/Attributes/Microsoft.Dynamics.CRM.StatusAttributeMetadata?$select=LogicalName,RequiredLevel&$expand=OptionSet,GlobalOptionSet`);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch option sets for ${entityName} Entity!`);\r\n }\r\n\r\n const optionSetsDefinition: IODataResponse = await response.json();\r\n return optionSetsDefinition;\r\n }\r\n private static async _getStateOptionSetsAsync(entityName: string): Promise> {\r\n const response = await sendMetadataGetRequest(`v9.1/EntityDefinitions(LogicalName='${entityName}')/Attributes/Microsoft.Dynamics.CRM.StateAttributeMetadata?$select=LogicalName,RequiredLevel&$expand=OptionSet,GlobalOptionSet`);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch option sets for ${entityName} Entity!`);\r\n }\r\n\r\n const optionSetsDefinition: IODataResponse = await response.json();\r\n return optionSetsDefinition;\r\n }\r\n private static async _getGlobalOptionSetsAsync(optionsetName: string): Promise {\r\n const response = await sendMetadataGetRequest(`v9.1/GlobalOptionSetDefinitions(Name='${optionsetName}')`);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch global option set ${optionsetName}!`);\r\n }\r\n\r\n const optionSetsDefinition: OptionSet = await response.json();\r\n return optionSetsDefinition;\r\n }\r\n private static async _getMultiSelectOptionSetAsync(entityName: string): Promise> {\r\n const response = await sendMetadataGetRequest(`v9.1/EntityDefinitions(LogicalName='${entityName}')/Attributes/Microsoft.Dynamics.CRM.MultiSelectPicklistAttributeMetadata?$select=LogicalName,RequiredLevel&$expand=OptionSet,GlobalOptionSet`);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch option sets for ${entityName} Entity!`);\r\n }\r\n\r\n const multiSelectOptionSetsDefinition: IODataResponse = await response.json();\r\n return multiSelectOptionSetsDefinition;\r\n }\r\n private static async _getGlobalMultiSelectOptionSetAsync(optionsetName: string): Promise {\r\n const response = await sendMetadataGetRequest(`v9.1/GlobalOptionSetDefinitions(Name='${optionsetName}')`);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch global option set ${optionsetName}!`);\r\n }\r\n\r\n const optionSetsDefinition: MultiSelectOptionSet = await response.json();\r\n return optionSetsDefinition;\r\n }\r\n}","import { SiteMap } from \"../../interfaces/sitemap\";\r\nimport { IconLoader } from \"@loaders/IconLoader\";\r\nimport { AppModule } from \"@configuration/AppModule\";\r\nimport * as queryString from 'query-string';\r\nimport { QueryData } from \"@pages/Control/interfaces\";\r\nimport { Exception } from \"../exceptions/Exception\";\r\nimport { ILocalizedLabel, LocalizeLabel } from \"@localization/helpers\";\r\nimport { EntityDefinition } from \"@definitions/EntityDefinition\";\r\nimport { DomParser } from \"../../Constants\";\r\n\r\nexport class SiteMapMapper {\r\n static async parseAsync(siteMapXml: any): Promise {\r\n const xmlDoc = DomParser.parseFromString(siteMapXml, \"text/xml\");\r\n const siteMap: SiteMap.Root = {\r\n areas: await this._parseAreas(xmlDoc.getElementsByTagName('Area'))\r\n };\r\n return siteMap;\r\n };\r\n private static async _parseAreas(areasCollection: HTMLCollectionOf): Promise {\r\n const areas: SiteMap.Area[] = [];\r\n for (const area of areasCollection) {\r\n areas.push({\r\n id: area.getAttribute('Id'),\r\n showGroups: area.getAttribute('ShowGroups') == 'true',\r\n groups: await this._parseGroups(area.getElementsByTagName('Group')),\r\n title: await this._getTitle(area),\r\n icon: await IconLoader.getAsync(area.getAttribute('Icon')),\r\n disabled: false,\r\n visible: true\r\n });\r\n }\r\n return areas;\r\n };\r\n\r\n private static async _parseGroups(groupsCollection: HTMLCollectionOf): Promise {\r\n const groups: SiteMap.Group[] = [];\r\n for (const group of groupsCollection) {\r\n const title = await this._getTitle(group);\r\n groups.push({\r\n id: group.getAttribute('Id'),\r\n subAreas: await this._parseSubAreas(title, group.getElementsByTagName('SubArea')),\r\n title: title,\r\n icon: await IconLoader.getAsync(group.getAttribute('Icon')),\r\n visible: true\r\n });\r\n }\r\n return groups;\r\n }\r\n\r\n private static async _parseSubAreas(parentGroupTitle: string, subAreasCollection: HTMLCollectionOf): Promise {\r\n const subAreas: SiteMap.SubArea[] = [];\r\n for (const _subArea of subAreasCollection) {\r\n const id = _subArea.getAttribute('Id');\r\n const url = this._unescapeXML(_subArea.getAttribute('Url'));\r\n let entity = _subArea.getAttribute('Entity');\r\n if (!url && !entity) {\r\n throw new Error(`Either URL or entity name has to be specified for sub area ${id} in the sitemap.`);\r\n }\r\n\r\n let portalUrl: string = `/${AppModule.get().uniquename}`;\r\n const dataQuery: QueryData = {};\r\n\r\n if (url) {\r\n const queryParams = queryString.parse(url.substring(url.indexOf(\"?\")));\r\n if (!queryParams?.pagetype) {\r\n portalUrl = url; //Opens a page that is outside the dataverse environment.\r\n } else {\r\n switch (queryParams.pagetype as string) {\r\n case \"entityrecord\":\r\n dataQuery.entityName = queryParams.etn as string;\r\n dataQuery.entityId = queryParams.id as string;\r\n dataQuery.formId = queryParams.formid as string;\r\n portalUrl += `/control/form?data=${JSON.stringify(dataQuery)}`;\r\n entity = queryParams.etn as string;\r\n break;\r\n case \"entitylist\": {\r\n dataQuery.entityName = queryParams.etn as string;\r\n dataQuery.viewId = queryParams.viewid as string;\r\n dataQuery.viewType = queryParams.viewtype as string;\r\n portalUrl += `/control/view?data=${JSON.stringify(dataQuery)}`;\r\n entity = queryParams.etn as string;\r\n break;\r\n }\r\n case \"control\": {\r\n portalUrl += `/control/${queryParams.controlName}?data=${queryParams.data}`;\r\n break;\r\n }\r\n case \"inlinedialog\": {\r\n dataQuery.name = queryParams.name as string;\r\n portalUrl += `/control/dialog?data=${JSON.stringify(dataQuery)}`;\r\n break;\r\n }\r\n default:\r\n //clear the local storage so user can switch to different app on error\r\n localStorage.removeItem('appModuleName');\r\n throw new Exception(`Unsupported sitemap URL. Current value: ${url}`);\r\n }\r\n }\r\n }\r\n else if (!url && entity) {\r\n dataQuery.entityName = entity;\r\n portalUrl += `/control/view?data=${JSON.stringify(dataQuery)}`;\r\n }\r\n\r\n const subArea: SiteMap.SubArea = {\r\n id: id,\r\n url: portalUrl,\r\n entity: entity,\r\n title: await this._getTitle(_subArea, entity),\r\n icon: await IconLoader.getAsync(_subArea.getAttribute('Icon')),\r\n disabled: false,\r\n visible: true,\r\n parentGroupTitle: parentGroupTitle\r\n };\r\n subAreas.push(subArea);\r\n }\r\n return subAreas;\r\n };\r\n\r\n private static _unescapeXML(input?: string) {\r\n return input?.replace('&', '&')\r\n .replace('<', '<')\r\n .replace('>', '>')\r\n .replace('"', '\"')\r\n .replace(''', \"'\");\r\n }\r\n\r\n private static async _getTitle(element: Element, entity?: string): Promise {\r\n const titlesWrap = element.getElementsByTagName('Titles')[0];\r\n if (!titlesWrap) {\r\n if (entity) {\r\n const entityDefinition = await EntityDefinition.getAsync(entity);\r\n return LocalizeLabel(entityDefinition.DisplayCollectionName.LocalizedLabels) ?? \"Unknown\";\r\n }\r\n return null;\r\n }\r\n\r\n const labels: ILocalizedLabel[] = [];\r\n for (const title of titlesWrap.getElementsByTagName('Title')) {\r\n labels.push({\r\n Label: title.getAttribute('Title'),\r\n LanguageCode: parseInt(title.getAttribute('LCID'))\r\n });\r\n }\r\n\r\n let label = LocalizeLabel(labels);\r\n // If we can't find label and are pointing to a view, fetch the label from collection name\r\n if (!label && entity) {\r\n const entityDefinition = await EntityDefinition.getAsync(entity);\r\n label = LocalizeLabel(entityDefinition.DisplayCollectionName.LocalizedLabels);\r\n }\r\n\r\n return label ?? \"Unknown\";\r\n };\r\n};","import {\r\n BaseSlots,\r\n createTheme,\r\n getColorFromString,\r\n isDark,\r\n IThemeRules,\r\n ThemeGenerator,\r\n themeRulesStandardCreator,\r\n} from '@fluentui/react';\r\n\r\nexport enum ThemeType {\r\n RIBBON = \"ribbon\",\r\n MAIN = \"main\",\r\n NAVIGATION = \"navigation\",\r\n NAVBAR = \"navbar\",\r\n}\r\n\r\nexport class ThemeDesigner {\r\n\r\n public static generateTheme(\r\n {\r\n primaryColor, textColor, backgroundColor,\r\n }: {\r\n primaryColor: string, textColor: string, backgroundColor: string,\r\n },\r\n ) {\r\n const themeRules = themeRulesStandardCreator();\r\n const colors = {\r\n primaryColor: getColorFromString(primaryColor)!,\r\n textColor: getColorFromString(textColor)!,\r\n backgroundColor: getColorFromString(backgroundColor)!,\r\n };\r\n\r\n const isCustomization = false;\r\n const overwriteCustomColor = true;\r\n\r\n ThemeGenerator.setSlot(\r\n themeRules[BaseSlots[BaseSlots.backgroundColor]],\r\n colors.backgroundColor,\r\n undefined,\r\n isCustomization,\r\n overwriteCustomColor,\r\n );\r\n\r\n const currentIsDark = isDark(themeRules[BaseSlots[BaseSlots.backgroundColor]].color!);\r\n\r\n ThemeGenerator.setSlot(\r\n themeRules[BaseSlots[BaseSlots.primaryColor]],\r\n colors.primaryColor,\r\n currentIsDark,\r\n isCustomization,\r\n overwriteCustomColor,\r\n );\r\n ThemeGenerator.setSlot(\r\n themeRules[BaseSlots[BaseSlots.foregroundColor]],\r\n colors.textColor,\r\n currentIsDark,\r\n isCustomization,\r\n overwriteCustomColor,\r\n );\r\n\r\n // strip out the unnecessary shade slots from the final output theme\r\n const abridgedTheme: IThemeRules = Object.entries(themeRules).reduce(\r\n (acc, [ruleName, ruleValue]) => (\r\n (\r\n ruleName.indexOf('ColorShade') === -1\r\n && ruleName !== 'primaryColor'\r\n && ruleName !== 'backgroundColor'\r\n && ruleName !== 'foregroundColor'\r\n && ruleName.indexOf('body') === -1\r\n )\r\n ? {\r\n ...acc,\r\n [ruleName]: ruleValue,\r\n }\r\n : acc\r\n ),\r\n {} as IThemeRules,\r\n );\r\n\r\n return createTheme({ palette: ThemeGenerator.getThemeAsJson(abridgedTheme), isInverted: isDark(themeRules[BaseSlots[BaseSlots.backgroundColor]].color!) });\r\n }\r\n}\r\n","import { isDev } from \"../../Functions\";\r\nimport { getTheme, loadTheme, mergeStyleSets } from \"@fluentui/react\";\r\nimport { buildMetadataUrl, getWebResourceUrl } from \"@definitions/MetadataApi\";\r\nimport { DEFAULT_BODY_MAIN_BACKGROUND_COLOR, FRONTEND_VERSION } from \"@src/app/Constants\";\r\nimport { createBrandVariants, createV9Theme } from \"@fluentui/react-migration-v8-v9\";\r\nimport color from 'color';\r\nimport { getControlTheme } from '@talxis/base-controls/dist/utils/Theme';\r\nimport { normalizeComponentStyling } from \"@talxis/base-controls/dist/utils/Theme\";\r\nimport { ITheme } from \"@talxis/base-controls/dist/interfaces/theme\";\r\nimport { ThemeDesigner, ThemeType } from \"../utilities/ThemeDesigner\";\r\n\r\nexport enum SitemapOrientation {\r\n Horizontal = 742070000,\r\n Vertical = 742070001\r\n}\r\nexport enum SitemapAlignment {\r\n Center = 742070000,\r\n Left = 742070001\r\n}\r\n\r\ninterface ISitemapParameters {\r\n horizontalAlignment: SitemapAlignment;\r\n showHorizontalIcons: boolean;\r\n veritalAreasAsTabs: boolean;\r\n orientation: SitemapOrientation;\r\n};\r\nexport class Theme {\r\n private _logoUrl?: string;\r\n private _ribbonTheme?: ITheme;\r\n private _navbarTheme?: ITheme;\r\n private _navigationTheme?: ITheme;\r\n private _mainTheme: ITheme;\r\n private _controlV9Theme: ComponentFramework.FluentDesignState;\r\n private _controlV8Theme: ITheme;\r\n private _navbarControlV9Theme: ComponentFramework.FluentDesignState;\r\n private _navbarControlV8Theme: ITheme;\r\n private _formHeaderControlV9Theme: ComponentFramework.FluentDesignState;\r\n public bodyBackgroudColor?: string;\r\n public gradientBackground: boolean;\r\n public containerWidth: number | undefined;\r\n public globalNotificationCollapseCount: number;\r\n public sitemap: ISitemapParameters;\r\n\r\n constructor(entity?: ComponentFramework.WebApi.Entity) {\r\n this.globalNotificationCollapseCount = entity?.[\"talxis_globalnotification_collapsecount\"] ?? 2;\r\n this.containerWidth = entity?.[\"talxis_bodywidth\"];\r\n this._injectCustomCss(entity);\r\n this._setSitemapParameters(entity);\r\n this._setThemeParameters(entity);\r\n this._setLogoUrl(entity);\r\n this._injectFavicon(entity);\r\n this._injectCSSVariables();\r\n loadTheme(this._mainTheme);\r\n }\r\n public get ribbon(): ITheme {\r\n return this._ribbonTheme;;\r\n }\r\n public get navigation(): ITheme {\r\n return this._navigationTheme;\r\n }\r\n public get navbar() {\r\n return this._navbarTheme;\r\n }\r\n public get main() {\r\n return this._mainTheme;\r\n }\r\n public get controlV8() {\r\n return this._controlV8Theme;\r\n }\r\n public get controlV9() {\r\n return this._controlV9Theme;\r\n }\r\n public get navbarControlV9() {\r\n return this._navbarControlV9Theme;\r\n }\r\n public get navbarControlV8() {\r\n return this._navbarControlV8Theme;\r\n }\r\n public get formHeaderControlV9() {\r\n return this._formHeaderControlV9Theme;\r\n };\r\n public get logoUrl() {\r\n return this._logoUrl;\r\n }\r\n\r\n private _setLogoUrl(entity: any) {\r\n if (entity?.['talxis_logotooltip']) {\r\n this._logoUrl = buildMetadataUrl(`v9.1/talxis_configuration_themes(${entity['talxis_configuration_themeid']})/talxis_logotooltip/$value`, false, isDev());\r\n return;\r\n }\r\n this._logoUrl = this._navbarTheme.isInverted ? `images/talxis_logo_white.png` : `images/talxis_logo_black.png`;\r\n }\r\n\r\n private _injectCSSVariables() {\r\n const variables: {\r\n [name: string]: string;\r\n } = {};\r\n const injectVaribles = (name: ThemeType, theme: ITheme) => {\r\n for (const [key, value] of Object.entries(theme.semanticColors)) {\r\n variables[`--talxis-${name}-${key}`] = value;\r\n }\r\n for (const [key, value] of Object.entries(theme.palette)) {\r\n variables[`--talxis-${name}-${key}`] = value;\r\n }\r\n };\r\n injectVaribles(ThemeType.MAIN, this._mainTheme);\r\n injectVaribles(ThemeType.NAVBAR, this._navbarTheme);\r\n injectVaribles(ThemeType.RIBBON, this._ribbonTheme);\r\n injectVaribles(ThemeType.NAVIGATION, this._navigationTheme);\r\n document.body.classList.add(mergeStyleSets({\r\n themeVariables: {\r\n '--talxis-main-bodyBackgroundMain': this.bodyBackgroudColor,\r\n ...(this.containerWidth && { '--talxis-main-bodyWidth': `${this.containerWidth}px` }),\r\n ...variables\r\n }\r\n }).themeVariables);\r\n };\r\n\r\n private _injectCustomCss(entity: any) {\r\n const customCSS = entity?.[\"talxis_cascadingstylesheets\"];\r\n if (!customCSS) {\r\n return;\r\n }\r\n const styleElement = document.createElement('style');\r\n styleElement.setAttribute('type', 'text/css');\r\n styleElement.setAttribute('id', 'customCSS');\r\n styleElement.innerHTML = this._replaceWebResourceLinksInCss(customCSS);\r\n document.head.appendChild(styleElement);\r\n }\r\n\r\n private _replaceWebResourceLinksInCss(customCSS: string) {\r\n const generatedCss = customCSS.replace(/: url\\(['\"]?\\/webresources\\/(.*)['\"]?\\)/i, `: url(${getWebResourceUrl(`webresources/$1`)})`);\r\n return generatedCss;\r\n }\r\n private _generateTheme(backgroundColor: string, primaryColor: string, textColor: string, themeType: ThemeType, defaultTheme?: ITheme): ITheme {\r\n return ThemeDesigner.generateTheme({\r\n backgroundColor: backgroundColor,\r\n primaryColor: primaryColor,\r\n textColor: textColor,\r\n });\r\n }\r\n private _generateControlThemes(baseTheme: ITheme, inputTheme?: {\r\n inputBackground?: string;\r\n inputBorder?: string;\r\n inputBorderHovered?: string;\r\n inputText?: string;\r\n inputPlaceholderText?: string;\r\n primaryColor?: string;\r\n underlined?: boolean\r\n }): [ComponentFramework.FluentDesignState, ITheme] {\r\n const theme = ThemeDesigner.generateTheme({\r\n backgroundColor: baseTheme.semanticColors.bodyBackground,\r\n primaryColor: inputTheme.primaryColor ?? baseTheme.palette.themePrimary,\r\n textColor: baseTheme.semanticColors.bodyText,\r\n });\r\n const v9 = createV9Theme(theme);\r\n const brand = createBrandVariants(theme.palette);\r\n\r\n const fluentDesignState: ComponentFramework.FluentDesignState = {\r\n brand: brand,\r\n tokenTheme: { ...v9, ...inputTheme, underlined: inputTheme?.underlined ?? true },\r\n isDarkTheme: new color(theme.semanticColors.bodyBackground).isDark(),\r\n };\r\n const v8 = getControlTheme(fluentDesignState);\r\n return [fluentDesignState, v8];\r\n\r\n }\r\n\r\n private _injectFavicon(entity: any) {\r\n let faviconUrl = `images/favicon.ico?v=${FRONTEND_VERSION}`;\r\n if (entity?.['talxis_faviconlogoid']) {\r\n const url = new URL(buildMetadataUrl(`v9.1/talxis_configuration_themes(${entity['talxis_configuration_themeid']})/talxis_faviconlogoid/$value`, false, isDev()));\r\n //&talxisFavicon parameter is used so the url does not end with .com since it breaks icon fetching\r\n url.searchParams.append('talxis_favicon', 'true');\r\n faviconUrl = url.toString();\r\n }\r\n const faviconElement = document.createElement('link');\r\n faviconElement.setAttribute('rel', 'icon');\r\n faviconElement.setAttribute('href', faviconUrl);\r\n document.head.appendChild(faviconElement);\r\n }\r\n\r\n private _setSitemapParameters(entity: any) {\r\n this.sitemap = {\r\n horizontalAlignment: entity?.[\"talxis_sitemapalignmenttypecode\"] ?? SitemapAlignment.Center,\r\n orientation: entity?.[\"talxis_sitemaporientationtypecode\"] ?? SitemapOrientation.Vertical,\r\n showHorizontalIcons: entity?.[\"talxis_showsitemapitemicons\"] ?? false,\r\n veritalAreasAsTabs: entity?.[\"talxis_areasastabs\"]\r\n };\r\n }\r\n\r\n private _setThemeParameters(entity: any) {\r\n //default value set to 2 to follow PowerApps design\r\n this.gradientBackground = entity?.[\"talxis_backgroundgradient\"];\r\n //this color refers to the background color of entire page and isn't reflected on surfaces\r\n this.bodyBackgroudColor = entity?.['talxis_bodybackgroundcolor'] ?? DEFAULT_BODY_MAIN_BACKGROUND_COLOR;\r\n const baseTheme = getTheme();\r\n //this applies to the background color of all fluent surfaces (card, callout, panel...)\r\n //we currently only support white background since a lot of PCF's and portal code expects these surfaces to be white\r\n //changing this color will break a lot of things, thus why it is currently hardcoded to white\r\n this._mainTheme = normalizeComponentStyling(this._generateTheme('white', entity?.[\"talxis_maincolor\"] ?? baseTheme.palette.themePrimary, entity?.[\"talxis_textcolor\"] ?? baseTheme.semanticColors.bodyText, ThemeType.MAIN));\r\n this._ribbonTheme = normalizeComponentStyling(this._generateTheme(entity?.[\"talxis_ribbonbackgroundcolor\"] ?? this._mainTheme.palette.neutralLighter, entity?.[\"talxis_ribbonprimarycolor\"] ?? this._mainTheme.palette.themePrimary, entity?.[\"talxis_ribbontextcolor\"] ?? this._mainTheme.palette.black, ThemeType.RIBBON, this._mainTheme));\r\n this._navbarTheme = normalizeComponentStyling(this._generateTheme(entity?.[\"talxis_navbarbackgroundcolor\"] ?? this._mainTheme.palette.themePrimary, entity?.[\"talxis_navbarprimarycolor\"] ?? this._mainTheme.palette.white, entity?.[\"talxis_navbartextcolor\"] ?? this._mainTheme.palette.white, ThemeType.NAVBAR, this._mainTheme));\r\n this._navigationTheme = normalizeComponentStyling(this._generateTheme(entity?.[\"talxis_navigationbackgroundcolor\"] ?? this._mainTheme.palette.neutralLighter, entity?.[\"talxis_navigationprimarycolor\"] ?? this._mainTheme.palette.themePrimary, entity?.[\"talxis_navigationtextcolor\"] ?? this._mainTheme.palette.black, ThemeType.NAVIGATION, this._mainTheme));\r\n\r\n [this._controlV9Theme, this._controlV8Theme] = this._generateControlThemes(this._mainTheme, {\r\n inputBackground: entity?.[\"talxis_controlinputbackgroundcolor\"],\r\n inputBorder: entity?.[\"talxis_controlinputbordercolor\"],\r\n inputBorderHovered: entity?.[\"talxis_controlinputborderhoveredcolor\"],\r\n inputPlaceholderText: entity?.[\"talxis_controlinputplaceholdertextcolor\"],\r\n inputText: entity?.[\"talxis_controlinputtextcolor\"],\r\n primaryColor: entity?.[\"talxis_controlprimarycolor\"],\r\n underlined: entity?.[\"talxis_controlinputunderlinedtypecode\"],\r\n\r\n });\r\n [this._navbarControlV9Theme, this._navbarControlV8Theme] = this._generateControlThemes(this._navbarTheme, {\r\n inputBackground: entity?.[\"talxis_navbarcontrolinputbackgroundcolor\"],\r\n inputBorder: entity?.[\"talxis_navbarcontrolinputbordercolor\"],\r\n inputBorderHovered: entity?.[\"talxis_navbarcontrolinputborderhoveredcolor\"],\r\n inputPlaceholderText: entity?.[\"talxis_navbarcontrolinputplaceholdertextcolor\"],\r\n inputText: entity?.[\"talxis_navbarcontrolinputtextcolor\"],\r\n primaryColor: entity?.[\"talxis_navbarcontrolprimarycolor\"],\r\n underlined: entity?.[\"talxis_navbarcontrolinputunderlinedtypecode\"]\r\n });\r\n [this._formHeaderControlV9Theme] = this._generateControlThemes(this._mainTheme, {\r\n inputPlaceholderText: entity?.[\"talxis_controlinputplaceholdertextcolor\"],\r\n inputText: entity?.[\"talxis_controlinputtextcolor\"],\r\n primaryColor: entity?.[\"talxis_controlprimarycolor\"],\r\n underlined: entity?.[\"talxis_controlunderlined\"],\r\n inputBackground: this._mainTheme.semanticColors.bodyBackground,\r\n inputBorder: 'transparent',\r\n inputBorderHovered: 'transparent',\r\n });\r\n }\r\n\r\n}","interface IAppModuleThemes {\r\n appModuleUniqueName: string;\r\n themeId: string;\r\n}\r\ninterface IAppModuleConnectionDTO { _talxis_themeid_value: string, talxis_appmoduleid: { talxis_uniquename: string } }\r\n\r\nexport class Website {\r\n public fallBackThemeId?: string;\r\n public allowedAppModules?: string[];\r\n public appModuleThemes: IAppModuleThemes[] = [];\r\n\r\n constructor(entity?: ComponentFramework.WebApi.Entity) {\r\n this.fallBackThemeId = entity?.[\"_talxis_themeid_value\"] as string;\r\n this.allowedAppModules = (entity?.[\"talxis_allowedappmodules\"] as string)?.trim()?.split(',');\r\n entity?.['talxis_talxis_website_talxis_appmodulewebsiteconnection_websiteid'].map((appModuleTheme: IAppModuleConnectionDTO) => {\r\n this.appModuleThemes.push({\r\n themeId: appModuleTheme._talxis_themeid_value,\r\n appModuleUniqueName: appModuleTheme.talxis_appmoduleid.talxis_uniquename\r\n });\r\n });\r\n }\r\n}","import { metadataRetrieveMultiple } from \"./MetadataApi\";\r\nimport { Website } from \"@models/Website\";\r\nexport class WebsiteDefinition {\r\n private static _website: Website | null = null;\r\n public static getWebsite(): Website | null {\r\n if (!this._website) {\r\n return null;\r\n }\r\n return this._website;\r\n }\r\n public static async loadWebsite() {\r\n try {\r\n let websiteResponse = await metadataRetrieveMultiple(`v9.1/talxis_websites?$select=talxis_allowedappmodules,_talxis_themeid_value&$filter=talxis_hostname eq '${window.location.host}'&$expand=talxis_talxis_website_talxis_appmodulewebsiteconnection_websiteid($select=talxis_appmodulewebsiteconnectionid,_talxis_themeid_value;$expand=talxis_appmoduleid($select=talxis_uniquename))`);\r\n if (!(websiteResponse?.entities?.length > 0)) {\r\n return;\r\n }\r\n const websiteRecord = websiteResponse.entities[0];\r\n this._website = new Website(websiteRecord);\r\n }\r\n catch (error) {\r\n // If website doesn't exist, portal shouldn't fail on it.\r\n }\r\n }\r\n}\r\n","import { metadataRetrieveMultiple } from \"./MetadataApi\";\r\nimport { Theme } from \"@models/Theme\";\r\nimport { WebsiteDefinition } from \"./WebsiteDefinition\";\r\nimport { AppModule } from \"../configuration/AppModule\";\r\nexport class ThemeDefinition {\r\n private static _theme: Theme;\r\n public static get(): Theme {\r\n if (!this._theme) {\r\n throw new Error('Theme is not defined, have you called ThemeDefinition.loadAsync()?');\r\n }\r\n return this._theme;\r\n }\r\n public static async loadTheme() {\r\n const website = WebsiteDefinition.getWebsite();\r\n const appModule = AppModule.get();\r\n const themeId = website?.appModuleThemes.find(appModuleTheme => appModuleTheme.appModuleUniqueName === appModule.uniquename)?.themeId ?? website?.fallBackThemeId;\r\n const filterQuery = themeId ? `?$filter=talxis_configuration_themeid eq '${themeId}'` : \"\";\r\n let configurationThemeResponse = await metadataRetrieveMultiple(`v9.1/talxis_configuration_themes${filterQuery}`);\r\n if (!configurationThemeResponse?.entities) {\r\n this._theme = new Theme();\r\n return;\r\n }\r\n const configurationTheme = configurationThemeResponse.entities[0];\r\n this._theme = new Theme(configurationTheme);\r\n }\r\n}\r\n","import { ICommandBarItemProps } from '@talxis/react-components';\r\nimport { SiteMap as ISiteMap } from '../../interfaces/sitemap';\r\nimport { history } from '@providers/HistoryProvider/HistoryProvider';\r\nimport { ContextualMenuItemType, GroupShowAll, INavLink, INavLinkGroup } from '@fluentui/react';\r\nimport cloneDeep from 'lodash/cloneDeep';\r\nimport { AppModule } from '@configuration/AppModule';\r\nimport { metadataRetrieveMultiple } from '@definitions/MetadataApi';\r\nimport { SpaConfiguration } from '@configuration/SpaConfiguration';\r\nimport { ThemeDefinition } from '../definitions/ThemeDefinition';\r\n\r\nexport enum SiteMarker {\r\n NotFound = \"not_found\",\r\n}\r\n\r\ninterface ITalxisWebPage {\r\n talxis_webpageid: string;\r\n talxis_name: string;\r\n talxis_slug: string;\r\n talxis_requiresauthentication: boolean;\r\n}\r\nexport interface IPageRoute {\r\n id: string;\r\n slug: string;\r\n requiresAuthentication: boolean;\r\n}\r\nexport class SiteMap {\r\n private _siteMapDefinition: ISiteMap.Root;\r\n private _pageRoutes: IPageRoute[];\r\n\r\n public constructor(siteMapDefinition: ISiteMap.Root) {\r\n this._siteMapDefinition = siteMapDefinition;\r\n }\r\n public getDefinition(): ISiteMap.Root {\r\n return cloneDeep(this._siteMapDefinition);\r\n }\r\n public async loadStaticPages(): Promise {\r\n if (!this._pageRoutes) {\r\n this._pageRoutes = await this._getStaticPageRoutes(this._siteMapDefinition.areas);\r\n\r\n for (const area of this._siteMapDefinition.areas) {\r\n for (const group of area.groups) {\r\n for (const subArea of group.subAreas) {\r\n if (subArea.url.includes(\"/control/TALXIS.PCF.WebPage\")) {\r\n const url = new URL(subArea.url, window.location.origin);\r\n const queryParams = new URLSearchParams(url.search);\r\n const webPages = this._pageRoutes;\r\n const params = JSON.parse(queryParams.get(\"data\"));\r\n if (params[\"id\"] && webPages.find(x => x.id === params[\"id\"])) {\r\n const page = webPages.find(x => x.id === params[\"id\"]);\r\n const currentAppModule = AppModule.get().uniquename;\r\n let routeContainsAppModule = false;\r\n if (window.location.pathname.startsWith(`/${currentAppModule}`)) {\r\n routeContainsAppModule = true;\r\n }\r\n if (currentAppModule !== SpaConfiguration.get().defaultAppModule || routeContainsAppModule) {\r\n subArea.url = `/${currentAppModule}${page.slug}`;\r\n }\r\n else {\r\n subArea.url = `${page.slug}`;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n public getVerticalNavigationItems(): INavLinkGroup[] {\r\n const areas: INavLinkGroup[] = [];\r\n for (const siteMapArea of this._siteMapDefinition.areas) {\r\n if (siteMapArea.id === 'other_pages') {\r\n continue;\r\n }\r\n const area: INavLinkGroup = {\r\n name: ThemeDefinition.get().sitemap.veritalAreasAsTabs === false && this._siteMapDefinition.areas.length < 2 ? null : siteMapArea.title,\r\n links: this._mapGroups(siteMapArea.groups),\r\n groupData: {\r\n id: siteMapArea.id,\r\n disabled: siteMapArea.disabled,\r\n visible: siteMapArea.visible\r\n }\r\n };\r\n areas.push(area);\r\n }\r\n return areas;\r\n }\r\n public getSitemapSubAreaByProp(prop: 'url' | 'entity', value: string): ISiteMap.SubArea {\r\n for (const area of this._siteMapDefinition.areas) {\r\n for (const group of area.groups) {\r\n for (const subArea of group.subAreas) {\r\n if (subArea[prop] === value) {\r\n return subArea;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n public getFirstSitemapSubArea(): ISiteMap.SubArea {\r\n for (const area of this._siteMapDefinition.areas) {\r\n for (const group of area.groups) {\r\n return group.subAreas[0];\r\n }\r\n }\r\n }\r\n private _createCommandBarItem(siteMapItem: ISiteMap.Area | ISiteMap.Group | ISiteMap.SubArea): ICommandBarItemProps | undefined {\r\n const area = siteMapItem as ISiteMap.Area;\r\n const group = siteMapItem as ISiteMap.Group;\r\n const subArea = siteMapItem as ISiteMap.SubArea;\r\n\r\n const isArea = area.groups?.length > 0;\r\n const isGroup = group.subAreas?.length > 0;\r\n\r\n if (subArea.visible === false) {\r\n return undefined;\r\n }\r\n return {\r\n key: subArea.url ?? siteMapItem.id,\r\n text: siteMapItem.title,\r\n disabled: subArea.disabled,\r\n title: subArea.disabledMessage ?? siteMapItem.title,\r\n itemType: isGroup && ContextualMenuItemType.Section,\r\n //only groups can have sectionProps\r\n iconProps: isArea && ThemeDefinition.get().sitemap.showHorizontalIcons &&\r\n {\r\n iconName: siteMapItem.icon?.type === 'fluent' && siteMapItem.icon?.value,\r\n imageProps: siteMapItem.icon?.type === 'url' && {\r\n src: siteMapItem.icon?.value,\r\n height: \"14px\",\r\n }\r\n },\r\n sectionProps: isGroup ? {\r\n title: siteMapItem.title,\r\n bottomDivider: true,\r\n items: group.subAreas?.map(group => this._createCommandBarItem(group)).filter(item => item !== undefined)\r\n } : undefined,\r\n //only areas can have subMenuProps\r\n subMenuProps: isArea ? {\r\n items: area.groups?.map(group => this._createCommandBarItem(group)).filter(item => item !== undefined)\r\n } : undefined,\r\n href: (siteMapItem as ISiteMap.SubArea).url,\r\n 'data-id': `sitemap-entity-${siteMapItem.id}`,\r\n onClick: subArea.url ? (e) => {\r\n e.preventDefault();\r\n if (subArea.url.startsWith(\"http\")) {\r\n window.open(subArea.url, '_blank');\r\n }\r\n history.push(subArea.url);\r\n //used to hide the callout when navigating between pages\r\n document.querySelector('body')?.click();\r\n } : undefined\r\n };\r\n }\r\n private _moveGroupUp(areas: ICommandBarItemProps[], groups: ICommandBarItemProps[], currentArea: ICommandBarItemProps): void {\r\n const areaIndex = areas.indexOf(currentArea);\r\n if (groups.length === 1) {\r\n areas[areaIndex] = groups[0];\r\n areas[areaIndex].subMenuProps = {\r\n items: areas[areaIndex].sectionProps?.items\r\n };\r\n areas[areaIndex].sectionProps = undefined;\r\n }\r\n\r\n }\r\n private _moveSubAreaUp(areas: ICommandBarItemProps[], subAreas: ICommandBarItemProps[], currentArea: ICommandBarItemProps): void {\r\n const areaIndex = areas.indexOf(currentArea);\r\n //we have only one subarea within the group and the area has only one group => move straight to Area\r\n if (subAreas?.length === 1 && areas[areaIndex].subMenuProps?.items?.length === 1) {\r\n areas[areaIndex] = subAreas[0];\r\n }\r\n }\r\n public async getHorizontalNavigationItems(): Promise {\r\n let items: ICommandBarItemProps[] = [];\r\n for (const area of this._siteMapDefinition.areas) {\r\n if (area.id === 'other_pages') {\r\n continue;\r\n }\r\n const commandBarItem = this._createCommandBarItem(area);\r\n if (commandBarItem) {\r\n items.push(commandBarItem);\r\n }\r\n }\r\n for (const area of items) {\r\n this._moveGroupUp(items, area.subMenuProps?.items, area);\r\n }\r\n for (const area of items) {\r\n for (const group of area.subMenuProps?.items) {\r\n //move the area up, some group might already been on area place from previous step, hence [group] is actually subArea\r\n this._moveSubAreaUp(items, group.sectionProps?.items ?? group.subMenuProps?.items ?? [group], area);\r\n }\r\n }\r\n const groups = items[0]?.subMenuProps?.items;\r\n //one area with one group => spread the subAreas to area position\r\n if (items.length === 1 && groups?.length === 1) {\r\n items = groups[0].sectionProps.items;\r\n }\r\n //one area with multiple groups => spread the groups to area position\r\n else if (items.length === 1 && groups?.length > 1) {\r\n for (const group of groups) {\r\n const groupIndex = groups.indexOf(group);\r\n if (group.sectionProps?.items) {\r\n group.subMenuProps = {\r\n items: group.sectionProps?.items\r\n };\r\n }\r\n if (group.subMenuProps?.items.length === 1) {\r\n items[0].subMenuProps.items[groupIndex] = group.subMenuProps.items[0];\r\n }\r\n }\r\n items = groups;\r\n }\r\n return items;\r\n }\r\n\r\n public disableSiteMapSubArea(id: string, disabled: boolean, disabledMessage?: string): void {\r\n const subArea = this._getSiteMapSubArea(id);\r\n subArea.disabled = disabled;\r\n subArea.disabledMessage = disabledMessage;\r\n }\r\n\r\n public toggleSiteMapSubAreaVisibility(id: string, visible: boolean): void {\r\n const subArea = this._getSiteMapSubArea(id);\r\n subArea.visible = visible;\r\n }\r\n public disableSiteMapArea(id: string, disabled: boolean, disabledMessage?: string): void {\r\n const area = this._getSiteMapArea(id);\r\n area.disabled = disabled;\r\n area.disabledMessage = disabledMessage;\r\n for (const group of area.groups)\r\n for (const subarea of group.subAreas)\r\n this.disableSiteMapSubArea(subarea.id, disabled, disabledMessage);\r\n }\r\n\r\n public toggleSiteMapAreaVisibility(id: string, visible: boolean): void {\r\n const area = this._getSiteMapArea(id);\r\n area.visible = visible;\r\n for (const group of area.groups) {\r\n this.toggleSiteMapGroupVisibility(group.id, visible);\r\n }\r\n }\r\n public toggleSiteMapGroupVisibility(id: string, visible: boolean): void {\r\n const group = this._getSiteMapGroup(id);\r\n group.visible = visible;\r\n for (const subarea of group.subAreas) {\r\n this.toggleSiteMapSubAreaVisibility(subarea.id, visible);\r\n }\r\n }\r\n\r\n public getWellKnownPage(marker: SiteMarker): string {\r\n switch (marker) {\r\n case SiteMarker.NotFound: {\r\n const subArea = this._getSiteMapSubArea(SiteMarker.NotFound);\r\n return this._getStaticPageId(subArea);\r\n }\r\n }\r\n };\r\n\r\n public getStaticPageRoutes(): IPageRoute[] {\r\n return this._pageRoutes;\r\n }\r\n\r\n private _getStaticPageId(subArea?: ISiteMap.SubArea) {\r\n if (!subArea) {\r\n return null;\r\n }\r\n const params = new URLSearchParams(subArea.url.substring(subArea.url.indexOf('?')));\r\n const queryData = JSON.parse(params.get('data'));\r\n return queryData?.id;\r\n }\r\n private async _getStaticPageDefinitions(areas: ISiteMap.Area[]): Promise {\r\n const ids: string[] = [];\r\n for (const area of areas) {\r\n for (const group of area.groups) {\r\n for (const subArea of group.subAreas) {\r\n const id = this._getStaticPageId(subArea);\r\n if (id) {\r\n ids.push(id);\r\n }\r\n }\r\n }\r\n }\r\n if (ids.length === 0) {\r\n return [];\r\n }\r\n const filter = `?$select=talxis_webpageid,talxis_name,talxis_slug,talxis_requiresauthentication&$filter=(${ids.map(x => `talxis_webpageid eq ${x}`).join(' or ')})`;\r\n const response = await metadataRetrieveMultiple(`v9.1/talxis_webpages${filter}`);\r\n return response.entities.map(x => {\r\n const webPage: ITalxisWebPage = {\r\n talxis_name: x[\"talxis_name\"],\r\n talxis_requiresauthentication: x[\"talxis_requiresauthentication\"],\r\n talxis_slug: x[\"talxis_slug\"],\r\n talxis_webpageid: x[\"talxis_webpageid\"]\r\n };\r\n return webPage;\r\n });\r\n }\r\n private async _getStaticPageRoutes(areas: ISiteMap.Area[]): Promise {\r\n return (await this._getStaticPageDefinitions(areas)).map(page => {\r\n return {\r\n id: page.talxis_webpageid,\r\n slug: page.talxis_slug,\r\n requiresAuthentication: page.talxis_requiresauthentication\r\n };\r\n });\r\n }\r\n\r\n private _getSiteMapSubArea(id: string): ISiteMap.SubArea | null {\r\n for (const area of this._siteMapDefinition.areas) {\r\n for (const group of area.groups) {\r\n const subArea = group.subAreas.find(subArea => subArea.id === id);\r\n if (subArea) {\r\n return subArea;\r\n }\r\n }\r\n }\r\n return null;\r\n }\r\n private _getSiteMapArea(id: string): ISiteMap.Area | null {\r\n return this._siteMapDefinition.areas.find(x => x.id === id) ?? null;\r\n }\r\n private _getSiteMapGroup(id: string): ISiteMap.Group | null {\r\n for (const area of this._siteMapDefinition.areas) {\r\n const group = area.groups.find(group => group.id === id);\r\n if (group) return group;\r\n }\r\n return null;\r\n }\r\n private _mapGroups(groups: ISiteMap.Group[]): INavLink[] {\r\n const _groups: INavLink[] = [];\r\n for (const group of groups) {\r\n const _group: INavLink = {\r\n isExpanded: true,\r\n name: group.title,\r\n disabled: groups.length < 2,\r\n url: null,\r\n links: this._mapSubAreas(group.subAreas)\r\n };\r\n _groups.push(_group);\r\n }\r\n return _groups;\r\n };\r\n\r\n private _mapSubAreas = (subAreas: ISiteMap.SubArea[]): INavLink[] => {\r\n const _subAreas: INavLink[] = [];\r\n for (const subArea of subAreas) {\r\n const _subArea: INavLink = {\r\n key: subArea.url,\r\n name: subArea.title,\r\n url: subArea.url,\r\n title: subArea.title,\r\n parentGroupTitle: subArea.parentGroupTitle,\r\n dataIcon: subArea.icon,\r\n disabled: subArea.disabled,\r\n // INavLink does not have visible property by default but has [propertyName: string]: any; which allows \r\n // us to declare custom property\r\n visible: subArea.visible,\r\n buttonStyles: {\r\n root: {\r\n display: subArea.visible ? null : 'none'\r\n }\r\n },\r\n disabledTooltipText: subArea.disabledMessage,\r\n iconProps: {\r\n iconName: subArea.icon?.type === 'fluent' && subArea.icon?.value\r\n },\r\n onClick: (e) => {\r\n e.preventDefault();\r\n if (subArea.url.startsWith(\"http\")) {\r\n window.open(subArea.url, '_blank');\r\n }\r\n history.push(subArea.url);\r\n }\r\n };\r\n _subAreas.push(_subArea);\r\n }\r\n return _subAreas;\r\n };\r\n}","import { SiteMapMapper } from '@mappers/SiteMapMapper';\r\nimport { AppComponents } from '@configuration/AppComponents';\r\nimport { IPromiseCache, cachedWrapper } from '@utilities/MemoryCachingHelpers';\r\nimport { sendMetadataGetRequest } from './MetadataApi';\r\nimport { IPageRoute, SiteMap, SiteMarker } from '@models/SiteMap';\r\n\r\nexport class SitemapDefinition {\r\n private static _sitemapDefinitionCache: IPromiseCache = {};\r\n private static _currentSitemap: SiteMap;\r\n public static async getAsync(sitemapId: string): Promise {\r\n return cachedWrapper(sitemapId, () => this._getSitemapDefinitionAsync(sitemapId), this._sitemapDefinitionCache);\r\n }\r\n public static getCurrentSiteMap(): SiteMap {\r\n if (!this._currentSitemap) {\r\n throw new Error('Current sitemap is undefined, have you called loadCurrentSitemapAsync?');\r\n }\r\n return this._currentSitemap;\r\n }\r\n public static async loadCurrentSitemapAsync(): Promise {\r\n const siteMapId = AppComponents.get().filter(appComponent => appComponent.componenttype == 62)[0].objectid;\r\n this._currentSitemap = await this.getAsync(siteMapId);\r\n }\r\n\r\n public static getWellKnownPage(marker: SiteMarker): string {\r\n return this._currentSitemap.getWellKnownPage(marker);\r\n }\r\n\r\n public static getStaticPageRoutes(): IPageRoute[] {\r\n return this._currentSitemap.getStaticPageRoutes();\r\n }\r\n\r\n private static async _getSitemapDefinitionAsync(siteMapId: string): Promise {\r\n const response = await sendMetadataGetRequest(`v9.1/sitemaps(${siteMapId})?$select=sitemapxml`);\r\n const json = await response.json();\r\n const siteMapXml = json['sitemapxml'];\r\n const siteMapRoot = await SiteMapMapper.parseAsync(siteMapXml);\r\n const sitemap = new SiteMap(siteMapRoot);\r\n await sitemap.loadStaticPages();\r\n return sitemap;\r\n }\r\n}","import { cloneDeep } from \"lodash\";\r\nimport { ISessionState } from \"./HistoryManager\";\r\n\r\nexport class State {\r\n private _id: string;\r\n private _nativeValues: ComponentFramework.Dictionary = {};\r\n private _controlValues: ComponentFramework.Dictionary = {};\r\n private _childStates: State[] = [];\r\n private _saveStateValuesChanges: () => void;\r\n\r\n constructor(id: string, sessionState?: ISessionState) {\r\n if (sessionState) {\r\n this._createStateFromSession(sessionState);\r\n return;\r\n }\r\n this._id = id;\r\n }\r\n public get id() {\r\n return this._id;\r\n }\r\n public get saveStateValuesChanges() {\r\n return this._saveStateValuesChanges;\r\n }\r\n /**\r\n * Tries to find a child control state for the given control id. If the control id is not provided, the \r\n * method will return the same state object that it's being invoked on.\r\n */\r\n public get(controlId?: string): State | null {\r\n if (!controlId || controlId === this._id) {\r\n return this;\r\n }\r\n for (const childState of this._childStates) {\r\n if (childState._id === controlId) {\r\n return childState;\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n public addChildState(state: State) {\r\n this._childStates.push(state);\r\n }\r\n public getValues(valueType: 'native' | 'pcf'): T {\r\n if (valueType === 'native') {\r\n return cloneDeep(this._nativeValues as T);\r\n }\r\n return cloneDeep(this._controlValues as T);\r\n }\r\n public setValues(valueType: 'native' | 'pcf', values: T) {\r\n if (!values) {\r\n return;\r\n }\r\n if (valueType === 'native') {\r\n this._nativeValues = values;\r\n return;\r\n }\r\n this._controlValues = values;\r\n }\r\n private _createStateFromSession(sessionState: ISessionState) {\r\n this._id = sessionState._id;\r\n this._nativeValues = sessionState._nativeValues ?? {};\r\n this._controlValues = sessionState._controlValues ?? {};\r\n if (!sessionState._childStates) {\r\n return;\r\n }\r\n for (const childSessionState of sessionState._childStates) {\r\n this._childStates.push(new State(childSessionState._id, childSessionState));\r\n }\r\n }\r\n public setSaveStateValuesChangesCallback(callback: () => void) {\r\n this._saveStateValuesChanges = callback;\r\n }\r\n}","import { Page } from \"./Page\";\r\nimport { parse, stringify } from 'flatted';\r\nimport { AppModule } from \"@src/app/classes/configuration/AppModule\";\r\nimport { replaceLast } from \"@src/app/Functions\";\r\n\r\nwindow.addEventListener('pagehide', () => {\r\n HistoryManager.showLoading();\r\n HistoryManager.saveHistory();\r\n});\r\n\r\nexport interface ISessionPage {\r\n _path: string;\r\n _index: number;\r\n _sitemapKey: string;\r\n _state: ISessionState;\r\n _previousPage: ISessionPage | null;\r\n _nextPage: ISessionPage | null;\r\n _isNextPage: boolean | undefined;\r\n}\r\nexport interface ISessionState {\r\n _id: string;\r\n _childStates: ISessionState[];\r\n _nativeValues?: ComponentFramework.Dictionary;\r\n _controlValues?: ComponentFramework.Dictionary;\r\n}\r\n\r\nexport class HistoryManager {\r\n private static _currentPageRef: React.MutableRefObject;\r\n public static pages: Page[] = [];\r\n public static activeControls: Set> = new Set();\r\n public static showLoading: () => void = () => { };\r\n public static setCurrentPageRef(ref: React.MutableRefObject) {\r\n this._currentPageRef = ref;\r\n }\r\n public static getCurrentPage(): Page {\r\n return HistoryManager._currentPageRef.current;\r\n }\r\n public static isUserOnLandingPage(): boolean {\r\n const currentAppModuleName = AppModule.get().uniquename;\r\n let pagePath = decodeURIComponent(`${window.location.pathname}${window.location.search}`);\r\n if (pagePath.endsWith(\"/\") && pagePath.length > 1) {\r\n pagePath = replaceLast(pagePath, \"/\", \"\");\r\n }\r\n if (pagePath === `/${currentAppModuleName}` || pagePath === '/') {\r\n return true;\r\n\r\n }\r\n return false;\r\n }\r\n public static getSessionPage(): Page | null {\r\n const pageString = sessionStorage.getItem('history');\r\n if (!pageString) {\r\n return null;\r\n }\r\n const sessionPage = parse(pageString) as ISessionPage;\r\n const page = new Page(sessionPage._path, sessionPage._index, null, sessionPage);\r\n //do not load session state if the last page path does not equal the current one\r\n if (decodeURIComponent(`${window.location.pathname}${window.location.search}`) !== page.path) {\r\n return null;\r\n }\r\n return page;\r\n }\r\n public static saveHistory() {\r\n //save the state of current page (native)\r\n HistoryManager._currentPageRef.current.state.saveStateValuesChanges();\r\n //save the state of all controls that are currently present on screen\r\n for (const control of HistoryManager.activeControls) {\r\n control.destroy();\r\n }\r\n const history = stringify(HistoryManager._currentPageRef.current, (key, value) => {\r\n if ((key === '_nativeValues' || key === '_controlValues') && Object.keys(value).length === 0) {\r\n return undefined;\r\n }\r\n if (key === '_childStates' && value.length === 0) {\r\n return undefined;\r\n }\r\n if (key === '_entityName') {\r\n return undefined;\r\n }\r\n return value;\r\n });\r\n sessionStorage.setItem('history', history);\r\n }\r\n};","import { SitemapDefinition } from \"@src/app/classes/definitions/SitemapDefinition\";\r\nimport { State } from \"./State\";\r\nimport { ISessionPage, HistoryManager } from \"./HistoryManager\";\r\nimport { Dataset } from \"@talxis/client-libraries\";\r\n\r\nenum PageType {\r\n Form,\r\n View,\r\n Other\r\n}\r\nexport class Page {\r\n private _path: string;\r\n private _index: number;\r\n private _sitemapKey: string;\r\n private _entityName: string | null;\r\n private _state: State;\r\n private _previousPage: Page | null;\r\n private _nextPage: Page | null;\r\n private _dataset?: Dataset;\r\n public getFormContext = (): Xrm.FormContext | null => { return null; };\r\n\r\n constructor(path: string, index: number, previousPage?: Page, sessionPage?: ISessionPage) {\r\n //store every new page instance in array so we can easily search existing pages\r\n this._path = path;\r\n this._index = index;\r\n this._entityName = this._getEntityNameFromPath();\r\n HistoryManager.pages.push(this);\r\n if (sessionPage) {\r\n this._createFromSession(sessionPage);\r\n return;\r\n }\r\n this._state = new State(path);\r\n this._previousPage = previousPage;\r\n this._sitemapKey = this._getSitemapKey();\r\n }\r\n\r\n public get previousPage() {\r\n return this._previousPage;\r\n }\r\n public get nextPage() {\r\n return this._nextPage;\r\n }\r\n public get path() {\r\n return this._path;\r\n }\r\n public get index() {\r\n return this._index;\r\n }\r\n public get sitemapKey() {\r\n return this._sitemapKey;\r\n }\r\n public get entityName() {\r\n return this._entityName;\r\n }\r\n public get state() {\r\n return this._state;\r\n }\r\n\r\n public setNextPage(page: Page) {\r\n this._nextPage = page;\r\n }\r\n\r\n public setPreviousPage(page: Page) {\r\n this._previousPage = page;\r\n }\r\n\r\n public isDirty() {\r\n if (this.getFormContext()?.data.getIsDirty()) {\r\n return true;\r\n }\r\n if (this._dataset?.isDirty()) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n public isFirst() {\r\n if (this.index === 0) {\r\n return true;\r\n }\r\n }\r\n\r\n public printPreviousPages() {\r\n const arr: string[] = [];\r\n const recursion = (arr: string[], previousPage: Page | null) => {\r\n if (!previousPage) {\r\n return;\r\n }\r\n arr.push(previousPage.path);\r\n recursion(arr, previousPage._previousPage);\r\n };\r\n recursion(arr, this);\r\n console.log(arr);\r\n }\r\n\r\n public setFormContext(value: Xrm.FormContext) {\r\n this.getFormContext = () => { return value; };\r\n }\r\n\r\n public setDataset(dataset: Dataset) {\r\n this._dataset = dataset;\r\n }\r\n public getDataset() {\r\n return this._dataset;\r\n }\r\n\r\n private _createFromSession(sessionPage: ISessionPage) {\r\n this._sitemapKey = sessionPage._sitemapKey;\r\n if (sessionPage._previousPage) {\r\n const existingPreviousPage = HistoryManager.pages.find(page => page.index === sessionPage._previousPage._index);\r\n this._previousPage = existingPreviousPage ?? new Page(sessionPage._previousPage._path, sessionPage._previousPage._index, null, sessionPage._previousPage);\r\n }\r\n if (sessionPage._nextPage) {\r\n const existingNextPage = HistoryManager.pages.find(page => page.index === sessionPage._nextPage._index);\r\n this._nextPage = existingNextPage ?? new Page(sessionPage._nextPage._path, sessionPage._nextPage._index, null, sessionPage._nextPage);\r\n }\r\n this._state = new State(this._path, sessionPage._state);\r\n }\r\n\r\n private _getEntityNameFromPath(): string {\r\n //this regex is used since '&' character breaks the data parameter parsing in both query-string and new URL\r\n const match = this.path.match(/\\?data=(\\{.*\\})/);\r\n if (!match) {\r\n return null;\r\n }\r\n try {\r\n return JSON.parse(match[1]).entityName ?? null;\r\n }\r\n catch (err) {\r\n return null;\r\n }\r\n }\r\n private _getSitemapKey(): string | null {\r\n const sitemap = SitemapDefinition.getCurrentSiteMap();\r\n //this regex is used since '&' character breaks the data parameter parsing in both query-string and new URL\r\n const match = this.path.match(/\\?data=(\\{.*\\})/);\r\n let strippedpath = this.path;\r\n if (match) {\r\n const { extraqs, ...strippedData } = JSON.parse(match[1]);\r\n const url = new URL(encodeURIComponent(this.path), this.path.startsWith(\"http\") ? undefined : window.location.origin);\r\n url.searchParams.set('data', JSON.stringify(strippedData));\r\n strippedpath = decodeURIComponent(`${window.location.pathname}${url.search}`);\r\n }\r\n //here we should check the sitemap items, the steps are following:\r\n //1) check if there is a sitemap item that matches the route exactly\r\n const exactMatchSubArea = sitemap.getSitemapSubAreaByProp('url', strippedpath);\r\n if (exactMatchSubArea) {\r\n return strippedpath;\r\n }\r\n //2) if no entity name is present and no exact url match was found, do not highlight anything\r\n if (!this.entityName) {\r\n return null;\r\n }\r\n //3) if entity name is present and it is the same as the last page, return the same sitemap path as previous page (=> staying in current context)\r\n if (this._previousPage?.entityName === this.entityName) {\r\n return this._previousPage.sitemapKey ?? null;\r\n }\r\n //4) if the entity name differs and no exact match was found, try to highlight the first item that matches the entity name of current page;\r\n const subArea = sitemap.getSitemapSubAreaByProp('entity', this.entityName);\r\n if (subArea) {\r\n return subArea.url;\r\n }\r\n //5) no suitable sitemap item has been found => no higlighting\r\n return null;\r\n }\r\n}","import { DefaultButton, Dialog, DialogFooter, DialogType, PrimaryButton } from '@fluentui/react';\r\nimport React from 'react';\r\nimport styles from './NavigationPromptDialog.module.css';\r\n\r\nexport interface INavigationPromptDialogProps {\r\n onDiscard: () => void;\r\n onSave: () => void;\r\n onDismiss: () => void;\r\n}\r\n\r\nexport const NavigationPromptDialog: React.FC = (props) => {\r\n return (