@techdocs/cli 0.8.13-next.0 → 0.8.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +45 -9
  3. package/dist/embedded-app/.config-schema.json +20 -4
  4. package/dist/embedded-app/index.html +1 -1
  5. package/dist/embedded-app/static/1553.3f1fcd49.chunk.js +3 -0
  6. package/dist/embedded-app/static/1553.3f1fcd49.chunk.js.map +1 -0
  7. package/dist/embedded-app/static/1959.657c7008.chunk.js +8 -0
  8. package/dist/embedded-app/static/1959.657c7008.chunk.js.map +1 -0
  9. package/dist/embedded-app/static/2426.82184352.chunk.js +3 -0
  10. package/dist/embedded-app/static/2426.82184352.chunk.js.map +1 -0
  11. package/dist/embedded-app/static/3825.b0488503.chunk.js +3 -0
  12. package/dist/embedded-app/static/3825.b0488503.chunk.js.map +1 -0
  13. package/dist/embedded-app/static/390.9bae5f6b.chunk.js +3 -0
  14. package/dist/embedded-app/static/390.9bae5f6b.chunk.js.map +1 -0
  15. package/dist/embedded-app/static/4022.919281f3.chunk.js +3 -0
  16. package/dist/embedded-app/static/4022.919281f3.chunk.js.map +1 -0
  17. package/dist/embedded-app/static/5011.c8e98520.chunk.js +3 -0
  18. package/dist/embedded-app/static/5011.c8e98520.chunk.js.map +1 -0
  19. package/dist/embedded-app/static/6235.d2d64119.chunk.js +3 -0
  20. package/dist/embedded-app/static/6235.d2d64119.chunk.js.map +1 -0
  21. package/dist/embedded-app/static/6583.fc990b80.chunk.js +3 -0
  22. package/dist/embedded-app/static/6583.fc990b80.chunk.js.map +1 -0
  23. package/dist/embedded-app/static/7758.5616a290.chunk.js +3 -0
  24. package/dist/embedded-app/static/7758.5616a290.chunk.js.map +1 -0
  25. package/dist/embedded-app/static/8061.4cacfdc7.chunk.js +3 -0
  26. package/dist/embedded-app/static/8061.4cacfdc7.chunk.js.map +1 -0
  27. package/dist/embedded-app/static/8718.cb2cefe2.chunk.js +4 -0
  28. package/dist/embedded-app/static/8718.cb2cefe2.chunk.js.map +1 -0
  29. package/dist/embedded-app/static/8792.f347f8eb.chunk.js +3 -0
  30. package/dist/embedded-app/static/8792.f347f8eb.chunk.js.map +1 -0
  31. package/dist/embedded-app/static/9028.e0a4340b.chunk.js +3 -0
  32. package/dist/embedded-app/static/9028.e0a4340b.chunk.js.map +1 -0
  33. package/dist/embedded-app/static/main.287af9cc.js +415 -0
  34. package/dist/embedded-app/static/main.287af9cc.js.map +1 -0
  35. package/dist/embedded-app/static/module-lodash.f158b49a.js +29 -0
  36. package/dist/embedded-app/static/{module-lodash.d85d8a0e.js.map → module-lodash.f158b49a.js.map} +1 -1
  37. package/dist/embedded-app/static/{module-material-table.f1dfcc79.js → module-material-table.a73fb7f5.js} +2 -2
  38. package/dist/embedded-app/static/{module-material-table.f1dfcc79.js.map → module-material-table.a73fb7f5.js.map} +1 -1
  39. package/dist/embedded-app/static/module-material-ui.c0e7547f.js +51 -0
  40. package/dist/embedded-app/static/module-material-ui.c0e7547f.js.map +1 -0
  41. package/dist/embedded-app/static/module-react-dom.40a0584f.js +18 -0
  42. package/dist/embedded-app/static/module-react-dom.40a0584f.js.map +1 -0
  43. package/dist/embedded-app/static/module-yaml.574c3290.js +151 -0
  44. package/dist/embedded-app/static/module-yaml.574c3290.js.map +1 -0
  45. package/dist/embedded-app/static/react-syntax-highlighter/{lowlight-import.051a03b1.chunk.js → lowlight-import.c14d776e.chunk.js} +3 -3
  46. package/dist/embedded-app/static/react-syntax-highlighter/lowlight-import.c14d776e.chunk.js.map +1 -0
  47. package/dist/embedded-app/static/{runtime.367d4ef1.js → runtime.287af9cc.js} +2 -2
  48. package/dist/embedded-app/static/{runtime.367d4ef1.js.map → runtime.287af9cc.js.map} +1 -1
  49. package/dist/embedded-app/static/vendor.287af9cc.js +147 -0
  50. package/dist/embedded-app/static/vendor.287af9cc.js.map +1 -0
  51. package/dist/index.cjs.js +2 -2
  52. package/dist/index.cjs.js.map +1 -1
  53. package/package.json +19 -13
  54. package/dist/embedded-app/static/1553.a3ba3bc9.chunk.js +0 -3
  55. package/dist/embedded-app/static/1553.a3ba3bc9.chunk.js.map +0 -1
  56. package/dist/embedded-app/static/1959.f2a5fbe8.chunk.js +0 -8
  57. package/dist/embedded-app/static/1959.f2a5fbe8.chunk.js.map +0 -1
  58. package/dist/embedded-app/static/2426.c303a0db.chunk.js +0 -3
  59. package/dist/embedded-app/static/2426.c303a0db.chunk.js.map +0 -1
  60. package/dist/embedded-app/static/3825.2314f84b.chunk.js +0 -3
  61. package/dist/embedded-app/static/3825.2314f84b.chunk.js.map +0 -1
  62. package/dist/embedded-app/static/390.088f14b3.chunk.js +0 -3
  63. package/dist/embedded-app/static/390.088f14b3.chunk.js.map +0 -1
  64. package/dist/embedded-app/static/4022.9a059830.chunk.js +0 -3
  65. package/dist/embedded-app/static/4022.9a059830.chunk.js.map +0 -1
  66. package/dist/embedded-app/static/4960.ef8f22a6.chunk.js +0 -3
  67. package/dist/embedded-app/static/4960.ef8f22a6.chunk.js.map +0 -1
  68. package/dist/embedded-app/static/6235.71cad128.chunk.js +0 -3
  69. package/dist/embedded-app/static/6235.71cad128.chunk.js.map +0 -1
  70. package/dist/embedded-app/static/6650.43f69504.chunk.js +0 -3
  71. package/dist/embedded-app/static/6650.43f69504.chunk.js.map +0 -1
  72. package/dist/embedded-app/static/804.c2c0104e.chunk.js +0 -3
  73. package/dist/embedded-app/static/804.c2c0104e.chunk.js.map +0 -1
  74. package/dist/embedded-app/static/8061.d52df3ec.chunk.js +0 -3
  75. package/dist/embedded-app/static/8061.d52df3ec.chunk.js.map +0 -1
  76. package/dist/embedded-app/static/8718.d8f22f92.chunk.js +0 -4
  77. package/dist/embedded-app/static/8718.d8f22f92.chunk.js.map +0 -1
  78. package/dist/embedded-app/static/8792.ffba5fe7.chunk.js +0 -3
  79. package/dist/embedded-app/static/8792.ffba5fe7.chunk.js.map +0 -1
  80. package/dist/embedded-app/static/9028.310b76ec.chunk.js +0 -3
  81. package/dist/embedded-app/static/9028.310b76ec.chunk.js.map +0 -1
  82. package/dist/embedded-app/static/illo.7884c54f..svg +0 -1
  83. package/dist/embedded-app/static/main.367d4ef1.js +0 -152
  84. package/dist/embedded-app/static/main.367d4ef1.js.map +0 -1
  85. package/dist/embedded-app/static/module-lodash.d85d8a0e.js +0 -29
  86. package/dist/embedded-app/static/module-material-ui.c0214b97.js +0 -51
  87. package/dist/embedded-app/static/module-material-ui.c0214b97.js.map +0 -1
  88. package/dist/embedded-app/static/module-react-dom.a4f98d7b.js +0 -25
  89. package/dist/embedded-app/static/module-react-dom.a4f98d7b.js.map +0 -1
  90. package/dist/embedded-app/static/react-syntax-highlighter/lowlight-import.051a03b1.chunk.js.map +0 -1
  91. package/dist/embedded-app/static/vendor.367d4ef1.js +0 -142
  92. package/dist/embedded-app/static/vendor.367d4ef1.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["webpack://techdocs-cli-embedded-app/../catalog-client/src/types/api.ts","webpack://techdocs-cli-embedded-app/../catalog-client/src/CatalogClient.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/entity/constants.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/entity/policies/DefaultNamespaceEntityPolicy.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/validation/CommonValidatorFunctions.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/validation/ajv.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/validation/entityEnvelopeSchemaValidator.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/validation/entityKindSchemaValidator.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/validation/entitySchemaValidator.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/validation/KubernetesValidatorFunctions.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/validation/makeValidator.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/entity/policies/FieldFormatEntityPolicy.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/entity/policies/SchemaValidEntityPolicy.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/entity/ref.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/entity/util.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/EntityPolicies.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/kinds/util.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/kinds/ApiEntityV1alpha1.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/kinds/ComponentEntityV1alpha1.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/kinds/DomainEntityV1alpha1.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/kinds/GroupEntityV1alpha1.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/kinds/LocationEntityV1alpha1.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/kinds/relations.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/kinds/ResourceEntityV1alpha1.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/kinds/SystemEntityV1alpha1.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/kinds/TemplateEntityV1beta2.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/kinds/UserEntityV1alpha1.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/location/annotation.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/location/helpers.ts","webpack://techdocs-cli-embedded-app/../catalog-model/src/location/validation.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/AlertApi/AlertApiForwarder.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/AnalyticsApi/NoOpAnalyticsApi.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/AppThemeApi/AppThemeSelector.ts","webpack://techdocs-cli-embedded-app/../config/src/reader.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/DiscoveryApi/UrlPatternDiscovery.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/ErrorApi/ErrorAlerter.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/ErrorApi/ErrorApiForwarder.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/ErrorApi/UnhandledErrorForwarder.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.tsx","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/FetchApi/createFetchApi.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/FetchApi/FetchMiddlewares.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/OAuthRequestApi/OAuthPendingRequests.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/StorageApi/WebStorage.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/atlassian/AtlassianAuth.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/auth0/Auth0Auth.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/github/GithubAuth.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/google/GoogleAuth.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/lib/AuthConnector/DefaultAuthConnector.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/okta/OktaAuth.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/lib/AuthConnector/DirectAuthConnector.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/saml/types.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/auth/saml/SamlAuth.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/system/ApiFactoryRegistry.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/system/ApiAggregator.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/system/ApiProvider.tsx","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/system/ApiResolver.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/extensions/traversal.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/plugins/collectors.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/routing/collectors.tsx","webpack://techdocs-cli-embedded-app/../core-app-api/src/routing/types.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/routing/RouteResolver.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/routing/RoutingProvider.tsx","webpack://techdocs-cli-embedded-app/../core-app-api/src/routing/RouteTracker.tsx","webpack://techdocs-cli-embedded-app/../core-app-api/src/routing/validation.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/app/AppContext.tsx","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/app/AppThemeProvider.tsx","webpack://techdocs-cli-embedded-app/../core-app-api/src/apis/system/ApiRegistry.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/app/resolveRouteBindings.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/app/AppManager.tsx","webpack://techdocs-cli-embedded-app/../core-app-api/src/app/createSpecializedApp.tsx","webpack://techdocs-cli-embedded-app/../core-app-api/src/app/defaultConfigLoader.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/lib/AuthSessionManager/common.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/lib/AuthSessionManager/SessionStateTracker.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/lib/AuthSessionManager/StaticAuthSessionManager.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/lib/AuthSessionManager/AuthSessionStore.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/lib/loginPopup.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/lib/subjects.ts","webpack://techdocs-cli-embedded-app/../core-app-api/src/routing/FeatureFlagged.tsx","webpack://techdocs-cli-embedded-app/../core-app-api/src/routing/FlatRoutes.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/AlertDisplay/AlertDisplay.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Avatar/Avatar.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Link/Link.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Button/Button.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/CopyTextButton/CopyTextButton.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/CodeSnippet/CodeSnippet.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/CreateButton/CreateButton.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/DependencyGraph/types.ts","webpack://techdocs-cli-embedded-app/../core-components/src/components/DependencyGraph/DefaultNode.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/DependencyGraph/constants.ts","webpack://techdocs-cli-embedded-app/../core-components/src/components/DependencyGraph/Node.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/DependencyGraph/DefaultLabel.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/DependencyGraph/Edge.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/DependencyGraph/DependencyGraph.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/DismissableBanner/DismissableBanner.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/EmptyState/EmptyStateImage.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/EmptyState/EmptyState.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/WarningPanel/WarningPanel.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/ErrorPanel/ErrorPanel.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/ResponseErrorPanel/ResponseErrorPanel.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/FeatureDiscovery/lib/usePortal.ts","webpack://techdocs-cli-embedded-app/../core-components/src/components/FeatureDiscovery/lib/useShowCallout.ts","webpack://techdocs-cli-embedded-app/../core-components/src/components/FeatureDiscovery/FeatureCalloutCircular.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/HeaderIconLinkRow/IconLinkVertical.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/HeaderIconLinkRow/HeaderIconLinkRow.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/HorizontalScrollGrid/HorizontalScrollGrid.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Lifecycle/Lifecycle.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/LogViewer/LogViewer.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/MarkdownContent/MarkdownContent.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/OAuthRequestDialog/LoginRequestListItem.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/OAuthRequestDialog/OAuthRequestDialog.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/OverflowTooltip/OverflowTooltip.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Progress/Progress.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/BottomLink/BottomLink.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/ErrorBoundary/ErrorBoundary.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/InfoCard/InfoCard.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/ProgressBars/Gauge.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/ProgressBars/GaugeCard.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/ProgressBars/LinearGauge.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Select/static/ClosedDropdown.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Select/static/OpenedDropdown.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Select/Select.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/SimpleStepper/SimpleStepper.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/SimpleStepper/SimpleStepperFooter.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/SimpleStepper/SimpleStepperStep.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Status/Status.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/StructuredMetadataTable/MetadataTable.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/StructuredMetadataTable/StructuredMetadataTable.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/hooks/useQueryParamState.ts","webpack://techdocs-cli-embedded-app/../core-components/src/hooks/useSupportConfig.ts","webpack://techdocs-cli-embedded-app/../core-components/src/icons/icons.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/SupportButton/SupportButton.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/config.ts","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/localStorage.ts","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/Page.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/SidebarGroup.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/MobileSidebar.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/Bar.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/utils.ts","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/SidebarSubmenu.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/icons/DoubleArrowLeft.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/icons/DoubleArrowRight.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/Items.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Sidebar/Intro.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Content/Content.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/HeaderTabs/HeaderTabs.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/TabbedLayout/RoutedTabs.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/TabbedLayout/TabbedLayout.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Table/SubvalueCell.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Table/Filters.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Table/Table.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Tabs/TabPanel.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Tabs/TabIcon.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Tabs/Tab.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Tabs/TabBar.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/Tabs/Tabs.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/components/TrendLine/TrendLine.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/ContentHeader/ContentHeader.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/ErrorPage/MicDrop.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/ErrorPage/ErrorPage.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Breadcrumbs/Breadcrumbs.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Header/Header.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/HeaderLabel/HeaderLabel.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/HomepageTimer/HomepageTimer.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/ItemCard/ItemCardHeader.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/ItemCard/ItemCard.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/ItemCard/ItemCardGrid.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Page/Page.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/Page/PageWithHeader.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/ProxiedSignInPage/types.ts","webpack://techdocs-cli-embedded-app/../core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.ts","webpack://techdocs-cli-embedded-app/../core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/SignInPage/styles.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/SignInPage/GuestUserIdentity.ts","webpack://techdocs-cli-embedded-app/../core-components/src/layout/SignInPage/LegacyUserIdentity.ts","webpack://techdocs-cli-embedded-app/../core-components/src/layout/SignInPage/UserIdentity.ts","webpack://techdocs-cli-embedded-app/../core-components/src/layout/SignInPage/commonProvider.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/SignInPage/guestProvider.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/SignInPage/customProvider.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/SignInPage/providers.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/SignInPage/SignInPage.tsx","webpack://techdocs-cli-embedded-app/../core-components/src/layout/TabbedCard/TabbedCard.tsx","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/analytics/AnalyticsContext.tsx","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/analytics/Tracker.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/analytics/useAnalytics.tsx","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/auth.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/AlertApi.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/AnalyticsApi.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/AppThemeApi.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/ConfigApi.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/DiscoveryApi.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/ErrorApi.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/FeatureFlagsApi.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/FetchApi.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/IdentityApi.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/OAuthRequestApi.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/definitions/StorageApi.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/system/ApiRef.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/system/helpers.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/apis/system/useApi.tsx","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/app/useApp.tsx","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/extensions/componentData.tsx","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/extensions/PluginErrorBoundary.tsx","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/extensions/extensions.tsx","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/extensions/useElementFilter.tsx","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/plugin/Plugin.tsx","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/routing/types.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/routing/RouteRef.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/routing/SubRouteRef.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/routing/ExternalRouteRef.ts","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/routing/useRouteRef.tsx","webpack://techdocs-cli-embedded-app/../core-plugin-api/src/routing/useRouteRefParams.ts","webpack://techdocs-cli-embedded-app/../errors/src/errors/assertion.ts","webpack://techdocs-cli-embedded-app/../errors/src/serialization/error.ts","webpack://techdocs-cli-embedded-app/../errors/src/errors/CustomErrorBase.ts","webpack://techdocs-cli-embedded-app/../errors/src/errors/common.ts","webpack://techdocs-cli-embedded-app/../errors/src/serialization/response.ts","webpack://techdocs-cli-embedded-app/../errors/src/errors/ResponseError.ts","webpack://techdocs-cli-embedded-app/../integration-react/src/api/ScmAuthApi.ts","webpack://techdocs-cli-embedded-app/../integration-react/src/api/ScmAuth.ts","webpack://techdocs-cli-embedded-app/../integration-react/src/api/ScmIntegrationsApi.ts","webpack://techdocs-cli-embedded-app/../integration-react/src/components/ScmIntegrationIcon/ScmIntegrationIcon.tsx","webpack://techdocs-cli-embedded-app/../integration/src/helpers.ts","webpack://techdocs-cli-embedded-app/../integration/src/azure/AzureUrl.ts","webpack://techdocs-cli-embedded-app/../integration/src/azure/config.ts","webpack://techdocs-cli-embedded-app/../integration/src/azure/AzureIntegration.ts","webpack://techdocs-cli-embedded-app/../integration/src/azure/core.ts","webpack://techdocs-cli-embedded-app/../integration/src/bitbucket/config.ts","webpack://techdocs-cli-embedded-app/../integration/src/bitbucket/BitbucketIntegration.ts","webpack://techdocs-cli-embedded-app/../integration/src/bitbucket/core.ts","webpack://techdocs-cli-embedded-app/../integration/src/github/config.ts","webpack://techdocs-cli-embedded-app/../integration/src/github/core.ts","webpack://techdocs-cli-embedded-app/../integration/src/github/SingleInstanceGithubCredentialsProvider.ts","webpack://techdocs-cli-embedded-app/../integration/src/github/DefaultGithubCredentialsProvider.ts","webpack://techdocs-cli-embedded-app/../integration/src/github/GitHubIntegration.ts","webpack://techdocs-cli-embedded-app/../integration/src/gitlab/config.ts","webpack://techdocs-cli-embedded-app/../integration/src/gitlab/core.ts","webpack://techdocs-cli-embedded-app/../integration/src/gitlab/GitLabIntegration.ts","webpack://techdocs-cli-embedded-app/../integration/src/awsS3/config.ts","webpack://techdocs-cli-embedded-app/../integration/src/awsS3/AwsS3Integration.ts","webpack://techdocs-cli-embedded-app/../integration/src/ScmIntegrations.ts","webpack://techdocs-cli-embedded-app/../app-defaults/src/defaults/apis.ts","webpack://techdocs-cli-embedded-app/../app-defaults/src/defaults/components.tsx","webpack://techdocs-cli-embedded-app/../app-defaults/src/defaults/icons.tsx","webpack://techdocs-cli-embedded-app/../theme/src/pageTheme.ts","webpack://techdocs-cli-embedded-app/../theme/src/baseTheme.ts","webpack://techdocs-cli-embedded-app/../theme/src/themes.ts","webpack://techdocs-cli-embedded-app/../app-defaults/src/defaults/themes.tsx","webpack://techdocs-cli-embedded-app/../app-defaults/src/createApp.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/CatalogResultListItem/CatalogResultListItem.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-common/src/permissions.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/EntityOrphanWarning/DeleteEntityDialog.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/EntityOrphanWarning/EntityOrphanWarning.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/EntityPageLayout/Tabbed/Tabbed.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/EntityPageLayout/EntityPageLayout.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/EntitySwitch/EntitySwitch.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/EntityNotFound/Illo/Illo.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/Router.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/plugin.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/client.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/EntityListDocsTable.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/TechDocsPicker.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/EntityListDocsGrid.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/plugin.ts","webpack://techdocs-cli-embedded-app/./src/apis.ts","webpack://techdocs-cli-embedded-app/./src/components/Root/LogoFull.tsx","webpack://techdocs-cli-embedded-app/./src/components/Root/LogoIcon.tsx","webpack://techdocs-cli-embedded-app/./src/components/Root/Root.tsx","webpack://techdocs-cli-embedded-app/./src/components/TechDocsPage/TechDocsPage.tsx","webpack://techdocs-cli-embedded-app/./src/config.ts","webpack://techdocs-cli-embedded-app/./src/App.tsx","webpack://techdocs-cli-embedded-app/./src/index.tsx","webpack://techdocs-cli-embedded-app/../version-bridge/src/lib/globalObject.ts","webpack://techdocs-cli-embedded-app/../version-bridge/src/lib/VersionedContext.ts","webpack://techdocs-cli-embedded-app/../version-bridge/src/lib/VersionedValue.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/api.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/apis/StarredEntitiesApi/migration.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/apis/StarredEntitiesApi/StarredEntitiesApi.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/routes.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useEntityCompoundName.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useEntity.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/utils/filters.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/utils/getEntityMetadataUrl.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/utils/getEntityRelations.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/utils/getEntitySourceLocation.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/utils/isOwnerOf.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useEntityListProvider.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntityRefLink/format.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/filters.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useEntityTypeFilter.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useEntityKinds.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useOwnUser.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useRelatedEntities.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useStarredEntities.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useStarredEntity.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useEntityOwnership.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useOwnedEntities.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/hooks/useEntityPermission.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntityTable/columns.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntityTable/presets.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntityTable/EntityTable.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/EntityTypePicker/EntityTypePicker.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/FavoriteEntity/FavoriteEntity.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/UnregisterEntityDialog/UnregisterEntityDialog.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog-react/src/testUtils/providers.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/AboutCard/AboutField.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/AboutCard/AboutContent.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/AboutCard/AboutCard.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/CatalogKindHeader/CatalogKindHeader.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/CatalogTable/columns.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/FilteredEntityLayout/FilteredEntityLayout.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/FilteredEntityLayout/FilterContainer.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/components/FilteredEntityLayout/EntityListContainer.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/catalog/src/routes.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/permission-react/src/apis/PermissionApi.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/permission-common/src/types/api.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/permission-common/src/PermissionClient.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/permission-react/src/apis/IdentityPermissionApi.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/permission-react/src/hooks/usePermission.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/permission-react/src/components/PermissionedRoute.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/apis.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/DefaultResultListItem/DefaultResultListItem.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchTracker/SearchTracker.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchBar/SearchBar.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchContext/SearchContext.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchModal/SearchModal.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/LegacySearchPage/LegacySearchBar.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/LegacySearchPage/Filters/FiltersButton.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/LegacySearchPage/Filters/Filters.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/LegacySearchPage/LegacySearchResult.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/LegacySearchPage/LegacySearchPage.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchPage/SearchPage.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchResult/SearchResult.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchResultPager/SearchResultPager.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/plugin.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/EntityPageDocs.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/Router.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/api.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/components/DocsResultListItem/DocsResultListItem.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/helpers.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/DocsCardGrid.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/DocsTable.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/LegacyTechDocsHome.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/TechDocsPageWrapper.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/actions.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/home/components/columns.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/addBaseUrl.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/addGitFeedbackLink.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/rewriteDocLinks.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/addLinkClickListener.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/copyToClipboard.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/removeMkdocsHeader.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/simplifyMkdocsFooter.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/onCssReady.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/sanitizeDOM.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/injectCss.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/scrollIntoAnchor.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/transformers/transformer.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/components/useReaderState.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/components/Reader.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/components/TechDocsNotFound.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/components/LegacyTechDocsPage.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/components/TechDocsPage.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/components/TechDocsPageHeader.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/Filters/FiltersButton.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/Filters/Filters.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchFilter/hooks.ts","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchFilter/SearchFilter.Autocomplete.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchFilter/SearchFilter.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchType/SearchType.Accordion.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchType/SearchType.Tabs.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SearchType/SearchType.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/search/src/components/SidebarSearch/SidebarSearch.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/components/TechDocsSearch.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/components/TechDocsBuildLogs.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/reader/components/TechDocsStateIndicator.tsx","webpack://techdocs-cli-embedded-app/../node_modules/@sucrase/webpack-loader/dist/plugins/techdocs/src/routes.ts"],"names":[],"mappings":"0vBAuBO,KAAM,GAAwB,OAAO,yBCwBrC,OAAqB,CAI1B,YAAY,EAAS,CAHnB,uBACA,mBAGA,KAAK,aAAe,EAAQ,aAC5B,KAAK,SAAW,EAAQ,UAAY,CAAE,MAAO,UAazC,oBACJ,EACA,EACA,CACA,KAAM,CAAE,OAAM,YAAW,QAAS,SAAe,EAAQ,WACzD,MAAO,MAAM,MAAK,gBAChB,MACA,qBAAqB,mBAAmB,MAAS,mBAC/C,MACG,mBAAmB,cACxB,QAcE,iBACJ,EACA,EACA,CACA,MAAO,MAAM,MAAK,gBAChB,MACA,cAAc,mBAAmB,KACjC,QAcE,aACJ,EACA,EACA,CACA,KAAM,CAAE,SAAS,GAAI,SAAS,GAAI,SAAQ,QAAO,SAAU,UAAW,GAChE,EAAc,CAAC,GAAQ,OACvB,EAAS,GAMf,SAAW,KAAc,GAAa,CACpC,KAAM,GAAc,GACpB,SAAW,CAAC,EAAK,KAAU,QAAO,QAAQ,GACxC,SAAW,MAAK,CAAC,IAAO,OAClB,KAAM,EACR,EAAY,KAAK,mBAAmB,IAC3B,MAAO,KAAM,UACtB,EAAY,KACV,GAAG,mBAAmB,MAAQ,mBAAmB,OAMrD,EAAY,QACd,EAAO,KAAK,UAAU,EAAY,KAAK,QAIvC,EAAO,QACT,EAAO,KAAK,UAAU,EAAO,IAAI,oBAAoB,KAAK,QAGxD,IAAW,QACb,EAAO,KAAK,UAAU,KAEpB,IAAU,QACZ,EAAO,KAAK,SAAS,KAEnB,IAAU,QACZ,EAAO,KAAK,SAAS,mBAAmB,MAG1C,KAAM,GAAQ,EAAO,OAAS,IAAI,EAAO,KAAK,OAAS,GACjD,EAAW,KAAM,MAAK,gBAC1B,MACA,YAAY,IACZ,GAGI,EAAa,CAAC,EAAG,IAAM,C,UAE3B,GACE,OAAE,WAAF,eAAY,QAAS,QACrB,EAAE,OAAS,QACX,OAAE,WAAF,eAAY,QAAS,QACrB,EAAE,OAAS,OAEX,MAAO,GAGT,KAAM,GAAO,SAAmB,GAC1B,GAAO,SAAmB,GAChC,MAAI,GAAO,GACF,GAEL,EAAO,GACF,EAEF,GAGT,MAAO,CAAE,MAAO,EAAS,KAAK,SAa1B,iBACJ,EACA,EACA,CACA,KAAM,CAAE,OAAM,YAAY,UAAW,QAAS,EAC9C,MAAO,MAAK,gBACV,MACA,qBAAqB,mBAAmB,MAAS,mBAC/C,MACG,mBAAmB,KACxB,QAYE,eAAc,EAAW,EAAS,CACtC,KAAM,GAAW,KAAM,MAAK,SAAS,MACnC,GAAG,KAAM,MAAK,aAAa,WAAW,qBACtC,CACE,QAAS,CACP,eAAgB,sBACZ,kBAAS,QAAS,CAAE,cAAe,UAAU,iBAAS,UAE5D,OAAQ,OACR,KAAM,KAAK,UAAU,CAAE,gBAI3B,GAAI,EAAS,SAAW,IACtB,KAAM,IAAI,OAAM,KAAM,GAAS,aAc7B,aACJ,CAAE,OAAO,MAAO,SAAQ,SAAQ,YAChC,EACA,CACA,KAAM,GAAW,KAAM,MAAK,SAAS,MACnC,GAAG,KAAM,MAAK,aAAa,WAAW,uBACpC,EAAS,eAAiB,KAE5B,CACE,QAAS,CACP,eAAgB,sBACZ,kBAAS,QAAS,CAAE,cAAe,UAAU,iBAAS,UAE5D,OAAQ,OACR,KAAM,KAAK,UAAU,CAAE,OAAM,SAAQ,eAIzC,GAAI,EAAS,SAAW,IACtB,KAAM,IAAI,OAAM,KAAM,GAAS,QAGjC,KAAM,CAAE,WAAU,WAAU,UAAW,KAAM,GAAS,OAEtD,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,0BAA0B,KAG5C,MAAO,CACL,WACA,WACA,eAcE,2BACJ,EACA,EACA,C,MACA,KAAM,GACJ,KAAO,SAAS,cAAhB,cAA8B,MAChC,MAAK,GAQE,MALW,MAAK,gBACrB,MACA,aACA,IAGC,IAAI,GAAK,EAAE,MACX,KAAK,GAAK,IAAqB,SAA2B,IAT3D,YAsBE,qBACJ,EACA,EACA,C,MACA,KAAM,GAAmB,KAAO,SAAS,cAAhB,cAA8B,MACvD,MAAK,GAQE,MALW,MAAK,gBACrB,MACA,aACA,IAGC,IAAI,GAAK,EAAE,MACX,KAAK,GAAK,IAAqB,SAA2B,IAT3D,YAoBE,oBACJ,EACA,EACA,CACA,KAAM,MAAK,eACT,SACA,cAAc,mBAAmB,KACjC,QAYE,mBACJ,EACA,EACA,CACA,KAAM,MAAK,eACT,SACA,oBAAoB,mBAAmB,KACvC,QAQG,gBACL,EACA,EACA,EACA,CACA,KAAM,GAAM,GAAG,KAAM,MAAK,aAAa,WAAW,aAAa,IACzD,EAAU,kBAAS,OACrB,CAAE,cAAe,UAAU,EAAQ,SACnC,GACE,EAAW,KAAM,MAAK,SAAS,MAAM,EAAK,CAAE,SAAQ,YAE1D,GAAI,CAAC,EAAS,GACZ,KAAM,MAAM,mBAA2B,QAIpC,iBACL,EACA,EACA,EACA,CACA,KAAM,GAAM,GAAG,KAAM,MAAK,aAAa,WAAW,aAAa,IACzD,EAAU,kBAAS,OACrB,CAAE,cAAe,UAAU,EAAQ,SACnC,GACE,EAAW,KAAM,MAAK,SAAS,MAAM,EAAK,CAAE,SAAQ,YAE1D,GAAI,CAAC,EAAS,GACZ,KAAM,MAAM,mBAA2B,GAGzC,MAAO,MAAM,GAAS,YAGjB,iBACL,EACA,EACA,EACA,CACA,KAAM,GAAM,GAAG,KAAM,MAAK,aAAa,WAAW,aAAa,IACzD,EAAU,kBAAS,OACrB,CAAE,cAAe,UAAU,EAAQ,SACnC,GACE,EAAW,KAAM,MAAK,SAAS,MAAM,EAAK,CAAE,SAAQ,YAE1D,GAAI,CAAC,EAAS,GAAI,CAChB,GAAI,EAAS,SAAW,IACtB,OAEF,KAAM,MAAM,mBAA2B,GAGzC,MAAO,MAAM,GAAS,U,ggBC7ZnB,KAAM,GAA2B,UAO3B,EAA+B,KAW/B,EAAsB,wBAOtB,EAAsB,wB,wBCpB5B,OAAoC,CAGzC,YAAY,EAAY,yBAA0B,CAFhD,oBAGA,KAAK,UAAY,OAGb,SAAQ,EAAQ,CACpB,MAAI,GAAO,SAAS,UACX,EAGF,OAAO,MAAM,CAAE,SAAU,CAAE,UAAW,KAAK,YAAe,ICd9D,OAA+B,OAU7B,0BACL,EACA,EACA,GACA,GACA,CACA,GAAI,MAAO,IAAU,SACnB,MAAO,GAGT,KAAM,IAAQ,EAAM,MAAM,GAC1B,MAAI,IAAM,SAAW,EACZ,GAAc,GAAM,IAClB,GAAM,SAAW,EACnB,GAAc,GAAM,KAAO,GAAc,GAAM,IAGjD,SAQF,YAAW,EAAO,CACvB,GAAI,CACF,MAAO,aAAe,EAAO,KAAK,MAAM,KAAK,UAAU,UACvD,CACA,MAAO,UAUJ,qBAAoB,EAAO,CAChC,MACE,OAAO,IAAU,UACjB,EAAM,QAAU,GAChB,EAAM,QAAU,KAChB,EAAM,MAAM,KAAK,MAAM,EAAyB,uBAU7C,iBAAgB,EAAO,CAC5B,MACE,OAAO,IAAU,UACjB,EAAM,QAAU,GAChB,EAAM,QAAU,IAChB,4BAA4B,KAAK,SAS9B,YAAW,EAAO,CACvB,MACE,OAAO,IAAU,UACjB,EAAM,QAAU,GAChB,EAAM,QAAU,IAChB,gCAAgC,KAAK,SASlC,YAAW,EAAO,CACvB,GAAI,MAAO,IAAU,SACnB,MAAO,GAGT,GAAI,CAEF,UAAI,KAAI,GACD,QACP,CACA,MAAO,UASJ,eAAc,EAAO,C,MAC1B,MAAO,OAAO,IAAU,UAAY,qBAAO,SAAP,cAAe,SAAU,G,4qRChHjE,KAAM,GAAsB,GAAI,KAG1B,EAA0B,CAC9B,EACA,EACA,EACA,GAGK,WACL,GACA,CACA,GAAI,CAAC,oBAAQ,QACX,KAAM,IAAI,WAAU,iBAGtB,KAAM,GAAQ,GAAO,GACrB,KAAM,IAAI,WACR,GAAG,EAAM,UAAY,YAAY,EAAM,UACrC,EAAM,OACF,MAAM,OAAO,QAAQ,EAAM,QACxB,IAAI,CAAC,CAAC,EAAK,MAAS,GAAG,MAAQ,MAC/B,KAAK,QACR,MAOH,WACL,GACA,EAAU,GACV,C,OACA,KAAM,GAAe,qBAAS,eAAT,QAAyB,GACxC,GAAW,EAAe,GAAK,KAAK,UAAU,IAEpD,GAAI,CAAC,EAAc,CACjB,KAAM,IAAS,EAAoB,IAAI,IACvC,GAAI,GACF,MAAO,IAIX,KAAM,IAAe,EAAgB,IAC/B,GAAM,GAAI,MAAI,CAClB,gBAAiB,GACjB,UAAW,GACX,eAAgB,KAEd,GAAa,QACf,GAAI,UAAU,GAAc,OAAW,OAAW,IAEpD,KAAM,IAAW,GAAI,QAAQ,IAE7B,MAAK,IACH,EAAoB,IAAI,GAAU,IAG7B,GAKT,WAAyB,GAAQ,CAC/B,GAAI,MAAO,KAAW,SACpB,MAAO,GAGT,KAAM,GAAO,GAAI,KACb,GAAO,KACT,EAAK,IAAI,GAAO,KAGlB,KAAM,GAAW,GAAI,OAEf,GAAO,CAAC,IACd,KAAO,GAAK,QAAQ,CAClB,KAAM,IAAU,GAAK,MAErB,SAAW,MAAO,GAAW,IAC3B,GAAI,CAAC,EAAK,IAAI,IAAM,CAClB,EAAK,IAAI,IAET,KAAM,IAAQ,EAAwB,KAAK,IAAK,GAAE,MAAQ,IACtD,IACF,GAAS,KAAK,IACd,GAAK,KAAK,MAMlB,MAAO,GAMT,WAAqB,GAAQ,CAC3B,KAAM,GAAO,CAAC,IACd,KAAO,EAAK,QAAQ,CAClB,KAAM,GAAU,EAAK,MACrB,GAAI,MAAO,IAAY,UAAY,EACjC,SAAW,CAAC,GAAK,KAAU,QAAO,QAAQ,GACpC,KAAQ,QAAU,MAAO,KAAU,SACrC,KAAM,IAAM,MAAM,KAAK,GAEvB,EAAK,KAAK,KCtFb,WAEN,GAAQ,CACP,KAAM,GAAW,iBACf,IAAqB,sBAGvB,MAAO,IAAQ,CAEb,GAAI,EADoB,KACT,GACb,MAAO,GAGT,KAAM,eAAc,EAAS,SCE1B,WACL,GACA,CACA,KAAM,GAAW,EAAiB,IAElC,MAAO,IAAQ,C,OAEb,GAAI,EADoB,KACT,GACb,MAAO,GAKT,KAAM,IAAiB,MAAS,SAAT,eAAiB,OAAO,IAC7C,CAAC,QAAS,eAAe,SAAS,GAAE,WAEtC,GACE,oBAAgB,SAChB,GAAe,MAAM,IAAK,GAAE,UAAY,QAExC,MAAO,GAGT,KAAM,GAAc,EAAS,SCzC1B,WACL,GACA,CACA,KAAM,GAAW,iBAAiB,IAAqB,cAEvD,MAAO,IAAQ,CAEb,GAAI,EADoB,KACT,GACb,MAAO,GAGT,KAAM,eAAc,EAAS,SC5B1B,QAAmC,OACjC,mBAAkB,EAAO,CAC9B,MAAO,4BACL,EACA,IACA,sBACA,GAAK,EAAE,QAAU,GAAK,EAAE,QAAU,IAAM,iBAAiB,KAAK,UAI3D,aAAY,EAAO,CACxB,MACE,OAAO,IAAU,UACjB,EAAM,QAAU,GAChB,EAAM,QAAU,IAChB,yBAAyB,KAAK,SAI3B,mBAAkB,EAAO,CAC9B,MACE,OAAO,IAAU,UACjB,EAAM,QAAU,GAChB,EAAM,QAAU,IAChB,6CAA6C,KAAK,SAI/C,kBAAiB,EAAO,CAC7B,MAAO,mBAAyC,SAG3C,iBAAgB,EAAO,CAC5B,MAAO,4BACL,EACA,IACA,sBACA,GAA6B,yBAI1B,mBAAkB,EAAO,CAC9B,MACE,KAAU,IAAM,GAA6B,kBAAkB,SAI5D,sBAAqB,EAAO,CACjC,MAAO,4BACL,EACA,IACA,sBACA,GAA6B,yBAI1B,wBAAuB,EAAO,CACnC,MAAO,OAAO,IAAU,UChE5B,KAAM,IAAoB,CACxB,kBAAmB,qBACnB,YAAa,eACb,kBAAmB,qBACnB,iBAAkB,oBAClB,gBAAiB,mBACjB,kBAAmB,qBACnB,qBAAsB,wBACtB,uBAAwB,0BACxB,WAAY,cAQP,YAAuB,GAAY,GAAI,CAC5C,MAAO,IACF,MACA,ICJA,QAA+B,CAGpC,YAAY,EAAa,gBAAiB,CAFxC,qBAGA,KAAK,WAAa,OAGd,SAAQ,EAAQ,C,yBACpB,WACE,GACA,GACA,GACA,CACA,GAA2B,IAAU,KACnC,KAAM,IAAI,OAAM,GAAG,wBAGrB,GAAI,IACJ,GAAI,CACF,GAAU,GAAU,UACb,GAAP,CACA,KAAM,IAAI,OAAM,GAAG,8BAAiC,MAGtD,GAAI,CAAC,GAAS,CACZ,GAAI,IACJ,OACE,GAAU,UAIL,wBACA,oBACH,GACE,sGACF,UACG,sBACA,wBACA,uBACH,GAAc,+BACd,UACG,uBACA,kBACH,GACE,0FACF,UACG,aACH,GACE,4FACF,UACG,yBACH,GAAc,WACd,UACG,cACH,GACE,qFACF,UACG,aACH,GAAc,+BACd,UACG,gBACH,GAAc,qBACd,cAEA,GAAc,OACd,MAIJ,KAAM,IAAU,GACZ,aAAa,iBAA0B,OACvC,GAEJ,KAAM,IAAI,OACR,IAAI,oBAAuB,4KAKjC,YACE,GACA,GACA,GACA,CACA,MAAO,MAAU,QAAa,EAAQ,GAAO,GAAO,IAGtD,EAAQ,aAAc,EAAO,WAAY,KAAK,WAAW,mBACzD,EAAQ,OAAQ,EAAO,KAAM,KAAK,WAAW,aAE7C,EAAQ,gBAAiB,EAAO,SAAS,KAAM,KAAK,WACjD,mBACH,GACE,qBACA,EAAO,SAAS,UAChB,KAAK,WAAW,kBAGlB,SAAW,CAAC,GAAG,KAAM,QAAO,QAAQ,MAAO,SAAS,SAAhB,QAA0B,IAC5D,EAAQ,UAAU,KAAK,GAAG,KAAK,WAAW,iBAC1C,EAAQ,UAAU,KAAK,GAAG,KAAK,WAAW,mBAG5C,SAAW,CAAC,GAAG,KAAM,QAAO,QAAQ,MAAO,SAAS,cAAhB,QAA+B,IACjE,EAAQ,eAAe,KAAK,GAAG,KAAK,WAAW,sBAC/C,EAAQ,eAAe,KAAK,GAAG,KAAK,WAAW,wBAGjD,KAAM,IAAO,MAAO,SAAS,OAAhB,QAAwB,GAErC,OAAS,IAAI,EAAG,GAAI,GAAK,OAAQ,EAAE,GACjC,EAAQ,QAAQ,KAAK,GAAK,IAAI,KAAK,WAAW,YAGhD,KAAM,IAAQ,MAAO,SAAS,QAAhB,QAAyB,GAEvC,OAAS,IAAI,EAAG,GAAI,GAAM,OAAQ,EAAE,GAClC,EAAQ,SAAS,SAAS,OAAM,MAAN,eACtB,IAAK,yBAAyB,YAClC,GACE,SAAS,WACT,OAAM,MAAN,eAAU,MACV,yBAAyB,eAE3B,GACE,SAAS,UACT,OAAM,MAAN,eAAU,KACV,6BAA6B,mBAIjC,MAAO,ICrIJ,QAA+B,CAA/B,a,CACJ,wBAEK,SAAQ,EAAQ,CACpB,GAAI,CAAC,KAAK,SAAU,CAClB,KAAM,IAAM,GAAI,KAAI,CAAE,gBAAiB,KACvC,KAAK,SAAW,GACb,UAAU,CAAC,aAAc,kBAAmB,OAAW,OAAW,IAClE,QAAQ,cAIb,GAAI,KADgB,SAAS,KACd,GACb,MAAO,GAGT,KAAM,CAAC,IAAS,KAAK,SAAS,QAAU,GACxC,KAAK,IAIC,GAAI,OACR,uBAAuB,GAAM,UAAY,YAAY,GAAM,WAJrD,GAAI,OAAM,sCChCtB,YAAwB,GAIvB,C,SACC,KAAM,GAAQ,kCAAkC,KAAK,GAAI,QACzD,GAAI,CAAC,EACH,KAAM,IAAI,WACR,qBAAqB,yDAIzB,MAAO,CACL,KAAM,KAAM,KAAN,cAAU,MAAM,EAAG,IACzB,UAAW,MAAM,KAAN,eAAU,MAAM,EAAG,IAC9B,KAAM,EAAM,IAYT,YAAuB,GAAQ,CACpC,MAAO,CACL,KAAM,GAAO,KACb,UAAW,GAAO,SAAS,WAAa,EACxC,KAAM,GAAO,SAAS,MA+BnB,YACL,GACA,EAAU,GACV,CACA,KAAM,CAAE,OAAM,aAAW,SAAS,GAAe,GAAK,CACpD,iBAAkB,4BACf,IAGL,GAAI,CAAC,EACH,KAAM,IAAI,OACR,oBAAoB,MAAa,6BAIrC,MAAO,CAAE,OAAM,aAAW,SAoDrB,YACL,GACA,EAAU,GAKX,C,UACC,GAAI,CAAC,GACH,KAAM,IAAI,OAAM,sCAGlB,GAAI,MAAO,KAAQ,SAAU,CAC3B,KAAM,IAAS,GAAe,IAC9B,MAAO,CACL,KAAM,OAAO,OAAP,QAAe,EAAQ,YAC7B,UAAW,OAAO,YAAP,QAAoB,EAAQ,iBACvC,KAAM,GAAO,MAIjB,KAAM,CAAE,OAAM,aAAW,SAAS,GAClC,GAAI,IAAS,GACX,KAAM,IAAI,OAAM,4CACX,GAAI,KAAc,GACvB,KAAM,IAAI,OAAM,iDACX,GAAI,CAAC,GACV,KAAM,IAAI,OAAM,yCAGlB,MAAO,CACL,KAAM,UAAQ,EAAQ,YACtB,UAAW,YAAa,EAAQ,iBAChC,SAeG,YACL,GAOA,CACA,GAAI,GACA,EACA,GAYJ,MAVI,YAAc,IAChB,GAAO,GAAI,KACX,EAAY,GAAI,SAAS,UACzB,GAAO,GAAI,SAAS,MAEpB,GAAO,GAAI,KACX,EAAY,GAAI,UAChB,GAAO,GAAI,MAIX,kBAAM,SAAS,OACf,kBAAM,SAAS,OACf,kBAAW,SAAS,OACpB,kBAAW,SAAS,OACpB,GAAK,SAAS,MACd,GAAK,SAAS,KAEP,CAAE,OAAM,YAAW,SAGrB,GAAG,EAAO,GAAG,KAAU,KAAK,EAAY,GAAG,KAAe,KAAK,KAiBjE,YACL,GACA,C,UACA,GAAI,GACA,EACA,GAEJ,MAAI,YAAc,IAChB,GAAO,GAAI,KACX,EAAY,OAAI,SAAS,YAAb,QAA0B,EACtC,GAAO,GAAI,SAAS,MAEpB,GAAO,GAAI,KACX,EAAY,OAAI,YAAJ,QAAiB,EAC7B,GAAO,GAAI,MAGN,GAAG,EAAK,kBAAkB,YAAY,EAAU,kBACrD,YACG,GAAK,kBAAkB,WAkBvB,YACL,GACA,EACA,EACA,CACA,KAAM,IAAa,GAAO,KACpB,GAAkB,GAAO,SAAS,WAAa,yBAC/C,GAAa,GAAO,SAAS,KAEnC,GAAI,IACA,GACA,GACJ,GAAI,MAAO,IAAQ,SAAU,CAC3B,KAAM,IAAS,GAAe,GAC9B,GAAU,GAAO,MAAQ,kBAAS,aAClC,GACE,GAAO,WAAa,kBAAS,mBAAoB,yBACnD,GAAU,GAAO,SAEjB,IAAU,EAAI,MAAQ,kBAAS,aAC/B,GACE,EAAI,WAAa,kBAAS,mBAAoB,yBAChD,GAAU,EAAI,KAGhB,GAAI,CAAC,IAAW,CAAC,GACf,KAAM,IAAI,OACR,kEAIJ,MACE,IAAW,kBAAkB,WAC3B,GAAQ,kBAAkB,UAC5B,GAAgB,kBAAkB,WAChC,GAAa,kBAAkB,UACjC,GAAW,kBAAkB,WAAa,GAAQ,kBAAkB,S,uBCvSjE,aAA6B,CAClC,MAAO,UAUF,aAA8B,CACnC,MAAO,IAAO,KAAK,SAAU,QAAQ,SAAS,UAAU,QAAQ,SAAU,IAoBrE,YAA0B,GAAU,EAAM,CAC/C,KAAM,GAAK,OAAO,UAAU,IACtB,GAAK,OAAO,UAAU,GAE5B,MAAK,GAAG,SAAS,QACf,GAAG,SAAS,OAAS,IAElB,GAAG,SAAS,QACf,IAAG,SAAS,OAAS,IAElB,EAAG,SAAS,aACf,GAAG,SAAS,YAAc,IAEvB,GAAG,SAAS,aACf,IAAG,SAAS,YAAc,IAEvB,EAAG,SAAS,MACf,GAAG,SAAS,KAAO,IAEhB,GAAG,SAAS,MACf,IAAG,SAAS,KAAO,IAIrB,MAAO,GAAG,SAAS,IACnB,MAAO,GAAG,SAAS,KACnB,MAAO,GAAG,SAAS,WACnB,MAAO,IAAG,SAAS,IACnB,MAAO,IAAG,SAAS,KACnB,MAAO,IAAG,SAAS,WAGnB,MAAO,GAAG,UACV,MAAQ,GAAK,OACb,MAAO,IAAG,UACV,MAAQ,IAAK,OAEN,CAAC,OAAO,QAAQ,EAAI,IAiBtB,YAA+B,GAAU,EAAM,CACpD,KAAM,CAAE,MAAK,QAAM,eAAe,GAAS,SAC3C,GAAI,CAAC,GAAO,CAAC,IAAQ,CAAC,GACpB,KAAM,IAAI,OAAM,sDAGlB,KAAM,IAAS,OAAO,UAAU,GAG1B,GAAW,GAAiB,GAAU,IACtC,GAAiB,CAAC,OAAO,QAAQ,GAAS,KAAM,GAAO,MAC7D,UAAO,SAAS,IAAM,EACtB,GAAO,SAAS,KAAO,GAAW,KAAuB,GACzD,GAAO,SAAS,WAAa,GAAiB,GAAa,EAAI,GAExD,GC3GT,QAAyB,CACvB,YAAc,EAAU,CAAE,KAAK,SAAW,OAEpC,SAAQ,EAAQ,CACpB,GAAI,GAAS,EACb,SAAW,MAAU,MAAK,SAAU,CAClC,KAAM,IAAS,KAAM,IAAO,QAAQ,GACpC,GAAI,CAAC,GACH,KAAM,IAAI,OACR,UAAU,GAAO,YAAY,gCAGjC,EAAS,GAEX,MAAO,IAMX,QAAuB,CACrB,YAAc,EAAU,CAAE,KAAK,SAAW,OAEpC,SAAQ,EAAQ,CACpB,SAAW,KAAU,MAAK,SAAU,CAClC,KAAM,IAAS,KAAM,GAAO,QAAQ,GACpC,GAAI,GACF,MAAO,IAGX,KAAM,IAAI,OAAM,8CASb,KAAM,IAAiB,CAC5B,MAAM,GAAU,CACd,MAAO,IAAI,IAAkB,KAE/B,MAAM,GAAU,CACd,MAAO,IAAI,IAAgB,M,unDCzCxB,YAAwC,GAAQ,CACrD,KAAM,GAAY,EAA0B,IAC5C,MAAO,MACC,OAAM,EAAM,CAChB,MAAO,GAAU,KAAU,ICmB1B,KAAM,IACX,GAA+B,I,qnECE1B,KAAM,IACX,GAA+B,I,y0BCR1B,KAAM,IACX,GAA+B,I,+8FCE1B,KAAM,IACX,GAA+B,I,65DCL1B,KAAM,GACX,GAA+B,ICXpB,EAAoB,UAQpB,EAAoB,UAQpB,EAAwB,cAQxB,EAA2B,gBAQ3B,GAAwB,cAQxB,GAA2B,gBAQ3B,GAAsB,YAQtB,GAAyB,eASzB,GAAqB,WASrB,GAAoB,UAQpB,GAAqB,WAQrB,GAAsB,YAQtB,GAAmB,SAQnB,GAAoB,U,m5CC5F1B,KAAM,IACX,GAA+B,I,+uCCH1B,KAAM,IACX,GAA+B,I,o/HCK1B,KAAM,IACX,GAA+B,I,srECP1B,KAAM,GACX,GAA+B,ICxBpB,EAAsB,mCAKtB,EACX,0CAMW,EAA6B,+BCHnC,YAAgC,GAGtC,CACC,GAAI,MAAO,KAAQ,SACjB,KAAM,IAAI,WACR,uCAAuC,4BAA6B,MAAO,OAI/E,KAAM,GAAa,GAAI,QAAQ,KAC/B,GAAI,EAAa,EACf,KAAM,IAAI,WACR,uCAAuC,iEAI3C,KAAM,GAAO,GAAI,OAAO,EAAG,GAAY,OACjC,GAAS,GAAI,OAAO,EAAa,GAAG,OAE1C,GAAI,CAAC,GAAQ,CAAC,GACZ,KAAM,IAAI,WACR,uCAAuC,iEAI3C,GAAI,IAAS,QAAU,IAAS,QAC9B,KAAM,IAAI,WACR,+BAA+B,gDAAiD,OAIpF,MAAO,CAAE,OAAM,WAeV,YAAoC,GAGzC,CACA,KAAM,CAAE,OAAM,UAAW,GAEzB,GAAK,GAEE,GAAI,CAAC,EACV,KAAM,IAAI,WAAU,4DAFpB,MAAM,IAAI,WAAU,sDAKtB,MAAO,GAAG,KAAQ,IAcb,YAAiC,GAGvC,C,kBACC,KAAM,GACJ,cAAO,WAAP,cAAiB,cAAjB,eAA+B,8BAA/B,QACA,WAAO,WAAP,eAAiB,cAAjB,eAA+B,qBAEjC,GAAI,CAAC,EACH,KAAM,IAAI,OACR,WAAW,mBAAmB,4BAIlC,MAAO,IAAuB,G,eC3FzB,KAAM,IAAqB,MACxB,CACN,KAAM,QAAa,WACnB,OAAQ,QAAa,WACrB,SAAU,QAAY,MAAM,CAAC,WAAY,eAE1C,YACA,WAQU,GAAiB,MACpB,CACN,GAAI,QAAa,WACjB,KAAM,QAAa,WACnB,OAAQ,QAAa,WACrB,SAAU,QAAY,MAAM,CAAC,WAAY,eAE1C,YACA,WAQU,GACX,MACU,CACN,SAAU,KAEX,YACA,Y,kFCrCE,OAAyB,CAAzB,a,CACH,iBAAU,GAAI,MAEhB,KAAK,EAAO,CACV,KAAK,QAAQ,KAAK,GAGpB,QAAS,CACP,MAAO,MAAK,W,mECXT,OAAwB,CAC7B,aAAa,EAAQ,K,kFCHvB,KAAM,GAAc,QAQb,OAAwB,CAkC7B,YAAc,EAAQ,CAHrB,wBACC,iBAAU,GAAI,KAAgB,SAER,KAAK,OAAS,QAjC/B,mBAAkB,EAAQ,C,MAC/B,KAAM,GAAW,GAAI,GAAiB,GAEtC,GAAI,CAAC,OAAO,aACV,MAAO,GAGT,KAAM,GACJ,UAAO,aAAa,QAAQ,KAA5B,OAA4C,OAE9C,SAAS,iBAAiB,GAE1B,EAAS,iBAAiB,UAAU,GAAW,CACzC,EACF,OAAO,aAAa,QAAQ,EAAa,GAEzC,OAAO,aAAa,WAAW,KAInC,OAAO,iBAAiB,UAAW,GAAS,C,MAC1C,GAAI,EAAM,MAAQ,EAAa,CAC7B,KAAM,GAAU,gBAAa,QAAQ,KAArB,OAAqC,OACrD,EAAS,iBAAiB,MAIvB,EAQT,oBAAqB,CACnB,MAAO,MAAK,OAAO,QAGrB,gBAAiB,CACf,MAAO,MAAK,QAGd,kBAAmB,CACjB,MAAO,MAAK,cAGd,iBAAiB,EAAS,CACxB,KAAK,cAAgB,EACrB,KAAK,QAAQ,KAAK,M,8GCxDtB,KAAM,GAA0B,2CAEhC,WAAkB,EAAO,CACvB,MAAO,OAAO,IAAU,UAAY,IAAU,MAAQ,CAAC,MAAM,QAAQ,GAGvE,WAAgB,EAAO,CACrB,GAAI,IAAU,KACZ,MAAO,OACF,GAAI,MAAM,QAAQ,GACvB,MAAO,QAET,KAAM,GAAO,MAAO,GACpB,MAAI,KAAS,UAAY,MAAM,GACtB,MAEL,IAAS,UAAY,IAAU,GAC1B,eAEF,EAIT,KAAM,GAAS,CACb,KAAK,EAAK,EAAS,EAAU,EAAU,CACrC,MAAO,mCAAmC,UAAY,WAAiB,aAAoB,KAE7F,QAAQ,EAAK,CACX,MAAO,qCAAqC,MAE9C,QAAQ,EAAK,EAAS,EAAU,CAC9B,MAAO,2CAA2C,UAAY,WAAiB,MAU5E,OAAoB,CA2CzB,YACI,EACA,EAAU,cACV,EACA,EAAS,GACX,CAxCD,uBACA,8BAAuB,GAAI,MAuCxB,KAAK,KAAO,EAAK,KAAK,QAAU,EAAQ,KAAK,SAAW,EAAS,KAAK,OAAS,QAlC5E,aAAY,EAAS,CAC1B,MAAI,GAAQ,SAAW,EACd,GAAI,GAAa,QAKnB,EAAQ,OACb,CAAC,EAAgB,CAAE,OAAM,UAAS,eAAc,oBAAqB,CACnE,KAAM,GAAS,GAAI,GAAa,EAAM,EAAS,GAG/C,GAFA,EAAO,aAAe,EAElB,EACF,SAAW,CAAE,MAAK,gBAAiB,GAEjC,QAAQ,KACN,0BAA0B,SAAW,4CACnC,GAAe,MAMvB,MAAO,IAET,QAYJ,IAAI,EAAK,C,QAEP,MAAI,MADe,UAAU,KACf,OACL,GAEF,WAAK,WAAL,cAAe,IAAI,KAAnB,OAA2B,GAIpC,MAAO,C,QACL,KAAM,GAAY,KAAK,KAAO,OAAO,KAAK,KAAK,MAAQ,GACjD,EAAe,WAAK,WAAL,cAAe,SAAf,OAAyB,GAC9C,MAAO,CAAC,GAAG,GAAI,KAAI,CAAC,GAAG,EAAW,GAAG,KAIvC,IAAI,EAAK,CACP,KAAM,GAAQ,KAAK,YAAY,GAC/B,GAAI,IAAU,OACZ,KAAM,IAAI,OAAM,EAAO,QAAQ,KAAK,QAAQ,UAAO,MAErD,MAAO,GAIT,YAAY,EAAK,C,MACf,KAAM,GAAQ,IAAU,KAAK,UAAU,IACjC,EAAgB,QAAK,WAAL,cAAe,YAAY,GAEjD,MAAI,KAAU,OAiBL,EACE,IAAkB,OACpB,EAKF,IAAU,GAAI,CAAE,MAAO,GAAiB,CAAE,SAAS,CAAC,EAAM,IAC/D,CAAC,EAAS,IAAS,CAAC,EAAS,GAAQ,EAAO,QAC5C,MAIJ,UAAU,EAAK,CACb,KAAM,GAAQ,KAAK,kBAAkB,GACrC,GAAI,IAAU,OACZ,KAAM,IAAI,OAAM,EAAO,QAAQ,KAAK,QAAQ,KAE9C,MAAO,GAIT,kBAAkB,EAAK,C,MACrB,KAAM,GAAQ,KAAK,UAAU,GACvB,EAAiB,QAAK,WAAL,cAAe,kBAAkB,GAExD,GAAI,EAAS,GACX,MAAO,MAAK,KAAK,EAAO,EAAK,GAE/B,GAAI,IAAU,OACZ,KAAM,IAAI,WACR,EAAO,KAAK,KAAK,QAAQ,GAAM,KAAK,QAAS,EAAO,GAAQ,WAGhE,MAAO,GAIT,eAAe,EAAK,CAClB,KAAM,GAAQ,KAAK,uBAAuB,GAC1C,GAAI,IAAU,OACZ,KAAM,IAAI,OAAM,EAAO,QAAQ,KAAK,QAAQ,KAE9C,MAAO,GAIT,uBAAuB,EAAK,CAC1B,KAAM,GAAU,KAAK,gBAAgB,EAAK,GAAU,CAClD,GAAI,CAAC,MAAM,QAAQ,GACjB,MAAO,CAAE,SAAU,gBAGrB,SAAW,CAAC,EAAO,IAAU,GAAO,UAClC,GAAI,CAAC,EAAS,GACZ,MAAO,CAAE,SAAU,eAAgB,QAAO,IAAK,GAAG,KAAO,MAG7D,MAAO,KAGT,GAAI,EAAC,EAkBL,MAAO,GAAQ,IAAI,CAAC,EAAK,IAAU,KAAK,KAAK,EAAK,GAAG,KAAO,OAI9D,UAAU,EAAK,CACb,KAAM,GAAQ,KAAK,kBAAkB,GACrC,GAAI,IAAU,OACZ,KAAM,IAAI,OAAM,EAAO,QAAQ,KAAK,QAAQ,KAE9C,MAAO,GAIT,kBAAkB,EAAK,CACrB,KAAM,GAAQ,KAAK,gBACjB,EACA,GACE,MAAO,IAAQ,UACf,MAAO,IAAQ,UAAY,CAAE,SAAU,WAE3C,GAAI,MAAO,IAAU,UAAY,IAAU,OACzC,MAAO,GAET,KAAM,GAAS,OAAO,GACtB,GAAI,CAAC,OAAO,SAAS,GACnB,KAAM,IAAI,OACR,EAAO,QAAQ,KAAK,QAAQ,GAAM,KAAK,QAAS,WAGpD,MAAO,GAIT,WAAW,EAAK,CACd,KAAM,GAAQ,KAAK,mBAAmB,GACtC,GAAI,IAAU,OACZ,KAAM,IAAI,OAAM,EAAO,QAAQ,KAAK,QAAQ,KAE9C,MAAO,GAIT,mBAAmB,EAAK,CACtB,MAAO,MAAK,gBACV,EACA,GAAS,MAAO,IAAU,WAAa,CAAE,SAAU,YAKvD,UAAU,EAAK,CACb,KAAM,GAAQ,KAAK,kBAAkB,GACrC,GAAI,IAAU,OACZ,KAAM,IAAI,OAAM,EAAO,QAAQ,KAAK,QAAQ,KAE9C,MAAO,GAIT,kBAAkB,EAAK,CACrB,MAAO,MAAK,gBACV,EACA,GACG,MAAO,IAAU,UAAY,IAAU,IAAO,CAAE,SAAU,WAKjE,eAAe,EAAK,CAClB,KAAM,GAAQ,KAAK,uBAAuB,GAC1C,GAAI,IAAU,OACZ,KAAM,IAAI,OAAM,EAAO,QAAQ,KAAK,QAAQ,KAE9C,MAAO,GAIT,uBAAuB,EAAK,CAC1B,MAAO,MAAK,gBAAgB,EAAK,GAAU,CACzC,GAAI,CAAC,MAAM,QAAQ,GACjB,MAAO,CAAE,SAAU,gBAErB,SAAW,CAAC,EAAO,IAAU,GAAO,UAClC,GAAI,MAAO,IAAU,UAAY,IAAU,GACzC,MAAO,CAAE,SAAU,eAAgB,QAAO,IAAK,GAAG,KAAO,MAG7D,MAAO,KAIV,QAAQ,EAAK,CACZ,MAAO,GAAG,KAAK,SAAS,KAAK,OAAS,IAAM,KAAK,IAGlD,KAAK,EAAM,EAAK,EAAU,CACzB,KAAM,GAAS,GAAI,GACjB,EACA,KAAK,QACL,EACA,KAAK,QAAQ,IAEf,SAAO,aAAe,KAAK,aACpB,EAGR,gBACC,EACA,EAGA,C,MACA,KAAM,GAAQ,KAAK,UAAU,GAE7B,GAAI,IAAU,OAgBZ,MAAO,QAAK,WAAL,cAAe,gBAAgB,EAAK,GAE7C,KAAM,GAAS,EAAS,GACxB,GAAI,IAAW,GAAM,CACnB,KAAM,CAAE,IAAK,EAAU,EAAK,MAAO,EAAW,EAAO,YAAa,EAClE,KAAM,IAAI,WACR,EAAO,KACL,KAAK,QAAQ,GACb,KAAK,QACL,EAAO,GACP,IAKN,MAAO,GAGR,UAAU,EAAK,CACd,KAAM,GAAQ,EAAM,EAAI,MAAM,KAAO,GACrC,SAAW,KAAQ,GACjB,GAAI,CAAC,EAAwB,KAAK,GAChC,KAAM,IAAI,WAAU,uBAAuB,MAI/C,GAAI,KAAK,OAAS,OAChB,OAGF,GAAI,GAAQ,KAAK,KACjB,SAAW,CAAC,EAAO,IAAS,GAAM,UAChC,GAAI,EAAS,GACX,EAAQ,EAAM,WACL,IAAU,OAAW,CAC9B,KAAM,GAAS,KAAK,QAAQ,EAAM,MAAM,EAAG,GAAO,KAAK,MACvD,KAAM,IAAI,WACR,EAAO,KAAK,EAAQ,KAAK,QAAS,EAAO,GAAQ,WAKvD,MAAO,M,kECzYX,KAAM,GAAe,iCAQd,OAA2B,OAQzB,SAAQ,EAAS,CACtB,KAAM,GAAQ,EAAQ,MAAM,0BACtB,EAAS,EAAM,KAAK,YAE1B,GAAI,GACJ,GAAI,CACF,EAAM,GAAI,KAAI,QACd,CACA,KAAM,IAAI,OAAM,GAAG,UAAqB,iBAE1C,GAAI,EAAI,KACN,KAAM,IAAI,OAAM,GAAG,8BAErB,GAAI,EAAI,OACN,KAAM,IAAI,OAAM,GAAG,+BAErB,GAAI,EAAO,SAAS,KAClB,KAAM,IAAI,OAAM,GAAG,mCAGrB,MAAO,IAAI,GAAoB,GAGhC,YAAc,EAAO,CAAE,KAAK,MAAQ,OAE/B,YAAW,EAAU,CACzB,MAAO,MAAK,MAAM,KAAK,M,oHChCpB,OAAoB,CACzB,YACI,EACA,EACF,CAAE,KAAK,SAAW,EAAS,KAAK,SAAW,EAE7C,KAAK,EAAO,EAAS,CACnB,MAAK,kBAAS,SACZ,KAAK,SAAS,KAAK,CAAE,QAAS,EAAM,QAAS,SAAU,UAGlD,KAAK,SAAS,KAAK,EAAO,GAGnC,QAAS,CACP,MAAO,MAAK,SAAS,U,eCdlB,OAAyB,CAAzB,a,CACH,iBAAU,GAAI,MAKhB,KAAK,EAAO,EAAS,CACnB,KAAK,QAAQ,KAAK,CAAE,QAAO,YAG7B,QAAS,CACP,MAAO,MAAK,SCbT,OAA8B,OAI5B,SAAQ,EAAU,EAAc,CACrC,OAAO,iBACL,qBACC,GAAM,CACL,EAAS,KAAK,EAAE,OAAS,Q,kFCZ1B,WAA0B,EAAM,CACrC,GAAI,EAAK,OAAS,EAChB,KAAM,IAAI,OACR,QAAQ,mEAIZ,GAAI,EAAK,OAAS,IAChB,KAAM,IAAI,OACR,QAAQ,mDAIZ,GAAI,CAAC,EAAK,MAAM,sBACd,KAAM,IAAI,OACR,QAAQ,+JAYP,OAAgC,CAAhC,a,CACJ,gCAAyB,IACzB,gBAED,aAAa,EAAM,CACjB,EAAiB,EAAK,MACtB,KAAK,uBAAuB,KAAK,GAGnC,oBAAqB,CACnB,MAAO,MAAK,uBAAuB,QAGrC,SAAS,EAAM,CACb,MAAK,MAAK,OACR,MAAK,MAAQ,KAAK,QAEb,KAAK,MAAM,IAAI,KAAU,0BAGlC,KAAK,EAAS,CACP,KAAK,OACR,MAAK,MAAQ,KAAK,QAEf,EAAQ,OACX,KAAK,MAAM,QAEb,SAAW,CAAC,EAAM,IAAU,QAAO,QAAQ,EAAQ,QACjD,KAAK,MAAM,IAAI,EAAM,GAGvB,KAAM,GAAU,MAAM,KAAK,KAAK,MAAM,WAAW,OAC/C,CAAC,CAAC,CAAE,KAAW,IAAU,2BAE3B,OAAO,aAAa,QAClB,eACA,KAAK,UAAU,OAAO,YAAY,KAIrC,MAAO,CACN,GAAI,CACF,KAAM,GAAU,OAAO,aAAa,QAAQ,gBAC5C,GAAI,CAAC,EACH,MAAO,IAAI,KAEb,KAAM,GAAO,KAAK,MAAM,GACxB,GAAI,MAAO,IAAS,UAAY,IAAS,MAAQ,MAAM,QAAQ,GAC7D,MAAO,IAAI,KAGb,KAAM,GAAU,OAAO,QAAQ,GAAM,OAAO,CAAC,CAAC,EAAM,KAClD,GAAiB,GACV,IAAU,4BAGnB,MAAO,IAAI,KAAI,QACf,CACA,MAAO,IAAI,S,0FC7EV,WAAwB,EAG7B,C,MACA,GAAI,GAAS,EAAQ,oBAAsB,IAAO,MAElD,KAAM,GAAa,CAAC,KAAQ,aAAR,OAAsB,IAAI,OAAO,UACrD,SAAW,KAAK,GACd,EAAS,EAAE,MAAM,GAGnB,MAAO,CACL,MAAO,GCnBJ,OAA2C,OACzC,QAAO,EASd,C,QACE,KAAM,GAAU,EAAa,GACvB,EAAa,MAAQ,SAAR,cAAgB,OAAQ,gBACrC,EAAc,MAAQ,SAAR,cAAgB,QAAU,IAAS,UAAU,KAEjE,MAAO,IAAI,GACT,EAAQ,YACR,EACA,EACA,GAIJ,YACI,EACA,EACA,EACA,EACF,CAAE,KAAK,YAAc,EAAY,KAAK,SAAW,EAAS,KAAK,WAAa,EAAW,KAAK,YAAc,EAE5G,MAAM,EAAM,CACV,MAAO,OAAO,EAAO,IAAS,CAG5B,KAAM,GAAU,GAAI,SAAQ,EAAO,GAC7B,CAAE,SAAU,KAAM,MAAK,YAAY,iBACzC,MACE,GAAQ,QAAQ,IAAI,KAAK,aACzB,MAAO,IAAU,UACjB,CAAC,GACD,CAAC,KAAK,SAAS,EAAQ,KAEhB,EAAK,EAAO,GAGrB,GAAQ,QAAQ,IAAI,KAAK,WAAY,KAAK,YAAY,IAC/C,EAAK,MAKlB,WAAsB,EAIpB,CACA,MAAI,GAAQ,SACH,EAAQ,SACN,EAAQ,mBACV,EAAmB,EAAQ,oBACzB,EAAQ,OACV,EAAmB,CAAC,EAAQ,OAAO,UAAU,qBAE/C,IAAM,GAGf,WAA4B,EAAU,CACpC,KAAM,GAAkB,EAAS,IAAI,GAAU,EAAO,QAAQ,MAAO,KACrE,MAAO,IACL,EAAgB,KACd,GAAU,IAAQ,GAAU,EAAI,WAAW,GAAG,OC3EpD,WAAc,EAAM,EAAO,CACzB,MAAI,CAAC,GAAS,IAAU,IACf,EAGF,GAAG,EAAK,QAAQ,MAAO,OAAO,EAAM,QAAQ,MAAO,MAOrD,OAA6C,CAClD,YAAc,EAAc,CAAE,KAAK,aAAe,EAElD,MAAM,EAAM,CACV,MAAO,OAAO,EAAO,IAAS,CAC5B,KAAM,GAAU,GAAI,SAAQ,EAAO,GAC7B,EAAS,YAEf,GAAI,CAAC,EAAQ,IAAI,WAAW,GAC1B,MAAO,GAAK,EAAO,GAKrB,KAAM,CAAE,WAAU,WAAU,SAAQ,OAAM,WAAU,YAAa,GAAI,KACnE,UAAU,EAAQ,IAAI,UAAU,EAAO,WAGzC,GAAI,GAAO,KAAM,MAAK,aAAa,WAAW,GAC9C,GAAI,GAAY,EAAU,CACxB,KAAM,GAAU,GAAI,KAAI,GAClB,GAAY,GAAG,IAAW,EAAW,IAAI,IAAa,MAC5D,EAAO,GAAG,EAAQ,aAAa,KAAY,EAAQ,OAAO,EAAQ,WAGpE,KAAM,GAAS,GAAG,EAAK,EAAM,KAAY,IAAS,IAClD,MAAO,GAAK,EAAQ,KC9BnB,OAAuB,OAerB,uBAAsB,EAE7B,CACE,MAAO,IAAI,GAAsC,EAAQ,oBAkBpD,oBAAmB,EAS1B,CACE,MAAO,GAAoC,OAAO,GAGnD,aAAc,K,kFC7CV,WACL,EACA,EACA,CACA,SAAW,KAAS,GAClB,GAAI,CAAC,EAAS,IAAI,GAChB,MAAO,GAGX,MAAO,GAGF,WACL,KACG,EACH,CACA,KAAM,GAAS,GAAI,KAAI,GAEvB,SAAW,KAAc,GACvB,SAAW,KAAS,GAClB,EAAO,IAAI,GAIf,MAAO,GAQF,OAA2B,CAA3B,a,CACJ,kBAAW,IACX,iBAAU,GAAI,KACb,KAAK,sBAGP,QAAQ,EAAQ,CACd,MAAO,IAAI,SAAQ,CAAC,EAAS,IAAW,CACtC,KAAK,SAAS,KAAK,CAAE,SAAQ,UAAS,WAEtC,KAAK,QAAQ,KAAK,KAAK,uBAI3B,QAAQ,EAAQ,EAAQ,CACtB,KAAK,SAAW,KAAK,SAAS,OAAO,GAC/B,EAAU,EAAQ,EAAQ,QAC5B,GAAQ,QAAQ,GACT,IAEF,IAGT,KAAK,QAAQ,KAAK,KAAK,qBAGzB,OAAO,EAAO,CACZ,KAAK,SAAS,QAAQ,GAAW,EAAQ,OAAO,IAChD,KAAK,SAAW,GAEhB,KAAK,QAAQ,KAAK,KAAK,qBAGzB,SAAU,CACR,MAAO,MAAK,QAGb,mBAAoB,CACnB,KAAM,GACJ,KAAK,SAAS,SAAW,EACrB,OACA,KAAK,SACF,MAAM,GACN,OACC,CAAC,EAAK,IAAY,EAAW,EAAK,EAAQ,QAC1C,KAAK,SAAS,GAAG,QAG3B,MAAO,CACL,OAAQ,EACR,QAAU,GAAU,CACd,GACF,KAAK,QAAQ,EAAe,IAGhC,OAAS,GAAW,CACd,GACF,KAAK,OAAO,MCrFf,OAA2B,CAA3B,a,CACH,iBAAU,GAAI,KAAgB,KAC/B,yBAAkB,IAClB,sBAAe,GAEhB,oBAAoB,EAAS,CACtB,EAAQ,SAAS,IAEpB,QAAQ,KACN,0HAGJ,KAAM,GAAU,GAAI,GAEd,EAAQ,KAAK,aACnB,YAAK,eAEL,EAAQ,UAAU,UAAU,CAC1B,KAAM,GAAgB,CACpB,KAAM,GAAc,KAAK,gBAAgB,QACnC,EAAU,KAAK,gBAAgB,EAAc,GAC9C,EAGH,EAAY,GAAS,EAFrB,MAAO,GAAY,GAIrB,KAAK,gBAAkB,EAEvB,KAAK,QAAQ,KAAK,EAAY,OAAO,aAIlC,GACE,EAAQ,QAAQ,GAK1B,gBACC,EACA,EACA,CACA,KAAM,CAAE,UAAW,EACnB,GAAI,EAAC,EAIL,MAAO,CACL,SAAU,EAAQ,SAClB,QAAS,SAAY,CACnB,KAAM,GAAS,KAAM,GAAQ,cAAc,GAC3C,EAAQ,QAAQ,IAElB,OAAQ,IAAM,CACZ,KAAM,GAAQ,GAAI,OAAM,kCACxB,EAAM,KAAO,gBACb,EAAQ,OAAO,KAKrB,cAAe,CACb,MAAO,MAAK,W,2FCzEhB,KAAM,GAAU,GAAI,KAOb,OAAkB,CACvB,YACI,EACA,EACF,CAoED,qBAAc,GAAI,MAIjB,oBAAa,GAAI,MAEpB,GACG,MAAK,YAAY,IAAI,GACd,IAAM,CACX,KAAK,YAAY,OAAO,OA7ExB,KAAK,UAAY,EAAU,KAAK,SAAW,QAExC,QAAO,EAGd,C,MACE,MAAO,IAAI,GAAW,KAAQ,YAAR,OAAqB,GAAI,EAAQ,UAGzD,IAAI,EAAK,CACP,MAAO,MAAK,SAAS,GAAK,MAG5B,SAAS,EAAK,CACZ,GAAI,GACA,EAAW,SACf,GAAI,CACF,KAAM,GAAO,aAAa,QAAQ,KAAK,WAAW,IAC9C,GACF,GAAQ,KAAK,MAAM,EAAM,CAAC,EAAM,IAC1B,OAAO,IAAQ,UAAY,IAAQ,MACrC,OAAO,OAAO,GAET,IAET,EAAW,gBAEb,CACA,KAAK,SAAS,KACZ,GAAI,OAAM,oDAAoD,MAGlE,MAAO,CAAE,MAAK,QAAO,SAAU,EAAO,YAGxC,UAAU,EAAM,CACd,KAAM,GAAa,GAAG,KAAK,aAAa,IACxC,MAAK,GAAQ,IAAI,IACf,EAAQ,IAAI,EAAY,GAAI,GAAW,EAAY,KAAK,WAEnD,EAAQ,IAAI,QAGf,KAAI,EAAK,EAAM,CACnB,aAAa,QAAQ,KAAK,WAAW,GAAM,KAAK,UAAU,IAC1D,KAAK,cAAc,QAGf,QAAO,EAAK,CAChB,aAAa,WAAW,KAAK,WAAW,IACxC,KAAK,cAAc,GAGrB,SAAS,EAAK,CACZ,MAAO,MAAK,WAAW,OAAO,CAAC,CAAE,IAAK,KAAiB,IAAe,GAGvE,WAAW,EAAK,CACf,MAAO,GAAG,KAAK,aAAa,mBAAmB,KAGhD,cAAc,EAAK,CAClB,KAAM,GAAW,KAAK,SAAS,GAC/B,SAAW,KAAgB,MAAK,YAC9B,EAAa,KAAK,M,kFC/ExB,KAAM,GAAmB,CACvB,GAAI,YACJ,MAAO,YACP,KAAM,IAAM,MAQC,OAAoB,OAC1B,QAAO,EAAS,CACrB,KAAM,CACJ,eACA,cAAc,cACd,WAAW,EACX,mBACE,EAEJ,MAAO,YAAc,CACnB,eACA,kBACA,WACA,mB,kFCxBN,KAAM,GAAmB,CACvB,GAAI,QACJ,MAAO,QACP,KAAM,IAAM,MAyBC,OAAgB,OACtB,QAAO,EAAS,CACrB,KAAM,CACJ,eACA,cAAc,cACd,WAAW,EACX,kBACA,gBAAgB,CAAC,SAAU,QAAS,YAClC,EAEJ,MAAO,YAAc,CACnB,eACA,kBACA,WACA,cACA,qB,iFC5BN,KAAM,GAAmB,CACvB,GAAI,YACJ,MAAO,YACP,KAAM,IAAM,MAQC,OAAoB,OAC1B,QAAO,EAAS,CACrB,KAAM,CACJ,eACA,cAAc,cACd,WAAW,EACX,kBACA,gBAAgB,CAAC,SACf,EAEJ,MAAO,YAAc,CACnB,eACA,kBACA,WACA,cACA,qB,2uDCzCN,KAAM,GAAmB,CACvB,GAAI,SACJ,MAAO,SACP,KAAM,IAAM,MAQC,OAAiB,OACvB,QAAO,EAAS,CACrB,KAAM,CACJ,eACA,cAAc,cACd,WAAW,EACX,kBACA,gBAAgB,CAAC,cACf,EAEJ,MAAO,YAAc,CACnB,eACA,kBACA,WACA,cACA,wBAOG,gBAAe,EAAO,CAC3B,GAAI,CAAC,EACH,MAAO,IAAI,KAGb,KAAM,GAAY,MAAM,QAAQ,GAC5B,EACA,EAAM,MAAM,UAAU,OAAO,SAEjC,MAAO,IAAI,KAAI,M,iFC1CnB,KAAM,GAAmB,CACvB,GAAI,SACJ,MAAO,SACP,KAAM,IAAM,MAQC,OAAiB,OACvB,QAAO,EAAS,CACrB,KAAM,CACJ,eACA,cAAc,cACd,WAAW,EACX,kBACA,gBAAgB,CAAC,cACf,EAEJ,MAAO,YAAc,CACnB,eACA,kBACA,WACA,cACA,qB,kFC1BN,KAAM,GAAmB,CACvB,GAAI,SACJ,MAAO,SACP,KAAM,IAAM,MAGR,EAAe,mCAON,OAAiB,OACvB,QAAO,EAAS,CACrB,KAAM,CACJ,eACA,kBACA,cAAc,cACd,WAAW,EACX,gBAAgB,CACd,SACA,GAAG,kBACH,GAAG,sBAEH,EAEJ,MAAO,YAAc,CACnB,eACA,kBACA,WACA,cACA,gBACA,eAAe,EAAQ,CACrB,MAAO,GAAO,IAAI,GACZ,IAAU,SACL,EAGL,IAAU,WAAa,IAAU,QAC5B,GAAG,aAAwB,IAGhC,EAAM,WAAW,GACZ,EAGF,GAAG,IAAe,W,slIC/CnC,KAAM,GAAmB,CACvB,GAAI,YACJ,MAAO,YACP,KAAM,IAAM,MAQC,OAAoB,OAC1B,QAAO,EAAS,CACrB,KAAM,CACJ,cAAc,cACd,WAAW,EACX,kBACA,eACA,gBAAgB,CACd,SACA,iBACA,UACA,QACA,cAEA,EAEJ,MAAO,YAAc,CACnB,eACA,kBACA,WACA,cACA,qB,kFCCN,WAA2B,EAAQ,CACjC,MAAO,CAAC,GAAG,GAAQ,KAAK,KAQnB,OAEP,CAQE,YAAY,EAAS,CAPnB,uBACA,sBACA,mBACA,yBACA,wBACA,2BAGA,KAAM,CACJ,eACA,cACA,WACA,aAAa,EACb,kBACA,mBAAmB,GAAM,GACvB,EAEJ,KAAK,cAAgB,EAAgB,oBAAoB,CACvD,WACA,cAAe,GAAU,KAAK,UAAU,KAG1C,KAAK,aAAe,EACpB,KAAK,YAAc,EACnB,KAAK,SAAW,EAChB,KAAK,eAAiB,EACtB,KAAK,iBAAmB,OAGpB,eAAc,EAAS,CAC3B,MAAI,GAAQ,aACH,KAAK,UAAU,EAAQ,QAEzB,KAAK,cAAc,EAAQ,aAG9B,iBAAiB,CACrB,KAAM,GAAM,KAAM,OAChB,KAAM,MAAK,SAAS,WAAY,CAAE,SAAU,KAC5C,CACE,QAAS,CACP,mBAAoB,kBAEtB,YAAa,YAEf,MAAM,GAAS,CACf,KAAM,IAAI,OAAM,gCAAgC,OAGlD,GAAI,CAAC,EAAI,GAAI,CACX,KAAM,GAAQ,GAAI,OAChB,gCAAgC,EAAI,cAEtC,QAAM,OAAS,EAAI,OACb,EAGR,KAAM,GAAW,KAAM,GAAI,OAE3B,GAAI,EAAS,MAAO,CAClB,KAAM,GAAQ,GAAI,OAAM,EAAS,MAAM,SACvC,KAAI,GAAS,MAAM,MACjB,GAAM,KAAO,EAAS,MAAM,MAExB,EAER,MAAO,MAAM,MAAK,iBAAiB,QAG/B,gBAAgB,CACpB,KAAM,GAAM,KAAM,OAAM,KAAM,MAAK,SAAS,WAAY,CACtD,OAAQ,OACR,QAAS,CACP,mBAAoB,kBAEtB,YAAa,YACZ,MAAM,GAAS,CAChB,KAAM,IAAI,OAAM,0BAA0B,OAG5C,GAAI,CAAC,EAAI,GAAI,CACX,KAAM,GAAQ,GAAI,OAAM,0BAA0B,EAAI,cACtD,QAAM,OAAS,EAAI,OACb,QAIH,WAAU,EAAQ,CACvB,KAAM,GAAQ,KAAK,eAAe,GAC5B,EAAW,KAAM,MAAK,SAAS,SAAU,CAC7C,QACA,OAAQ,SAAS,SAGb,EAAU,KAAM,QAAe,CACnC,IAAK,EACL,KAAM,GAAG,KAAK,SAAS,cACvB,OAAQ,GAAI,KAAI,GAAU,OAC1B,MAAO,IACP,OAAQ,MAGV,MAAO,MAAM,MAAK,iBAAiB,QAG9B,UACL,EACA,EACA,CACA,KAAM,GAAU,KAAM,MAAK,aAAa,WAAW,QAC7C,EAAc,KAAK,iBAAiB,IACrC,EACH,IAAK,KAAK,cAGZ,MAAO,GAAG,KAAW,KAAK,SAAS,KAAK,IAAO,IAGhD,iBAAiB,EAElB,CACE,GAAI,CAAC,EACH,MAAO,GAGT,KAAM,GAAc,OAAO,QAAQ,GAChC,IAAI,CAAC,CAAC,EAAK,KAAW,CACrB,GAAI,MAAO,IAAU,SACnB,MAAO,GAAG,mBAAmB,MAAQ,mBAAmB,KACnD,GAAI,EACT,MAAO,oBAAmB,KAI7B,OAAO,SACP,KAAK,KAER,MAAK,GAGE,IAAI,IAFF,I,eCtJb,KAAM,GAAmB,CACvB,GAAI,SACJ,MAAO,yBACP,KAAM,IAAM,MAQC,OAOf,CAmDG,YAAY,EAGb,CANE,yBACA,yBAMA,KAAK,eAAiB,EAAQ,eAC9B,KAAK,eAAiB,EAAQ,qBAvDzB,QAAO,EAAS,CACrB,KAAM,CACJ,eACA,cAAc,cACd,WAAW,EACX,kBACA,gBAAgB,GAChB,iBAAiB,GAAK,GACpB,EAEE,EAAY,GAAI,GAAqB,CACzC,eACA,cACA,WACA,gBAAiB,EACjB,iBAAiB,EAAK,CACpB,MAAO,IACF,EACH,aAAc,CACZ,QAAS,EAAI,aAAa,QAC1B,YAAa,EAAI,aAAa,YAC9B,OAAQ,EAAO,gBACb,EACA,EAAI,aAAa,OAEnB,UAAW,GAAI,MACb,KAAK,MAAQ,EAAI,aAAa,iBAAmB,UAOrD,EAAiB,GAAI,MAA6B,CACtD,YACA,cAAe,GAAI,KAAI,GACvB,cAAgB,GAAY,EAAQ,aAAa,OACjD,qBAAuB,GAGd,GADI,aAAa,UAAU,UAAY,KAAK,OAAS,IACtC,GAAK,IAI/B,MAAO,IAAI,GAAO,CAAE,iBAAgB,wBAchC,SAAS,CACb,KAAM,MAAK,sBAGP,UAAU,CACd,KAAM,MAAK,eAAe,gBAG5B,eAAgB,CACd,MAAO,MAAK,eAAe,qBAGvB,gBACJ,EACA,EACA,C,MACA,KAAM,GAAmB,EAAO,gBAAgB,KAAK,eAAgB,GAC/D,EAAU,KAAM,MAAK,eAAe,WAAW,IAChD,EACH,OAAQ,IAEV,MAAO,oBAAS,aAAa,cAAtB,OAAqC,QAGxC,YAAW,EAAU,GAAI,C,MAC7B,KAAM,GAAU,KAAM,MAAK,eAAe,WAAW,GACrD,MAAO,oBAAS,aAAa,UAAtB,OAAiC,QAGpC,sBACJ,EAAU,GACV,CACA,KAAM,GAAU,KAAM,MAAK,eAAe,WAAW,GACrD,MAAO,kBAAS,uBAGZ,YAAW,EAAU,GAAI,CAC7B,KAAM,GAAU,KAAM,MAAK,eAAe,WAAW,GACrD,MAAO,kBAAS,cAGV,iBACN,EACA,EACA,CACA,GAAI,CAAC,EACH,MAAO,IAAI,KAGb,KAAM,GAAY,MAAM,QAAQ,GAC5B,EACA,EAAO,MAAM,UAAU,OAAO,SAElC,MAAO,IAAI,KAAI,EAAe,O,qqECnKlC,KAAM,GAAmB,CACvB,GAAI,OACJ,MAAO,OACP,KAAM,IAAM,MAGR,EAAmB,GAAI,KAAI,CAC/B,SACA,UACA,QACA,QACA,UACA,SACA,mBAGI,EAAoB,QAOX,OAAe,OACrB,QAAO,EAAS,CACrB,KAAM,CACJ,eACA,cAAc,cACd,WAAW,EACX,kBACA,gBAAgB,CAAC,SAAU,QAAS,UAAW,mBAC7C,EAEJ,MAAO,YAAc,CACnB,eACA,kBACA,WACA,cACA,gBACA,eAAe,EAAQ,CACrB,MAAO,GAAO,IAAI,GACZ,EAAiB,IAAI,IAIrB,EAAM,WAAW,GACZ,EAGF,GAAG,IAAoB,W,kFClCxC,KAAM,GAAmB,CACvB,GAAI,WACJ,MAAO,WACP,KAAM,IAAM,MAGR,EAAc,GAAI,KAAI,CAC1B,SACA,UACA,QACA,QACA,UACA,SACA,mBAGI,EAAe,YAON,OAAmB,OACzB,QACL,EACA,CACA,KAAM,CACJ,eACA,cAAc,cACd,WAAW,EACX,mBACE,EAEJ,MAAO,YAAc,CACnB,eACA,kBACA,WACA,cACA,cAAe,CAAC,SAAU,QAAS,UAAW,kBAC9C,eAAe,EAAQ,CACrB,MAAO,GAAO,IAAI,GACZ,EAAY,IAAI,IAIhB,EAAM,WAAW,GACZ,EAGF,GAAG,IAAe,W,kFC9D5B,OAA0B,CAK/B,YAAY,EAAS,CAJnB,uBACA,sBACA,mBAGA,KAAM,CAAE,eAAc,cAAa,YAAa,EAEhD,KAAK,aAAe,EACpB,KAAK,YAAc,EACnB,KAAK,SAAW,OAGZ,gBAAgB,CACpB,KAAM,GAAW,KAAM,MAAK,SAAS,UAC/B,EAAU,KAAM,QAAe,CACnC,IAAK,EACL,KAAM,GAAG,KAAK,SAAS,cACvB,OAAQ,GAAI,KAAI,GAAU,OAC1B,MAAO,IACP,OAAQ,MAGV,MAAO,IACF,EACH,GAAI,EAAQ,QAAQ,YAIlB,iBAAiB,OAEjB,gBAAgB,CACpB,KAAM,GAAM,KAAM,OAAM,KAAM,MAAK,SAAS,WAAY,CACtD,OAAQ,OACR,QAAS,CACP,mBAAoB,kBAEtB,YAAa,YACZ,MAAM,GAAS,CAChB,KAAM,IAAI,OAAM,0BAA0B,OAG5C,GAAI,CAAC,EAAI,GAAI,CACX,KAAM,GAAQ,GAAI,OAAM,0BAA0B,EAAI,cACtD,QAAM,OAAS,EAAI,OACb,QAIH,UAAS,EAAM,CAEpB,MAAO,GADS,KAAM,MAAK,aAAa,WAAW,WAC9B,KAAK,SAAS,KAAK,SAAY,KAAK,e,0BCjCtD,KAAM,GAAoB,WAAS,CACxC,QAAS,WAAS,CAChB,MAAO,aAAW,WAClB,YAAa,aAAW,WACxB,QAAS,aAAW,aAEtB,kBAAmB,WAAS,CAC1B,GAAI,aACJ,MAAO,aACP,SAAU,WAAS,CACjB,KAAM,YAAU,QAChB,cAAe,aACf,oBAAqB,UAAQ,oBCb7B,EAAmB,CACvB,GAAI,OACJ,MAAO,OACP,KAAM,IAAM,MAQC,OAEf,OACS,QAAO,EAAS,CACrB,KAAM,CACJ,eACA,cAAc,cACd,WAAW,GACT,EAEE,EAAY,GAAI,GAAoB,CACxC,eACA,cACA,aAGI,EAAiB,GAAI,MAAyB,CAClD,cAGI,EAAmB,GAAI,MAAiB,CAC5C,QAAS,EACT,WAAY,GAAG,EAAS,YACxB,OAAQ,IAGV,MAAO,IAAI,GAAS,GAGtB,eAAgB,CACd,MAAO,MAAK,eAAe,gBAG5B,YACG,EACF,CAAE,KAAK,eAAiB,OAEpB,SAAS,CACb,KAAM,MAAK,qBAAqB,SAE5B,UAAU,CACd,KAAM,MAAK,eAAe,qBAGtB,sBACJ,EAAU,GACV,CACA,KAAM,GAAU,KAAM,MAAK,eAAe,WAAW,GACrD,MAAO,kBAAS,uBAGZ,YAAW,EAAU,GAAI,CAC7B,KAAM,GAAU,KAAM,MAAK,eAAe,WAAW,GACrD,MAAO,kBAAS,W,g0NCvEpB,GAAI,GAAgB,UAAU,EAAe,CAC3C,EAAc,EAAc,QAAa,IAAM,UAC/C,KAAM,GAAM,GAAI,EAAc,EAAc,IAAS,GAAO,MAC5D,EAAc,EAAc,OAAY,KAAO,WAC9C,GAAkB,GAAgB,KAgB9B,OAA0B,CAA1B,a,CACH,mBAAY,GAAI,MASlB,SACE,EACA,EACA,CACA,KAAM,GAAW,EAAc,GACzB,EAAW,KAAK,UAAU,IAAI,EAAQ,IAAI,IAChD,MAAI,IAAY,EAAS,UAAY,EAC5B,GAGT,MAAK,UAAU,IAAI,EAAQ,IAAI,GAAI,CAAE,WAAU,YACxC,IAGT,IACE,EACA,CACA,KAAM,GAAQ,KAAK,UAAU,IAAI,EAAI,IACrC,GAAI,EAAC,EAGL,MAAO,GAAM,QAGf,YAAa,CACX,KAAM,GAAO,GAAI,KACjB,SAAW,CAAE,YAAa,MAAK,UAAU,SACvC,EAAK,IAAI,EAAQ,KAEnB,MAAO,M,qGCtEJ,OAAqB,CAG1B,eAAe,EAAS,CAFtB,kBAGA,KAAK,QAAU,EAGjB,IAAI,EAAQ,CACV,SAAW,KAAU,MAAK,QAAS,CACjC,KAAM,GAAM,EAAO,IAAI,GACvB,GAAI,EACF,MAAO,K,eCCf,KAAM,GAAa,SAAuB,eAQ7B,EAAe,GAAU,C,MACpC,KAAM,CAAE,OAAM,YAAa,EACrB,EAAe,G,GAAA,cAAW,KAAX,cAAwB,UAAU,GACjD,EAAS,EAAe,GAAI,GAAc,EAAM,GAAgB,EAEtE,MACE,iBAAoB,EAAW,SAAU,CACvC,MAAO,SAAwB,CAAE,EAAG,IACpC,SAAU,KAKhB,EAAY,UAAY,CACtB,KAAM,UAAgB,CAAE,IAAK,sBAA6B,WAC1D,SAAU,W,mEC3BL,OAAmB,CAmCxB,YAAc,EAAW,CAFvB,cAAO,GAAI,MAEc,KAAK,UAAY,QA9BrC,mBACL,EACA,EACA,CACA,SAAW,KAAO,GAAM,CACtB,KAAM,GAAO,CAAC,GACR,EAAU,GAAI,KAEpB,KAAO,EAAK,QAAQ,CAClB,KAAM,GAAS,EAAK,QACd,EAAU,EAAU,IAAI,GAC9B,GAAI,EAAC,EAIL,SAAW,KAAO,QAAO,OAAO,EAAQ,MAAO,CAC7C,GAAI,EAAI,KAAO,EAAI,GACjB,KAAM,IAAI,OAAM,0CAA0C,KAEvD,EAAQ,IAAI,IACf,GAAQ,IAAI,GACZ,EAAK,KAAK,OAWpB,IAAI,EAAK,CACP,MAAO,MAAK,KAAK,GAGlB,KAAK,EAAK,EAAU,GAAI,CACvB,KAAM,GAAO,KAAK,KAAK,IAAI,EAAI,IAC/B,GAAI,EACF,MAAO,GAGT,KAAM,GAAU,KAAK,UAAU,IAAI,GACnC,GAAI,CAAC,EACH,OAGF,GAAI,EAAQ,SAAS,EAAQ,KAC3B,KAAM,IAAI,OAAM,0CAA0C,EAAQ,OAGpE,KAAM,GAAO,KAAK,SAAS,EAAK,EAAQ,KAAM,CAAC,GAAG,EAAS,EAAQ,MAC7D,EAAM,EAAQ,QAAQ,GAC5B,YAAK,KAAK,IAAI,EAAI,GAAI,GACf,EAGR,SACC,EACA,EACA,EACA,CACA,KAAM,GAAQ,GAEd,SAAW,KAAO,GAChB,GAAI,EAAK,eAAe,GAAM,CAC5B,KAAM,GAAM,EAAK,GAEX,EAAM,KAAK,KAAK,EAAK,GAC3B,GAAI,CAAC,EACH,KAAM,IAAI,OACR,2CAA2C,kBAAoB,KAGnE,EAAM,GAAO,EAIjB,MAAO,M,ikFC/EJ,WAA6B,EAIlC,CACA,KAAM,GAEL,GAGD,SAAW,KAAQ,GAAQ,WACrB,EAAQ,WAAW,eAAe,IACpC,GAAW,GAAQ,EAAQ,WAAW,MAW1C,KAAM,GAAQ,CACZ,CACE,KAAM,mBAAiB,EAAQ,MAC/B,OAAQ,OACR,SAAU,KAId,KAAO,EAAM,SAAW,GAAG,CACzB,KAAM,CAAE,OAAM,SAAQ,aAAa,EAAM,QAKzC,mBAAiB,EAAM,IAAW,CAChC,GAAI,CAAC,qBAAe,IAClB,OAGF,KAAM,IAAe,GAIrB,SAAW,MAAQ,GACjB,GAAI,EAAW,eAAe,IAAO,CACnC,KAAM,IAAY,EAAW,IAE7B,GAAa,IAAQ,GAAU,MAC7B,GAAU,YACV,GACA,EACA,GAAS,KAMf,SAAW,MAAc,GAAQ,YAAa,CAC5C,KAAM,IAAW,GAAW,IACxB,IACF,EAAM,KAAK,CACT,KAAM,GACN,OAAQ,GACR,SAAU,QAOpB,MAAO,QAAO,YACZ,OAAO,QAAQ,GAAY,IAAI,CAAC,CAAC,EAAM,KAAO,CAAC,EAAM,EAAE,eAIpD,WACL,EACA,EACA,CACA,MAAO,IAAO,EAAE,YAAa,IAAsB,UAG9C,WAAyB,EAAS,C,MACvC,MAAO,KAAQ,QAAR,cAAe,SAGjB,WAAgC,EAAS,C,UAC9C,GAAI,MAAQ,QAAR,cAAe,OAAQ,MAAQ,QAAR,cAAe,SACxC,MAAO,KAAQ,QAAR,cAAe,QC1GnB,KAAM,GAAkB,EAC7B,IAAM,GAAI,KACV,CAAC,EAAK,IAAS,CACb,KAAM,GAAS,uBACb,EACA,eAEE,GACF,EAAI,IAAI,K,eCDd,WAAuB,EAAM,C,MAC3B,KAAM,GAAU,KAAK,QAAL,cAAY,QAE5B,GAAI,GAAW,uBAAiB,EAAM,mBACtC,MAAI,CAAC,GAAY,qBAAe,IAC9B,GAAW,uBAAiB,EAAS,oBAGhC,EAGF,KAAM,GAAqB,EAChC,IAAM,GAAI,KACV,CAAC,EAAK,EAAM,EAAQ,IAAY,C,UAG9B,GAAI,GAAiB,EAErB,GAAI,kBAAQ,MAAM,WAAY,EAC5B,MAAO,GAIT,GAAI,uBAAiB,EAAM,0BAA2B,CACpD,KAAM,IAAO,MAAK,QAAL,eAAY,KACzB,GAAI,CAAC,GACH,KAAM,IAAI,OAAM,yCAElB,EAAiB,GAGnB,KAAM,IAAW,EAAc,GAC/B,GAAI,GAAU,CACZ,GAAI,IAAO,MAAK,QAAL,eAAY,KAUvB,GAPI,GACF,CAAI,GACF,EAAiB,OAEjB,GAAO,GAGP,CAAC,GACH,KAAM,IAAI,OAAM,+CAElB,EAAI,IAAI,GAAU,IAEpB,MAAO,KAIE,EAAuB,EAClC,IAAM,GAAI,KACV,CAAC,EAAK,EAAM,EAAQ,IAAmB,C,OACrC,GAAI,kBAAQ,MAAM,WAAY,EAC5B,MAAO,GAGT,GAAI,GAAa,EAEjB,KAAM,IAAW,EAAc,GAqB/B,MApBI,KAGF,CAAI,GAAkB,UAAY,GAChC,GAAI,IAAI,GAAU,EAAe,QAI7B,OAAK,QAAL,eAAY,MACd,EAAa,GAEb,EAAa,GAGf,GAAI,IAAI,GAAU,GAClB,EAAa,KAKb,uBAAiB,EAAM,0BAClB,CAAE,OAAQ,GAGZ,IAQE,EAAkB,CAC7B,cAAe,GACf,KAAM,KACN,QAAS,YACT,UAAW,GAAI,MAGJ,EAAuB,EAClC,IAAM,QACN,CAAC,EAAK,EAAM,EAAQ,IAAc,C,aAChC,KAAM,GAAiB,qBAAW,WAAX,QAAuB,EAC9C,GAAI,kBAAQ,MAAM,WAAY,EAC5B,MAAO,GAGT,KAAM,IAAO,MAAK,QAAL,eAAY,KACnB,GAAgB,QAAQ,MAAK,QAAL,eAAY,eAEpC,GAAW,EAAc,GAC/B,GAAI,GAAU,CACZ,GAAI,GAAM,CACR,KAAM,IAAY,CAChB,iBACA,QACA,QAAS,UACT,UAAW,GAAI,KAAI,CAAC,KACpB,SAAU,CAAC,GACX,OAAQ,uBACN,EAAK,MAAM,QACX,gBAGJ,SAAe,KAAK,IACb,GAGT,WAAW,UAAU,IAAI,IAO3B,GAJmB,uBACjB,EACA,0BAEc,CACd,GAAI,CAAC,GACH,KAAM,IAAI,OAAM,yCAElB,KAAM,IAAY,CAChB,iBACA,QACA,QAAS,WACT,UAAW,GAAI,KACf,SAAU,CAAC,GACX,OAAQ,iBAAW,QAErB,SAAe,KAAK,IACb,GAGT,MAAO,KAIE,EAAuB,EAClC,IAAM,GAAI,KACV,CAAC,EAAK,IAAS,CACb,GAAI,EAAK,OAAS,IAAgB,CAChC,KAAM,GAAQ,EAAK,MACnB,EAAI,IAAI,QAAU,GAAQ,EAAM,KAAO,EAAM,Y,eChK5C,KAAM,GAAe,SAC1B,iBACA,IAAM,OAAO,mBA6BR,WACL,EAIA,CACA,MAAO,GAAS,KAAkB,WAG7B,WACL,EAIA,CACA,MAAO,GAAS,KAAkB,MAG7B,YAIL,EAIA,CACA,MAAO,GAAS,KAAkB,WCpDpC,eAAsB,EAAO,CAC3B,KAAM,GAAa,EAAM,KAAK,KAAK,QAAQ,SAAU,KACrD,MAAI,KAAe,KAAO,EAAW,SAAS,KACrC,EAAW,MAAM,EAAG,IAEtB,EAST,YACE,EACA,EACA,EACA,CAGA,GAAI,GACA,EAAe,GACnB,GAAI,EAAW,GACb,EAAY,UACH,EAAc,GACvB,EAAY,EAAY,OACxB,EAAe,EAAY,aAClB,GAAmB,GAAc,CAC1C,KAAM,IAAgB,EAAc,IAAI,GACxC,GAAI,CAAC,GACH,MAAO,CAAC,OAAW,IAErB,GAAI,EAAW,IACb,EAAY,WACH,EAAc,IACvB,EAAY,GAAc,OAC1B,EAAe,GAAc,SAE7B,MAAM,IAAI,OACR,iDAAiD,UAGhD,MAAI,GAAY,GACf,GAAI,OACR,sCAAsC,EAAY,MAG9C,GAAI,OAAM,6CAA6C,KAI/D,GAAI,CAAC,EACH,MAAO,CAAC,OAAW,IAIrB,KAAM,IAAe,EAAW,IAAI,GACpC,GAAI,CAAC,GACH,MAAO,CAAC,OAAW,IAIrB,KAAM,IAAa,GAAU,GAAc,GAC3C,MAAO,CAAC,EAAW,IAMrB,YACE,EACA,EACA,EACA,EACA,EACA,C,OAOA,KAAM,IAAQ,I,GAAA,MAAY,EAAc,KAA1B,QAA6C,GAKrD,GAAc,QAEpB,GAAI,IAAa,GACjB,OACM,IAAkB,EACtB,IAOA,IAAa,GAAM,UAAU,IAC1B,GAAE,MAAQ,UAAU,IAAI,KAEvB,KAAe,IATnB,GAAkB,EAAa,IAAI,IAgBnC,GAAY,QAAQ,IAMlB,GAAY,SAAW,GACzB,KAAc,GAKhB,KAAM,IAAa,KAAe,GAAK,GAAK,GAAM,IAAY,SAMxD,GAAW,GACf,GAAG,GAAY,MAAM,EAAG,IAAI,IAAI,IAAO,CACrC,KAAM,IAAO,EAAW,IAAI,IAC5B,GAAI,CAAC,GACH,KAAM,IAAI,OAAM,eAAe,MAEjC,GAAI,GAAK,SAAS,KAChB,KAAM,IAAI,OACR,mBAAmB,iBAAyB,2BAGhD,MAAO,OAIX,MAAO,IAAa,GAGf,QAAoB,CACzB,YACI,EACA,EACA,EACA,EAIA,GACF,CAAE,KAAK,WAAa,EAAW,KAAK,aAAe,EAAa,KAAK,aAAe,EAAa,KAAK,cAAgB,EAAc,KAAK,YAAc,GAEzJ,QACE,EAIA,EACA,CAEA,KAAM,CAAC,EAAW,GAAc,GAC9B,EACA,KAAK,WACL,KAAK,eAEP,GAAI,CAAC,EACH,OAKF,GAAI,IACA,MAAO,IAAmB,SAC5B,GAAyB,KAAK,SAAS,GAC9B,EAAe,SACxB,GAAyB,IACpB,EACH,SAAU,KAAK,SAAS,EAAe,WAGzC,GAAyB,EAM3B,KAAM,IACJ,KAAK,YACL,GACE,EACA,GACA,KAAK,WACL,KAAK,aACL,KAAK,cAMT,MAHkB,IAAI,CAAC,MACd,GAAW,SAAa,EAAY,IAK9C,SAAS,EAAY,CACpB,MAAK,IAID,GAAW,WAAW,KAAK,aACtB,EAAW,MAAM,KAAK,YAAY,QAEpC,IC7NX,KAAM,IACJ,SAAuB,mBAWZ,GAAkB,CAAC,CAC9B,aACA,eACA,eACA,gBACA,WAAW,GACX,eACI,CACJ,KAAM,IAAW,GAAI,IACnB,EACA,EACA,EACA,EACA,GAGI,GAAiB,SAAwB,CAAE,EAAG,KACpD,MACE,iBAAoB,GAAe,SAAU,CAAE,MAAO,IAClD,KCxBF,GAAsB,CAC1B,EACA,IACG,C,QACH,GAAI,CAEF,KAAM,GAAU,SAAY,EAAQ,CAAE,aAMhC,GAAc,oBAChB,OAAO,IAAM,C,OAAG,8BAAO,MAAM,YAAb,eAAwB,MAAO,IAChD,QAFiB,cAEV,MAGV,GAAI,CAAC,GACH,MAAO,GAKT,GAAI,IACJ,MAAI,IAAY,UAAU,OAAS,GACjC,IAAW,GAAY,UAAU,SAAS,OAAO,OAG5C,CACL,UAAW,MACX,SAAU,OAAY,SAAZ,cAAoB,UAAW,UACrC,GAAW,CAAE,SAAW,GAAW,IAAO,SAEhD,CACA,MAAO,KAOL,GAAkB,CAAC,CACvB,WACA,SACA,UAKG,CACH,KAAM,GAAY,qBAElB,sBAAU,IAAM,CACd,EAAU,aAAa,WAAY,GAAG,IAAW,IAAS,MACzD,CAAC,EAAW,EAAU,EAAQ,IAE1B,MAOI,GAAe,CAAC,CAAE,UAAW,CACxC,KAAM,CAAE,WAAU,SAAQ,QAAS,WAG7B,CAAE,gBAAiB,cAAQ,IACxB,EAAoB,CACzB,KAAM,EACN,YAAa,CAAC,EAAiB,GAC/B,WAAY,CACV,aAAc,KAGjB,CAAC,IAEJ,MACE,iBAAoB,mBAAkB,CAAE,WAAY,GAAoB,EAAU,IAC9E,gBAAoB,GAAiB,CAAE,SAAU,EAAU,OAAQ,EAAQ,KAAM,MC1FlF,YACL,EACA,EACA,CACA,KAAM,GAAgB,GAAI,KAAI,EAAa,UAC3C,EAAc,OAAO,QAErB,SAAW,KAAS,GAAa,OAAQ,CACvC,GAAI,EAAc,IAAI,GACpB,SAGF,GAAI,GAAkB,EAElB,GAAW,GACf,KAAO,GAAiB,CACtB,KAAM,IAAO,EAAW,IAAI,GAC5B,GAAI,CAAC,GACH,KAAM,IAAI,OAAM,eAAe,KAEjC,GAAW,GAAG,KAAO,KACrB,EAAkB,EAAa,IAAI,GAGrC,KAAM,IAAS,GAAS,MAAM,WAC9B,GAAI,IACF,OAAS,IAAI,EAAG,GAAI,GAAO,OAAQ,KACjC,OAAS,IAAI,GAAI,EAAG,GAAI,GAAO,OAAQ,KACrC,GAAI,GAAO,MAAO,GAAO,IACvB,KAAM,IAAI,OACR,aAAa,GAAO,6BAA4B,QAUvD,YACL,EACA,EACA,CACA,SAAW,KAAU,GACnB,GAAI,EAAC,EAAO,gBAIZ,SAAW,CAAC,EAAM,IAAqB,QAAO,QAC5C,EAAO,gBAEP,GAAI,GAAiB,UAIjB,CAAC,EAAc,IAAI,GACrB,KAAM,IAAI,OACR,mBAAmB,cAAiB,EAAO,4GC5DrD,KAAM,IAAa,SAAuB,eAM7B,GAAqB,CAAC,CACjC,aACA,cACI,CACJ,KAAM,GAAiB,SAAwB,CAAE,EAAG,IAEpD,MAAO,iBAAoB,GAAW,SAAU,CAAE,MAAO,EAAgB,SAAU,KCbrF,YAAiB,EAAO,CACtB,MAAO,IAAI,OACT,+BAA+B,2BAInC,YAAwB,EAAO,CAE7B,QAAQ,KACN,oBAAoB,gDAgBjB,QAAwB,CAK7B,aAAc,CAJb,iBACA,wBACA,uBAAgB,IAAM,IAGrB,KAAK,cAAgB,GAAI,SAAQ,GAAW,CAC1C,KAAK,cAAgB,IAKzB,UAAU,EAAa,CACrB,KAAK,OAAS,EACd,KAAK,cAAc,GAGrB,WAAY,CACV,GAAI,CAAC,KAAK,OACR,KAAM,IAAQ,aAEhB,GAAI,CAAC,KAAK,OAAO,UACf,KAAM,IAAI,OAAM,4CAElB,UAAe,aACR,KAAK,OAAO,YAGrB,YAAa,CACX,GAAI,CAAC,KAAK,OACR,KAAM,IAAQ,cAEhB,GAAI,CAAC,KAAK,OAAO,WACf,KAAM,IAAI,OAAM,6CAElB,UAAe,cACR,KAAK,OAAO,kBAGf,iBAAiB,CACrB,MAAO,MAAK,cAAc,KAAK,GAAU,EAAO,uBAG5C,uBAAuB,CAC3B,KAAM,GAAW,KAAM,MAAK,cAAc,KAAK,GAC7C,EAAO,wBAET,MAAK,GAAS,cAAc,MAAM,gBAEhC,QAAQ,KACN,oEAAoE,EAAS,+FAK1E,OAGH,iBAAiB,CACrB,MAAO,MAAK,cAAc,KAAK,GAAU,EAAO,uBAG5C,aAAa,CACjB,MAAO,MAAK,cAAc,KAAK,GAAU,CACvC,GAAI,CAAC,EAAO,WACV,KAAM,IAAI,OAAM,6CAElB,UAAe,cACR,EAAO,oBAIZ,UAAU,CACd,KAAM,MAAK,cAAc,KAAK,GAAU,EAAO,WAC/C,SAAS,U,gBCnGb,YACE,EACA,EACA,EACA,CACA,GAAI,IAAY,OAAW,CACzB,KAAM,GAAgB,EAAO,KAAK,IAAS,GAAM,KAAO,GACxD,GAAI,EACF,MAAO,GAIX,GAAI,EAAkB,CACpB,KAAM,GAAY,EAAO,KAAK,IAAS,GAAM,UAAY,QACzD,GAAI,EACF,MAAO,GAIX,KAAM,GAAa,EAAO,KAAK,GAAS,EAAM,UAAY,SAC1D,MAAI,IAIG,EAAO,GAGhB,KAAM,IAA2B,IAAM,CACrC,KAAM,GAAa,cACjB,IAAM,OAAO,WAAW,gCACxB,IAEI,CAAC,EAAkB,GAAkB,eAAS,EAAW,SAE/D,sBAAU,IAAM,CACd,KAAM,GAAY,GAAU,CAC1B,EAAe,EAAM,UAEvB,SAAW,YAAY,GAChB,IAAM,CACX,EAAW,eAAe,KAE3B,CAAC,IAEG,GAGF,YAA0B,CAAE,YAAY,CAC7C,KAAM,GAAc,aAAO,kBACrB,EAAU,SACd,EAAY,iBACZ,EAAY,oBAIR,EAAmB,QAAQ,OAAO,YACpC,KACA,GAEE,EAAW,GACf,EACA,EACA,EAAY,sBAEd,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,qBAGlB,MAAO,iBAAoB,EAAS,SAAU,CAAE,SAAU,I,gBCrE5D,QAAyB,CAAzB,a,CACG,cAAO,IAER,IAAI,EAAK,EAAM,CACb,YAAK,KAAK,KAAK,CAAC,EAAI,GAAI,IACjB,EAGT,OAAQ,CAEN,MAAO,IAAI,IAAY,GAAI,KAAI,KAAK,QASjC,QAAmB,OACjB,UAAU,CACf,MAAO,IAAI,UAQN,MAAK,EAAM,CAChB,MAAO,IAAI,IAAY,GAAI,KAAI,EAAK,IAAI,CAAC,CAAC,EAAK,KAAU,CAAC,EAAI,GAAI,YAS7D,MAAK,EAAK,EAAM,CACrB,MAAO,IAAI,IAAY,GAAI,KAAI,CAAC,CAAC,EAAI,GAAI,MAG3C,YAAc,EAAM,CAAE,KAAK,KAAO,EAQlC,KAAK,EAAK,EAAM,CACd,MAAO,IAAI,IAAY,GAAI,KAAI,CAAC,GAAG,KAAK,KAAM,CAAC,EAAI,GAAI,MAGzD,IAAI,EAAK,CACP,MAAO,MAAK,KAAK,IAAI,EAAI,KCtDtB,YAA8B,EAAY,CAC/C,KAAM,GAAS,GAAI,KAEnB,MAAI,IAoBF,EAAW,CAAE,KAnBA,CACX,EACA,IACG,CACH,SAAW,CAAC,GAAK,KAAU,QAAO,QAAQ,GAAe,CACvD,KAAM,IAAgB,EAAe,IACrC,GAAI,CAAC,GACH,KAAM,IAAI,OAAM,OAAO,wCAEzB,GAAI,CAAC,IAAS,CAAC,GAAc,SAC3B,KAAM,IAAI,OACR,kBAAkB,oCAGlB,IACF,EAAO,IAAI,GAAe,QAO3B,EC4CT,YAAqB,EAAW,C,MAC9B,GAAI,CAAE,YAAa,GAAI,KACrB,KAAU,kBAAkB,iBAA5B,OAA8C,IAC9C,oBAEF,SAAW,EAAS,QAAQ,OAAQ,IAC7B,EAGT,YACE,EACA,EACA,EACA,C,OAEA,KAAM,GAAY,QAAQ,GACpB,EAAS,cAAS,GAAiB,KAAM,QAAQ,QAAQ,MAE/D,GAAI,IAEJ,GAAI,GAAa,EAAO,QAAS,CAC/B,KAAM,CAAE,aAAa,EACrB,GAAe,gBAAoB,GAAU,cACpC,EAAO,MAAO,CACvB,KAAM,CAAE,kBAAkB,EAC1B,GAAe,gBAAoB,GAAe,CAAE,KAAM,cAAe,MAAO,EAAO,QAGzF,KAAM,CAAE,iBAAgB,IAAqB,EAG7C,MAAI,IACK,CACL,KACE,gBAAoB,cAAa,CAAE,KAAM,QAAiB,iBAAgB,IACtE,gBAAoB,GAAe,KAAM,MAQ5C,CAAE,IAFY,2BAAyB,MAAO,QAAP,QAAgB,KAKhE,QAAsB,CACpB,YAAc,EAAK,CAAE,KAAK,IAAM,EAEhC,YAAa,CACX,MAAO,MAAK,IAAI,aAGlB,cAAc,EAAK,CACjB,MAAO,MAAK,IAAI,cAAc,GAGhC,eAAgB,CACd,MAAO,MAAK,IAAI,iBAIb,QAAkB,CAgBvB,YAAY,EAAS,CAfpB,oBACA,oBAEC,eACA,gBACA,kBACA,qBACA,iBACA,uBACA,sBACA,qBAEA,0BAAmB,GAAI,KACvB,6B,aAGA,KAAK,KAAO,KAAQ,OAAR,OAAgB,GAC5B,KAAK,MAAQ,EAAQ,MACrB,KAAK,QAAU,GAAI,KAAK,KAAQ,UAAR,OAAqB,IAC7C,KAAK,WAAa,EAAQ,WAC1B,KAAK,OAAS,EAAQ,OACtB,KAAK,aAAe,KAAQ,eAAR,OAAwB,KAC5C,KAAK,YAAc,MAAQ,cAAR,QAAuB,GAC1C,KAAK,WAAa,EAAQ,WAC1B,KAAK,mBAAqB,GAAI,MAGhC,YAAa,CACX,MAAO,OAAM,KAAK,KAAK,SAGzB,cAAc,EAAK,CACjB,MAAO,MAAK,MAAM,GAGpB,eAAgB,CACd,MAAO,MAAK,WAGd,aAAc,CACZ,KAAM,GAAa,GAAI,IAAe,MAGtC,GAAI,GAA0B,GAwH9B,MAtHiB,CAAC,CAAE,cAAe,CACjC,KAAM,IAAc,cAClB,IAAM,qCAAmC,KAAK,QAC9C,IAGI,CACJ,cACA,gBACA,gBACA,gBACA,kBACE,cAAQ,IAAM,CAChB,KAAM,IAAS,EAAoB,CACjC,KAAM,EACN,YAAa,CAAC,EAAiB,GAC/B,WAAY,CACV,WAAY,EACZ,aAAc,EACd,aAAc,EACd,iBAAkB,EAClB,aAAc,KAQlB,UAAO,iBAAiB,QAAQ,IAAU,KAAK,QAAQ,IAAI,KAC3D,KAAK,cAAc,KAAK,SAGxB,KAAK,eACE,IACF,GACH,cAAe,GAAqB,KAAK,cAE1C,CAAC,IAEC,GACH,GAA0B,GAC1B,GAAwB,GAAY,IACpC,GACE,GACA,KAAK,UAIT,KAAM,IAAe,GACnB,KAAK,aACL,KAAK,WACL,IAGI,GAAe,OAAS,IAC9B,GAAI,GAAc,CAChB,KAAM,CAAE,QAAQ,GAChB,KAAK,UAAY,GAmCnB,GAhCA,gBAAU,IAAM,CACd,GAAI,GAAc,CAChB,KAAM,IAAkB,KAAK,eAAe,IAAI,sBAEhD,SAAW,MAAU,MAAK,QAAQ,SAChC,GAAI,mBAAqB,IACvB,SAAW,MAAQ,IAAO,kBACxB,GAAgB,aAAa,CAC3B,KAAM,GAAK,KACX,SAAU,GAAO,cAIrB,UAAW,MAAU,IAAO,SACtB,GAAO,OAAS,gBAClB,GAAgB,aAAa,CAC3B,KAAM,GAAO,KACb,SAAU,GAAO,UAS3B,SAAW,MAAQ,IACjB,GAAgB,aAAa,CAAE,QAAM,SAAU,OAGlD,CAAC,GAAc,GAAc,KAE5B,QAAU,IAEZ,MAAO,IAAa,KAGtB,KAAM,CAAE,iBAAgB,IAAqB,KAAK,WAElD,MACE,iBAAoB,cAAa,CAAE,KAAM,KAAK,gBAC1C,gBAAoB,GAAoB,CAAE,WAAY,GACpD,gBAAoB,GAAe,KACjC,gBAAoB,GAAiB,CACrC,WAAY,GACZ,aAAc,GACd,aAAc,GACd,cAAe,GACf,SAAU,GAAY,GAAa,MAEjC,OAUhB,WAAY,CACV,KAAM,CAAE,OAAQ,EAAiB,WAAY,GAC3C,KAAK,WAGD,EAAoB,CAAC,CACzB,UAAW,GACX,eAID,CACC,KAAM,CAAC,GAAa,IAAkB,iBAEtC,MAAK,IAIL,MAAK,iBAAiB,UAAU,IACzB,IAJE,gBAAoB,GAAW,CAAE,gBAAiB,MAuD7D,MAhDkB,CAAC,CAAE,eAAe,CAClC,KAAM,IAAY,aAAO,gBACnB,GAAY,GAAG,GAAY,QAGjC,MAAK,GAgCH,gBAAoB,EAAiB,KACjC,gBAAoB,GAAc,CAAE,KAAM,KAC1C,gBAAoB,EAAmB,CAAE,UAAW,GAClD,gBAAoB,KAAQ,KAC1B,gBAAoB,KAAO,CAAE,KAAM,GAAW,QAAS,gBAAoB,WAAgB,KAAM,SAnCzG,MAAK,iBAAiB,UAAU,CAC9B,UAAW,IAAM,QACjB,WAAY,SAAS,GACrB,WAAY,IAAO,EACjB,MAAO,oBACP,YAAa,UAEf,eAAgB,SAAa,EAC3B,MAAO,oBACP,YAAa,UAEf,qBAAsB,SAAa,EACjC,KAAM,OACN,cAAe,qBACf,oBAAqB,CAAC,wBAExB,eAAgB,SAAa,KAC7B,QAAS,SAAY,KAIrB,gBAAoB,EAAiB,KACjC,gBAAoB,GAAc,CAAE,KAAM,KAC1C,gBAAoB,KAAQ,KAC1B,gBAAoB,KAAO,CAAE,KAAM,GAAW,QAAS,gBAAoB,WAAgB,KAAM,UAqB9G,cAAe,CACd,GAAI,KAAK,UAAW,CAGlB,SAAW,KAAU,MAAK,QACxB,SAAW,KAAW,GAAO,UACtB,KAAK,mBAAmB,IAAI,EAAQ,MACvC,KAAK,mBAAmB,SAAS,UAAW,GAIlD,8BACE,KAAK,mBACL,KAAK,mBAAmB,cAEnB,KAAK,UAEd,KAAK,mBAAmB,SAAS,SAAU,CACzC,IAAK,iBACL,KAAM,GACN,QAAS,IAAM,qCAAmC,KAAK,UAEzD,KAAK,mBAAmB,SAAS,SAAU,CACzC,IAAK,eACL,KAAM,GACN,QAAS,IAAM,CACb,GAAI,CAAC,KAAK,UACR,KAAM,IAAI,OACR,uDAGJ,MAAO,MAAK,aAGhB,KAAK,mBAAmB,SAAS,SAAU,CACzC,IAAK,iBACL,KAAM,GACN,QAAS,IAAM,KAAK,mBAKtB,KAAK,mBAAmB,SAAS,UAAW,CAC1C,IAAK,qBACL,KAAM,GACN,QAAS,IAAM,GAAI,8BAErB,SAAW,KAAW,MAAK,YACzB,KAAK,mBAAmB,SAAS,UAAW,GAG9C,SAAW,KAAU,MAAK,QACxB,SAAW,KAAW,GAAO,UAC3B,GAAI,CAAC,KAAK,mBAAmB,SAAS,UAAW,GAC/C,KAAM,IAAI,OACR,UAAU,EAAO,oEACf,EAAQ,OAOlB,SAAW,KAAW,MAAK,KACzB,GAAI,CAAC,KAAK,mBAAmB,SAAS,MAAO,GAC3C,KAAM,IAAI,OACR,0CAA0C,EAAQ,cAKxD,8BACE,KAAK,mBACL,KAAK,mBAAmB,cAG1B,KAAK,UAAY,GAAI,MAAY,KAAK,oBAC/B,KAAK,UAGb,cAAc,EAAS,CACtB,KAAM,GAAY,GAAI,KAEtB,SAAW,KAAU,GAAS,CAC5B,KAAM,GAAK,EAAO,QAClB,GAAI,EAAU,IAAI,GAChB,KAAM,IAAI,OAAM,2BAA2B,MAE7C,EAAU,IAAI,KClcb,YAA8B,EAAS,CAC5C,MAAO,IAAI,IAAW,K,mECFjB,KAAM,GAAsB,MAIjC,EAAoB,oCACjB,CACH,KAAM,GAAY,uNAClB,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,oCAElB,GAAI,CAAC,MAAM,QAAQ,GACjB,KAAM,IAAI,OAAM,2CAElB,KAAM,GAAU,EAAU,QAG1B,GACE,IACA,kCAAkC,kBAAkB,SAEpD,GAAI,CACF,KAAM,GAAO,KAAK,MAAM,GACpB,MAAM,QAAQ,GAChB,EAAQ,KAAK,GAAG,GAEhB,EAAQ,KAAK,CAAE,OAAM,QAAS,cAEzB,EAAP,CACA,KAAM,IAAI,OAAM,yCAAyC,KAI7D,KAAM,GAAmB,OAAS,eAClC,MAAI,IACF,EAAQ,KAAK,CACX,QAAS,SACT,KAAM,IAGH,I,ozHCrDF,WACL,EACA,EACA,CACA,SAAW,KAAS,GAClB,GAAI,CAAC,EAAS,IAAI,GAChB,MAAO,GAGX,MAAO,GAQF,OAAyB,CAC9B,YAAc,EAAS,CAAE,KAAK,QAAU,EAExC,yBACE,EACA,EACA,CACA,GAAI,CAAC,EACH,MAAO,GAKT,GAHI,CAAC,GAGD,KAAK,QAAQ,gBAAkB,OACjC,MAAO,GAET,KAAM,GAAgB,KAAK,QAAQ,cAAc,GACjD,MAAO,GAAU,EAAe,GAGlC,iBAAiB,EAAS,EAAQ,CAChC,KAAM,GAAW,GAAI,KAAI,KAAK,QAAQ,eACtC,GAAI,GAAW,KAAK,QAAQ,gBAAkB,OAAW,CACvD,KAAM,GAAgB,KAAK,QAAQ,cAAc,GACjD,SAAW,KAAS,GAClB,EAAS,IAAI,GAGjB,GAAI,EACF,SAAW,KAAS,GAClB,EAAS,IAAI,GAGjB,MAAO,I,0BChDJ,OAA0B,CAA1B,a,CACH,iBAAU,GAAI,KACd,2BAGD,kBAAW,IAEZ,cAAc,EAAY,CACpB,KAAK,WAAa,GACpB,MAAK,SAAW,EAChB,KAAK,QAAQ,KACX,KAAK,SAAW,wBAAwB,2BAK9C,eAAgB,CACd,MAAO,MAAK,SCIT,OAAmC,CAUxC,YAAY,EAAS,CATnB,oBACA,iBACA,4BACA,mCACA,sBAAe,GAAI,IAEpB,yBACA,yBAGC,KAAM,CACJ,YACA,gBAAgB,GAAI,KACpB,gBACA,wBACE,EAEJ,KAAK,UAAY,EACjB,KAAK,kBAAoB,EACzB,KAAK,yBAA2B,EAChC,KAAK,OAAS,GAAI,GAAmB,CAAE,gBAAe,uBAGlD,YAAW,EAAS,CACxB,GACE,KAAK,OAAO,yBAAyB,KAAK,eAAgB,EAAQ,QAClE,CAEA,GAAI,CADkB,KAAK,yBAAyB,KAAK,gBAEvD,MAAO,MAAK,eAGd,GAAI,CACF,KAAM,GAAmB,KAAM,MAAK,0BAC9B,EAAgB,KAAK,kBAAkB,KAAK,gBAC5C,EAAkB,KAAK,kBAAkB,GAC/C,MAAI,GAAU,EAAiB,IAC7B,MAAK,eAAiB,GAEjB,QACA,EAAP,CACA,GAAI,EAAQ,SACV,OAEF,KAAM,IAWV,GAAI,CAAC,KAAK,gBAAkB,CAAC,EAAQ,aACnC,GAAI,CACF,KAAM,GAAa,KAAM,MAAK,0BAC9B,YAAK,eAAiB,EAEf,KAAK,WAAW,QACvB,EAMJ,GAAI,GAAQ,SAKZ,YAAK,eAAiB,KAAM,MAAK,UAAU,cAAc,IACpD,EACH,OAAQ,KAAK,OAAO,iBAAiB,KAAK,eAAgB,EAAQ,UAEpE,KAAK,aAAa,cAAc,IACzB,KAAK,oBAGR,gBAAgB,CACpB,KAAK,eAAiB,OACtB,KAAM,MAAK,UAAU,gBACrB,KAAK,aAAa,cAAc,IAGlC,eAAgB,CACd,MAAO,MAAK,aAAa,qBAGpB,0BAA0B,CAC/B,GAAI,KAAK,eACP,MAAO,MAAK,eAGd,KAAK,eAAiB,KAAK,UAAU,iBAErC,GAAI,CACF,KAAM,GAAU,KAAM,MAAK,eAC3B,YAAK,aAAa,cAAc,IACzB,SACP,CACA,MAAO,MAAK,iBC/GX,OAA+B,CAOpC,YAAY,EAAS,CANnB,oBACA,iBACA,sBAAe,GAAI,IAEpB,yBAGC,KAAM,CAAE,YAAW,gBAAgB,GAAI,KAAO,iBAAkB,EAEhE,KAAK,UAAY,EACjB,KAAK,OAAS,GAAI,GAAmB,CAAE,gBAAe,kBAGxD,WAAW,EAAS,CAClB,KAAK,eAAiB,EACtB,KAAK,aAAa,cAAc,QAAQ,SAGpC,YAAW,EAAS,CACxB,GACE,KAAK,OAAO,yBAAyB,KAAK,eAAgB,EAAQ,QAElE,MAAO,MAAK,eAId,GAAI,GAAQ,SAKZ,YAAK,eAAiB,KAAM,MAAK,UAAU,cAAc,IACpD,EACH,OAAQ,KAAK,OAAO,iBAAiB,KAAK,eAAgB,EAAQ,UAEpE,KAAK,aAAa,cAAc,IACzB,KAAK,oBASR,gBAAgB,CACpB,KAAK,eAAiB,OACtB,KAAK,aAAa,cAAc,IAGlC,eAAgB,CACd,MAAO,MAAK,aAAa,iBCzCtB,OAAuB,CAO5B,YAAY,EAAS,CANnB,kBACA,qBACA,iBACA,mCACA,iBAGA,KAAM,CACJ,UACA,aACA,SACA,gBACA,uBAAuB,IAAM,IAC3B,EAEJ,KAAK,QAAU,EACf,KAAK,WAAa,EAClB,KAAK,OAAS,EACd,KAAK,yBAA2B,EAChC,KAAK,OAAS,GAAI,GAAmB,CACnC,gBACA,cAAe,GAAI,OAIvB,WAAW,EAAS,CAClB,KAAK,QAAQ,WAAW,GACxB,KAAK,YAAY,QAGb,YAAW,EAAS,CACxB,KAAM,CAAE,UAAW,EACb,EAAU,KAAK,cAErB,GAAI,KAAK,OAAO,yBAAyB,EAAS,IAG5C,CAFkB,KAAK,yBAAyB,GAGlD,YAAK,QAAQ,WAAW,GACjB,EAIX,KAAM,GAAa,KAAM,MAAK,QAAQ,WAAW,GACjD,YAAK,YAAY,GACV,OAGH,gBAAgB,CACpB,aAAa,WAAW,KAAK,YAC7B,KAAM,MAAK,QAAQ,gBAGrB,eAAgB,CACd,MAAO,MAAK,QAAQ,gBAGrB,aAAc,CACb,GAAI,CACF,KAAM,GAAc,aAAa,QAAQ,KAAK,YAC9C,GAAI,EAAa,CACf,KAAM,GAAU,KAAK,MAAM,EAAa,CAAC,EAAM,IACzC,kBAAO,UAAW,MACb,GAAI,KAAI,EAAM,SAEhB,GAGT,GAAI,CACF,MAAO,MAAK,OAAO,MAAM,SAClB,EAAP,CAEA,cAAQ,IACN,gGAAgG,KAE5F,GAIV,YACA,CACA,aAAa,WAAW,KAAK,YAC7B,QAIH,YAAY,EAAS,CACpB,GAAI,IAAY,OAAW,CACzB,aAAa,WAAW,KAAK,YAC7B,OAGF,GAAI,CACF,KAAK,OAAO,MAAM,SACX,EAAP,CAEA,QAAQ,KACN,8FAA8F,KAEhG,OAGF,aAAa,QACX,KAAK,WACL,KAAK,UAAU,EAAS,CAAC,EAAM,IACzB,YAAiB,KACZ,CACL,OAAQ,MACR,QAAS,MAAM,KAAK,IAGjB,O,mECxFR,WAAwB,EAAS,CACtC,MAAO,IAAI,SAAQ,CAAC,EAAS,IAAW,CACtC,KAAM,GAAQ,EAAQ,OAAS,IACzB,EAAS,EAAQ,QAAU,IAC3B,EAAO,OAAO,OAAO,MAAQ,EAAI,EAAQ,EACzC,EAAM,OAAO,OAAO,OAAS,EAAI,EAAS,EAE1C,EAAQ,OAAO,KACnB,EAAQ,IACR,EAAQ,KACR,qEAAqE,YAAgB,SAAc,UAAY,KAGjH,GAAI,GAAe,GAEnB,GAAI,CAAC,GAAS,MAAO,GAAM,QAAW,aAAe,EAAM,OAAQ,CACjE,KAAM,GAAQ,GAAI,OAAM,8BACxB,EAAM,KAAO,qBACb,EAAO,GACP,OAGF,KAAM,GAAmB,GAAU,CAIjC,GAHI,EAAM,SAAW,GAGjB,EAAM,SAAW,EAAQ,OAC3B,OAEF,KAAM,CAAE,QAAS,EAEjB,GAAI,EAAK,OAAS,cAAe,CAC/B,EAAe,EAAK,aACpB,OAGF,GAAI,EAAK,OAAS,yBAChB,OAEF,KAAM,GAAa,EAEnB,GAAI,SAAW,GAAY,CACzB,KAAM,GAAQ,GAAI,OAAM,EAAW,MAAM,SACzC,EAAM,KAAO,EAAW,MAAM,KAG9B,EAAO,OAEP,GAAQ,EAAW,UAErB,KAGI,EAAa,YAAY,IAAM,CACnC,GAAI,EAAM,OAAQ,CAChB,KAAM,GAAa,iBACjB,GAAgB,IAAiB,OAAO,SAAS,OAC7C,kCAAkC,IAClC,qBAEA,EAAQ,GAAI,OAAM,GACxB,EAAM,KAAO,mBACb,EAAO,GACP,MAED,KAEH,YAAgB,CACd,OAAO,oBAAoB,UAAW,GACtC,cAAc,GAGhB,OAAO,iBAAiB,UAAW,O,kHC9GhC,OAEP,CAFO,a,CAGJ,kBAAW,IACX,2BAEC,oBAAa,GAAI,MAAe,GAC5B,KAAK,SACP,CAAI,KAAK,iBACP,EAAW,MAAM,KAAK,kBAEtB,EAAW,WAEN,IAAM,IAGf,MAAK,YAAY,IAAI,GACd,IAAM,CACX,KAAK,YAAY,OAAO,OAI1B,qBAAc,GAAI,OAInB,OAAO,aAAc,CACpB,MAAO,SAGL,SAAS,CACX,MAAO,MAAK,SAGd,KAAK,EAAO,CACV,GAAI,KAAK,SACP,KAAM,IAAI,OAAM,4BAElB,KAAK,YAAY,QAAQ,GAAc,EAAW,KAAK,IAGzD,MAAM,EAAO,CACX,GAAI,KAAK,SACP,KAAM,IAAI,OAAM,4BAElB,KAAK,SAAW,GAChB,KAAK,iBAAmB,EACxB,KAAK,YAAY,QAAQ,GAAc,EAAW,MAAM,IAG1D,UAAW,CACT,GAAI,KAAK,SACP,KAAM,IAAI,OAAM,4BAElB,KAAK,SAAW,GAChB,KAAK,YAAY,QAAQ,GAAc,EAAW,YASpD,UACE,EACA,EACA,EACA,CACA,KAAM,GACJ,MAAO,IAAW,WACd,CACE,KAAM,EACN,MAAO,EACP,SAAU,GAEZ,EAEN,MAAO,MAAK,WAAW,UAAU,IAgB9B,OAEP,CAME,YAAY,EAAO,CALlB,mBACA,uBACA,2BACC,qBAyBA,qBAAc,GAAI,MAtBlB,KAAK,SAAW,GAChB,KAAK,aAAe,EACpB,KAAK,iBAAmB,OACxB,KAAK,WAAa,GAAI,MAAe,GAC/B,KAAK,SACP,CAAI,KAAK,iBACP,EAAW,MAAM,KAAK,kBAEtB,EAAW,WAEN,IAAM,IAGf,GAAW,KAAK,KAAK,cAErB,KAAK,YAAY,IAAI,GACd,IAAM,CACX,KAAK,YAAY,OAAO,OAS7B,OAAO,aAAc,CACpB,MAAO,SAGL,SAAS,CACX,MAAO,MAAK,SAGd,KAAK,EAAO,CACV,GAAI,KAAK,SACP,KAAM,IAAI,OAAM,6BAElB,KAAK,aAAe,EACpB,KAAK,YAAY,QAAQ,GAAc,EAAW,KAAK,IAGzD,MAAM,EAAO,CACX,GAAI,KAAK,SACP,KAAM,IAAI,OAAM,6BAElB,KAAK,SAAW,GAChB,KAAK,iBAAmB,EACxB,KAAK,YAAY,QAAQ,GAAc,EAAW,MAAM,IAG1D,UAAW,CACT,GAAI,KAAK,SACP,KAAM,IAAI,OAAM,6BAElB,KAAK,SAAW,GAChB,KAAK,YAAY,QAAQ,GAAc,EAAW,YASpD,UACE,EACA,EACA,EACA,CACA,KAAM,GACJ,MAAO,IAAW,WACd,CACE,KAAM,EACN,MAAO,EACP,SAAU,GAEZ,EAEN,MAAO,MAAK,WAAW,UAAU,M,4FC7K9B,KAAM,GAAkB,GAAU,CACvC,KAAM,CAAE,YAAa,EACf,EAAiB,aAAO,sBACxB,EACJ,QAAU,GACN,EAAe,SAAS,EAAM,MAC9B,CAAC,EAAe,SAAS,EAAM,SACrC,MAAO,iBAAoB,WAAgB,KAAM,EAAY,EAAW,OAG1E,0BAAoB,EAAgB,sBAAuB,K,uGCHpD,KAAM,GAAc,GAAU,CACnC,KAAM,GAAM,eACN,CAAE,qBAAsB,EAAI,gBAC5B,EAAS,uBAAiB,EAAM,SAAU,GAC9C,EACG,cACA,QAAQ,GAAS,C,MAChB,GAAI,GAAO,EAAM,MAAM,KAGvB,MAAI,KAAS,GACJ,GAET,GAAO,oBAAM,QAAQ,QAAS,MAAvB,OAA8B,IAE9B,CACL,CACE,OACA,QAAS,EACT,SAAU,EAAM,MAAM,SAClB,CAGE,CACE,KAAM,IAAS,IAAM,IAAM,KAC3B,QAAS,EAAM,MAAM,WAGzB,YAKT,KAAK,CAAC,EAAG,IAAM,EAAE,KAAK,cAAc,EAAE,OAEtC,IAAI,GACH,GAAI,KAAO,EAAI,OAAS,IAAM,IAAM,GAAG,EAAI,SACpC,KAKb,SAAO,KAAK,CACV,QAAS,gBAAoB,EAAmB,MAChD,KAAM,OAGD,SAAU,I,2iDC5DZ,WAAsB,EAAQ,CACnC,KAAM,CAAC,EAAU,GAAe,SAAS,IACnC,EAAW,OAAO,aAYxB,GAVA,UAAU,IAAM,CACd,KAAM,GAAe,EAClB,SACA,UAAU,GAAW,EAAY,GAAQ,EAAK,OAAO,KAExD,MAAO,IAAM,CACX,EAAa,gBAEd,CAAC,IAEA,EAAS,SAAW,EACtB,MAAO,MAGT,KAAM,CAAC,GAAgB,EAEjB,EAAc,IAAM,CACxB,EAAY,GAAQ,EAAK,OAAO,GAAO,IAAQ,KAGjD,MACE,OAAM,cAAc,SAAU,CAAE,KAAM,GAAM,aAAc,CAAE,SAAU,MAAO,WAAY,WACrF,MAAM,cAAc,MAAO,CAC3B,OACE,MAAM,cAAc,WAAY,CAC9B,MAAO,UACP,KAAM,QACN,QAAS,EACT,cAAe,sBAEb,MAAM,cAAc,UAAW,OAGrC,SAAU,EAAa,UAErB,MAAM,cAAc,OAAQ,KAC1B,EAAa,QAAQ,WACrB,EAAS,OAAS,GAClB,MAAM,cAAc,KAAM,KAAM,KAAK,EAAS,OAAS,WAAW,UAChE,UACA,EAAS,OAAS,U,0BCtDhC,KAAM,GAAY,QACf,GACC,QAAa,CACX,OAAQ,CACN,MAAO,OACP,OAAQ,OACR,MAAO,OACP,WAAY,EAAM,WAAW,eAC7B,cAAe,MACf,cAAe,eAGrB,CAAE,KAAM,oBA+BH,WAAgB,EAAO,CAC5B,KAAM,CAAE,cAAa,UAAS,gBAAiB,EACzC,EAAU,IAChB,MACE,OAAM,cAAc,eAAgB,CAClC,IAAK,EACL,IAAK,EACL,UAAW,EAAQ,OACnB,MAAO,CACL,gBAAiB,cAAc,GAAe,GAAW,OACtD,IAGH,GAAe,gBAAgB,I,qCCrDhC,KAAM,GAAiB,GAAQ,gBAAgB,KAAK,GAarD,EAAe,GAAS,C,MAE5B,MAAI,aAAgB,OACX,EAAK,IAAI,GAAa,KAAK,KAAK,OAIrC,MAAO,IAAS,UAAY,EACvB,EAAa,oBAAQ,QAAR,cAAe,UAIjC,CAAC,SAAU,UAAU,SAAS,MAAO,IAChC,OAAO,GAIT,IAQH,EAAa,aACjB,CAAC,CAAE,UAAS,aAAY,GAAS,IAAQ,CACvC,KAAM,GAAY,qBACZ,EAAK,OAAO,EAAM,IAClB,EAAW,EAAY,EAAM,WAAa,EAC1C,EAAW,EAAc,GACzB,EAAY,GAAY,CAAC,CAAC,WAAW,KAAK,GAE1C,EAAe,IAAU,CAC7B,WAAU,IACL,GACH,EAAU,aAAa,QAAS,EAAU,CAAE,WAAY,CAAE,SAI9D,MAAO,GAEL,gBAAoB,IAAc,CAChC,IAAK,EACL,KAAM,EACN,QAAS,KACL,EAAY,CAAE,OAAQ,SAAU,IAAK,YAAe,MACrD,IAIL,gBAAoB,IAAc,CAChC,IAAK,EACL,UAAW,KACX,QAAS,KACN,MChDL,EAAc,aAAiB,CAAC,EAAO,IAC3C,gBAAoB,EAAM,CAAE,IAAK,KAAQ,EAAO,MAAO,aAInD,EAAe,aAAiB,CAAC,EAAO,IAC5C,gBAAoB,IAAgB,CAAE,IAAK,EAAK,UAAW,KAAgB,K,2DCctE,YAAwB,EAAO,CACpC,KAAM,CACJ,OACA,eAAe,IACf,cAAc,4BACZ,EACE,EAAW,aAAO,eAClB,CAAC,EAAM,GAAW,eAAS,IAC3B,CAAC,CAAE,SAAS,GAAmB,UAErC,gBAAU,IAAM,CACV,GACF,EAAS,KAAK,IAEf,CAAC,EAAO,IAEX,KAAM,GAAkB,IAAK,CAC3B,GAAE,kBACF,EAAQ,IACR,EAAgB,IAGlB,MACE,iBAAoB,WAAgB,KAChC,gBAAoB,KAAS,CAC7B,GAAI,oBACJ,MAAO,EACP,UAAW,MACX,WAAY,EACZ,QAAS,IAAM,EAAQ,IACvB,KAAM,GAEJ,gBAAoB,IAAY,CAAE,QAAS,GACzC,gBAAoB,IAAU,S,wCCzBnC,YAAqB,EAAO,CACjC,KAAM,CACJ,OACA,WACA,kBAAkB,GAClB,qBACA,cACA,qBAAqB,IACnB,EACE,EAAQ,UACR,EAAO,EAAM,QAAQ,OAAS,OAAS,KAAO,KAC9C,EAAiB,EAAM,QAAQ,OAAS,OAAS,UAAY,UAEnE,MACE,iBAAoB,MAAO,CAAE,MAAO,CAAE,SAAU,aAC5C,gBAAoB,KAAY,CAChC,YAAa,EACb,SAAU,EACV,MAAO,EACP,gBAAiB,EACjB,UAAW,GACX,gBAAiB,CAAE,MAAO,EAAM,QAAQ,gBACxC,UAAY,IACV,kBAAoB,SAAS,KACzB,CACE,MAAO,CACL,gBAAiB,IAGrB,IAGJ,GAEF,GACA,gBAAoB,MAAO,CAAE,MAAO,CAAE,SAAU,WAAY,IAAK,EAAG,MAAO,IACvE,gBAAoB,GAAgB,CAAE,KAAM,M,4BCxEjD,YAAsB,EAAO,CAClC,KAAM,CAAE,QAAO,MAAO,EAChB,EAAa,SAAc,GAC/B,EAAM,YAAY,KAAK,OAGzB,MAAK,GAIE,EACL,gBAAoB,IAAY,CAC9B,UAAW,KACX,MAAO,UACP,MAAO,EACP,KAAM,QACN,GAAI,GAEF,gBAAoB,KAAkB,OAG1C,gBAAoB,IAAQ,CAAE,UAAW,KAAY,QAAS,YAAa,MAAO,UAAW,GAAI,GAC7F,GAfG,KCqCJ,GAAI,IAAY,UAAU,EAAW,CAI1C,KAAM,GAAa,KAAM,EAAU,WAAgB,EAInD,KAAM,GAAa,KAAM,EAAU,WAAgB,EAInD,KAAM,GAAa,KAAM,EAAU,WAAgB,EAInD,KAAM,GAAa,KAAM,EAAU,WAAgB,IAClD,IAAc,IAAY,KAOtB,GAAI,IAAY,UAAU,EAAW,CAI1C,KAAM,GAAU,KAAM,EAAU,QAAa,EAI7C,KAAM,GAAW,KAAM,EAAU,SAAc,EAI/C,KAAM,GAAY,KAAM,EAAU,UAAe,EAIjD,KAAM,GAAa,KAAM,EAAU,WAAgB,IAClD,IAAc,IAAY,KAKtB,GAAI,IAAS,UAAU,EAAQ,CAIpC,KAAM,GAAkB,kBAAmB,EAAO,gBAAqB,EAIvE,KAAM,GAAa,aAAc,EAAO,WAAgB,EAQxD,KAAM,GAAe,eAAgB,EAAO,aAAkB,IAC7D,IAAW,IAAS,KAOhB,GAAI,IAAgB,UAAU,EAAe,CAClD,KAAM,GAAO,IAAK,EAAc,KAAU,EAC1C,KAAM,GAAQ,IAAK,EAAc,MAAW,EAC5C,KAAM,GAAS,IAAK,EAAc,OAAY,IAC7C,IAAkB,IAAgB,K,kGCpIrC,KAAM,IAAY,QACf,GAAW,EACV,KAAM,CACJ,KAAM,EAAM,QAAQ,QAAQ,MAC5B,OAAQ,EAAM,QAAQ,QAAQ,OAEhC,KAAM,CACJ,KAAM,EAAM,QAAQ,QAAQ,gBAGhC,CAAE,KAAM,wCAIH,YAAqB,CAAE,KAAM,CAAE,OAAQ,CAC5C,KAAM,GAAU,KACV,CAAC,EAAO,GAAY,WAAe,GACnC,CAAC,EAAQ,GAAa,WAAe,GACrC,EAAQ,SAAa,MAE3B,kBAAsB,IAAM,CAE1B,GAAI,EAAM,QAAS,CACjB,GAAI,CAAE,OAAQ,GAAgB,MAAO,IACnC,EAAM,QAAQ,UAChB,GAAiB,KAAK,MAAM,IAC5B,GAAgB,KAAK,MAAM,IAEvB,MAAmB,GAAU,KAAkB,IACjD,GAAS,IACT,EAAU,OAGb,CAAC,EAAO,IAEX,KAAM,GAAU,GACV,EAAc,EAAQ,EAAU,EAChC,EAAe,EAAS,EAAU,EAExC,MACE,iBAAoB,IAAK,KACrB,gBAAoB,OAAQ,CAC5B,UAAW,EAAQ,KACnB,MAAO,EACP,OAAQ,EACR,GAAI,KAEJ,gBAAoB,OAAQ,CAC5B,IAAK,EACL,UAAW,EAAQ,KACnB,EAAG,EAAe,EAClB,EAAG,EAAc,EACjB,WAAY,SACZ,kBAAmB,UAEjB,IC/DH,KAAM,IAAkB,eAElB,GAAe,OACf,GAAe,OACf,GAAgB,QCMvB,GAAY,SAChB,GAAU,EACR,KAAM,CACJ,WAAY,GAAG,EAAM,YAAY,SAAS,gBAG9C,CAAE,KAAM,iCAWJ,GAAiB,GAAU,gBAAoB,GAAa,IAAK,IAEhE,YAAc,CACnB,SAAS,GACT,UACA,QACC,CACD,KAAM,CAAE,QAAO,SAAQ,IAAI,EAAG,IAAI,GAAM,EAClC,EAAY,EACZ,EAAU,KACV,EAAU,SAAa,MAE7B,yBAAsB,IAAM,CAE1B,GAAI,EAAQ,QAAS,CACnB,GAAI,CAAE,OAAQ,GAAgB,MAAO,IACnC,EAAQ,QAAQ,UAClB,GAAiB,KAAK,MAAM,IAC5B,GAAgB,KAAK,MAAM,IAEvB,MAAmB,GAAU,KAAkB,IACjD,EAAQ,EAAK,GAAI,IACZ,EACH,OAAQ,GACR,MAAO,OAIZ,CAAC,EAAM,EAAO,EAAQ,IAGvB,gBAAoB,IAAK,CACvB,IAAK,EACL,cAAe,GACf,UAAW,EAAQ,KACnB,UAAW,aAAa,EAAI,EAAQ,KAAK,EAAI,EAAS,MAEpD,EAAO,CAAE,KAAM,K,+CCxDvB,KAAM,GAAY,SACf,GAAW,EACV,KAAM,CACJ,KAAM,EAAM,QAAQ,gBAGxB,CAAE,KAAM,yCAIH,WAAsB,CAAE,KAAM,CAAE,UAAW,CAChD,KAAM,GAAU,IAChB,MACE,iBAAoB,OAAQ,CAAE,UAAW,EAAQ,KAAM,WAAY,UAC/D,GCQR,KAAM,IAAY,SACf,GAAW,EACV,KAAM,CACJ,YAAa,EACb,OAAQ,EAAM,QAAQ,WACtB,KAAM,OACN,WAAY,GAAG,EAAM,YAAY,SAAS,cAE5C,MAAO,CACL,WAAY,GAAG,EAAM,YAAY,SAAS,gBAG9C,CAAE,KAAM,iCAgBJ,GAAiB,GACrB,gBAAoB,EAAc,IAAK,IAGnC,GAAa,OAEhB,EAAE,GAAK,EAAE,GACT,EAAE,GAAK,EAAE,GACT,MAAM,KAEF,YAAc,CACnB,SAAS,GACT,UACA,KACA,QACC,CACD,KAAM,CAAE,IAAI,EAAG,IAAI,EAAG,QAAO,SAAQ,UAAW,EAC1C,EAAa,EACb,GAAU,KAEV,GAAW,SAAa,MAE9B,kBAAsB,IAAM,CAE1B,GAAI,GAAS,QAAS,CACpB,GAAI,CAAE,OAAQ,GAAgB,MAAO,IACnC,GAAS,QAAQ,UACnB,GAAiB,KAAK,MAAM,IAC5B,GAAgB,KAAK,MAAM,IAEvB,MAAmB,GAAU,KAAkB,IACjD,EAAQ,EAAI,IACP,EACH,OAAQ,GACR,MAAO,OAIZ,CAAC,EAAM,EAAQ,EAAO,EAAS,IAElC,GAAI,IAAO,GAEX,GAAI,EAAQ,CACV,KAAM,IAAe,EAAO,OACzB,IAAU,IAAS,GAAM,IAAM,IAAS,GAAM,IAEjD,GAAO,GAAW,KAAiB,GAGrC,MACE,iBAAoB,WAAgB,KAChC,IACA,gBAAoB,OAAQ,CAC1B,cAAe,GACf,UAAW,GAAQ,KACnB,UAAW,QAAQ,MACnB,EAAG,KAGL,EAAW,MACX,gBAAoB,IAAK,CACvB,IAAK,GACL,cAAe,GACf,UAAW,GAAQ,MACnB,UAAW,aAAa,KAAK,MAE3B,EAAO,CAAE,KAAM,KAEjB,MCwBV,KAAM,IAAe,YAOd,YACL,EACA,C,UACA,KAAM,CACJ,QACA,QACA,aACA,YAAY,GAAU,WACtB,QACA,aAAa,GACb,aAAa,GACb,aAAa,GACb,WAAW,EACX,YAAW,EACX,aACA,UAAS,GAAO,gBAChB,iBAAgB,GAAc,MAC9B,eAAc,GACd,aAAY,EACZ,cAAa,EACb,eACA,QACA,QAAO,aACJ,IACD,EACE,GAAQ,WACR,CAAC,GAAgB,IAAqB,WAAe,KACrD,CAAC,GAAiB,IAAsB,WAAe,KAEvD,GAAQ,SACZ,GAAI,uBAEA,CAAC,GAAY,IAAiB,WAClC,QAAM,QAAQ,UAAd,eAAuB,QAAS,GAE5B,CAAC,GAAa,IAAkB,WACpC,QAAM,QAAQ,UAAd,eAAuB,SAAU,GAE7B,CAAC,GAAY,IAAiB,WAAe,IAC7C,CAAC,GAAY,IAAiB,WAAe,IAE7C,GAAW,KAAK,IAAI,GAAY,IAChC,GAAY,KAAK,IAAI,GAAa,IAElC,GAAe,UACnB,IACE,KAAU,IAAS,CACjB,GAAI,CAAC,GACH,OAGF,KAAM,IAAY,KAAmB,IAC/B,GAAY,KAAmB,GAAK,eAAe,KAEzD,aAAsB,CACpB,GAAU,KACR,QAEG,YAAY,CAAC,EAAG,KAChB,GAAG,OAAQ,IAAS,CACnB,GAAM,UAAU,EAAI,KAAK,IACvB,EACA,KAAK,IACH,GAAM,UAAU,EAChB,GAAW,GAAW,GAAM,UAAU,IAG1C,GAAM,UAAU,EAAI,KAAK,IACvB,EACA,KAAK,IACH,GAAM,UAAU,EAChB,GAAY,GAAY,GAAM,UAAU,IAG5C,GAAU,KAAK,YAAa,GAAM,cAKtC,KAAS,UACX,KACS,KAAS,mBAClB,GAAU,GAAG,QAAS,IAAM,MAG9B,KAAM,CAAE,MAAO,GAAmB,OAAQ,IACxC,GAAK,wBACH,KAAmB,IACrB,GAAkB,IAEhB,KAAoB,IACtB,GAAmB,KAEpB,KACL,CAAC,GAAiB,GAAgB,GAAU,GAAW,KAGnD,GAAmB,cAAkB,IAAM,CAE/C,KAAM,IAAoB,GAAM,QAAQ,QAClC,GAAoB,GAAM,QAAQ,QAExC,GAAkB,QAAQ,IAAU,CAE7B,EADuB,KAAK,IAAQ,GAAK,KAAO,KAEnD,GAAM,QAAQ,WAAW,MAI7B,GAAkB,QAAQ,IAAK,CAIxB,EAHuB,KAC1B,IAAQ,GAAK,OAAS,GAAE,GAAK,GAAK,KAAO,GAAE,IAG3C,GAAM,QAAQ,WAAW,GAAE,EAAG,GAAE,KAKpC,EAAM,QAAQ,IAAQ,CACpB,KAAM,IAAe,GAAM,QACxB,QACA,KAAK,IAAU,GAAK,KAAO,IAE9B,GAAI,IAAgB,GAAM,QAAQ,KAAK,IAAe,CACpD,KAAM,CAAE,SAAO,UAAQ,KAAG,MAAM,GAAM,QAAQ,KAAK,IACnD,GAAM,QAAQ,QAAQ,GAAc,IAAK,GAAM,SAAO,UAAQ,KAAG,WAEjE,IAAM,QAAQ,QAAQ,GAAK,GAAI,IAAK,GAAM,MAAO,EAAG,OAAQ,MAIhE,EAAM,QAAQ,IAAK,CACjB,GAAM,QAAQ,QAAQ,GAAE,KAAM,GAAE,GAAI,IAC/B,GACH,MAAO,GAAE,MACT,MAAO,EACP,OAAQ,EACR,SAAU,GACV,YAAa,GACb,OAAQ,GACR,OAAQ,QAGX,CAAC,EAAO,EAAO,GAAe,GAAa,GAAY,KAEpD,GAAc,UAClB,IACE,KACE,IAAM,CACJ,YAAa,GAAM,SACnB,KAAM,CAAE,UAAQ,UAAU,GAAM,QAAQ,QAClC,GAAY,KAAK,IAAI,EAAG,IAAU,GAClC,GAAW,KAAK,IAAI,EAAG,IAAS,GACtC,GAAc,IACd,GAAe,IAEf,GAAc,GAAM,QAAQ,SAC5B,GAAc,GAAM,QAAQ,UAE9B,IACA,CAAE,QAAS,KAEf,IAGF,YAAgB,IACd,IAAM,QAAQ,SAAS,CACrB,QAAS,EACT,QACA,QAAS,EACT,QAAS,EACT,QAAS,EACT,QAAS,EACT,QAAS,GACT,aACA,YAGF,KACA,KAEO,GAAY,QAClB,CACD,GACA,EACA,EACA,EACA,EACA,GACA,EACA,EACA,GACA,GACA,KAGF,YAAiB,GAAI,GAAM,CACzB,UAAM,QAAQ,QAAQ,GAAI,IAC1B,KACO,GAAM,QAGf,YAAiB,GAAI,GAAM,CACzB,UAAM,QAAQ,QAAQ,GAAI,IAC1B,KACO,GAAM,QAGf,MACE,iBAAoB,MAAO,CACzB,IAAK,MACF,GACH,MAAO,OACP,OAAQ,GACR,QAAS,OAAO,MAAY,MAE1B,gBAAoB,OAAQ,KAC1B,gBAAoB,SAAU,CAC9B,GAAI,GACJ,QAAS,YACT,YAAa,KACb,aAAc,KACd,KAAM,KACN,KAAM,KACN,OAAQ,OACR,YAAa,eAEX,gBAAoB,OAAQ,CAC5B,KAAM,GAAM,QAAQ,WACpB,EAAG,4DAGL,IAEF,gBAAoB,IAAK,CAAE,GAAI,IAC7B,gBAAoB,MAAO,CAC3B,MAAO,GACP,OAAQ,GACR,EAAG,GAAY,EAAI,GAAc,EACjC,EAAG,GAAW,EAAI,GAAa,EAC/B,QAAS,OAAO,MAAc,MAE5B,GAAW,IAAI,IAAK,CACpB,KAAM,IAAO,GAAM,QAAQ,KAAK,IAChC,MAAK,IAEH,gBAAoB,GAAM,CACxB,IAAK,GAAG,GAAE,KAAK,GAAE,IACjB,GAAI,GACJ,QAAS,GACT,OAAQ,GACR,KAAM,KAPQ,OAWlB,GAAW,IAAK,IAAO,CACvB,KAAM,IAAO,GAAM,QAAQ,KAAK,IAChC,MAAK,IAEH,gBAAoB,GAAM,CACxB,IAAK,GACL,QAAS,GACT,OAAQ,EACR,KAAM,KANQ,U,2BCpY9B,KAAM,IAAY,QACf,GAAO,C,MAAI,OACV,KAAM,CACJ,QAAS,EAAM,QAAQ,GACvB,aAAc,EAAM,QAAQ,GAC5B,UAAW,EAAM,QAAQ,GACzB,QAAS,OACT,SAAU,cAGZ,YAAa,CACX,SAAU,WACV,aAAc,EAAM,QAAQ,GAC5B,UAAW,CAAC,EAAM,QAAQ,GAC1B,OAAQ,SAEV,KAAM,CACJ,SAAU,IAEZ,QAAS,CACP,MAAO,OACP,SAAU,UACV,SAAU,UAEZ,QAAS,CACP,QAAS,OACT,WAAY,SACZ,MAAO,EAAM,QAAQ,OAAO,KAC5B,MAAO,CACL,MAAO,EAAM,QAAQ,OAAO,OAGhC,KAAM,CACJ,gBAAiB,EAAM,QAAQ,OAAO,MAExC,MAAO,CACL,gBAAiB,EAAM,QAAQ,OAAO,OAExC,QAAS,CACP,gBACE,KAAM,QAAQ,OAAO,UAArB,OAAgC,EAAM,QAAQ,OAAO,SAG3D,CAAE,KAAM,+BAWG,GAAqB,GAAU,C,OAC1C,KAAM,CAAE,UAAS,UAAS,KAAI,QAAQ,IAAU,EAC1C,EAAU,KAEV,EAAqB,OADD,eACY,UAAU,iBAC1C,EACJ,MAAmB,IAAI,sBAAvB,QAA8C,GAE1C,CAAC,EAAkB,IAAuB,SAC9C,GAAI,KAAI,IAGJ,GAAgB,cACpB,EAAmB,SAAS,qBAG9B,UAAU,IAAM,C,OACd,GAAI,mBAAe,SAAU,CAC3B,KAAM,IAAe,uBAAe,WAAf,QAA2B,GAChD,GAAoB,GAAI,KAAI,OAE7B,CAAC,mBAAe,WAEnB,KAAM,IAAc,IAAM,CACxB,EAAmB,IAAI,mBAAoB,CAAC,GAAG,EAAkB,KAGnE,MACE,OAAM,cAAc,SAAU,CAC5B,aACE,EACI,CAAE,SAAU,SAAU,WAAY,UAClC,CAAE,SAAU,MAAO,WAAY,UAErC,KAAM,CAAC,EAAiB,IAAI,GAC5B,QAAS,CACP,KAAM,WAAW,EAAQ,KAAM,CAAC,GAAS,EAAQ,eAGjD,MAAM,cAAc,gBAAiB,CACrC,QAAS,CACP,KAAM,WAAW,EAAQ,QAAS,EAAQ,IAC1C,QAAS,EAAQ,SAEnB,QAAS,EACT,OAAQ,CACN,MAAM,cAAc,WAAY,CAC9B,IAAK,UACL,MAAO,mCACP,MAAO,UACP,QAAS,IAEP,MAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,a,2ECvH9D,KAAM,IAAY,QAChB,CACE,WAAY,CACV,MAAO,MACP,OAAQ,EACR,SAAU,WACV,KAAM,MACN,IAAK,MACL,UAAW,yBAGf,CAAE,KAAM,6BAIG,EAAkB,CAAC,CAAE,aAAc,CAC9C,KAAM,GAAU,KAChB,OAAQ,OACD,QACH,MACE,iBAAoB,MAAO,CACzB,IAAK,GACL,UAAW,EAAQ,WACnB,IAAK,8BAGN,OACH,MACE,iBAAoB,MAAO,CACzB,IAAK,GACL,IAAK,iBACL,UAAW,EAAQ,iBAGpB,UACH,MACE,iBAAoB,MAAO,CACzB,IAAK,GACL,IAAK,mBACL,UAAW,EAAQ,iBAGpB,OACH,MACE,iBAAoB,MAAO,CAAE,IAAK,GAAS,IAAK,WAAa,UAAW,EAAQ,qBAGlF,MAAO,QCpDP,EAAY,QAChB,GAAU,EACR,KAAM,CACJ,gBAAiB,EAAM,QAAQ,WAAW,QAC1C,QAAS,EAAM,QAAQ,EAAG,EAAG,EAAG,IAElC,OAAQ,CACN,UAAW,EAAM,QAAQ,IAE3B,eAAgB,CACd,SAAU,cAGd,CAAE,KAAM,wBAgBH,WAAoB,EAAO,CAChC,KAAM,CAAE,QAAO,cAAa,UAAS,UAAW,EAC1C,EAAU,IAChB,MACE,iBAAoB,KAAM,CACxB,UAAW,GACX,UAAW,MACX,eAAgB,eAChB,WAAY,aACZ,UAAW,EAAQ,KACnB,QAAS,GAEP,gBAAoB,KAAM,CAAE,KAAM,GAAM,GAAI,GAAI,GAAI,GAClD,gBAAoB,KAAM,CAAE,UAAW,GAAM,UAAW,UACtD,gBAAoB,KAAM,CAAE,KAAM,GAAM,GAAI,IAC1C,gBAAoB,KAAY,CAAE,QAAS,MAAQ,IAErD,gBAAoB,KAAM,CAAE,KAAM,GAAM,GAAI,IAC1C,gBAAoB,KAAY,CAAE,QAAS,SAAW,IAExD,gBAAoB,KAAM,CAAE,KAAM,GAAM,GAAI,GAAM,UAAW,EAAQ,QACnE,KAIN,gBAAoB,KAAM,CAAE,KAAM,GAAM,GAAI,GAAI,GAAI,EAAG,UAAW,EAAQ,gBACxE,gBAAoB,EAAiB,CAAE,QAAS,MCvD1D,KAAM,GAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAkBjB,GAAY,QAChB,GAAU,EACR,KAAM,CACJ,aAAc,EACd,OAAQ,GAAG,EAAM,QAAQ,WACzB,WAAY,EAAM,QAAQ,OAAS,OAAS,OAAS,UAGzD,CAAE,KAAM,yCAGH,YAAqC,EAAO,CACjD,KAAM,CAAE,cAAe,EACjB,EAAU,KACV,EACJ,gBAAoB,WAAgB,KAAM,OACrC,gBAAoB,OAAQ,KAAM,GAAa,6GAItD,MACE,iBAAoB,EAAY,CAC9B,QAAS,QACT,MAAO,qBACP,YAAa,EACb,OACE,gBAAoB,WAAgB,KAChC,gBAAoB,KAAY,CAAE,QAAS,SAAW,wFAItD,gBAAoB,MAAO,CAAE,UAAW,EAAQ,MAC9C,gBAAoB,GAAa,CACjC,KAAM,EAAe,QAAQ,aAAc,GAC3C,SAAU,OACV,gBAAiB,GACjB,mBAAoB,CAAC,EAAG,GACxB,YAAa,CAAE,WAAY,UAAW,SAAU,WAGlD,gBAAoB,IAAQ,CAC5B,MAAO,UACP,UAAW,EACX,GAAI,8EACJ,gB,6GC7DZ,KAAM,IAAsB,CAC1B,EACA,IAGO,GADgB,QAAQ,OAAS,QAAU,MAAS,OAC3C,EAAM,QAAQ,GAAU,MAAO,IAG3C,GAA4B,CAChC,EACA,IAGO,GAD0B,QAAQ,OAAS,QAAU,MAAU,OAC5C,EAAM,QAAQ,GAAU,MAAO,IAGrD,GAAwB,QAAW,GAAU,EACjD,KAAM,CACJ,YAAa,EAAM,QAAQ,GAC3B,KAAM,CAAC,CAAE,cACP,GACE,EACA,OAKF,GAAqB,CAAC,CAAE,cAAe,CAC3C,KAAM,GAAU,GAAsB,CAAE,aACxC,MAAO,iBAAoB,IAAc,CAAE,QAAS,KAEhD,GAAuB,CAAC,CAAE,cAAe,CAC7C,KAAM,GAAU,GAAsB,CAAE,aACxC,MAAO,iBAAoB,KAAgB,CAAE,QAAS,KAUlD,GAAY,QAChB,GAAU,EACR,MAAO,CACL,gBAAiB,CAAC,CAAE,cAClB,GACE,EACA,GAEJ,MAAO,CAAC,CAAE,cACR,GACE,EACA,GAEJ,cAAe,UAEjB,QAAS,CACP,QAAS,OACT,cAAe,OAEjB,YAAa,CACX,MAAO,CAAC,CAAE,cACR,GACE,EACA,GAEJ,WAAY,QAEd,QAAS,CACP,MAAO,OACP,QAAS,QACT,MAAO,CAAC,CAAE,cACR,GACE,EACA,GAEJ,gBAAiB,CAAC,CAAE,cAClB,GACE,EACA,IAGN,QAAS,CACP,MAAO,OACP,QAAS,QACT,MAAO,EAAM,QAAQ,aACrB,gBAAiB,EAAM,QAAQ,WAAW,QAC1C,OAAQ,aAAa,EAAM,QAAQ,SACnC,QAAS,EAAM,QAAQ,GACvB,WAAY,gBAGhB,CAAE,KAAM,0BAWJ,GAAc,GACX,EAAE,OAAO,GAAG,kBAAkB,SAAW,EAAE,MAAM,GAiBnD,YAAsB,EAAO,CAClC,KAAM,CACJ,WAAW,UACX,QACA,UACA,WACA,mBACE,EACE,EAAU,GAAU,CAAE,aAGtB,EAAW,GAAW,GAAa,GAAQ,KAAK,IAAU,IAEhE,MACE,iBAAoB,KAAW,CAC7B,gBAAiB,UAAmB,GACpC,UAAW,EAAQ,MACnB,KAAM,SAEJ,gBAAoB,KAAkB,CACtC,WAAY,gBAAoB,GAAsB,CAAE,SAAU,IAClE,UAAW,EAAQ,SAEjB,gBAAoB,GAAoB,CAAE,SAAU,IACpD,gBAAoB,KAAY,CAAE,UAAW,EAAQ,YAAa,QAAS,aACzE,IAGH,IAAW,IACZ,gBAAoB,IAAkB,KAClC,gBAAoB,KAAM,CAAE,UAAW,IACrC,GACA,gBAAoB,KAAM,CAAE,KAAM,GAAM,GAAI,IACxC,gBAAoB,KAAY,CAAE,UAAW,EAAQ,QAAS,QAAS,SACrE,IAIN,GACA,gBAAoB,KAAM,CAAE,KAAM,GAAM,GAAI,GAAI,UAAW,EAAQ,SAC/D,MClKlB,KAAM,IAAY,QAChB,GAAU,EACR,KAAM,CACJ,WAAY,YACZ,WAAY,MACZ,UAAW,OACX,YAAa,EAAM,QAAQ,IAE7B,QAAS,CACP,OAAQ,EAAM,QAAQ,MAG1B,CAAE,KAAM,wBAWJ,GAAY,CAAC,CACjB,QACA,UACA,QACA,cACI,CACJ,KAAM,GAAU,KAEhB,MACE,iBAAoB,KAAM,CAAE,MAAO,IAC/B,gBAAoB,KAAU,CAAE,WAAY,cAC1C,gBAAoB,KAAc,CAClC,QAAS,CAAE,UAAW,EAAQ,MAC9B,QAAS,QACT,UAAW,IAEX,gBAAoB,GAAgB,CAAE,KAAM,KAG9C,gBAAoB,KAAU,CAAE,WAAY,cAC1C,gBAAoB,KAAc,CAClC,QAAS,CAAE,UAAW,EAAQ,MAC9B,QAAS,UACT,UAAW,IAEX,gBAAoB,GAAgB,CAAE,KAAM,KAG9C,GACA,gBAAoB,KAAU,CAAE,WAAY,cACxC,gBAAoB,KAAc,CAClC,QAAS,CAAE,UAAW,EAAQ,MAC9B,QAAS,cACT,UAAW,IAEX,gBAAoB,GAAgB,CAAE,KAAM,KAIhD,IAiBD,YAAoB,EAAO,CAChC,KAAM,CAAE,QAAO,QAAO,kBAAiB,YAAa,EACpD,MACE,iBAAoB,GAAc,CAChC,SAAU,QACV,MAAO,UAAS,EAAM,QACtB,gBAAiB,GAEf,gBAAoB,GAAW,CAC/B,MAAO,EAAM,KACb,QAAS,EAAM,QACf,MAAO,EAAM,MACb,SAAU,K,gBC1FlB,KAAM,IAAY,QAChB,GAAU,EACR,KAAM,CACJ,WAAY,YACZ,WAAY,MACZ,UAAW,OACX,YAAa,EAAM,QAAQ,IAE7B,QAAS,CACP,OAAQ,EAAM,QAAQ,MAG1B,CAAE,KAAM,gCASH,YAA4B,EAAO,C,OACxC,KAAM,CAAE,QAAO,QAAO,mBAAoB,EACpC,EAAU,KAEhB,GAAI,EAAM,OAAS,gBACjB,MACE,iBAAoB,GAAY,CAC9B,MAAO,UAAS,EAAM,QACtB,gBAAiB,EACjB,MAAO,IAKb,KAAM,CAAE,OAAM,SAAU,EAClB,CAAE,UAAS,YAAa,EAExB,EAAc,GAAG,EAAS,eAAe,EAAM,OAC/C,GAAgB,GAAW,GAAG,EAAQ,UAAU,EAAQ,MACxD,GAAgB,EAAM,QAAQ,QAAQ,OAAQ;AAAA,GAC9C,GAAc,MAAM,QAAN,eAAa,QAAQ,OAAQ;AAAA,GAC3C,GAAa,KAAK,UAAU,EAAM,OAAW,GAEnD,MACE,iBAAoB,GAAY,CAC9B,MAAO,UAAS,EAAM,QACtB,gBAAiB,EACjB,MAAO,CAAE,KAAM,EAAa,QAAS,GAAe,MAAO,KAEzD,IACA,gBAAoB,KAAU,CAAE,WAAY,cACxC,gBAAoB,KAAc,CAClC,QAAS,CAAE,UAAW,EAAQ,MAC9B,QAAS,UACT,UAAW,EAAU,GAAG,KAAkB,SAE1C,gBAAoB,GAAgB,CAAE,KAAM,MAGhD,gBAAoB,WAAgB,KAClC,gBAAoB,KAAS,CAAE,UAAW,KAAM,UAAW,EAAQ,UACnE,gBAAoB,KAAU,CAAE,WAAY,cAC1C,gBAAoB,KAAc,CAClC,QAAS,CAAE,UAAW,EAAQ,MAC9B,QAAS,wBAGX,gBAAoB,GAAa,CAAE,SAAU,OAAQ,KAAM,GAAY,mBAAoB,O,gBC5ErG,YAA2B,EAAI,CAC7B,KAAM,GAAgB,SAAS,cAAc,OAC7C,SAAc,aAAa,KAAM,GAC1B,EAMT,YAAwB,EAAU,CAChC,SAAS,KAAK,aACZ,EACA,SAAS,KAAK,iBAAiB,oBAkB5B,YAAmB,EAAI,CAC5B,KAAM,GAAc,OAAO,MAE3B,UACE,UAAwB,CAEtB,KAAM,GAAiB,SAAS,cAAc,IAAI,KAE5C,EAAa,GAAkB,GAAkB,GAGvD,MAAK,IACH,GAAe,GAIjB,EAAW,YAAY,EAAY,SAE5B,UAAyB,CAC9B,EAAY,QAAQ,SAChB,EAAW,WAAW,SAAW,IACnC,EAAW,WAIjB,CAAC,IAaH,YAAuB,CACrB,MAAK,GAAY,SACf,GAAY,QAAU,SAAS,cAAc,QAExC,EAAY,QAGrB,MAAO,KAGT,OAAe,KChFf,KAAM,IAA2B,mBAEjC,aAGC,CACC,KAAM,CAAC,EAAQ,GAAa,SAAS,IAAM,CACzC,KAAM,GAAM,aAAa,QAAQ,IACjC,MAAO,GAAM,KAAK,MAAM,GAAO,KAG3B,EAAW,YAAY,CAAC,EAAK,IAAU,CAC3C,KAAM,GAAM,aAAa,QAAQ,IAE3B,EAAY,IADA,EAAM,KAAK,MAAM,GAAO,IACP,GAAM,GACzC,EAAU,GACV,aAAa,QAAQ,GAA0B,KAAK,UAAU,KAC7D,IAEH,MAAO,CAAE,SAAQ,YAGnB,YAA+B,EAG9B,CACC,KAAM,CAAE,SAAQ,YAAa,KAEvB,EAAW,YAAY,IAAM,CACjC,EAAS,EAAW,KACnB,CAAC,EAAU,IAEd,MAAO,CAAE,KAAM,EAAO,KAAe,GAAM,YAGtC,YAAwB,EAG9B,CACC,KAAM,CAAE,OAAM,YAAa,GAAsB,GACjD,MAAO,CAAE,KAAM,IAAS,GAAO,KAAM,GCjBvC,KAAM,IAAY,QAChB,CACE,6BAA8B,CAC5B,KAAM,CAAE,UAAW,cACnB,OAAQ,CAAE,UAAW,eAEvB,4BAA6B,CAC3B,KAAM,CAAE,UAAW,aAAc,QAAS,IAC1C,OAAQ,CAAE,UAAW,aAAc,QAAS,IAE9C,eAAgB,CACd,SAAU,YAEZ,SAAU,CACR,OAAQ,IACR,SAAU,QACV,SAAU,SACV,KAAM,EACN,MAAO,EACP,IAAK,EACL,OAAQ,GAEV,IAAK,CACH,SAAU,WACV,gBAAiB,cACjB,aAAc,OACd,OAAQ,sCACR,UAAW,yCACX,OAAQ,KACR,gBAAiB,gBACjB,UACE,gFAEJ,YAAa,CACX,MAAO,OACP,OAAQ,OACR,gBAAiB,cACjB,aAAc,OACd,OAAQ,kBACR,OAAQ,KACR,gBAAiB,gBACjB,UACE,oEAEJ,KAAM,CACJ,SAAU,WACV,MAAO,QACP,OAAQ,OAGZ,CAAE,KAAM,oCAyBH,YAAgC,EAAO,CAC5C,KAAM,CAAE,YAAW,QAAO,cAAa,YAAa,EAC9C,CAAE,OAAM,QAAS,eAAe,GAChC,EAAgB,UAAU,gBAC1B,EAAa,OAAO,MACpB,CAAC,EAAW,IAAgB,WAC5B,GAAU,KAEV,GAAS,YAAY,IAAM,CAC/B,GAAI,EAAW,QAAS,CACtB,KAAM,IAAgB,EAAW,QAAQ,wBACnC,GAAU,KAAK,IAAI,GAAc,MAAO,GAAc,QAEtD,GAAc,IACd,GACJ,GAAc,EAAK,IAAU,GAAc,OAAS,EAAI,GACpD,GACJ,GAAc,EAAK,IAAU,GAAc,QAAU,EAAI,GACrD,GAAU,GAAU,EAAI,GAExB,GAAY,IACZ,GAAW,GAAc,EAAI,GAAc,MAAQ,EAAI,GACvD,GACJ,GAAc,EAAK,IAAU,GAAc,QAAU,EAAI,GAAU,GAErE,GAAa,CACX,WACA,UACA,WACA,eACA,WACA,YACA,iBAGH,IAaH,MAXA,WAAU,IACR,QAAO,iBAAiB,SAAU,IAClC,OAAO,iBAAiB,SAAU,IAC3B,IAAM,CACX,OAAO,oBAAoB,SAAU,IACrC,OAAO,oBAAoB,SAAU,MAEtC,CAAC,KAEJ,gBAAgB,GAAQ,CAAC,EAAW,QAAS,KAExC,EAKH,MAAM,cAAc,MAAM,SAAU,KAChC,MAAM,cAAc,MAAO,CAAE,UAAW,GAAQ,eAAgB,IAAK,GACnE,GAEF,aACA,MAAM,cAAc,MAAO,CAAE,UAAW,GAAQ,UAC5C,MAAM,cAAc,kBAAmB,CAAE,YAAa,GACpD,MAAM,cAAc,MAAM,SAAU,KAClC,MAAM,cAAc,MAAO,CAC3B,UAAW,GAAQ,IACnB,cAAe,MACf,MAAO,CACL,KAAM,iBAAW,QACjB,IAAK,iBAAW,OAChB,MAAO,iBAAW,QAClB,OAAQ,iBAAW,QACnB,YAAa,iBAAW,aAE1B,QAAS,EACT,UAAW,EACX,KAAM,SACN,SAAU,GAER,MAAM,cAAc,MAAO,CAAE,UAAW,GAAQ,eAElD,MAAM,cAAc,MAAO,CAC3B,UAAW,GAAQ,KACnB,cAAe,OACf,MAAO,CACL,KAAM,iBAAW,SACjB,IAAK,iBAAW,QAChB,MAAO,iBAAW,YAGlB,MAAM,cAAc,WAAY,CAAE,QAAS,KAAM,UAAW,IAC1D,GAEF,MAAM,cAAc,WAAY,KAAM,OAKhD,IA9CG,MAAM,cAAc,MAAM,SAAU,KAAM,G,gBC7HrD,KAAM,IAAgB,QACpB,GAAU,EACR,KAAM,CACJ,QAAS,OACT,aAAc,SACd,QAAS,EACT,UAAW,UAEb,SAAU,CACR,MAAO,OACP,OAAQ,WAEV,QAAS,CACP,MAAO,EAAM,QAAQ,QAAQ,MAE/B,UAAW,CACT,MAAO,EAAM,QAAQ,UAAU,MAEjC,MAAO,CACL,SAAU,SACV,cAAe,YACf,WAAY,IACZ,cAAe,OAGnB,CAAE,KAAM,8BAIH,YAA0B,CAC/B,QAAQ,UACR,WAAW,GACX,OAAO,IACP,OAAO,gBAAoB,KAAU,MACrC,QACA,UACA,SACC,CACD,KAAM,GAAU,KAEhB,MAAI,GAEA,gBAAoB,IAAM,CACxB,MAAO,EACP,UAAW,KAAW,EAAQ,KAAM,EAAQ,UAC5C,UAAW,QAET,EACA,gBAAoB,OAAQ,CAAE,UAAW,EAAQ,OAAS,IAMhE,gBAAoB,IAAM,CACxB,MAAO,EACP,UAAW,KAAW,EAAQ,KAAM,EAAQ,IAC5C,GAAI,EACJ,UAAW,EACX,QAAS,GAEP,EACA,gBAAoB,OAAQ,CAAE,UAAW,EAAQ,OAAS,IChFlE,KAAM,IAAY,QAChB,GAAU,EACR,MAAO,CACL,OAAQ,EAAM,QAAQ,EAAG,GACzB,QAAS,OACT,aAAc,SACd,gBAAiB,cACjB,QAAS,EAAM,QAAQ,MAG3B,CAAE,KAAM,+BAaH,YAA2B,EAAO,CACvC,KAAM,CAAE,SAAU,EACZ,EAAU,KAChB,MACE,iBAAoB,MAAO,CAAE,UAAW,EAAQ,OAC5C,EAAM,IAAI,CAAC,EAAM,IACjB,gBAAoB,GAAkB,CAAE,IAAK,EAAQ,KAAM,MC3BnE,KAAM,IAAyB,GAAc,CAG3C,KAAM,GAAY,IAAc,OAAS,MAAQ,MAEjD,MAAO;AAAA,iBACQ;AAAA,kBACC;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,KAIZ,GAAW,IACX,GAAc,GAoBd,GAAY,QAChB,GAAU,EACR,KAAM,CACJ,SAAU,WACV,QAAS,OACT,SAAU,aACV,WAAY,UAEd,UAAW,CACT,SAAU,OACV,eAAgB,EAChB,uBAAwB,CACtB,QAAS,SAGb,KAAM,CACJ,SAAU,WACV,MAAO,GACP,OAAQ,eAAe,QACvB,WAAY,gBACZ,cAAe,QAEjB,SAAU,CACR,KAAM,CAAC,GACP,WAAY,0BAA0B,GACpC,EAAM,QAAQ,UAGlB,UAAW,CACT,MAAO,CAAC,GACR,WAAY,2BAA2B,GACrC,EAAM,QAAQ,UAGlB,WAAY,CACV,QAAS,GAEX,OAAQ,CACN,SAAU,YAEZ,WAAY,CACV,KAAM,CAAC,EAAM,QAAQ,IAEvB,YAAa,CACX,MAAO,CAAC,EAAM,QAAQ,MAG1B,CAAE,KAAM,kCAIV,YACE,EACA,CACA,KAAM,CAAC,CAAC,EAAY,GAAc,GAAa,MAAM,SAEtD,CAAC,EAAG,IAEH,aAAM,gBAAgB,IAAM,CAC1B,KAAM,GAAK,EAAI,QACf,GAAI,CAAC,EAAI,CACP,EAAU,CAAC,EAAG,IACd,OAGF,KAAM,GAAe,IAAM,CACzB,KAAM,GAAO,EAAG,WACV,EAAQ,EAAG,YAAc,EAAG,YAAc,EAAG,WACnD,EAAU,CAAC,EAAM,KAGnB,WAEA,EAAG,iBAAiB,SAAU,GAC9B,OAAO,iBAAiB,SAAU,GAI3B,IAAM,CACX,EAAG,oBAAoB,SAAU,GACjC,OAAO,oBAAoB,SAAU,KAEtC,CAAC,IAEG,CAAC,EAAY,GAKtB,YACE,EACA,EACA,EACA,CACA,KAAM,CAAC,EAAc,GAAmB,MAAM,SAAS,GAEvD,aAAM,gBAAgB,IAAM,CAC1B,GAAI,IAAiB,EACnB,OAGF,KAAM,GAAY,YAAY,MACxB,EAAK,sBAAsB,GAAa,CAC5C,GAAI,CAAC,EAAI,QACP,OAEF,KAAM,GAAgB,EAAY,EAC5B,EAAkB,KAAK,IAAI,GAAgB,EAAiB,EAE5D,GAAe,KADa,IAAI,EAAa,GACP,KAAK,KAAK,GAEtD,EAAI,QAAQ,SAAS,CAAE,KAAM,KAE7B,KAAM,IAAkB,EAAe,GACnC,KAAK,KAAK,KAAkB,KAAK,KAAK,IACxC,EAAgB,GAEhB,EAAgB,MAOpB,MAAO,IAAM,qBAAqB,IACjC,CAAC,EAAK,EAAc,EAAO,IAEvB,EASF,YAA8B,EAAO,CAC1C,KAAM,CACJ,aAAa,IACb,cAAc,GACd,oBAAoB,EACpB,cACG,GACD,EACE,EAAU,GAAU,GACpB,EAAM,MAAM,SAEZ,CAAC,EAAY,GAAe,GAAkB,GAC9C,GAAkB,GAAgB,EAAK,EAAa,GAEpD,GAAqB,IAAa,CAElC,CADO,EAAI,SAIf,GAAgB,GAAW,EAAa,CAAC,IAG3C,MACE,OAAM,cAAc,MAAO,IAAK,EAAY,UAAW,EAAQ,MAC3D,MAAM,cAAc,KAAM,CAC1B,UAAW,GACX,UAAW,MACX,KAAM,SACN,UAAW,EAAQ,UACnB,IAAK,GAEH,GAEF,MAAM,cAAc,MAAO,CAC3B,UAAW,WAAW,EAAQ,KAAM,EAAQ,SAAU,EACnD,EAAQ,YAAa,IAAe,MAGvC,MAAM,cAAc,MAAO,CAC3B,UAAW,WAAW,EAAQ,KAAM,EAAQ,UAAW,EACpD,EAAQ,YAAa,IAAgB,MAGxC,EAAa,GACb,MAAM,cAAc,WAAY,CAC9B,MAAO,cACP,QAAS,IAAM,GAAkB,IACjC,UAAW,WAAW,EAAQ,OAAQ,EAAQ,WAAY,KAExD,MAAM,cAAc,gBAAiB,OAGzC,EAAc,GACd,MAAM,cAAc,WAAY,CAC9B,MAAO,eACP,QAAS,IAAM,GAAkB,IACjC,UAAW,WAAW,EAAQ,OAAQ,EAAQ,YAAa,KAEzD,MAAM,cAAc,iBAAkB,QC7OlD,KAAM,IAAY,QAChB,CACE,MAAO,CACL,MAAO,UACP,WAAY,QACZ,WAAY,SACZ,UAAW,UAEb,KAAM,CACJ,MAAO,UACP,WAAY,QACZ,WAAY,SACZ,UAAW,WAGf,CAAE,KAAM,uBAGH,YAAmB,EAAO,CAC/B,KAAM,GAAU,GAAU,GACpB,CAAE,YAAW,SAAU,EAC7B,MAAO,GACL,MAAM,cAAc,OAAQ,CAC1B,UAAW,EAAQ,EAAQ,QAAU,QACrC,MAAO,CAAE,SAAU,SAEjB,EAAQ,MAAM,cAAc,MAAM,SAAU,KAAM,UAAO,MAAM,cAAc,MAAM,SAAU,KAAM,WAGvG,MAAM,cAAc,OAAQ,CAAE,UAAW,EAAQ,EAAQ,QAAU,SAC/D,EAAQ,QAAU,QCtC1B,KAAM,IAAgB,WAAK,IACzB,wDAA0B,KAAK,GAAM,EAAE,QAAS,EAAE,kBAoC7C,YAAmB,EAAO,CAC/B,KAAM,CAAE,YAAa,eAAS,gBAC9B,MACE,iBAAoB,WAAU,CAAE,SAAU,gBAAoB,EAAU,OACpE,gBAAoB,GAAe,IAAK,KCnChD,KAAM,IAAY,QAChB,GAAU,EACR,SAAU,CACR,UAAW,CACT,eAAgB,WAChB,OAAQ,aAAa,EAAM,QAAQ,UAErC,aAAc,CACZ,OAAQ,aAAa,EAAM,QAAQ,SACnC,QAAS,EAAM,QAAQ,IAEzB,OAAQ,CACN,UAAW,aACX,SAAU,SACV,cAAe,SACf,WAAY,IACZ,OAAQ,EACR,QAAS,EAAM,QAAQ,EAAG,EAAG,EAAG,KAChC,aAAc,GAEhB,OAAQ,CACN,gBAAiB,EAAM,QAAQ,WAAW,OAE5C,OAAQ,CACN,gBAAiB,EAAM,QAAQ,WAAW,OAE5C,sBAAuB,CACrB,gBAAiB,EAAM,QAAQ,WAAW,SAG5C,MAAO,CACL,MAAO,EAAM,QAAQ,MAEvB,QAAS,CACP,SAAU,WAIhB,CAAE,KAAM,6BASJ,GAAa,CACjB,KAAM,CAAC,CAAE,SAAQ,YAAW,cAAa,KAAY,CACnD,KAAM,GAAO,OAAO,GAAU,QAAQ,OAAQ,IACxC,EAAQ,iBAAiB,KAAK,GAAa,IACjD,MAAO,CAAC,GAAU,EAChB,gBAAoB,GAAa,CAAE,SAAU,EAAM,GAAI,KAAM,IAE7D,gBAAoB,OAAQ,CAAE,UAAW,KAAc,GACnD,KAYH,YAAyB,EAAO,CACrC,KAAM,CAAE,UAAS,UAAU,MAAO,cAAe,EAC3C,EAAU,KAChB,MACE,OAAM,cAAc,cAAe,CACjC,cAAe,IAAY,MAAQ,CAAC,KAAO,GAC3C,UAAW,EAAQ,SACnB,SAAU,EACV,WAAY,GACZ,WAAY,I,gBCzElB,KAAM,IAAgB,QACpB,GAAU,EACR,KAAM,CACJ,YAAa,EAAM,QAAQ,MAG/B,CAAE,KAAM,kCASJ,GAAuB,CAAC,CAAE,UAAS,OAAM,aAAc,CAC3D,KAAM,GAAU,KACV,CAAC,EAAO,GAAY,WAEpB,EAAiB,SAAY,CACjC,EAAQ,IACR,GAAI,CACF,KAAM,GAAQ,gBACP,EAAP,CACA,EAAS,QAAQ,GAAK,EAAE,QAAU,wCAClC,CACA,EAAQ,MAIN,EAAgB,EAAQ,SAAS,KAEvC,MACE,OAAM,cAAc,SAAU,CAAE,OAAQ,GAAM,SAAU,EAAM,QAAS,CAAE,KAAM,EAAQ,OACnF,MAAM,cAAc,eAAgB,KAClC,MAAM,cAAc,EAAe,CAAE,SAAU,WAEjD,MAAM,cAAc,aAAc,CAClC,QAAS,EAAQ,SAAS,MAC1B,UAAW,GAAS,MAAM,cAAc,WAAY,CAAE,MAAO,SAAW,KAExE,MAAM,cAAc,OAAQ,CAAE,MAAO,UAAW,QAAS,YAAa,QAAS,GAAkB,YAOzG,OAAe,KC1Cf,KAAM,IAAY,QAChB,GAAU,EACR,OAAQ,CACN,WAAY,EAAM,QAAQ,IAE5B,MAAO,CACL,SAAU,GAEZ,YAAa,CACX,QAAS,GAEX,cAAe,CACb,QAAS,EAAM,QAAQ,EAAG,MAG9B,CAAE,KAAM,uBAGH,YAA4B,EAAQ,CACzC,KAAM,GAAU,KACV,CAAC,EAAM,GAAW,SAAS,IAC3B,EAAkB,OAAO,oBACzB,EAAW,cACf,QAAQ,IAAM,EAAgB,eAAgB,CAAC,IAC/C,IAGI,EAAkB,IAAM,CAC5B,EAAS,QAAQ,GAAW,EAAQ,WAGtC,MACE,OAAM,cAAc,OAAQ,CAC1B,KAAM,QAAQ,EAAS,QACvB,UAAW,GACX,SAAU,KACV,QAAS,CAAE,MAAO,EAAQ,SAExB,MAAM,cAAc,YAAa,CAAE,QAAS,CAAE,KAAM,EAAQ,QAAW,kBAIvE,MAAM,cAAc,cAAe,CAAE,SAAU,GAAM,QAAS,CAAE,KAAM,EAAQ,cAC5E,MAAM,cAAc,KAAM,KACxB,EAAS,IAAI,GACb,MAAM,cAAc,qBAAsB,CACxC,IAAK,EAAQ,SAAS,MACtB,QAAS,EACT,KAAM,EACN,QAAS,OAMf,MAAM,cAAc,cAAe,CAAE,QAAS,CAAE,KAAM,EAAQ,gBAC5D,MAAM,cAAc,OAAQ,CAAE,QAAS,GAAmB,gB,uCC1DpE,KAAM,IAAY,QAChB,CACE,UAAW,CACT,SAAU,uBAGd,CAAE,KAAM,6BAGH,YAAyB,EAAO,C,MACrC,KAAM,CAAC,EAAO,GAAY,eAAS,IAC7B,EAAY,iBACZ,EAAU,KAEV,EAAiB,GAAc,CAC/B,KACF,EAAS,IAIb,MACE,iBAAoB,KAAS,CAC3B,MAAO,KAAM,QAAN,OAAgB,EAAM,MAAQ,GACrC,UAAW,EAAM,UACjB,qBAAsB,CAAC,GAErB,gBAAoB,KAAc,CAClC,KAAM,EAAM,KACZ,KAAM,EAAM,KACZ,UAAW,EACX,mBAAoB,EAAQ,a,gBCzC7B,YAAkB,EAAO,CAC9B,KAAM,CAAC,EAAW,GAAgB,eAAS,IAE3C,sBAAU,IAAM,CACd,KAAM,GAAS,WAAW,IAAM,EAAa,IAAO,KACpD,MAAO,IAAM,aAAa,IACzB,IAEI,EACL,gBAAoB,KAAgB,IAAK,EAAO,cAAe,aAE/D,gBAAoB,MAAO,CAAE,MAAO,CAAE,QAAS,U,oFCJnD,KAAM,IAAY,QAChB,GAAU,EACR,KAAM,CACJ,SAAU,cACV,QAAS,EAAM,QAAQ,EAAG,EAAG,EAAG,MAElC,SAAU,CACR,OAAQ,EACR,MAAO,EAAM,QAAQ,YAEvB,MAAO,CACL,MAAO,EAAM,QAAQ,cAGzB,CAAE,KAAM,wBAgBH,YAAoB,EAAO,CAChC,KAAM,CAAE,OAAM,QAAO,WAAY,EAC3B,EAAU,KAEhB,MACE,iBAAoB,MAAO,KACvB,gBAAoB,KAAS,MAC7B,gBAAoB,EAAM,CAAE,GAAI,EAAM,QAAS,EAAS,UAAW,QACjE,gBAAoB,IAAK,CAAE,QAAS,OAAQ,WAAY,SAAU,UAAW,EAAQ,MACnF,gBAAoB,IAAK,CAAE,UAAW,EAAQ,SAAU,WAAY,iBAAkB,EAAG,GACvF,gBAAoB,KAAY,KAC9B,gBAAoB,SAAU,KAAM,KAGxC,gBAAoB,KAAW,CAAE,UAAW,EAAQ,WCpChE,KAAM,IAAa,GAAU,CAC3B,KAAM,CAAE,gBAAiB,EAEzB,GAAK,EAEE,IAAI,MAAO,IAAiB,SACjC,MAAO,iBAAoB,WAAgB,KAAM,kBAAqB,EAAc,cAC/E,GAAI,CAAC,EAAa,KACvB,MAAO,iBAAoB,WAAgB,KAAM,kBAAqB,EAAa,KAAM,kBAJzF,OAAO,MAOT,MACE,iBAAoB,EAAQ,CAAE,GAAI,EAAa,KAAM,QAAS,aAC1D,EAAa,OAMR,GAGV,aAA4B,YAAU,CACvC,YAAY,EAAO,CACjB,MAAM,GACN,KAAK,MAAQ,CACX,MAAO,OACP,UAAW,QAIf,kBAAkB,EAAO,EAAW,CAElC,QAAQ,MAAM,yBAAyB,YAAgB,KACvD,KAAK,SAAS,CAAE,QAAO,cAGzB,QAAS,CACP,KAAM,CAAE,eAAc,YAAa,KAAK,MAClC,CAAE,SAAU,KAAK,MAEvB,MAAK,GAKH,gBAAoB,GAAY,CAAE,MAAO,uBAA0B,MAAO,GACtE,gBAAoB,GAAW,CAAE,aAAc,KAL5C,ICzCP,GAAY,QAChB,GAAU,EACR,UAAW,CACT,QAAS,EACT,eAAgB,CACd,cAAe,IAGnB,OAAQ,CACN,QAAS,EAAM,QAAQ,EAAG,EAAG,EAAG,MAElC,YAAa,CACX,WAAY,KAEd,gBAAiB,CACf,WAAY,EAAM,QAAQ,IAE5B,aAAc,GACd,aAAc,GACd,cAAe,GACf,UAAW,CACT,QAAS,UAGb,CAAE,KAAM,sBAMJ,GAAsB,QAC1B,GAAU,EACR,KAAM,CACJ,QAAS,eACT,QAAS,EAAM,QAAQ,EAAG,EAAG,EAAG,GAChC,MAAO,WAGX,CAAE,KAAM,yCACR,MAEI,GAAiB,CACrB,KAAM,CACJ,KAAM,CACJ,QAAS,OACT,cAAe,UAEjB,WAAY,CACV,QAAS,OACT,cAAe,SACf,OAAQ,QAEV,SAAU,CACR,QAAS,OACT,cAAe,SACf,OAAQ,oBACR,aAAc,SAGlB,YAAa,CACX,WAAY,CACV,KAAM,GAER,SAAU,CACR,KAAM,KAuDL,YAAkB,EAAO,CAC9B,KAAM,CACJ,QACA,YACA,UAAU,GACV,WACA,eACA,qBACA,UACA,WACA,cACA,eACA,QACA,UACA,oBACA,WACA,iBACA,mBACA,aACA,aACA,yBACE,EACE,GAAU,KAKhB,GAAI,IAAkB,GAClB,GAAsB,GACtB,GAEF,EADyB,MAAM,UACtB,QAAQ,IAAQ,CACvB,GAAkB,IACb,MACA,GAAe,KAAK,KAEzB,GAAsB,IACjB,MACA,GAAe,YAChB,OAMR,KAAM,IAAe,IAEjB,gBAAoB,MAAO,CAAE,UAAW,GAAQ,iBAC5C,GAAa,gBAAoB,MAAO,CAAE,UAAW,GAAQ,WAAa,GAC1E,IAKF,GACJ,GAAuB,GAAe,CAAE,gBAAiB,IAE3D,MACE,iBAAoB,KAAM,CAAE,MAAO,GAAiB,UAAW,IAC3D,gBAAoB,GAAe,IAAK,IACtC,GACA,gBAAoB,IAAY,CAC9B,QAAS,CACP,KAAM,GAAQ,OACd,MAAO,GAAQ,YACf,UAAW,GAAQ,gBACnB,OAAQ,GAAQ,aAChB,OAAQ,GAAQ,aAChB,QAAS,GAAQ,eAEnB,MAAO,EACP,UAAW,KACX,OAAQ,GACR,MAAO,IAAK,GACZ,qBAAsB,MACnB,KAGL,IACA,gBAAoB,GAAqB,KAAM,IAE/C,GAAW,gBAAoB,KAAS,MACxC,gBAAoB,IAAa,CACjC,UAAW,KAAW,GAAe,EAClC,GAAQ,WAAY,KAEvB,MAAO,IAEL,GAEF,IACA,gBAAoB,KAAa,CAAE,UAAW,IAAoB,IAElE,GAAY,gBAAoB,GAAY,IAAK,M,gBC5N3D,KAAM,IAAY,QAChB,GAAU,EACR,KAAM,CACJ,SAAU,WACV,WAAY,GAEd,QAAS,CACP,SAAU,WACV,IAAK,MACL,KAAM,MACN,UAAW,wBACX,SAAU,GACV,WAAY,OACZ,MAAO,EAAM,QAAQ,cAEvB,YAAa,CACX,SAAU,OACV,IAAK,MACL,KAAM,MACN,UAAW,wBACX,SAAU,WACV,UAAW,YACX,QAAS,gBAEX,OAAQ,CACN,MAAO,MACP,UAAW,qBAEb,aAAc,KAEhB,CAAE,KAAM,mBAyBJ,GAAoB,CACxB,WAAY,GACZ,QAAS,GACT,KAAM,IACN,IAAK,KAGM,GAAmB,CAAC,CAC/B,UACA,QACA,UACA,SACI,CACJ,GAAI,MAAM,GACR,MAAO,OAGT,KAAM,GAAY,GAAY,GAAkB,IAC1C,EAAc,EAAU,EAAY,EAAQ,EAElD,MAAI,GAAc,EAAY,EACrB,EAAQ,OAAO,MACb,EAAc,EAAa,GAAI,GACjC,EAAQ,OAAO,QAGjB,EAAQ,OAAO,IAUjB,YAAe,EAAO,CAC3B,KAAM,CAAC,EAAU,GAAe,SAAS,MACnC,CAAE,WAAW,IAAqB,EAClC,EAAU,GAAU,GACpB,CAAE,WAAY,WACd,CAAE,QAAO,aAAY,UAAS,OAAM,OAAK,gBAAgB,IAC1D,MACA,GAGC,GAAe,EAAa,KAAK,MAAM,EAAQ,IAAO,EACtD,GAAW,KAAQ,IAAM,KAAK,MAAM,GAAS,GAE7C,CAAC,GAAY,IAAiB,SAAS,IAE7C,iBAAU,IAAM,CACd,KAAM,IAAO,EACP,GAAkB,IAAM,GAAc,IACtC,GAAiB,IAAM,GAAc,IAC3C,MAAI,KAAQ,GACV,IAAK,iBAAiB,aAAc,IACpC,GAAK,iBAAiB,aAAc,IAE7B,IAAM,CACX,GAAK,oBAAoB,aAAc,IACvC,GAAK,oBAAoB,aAAc,MAGpC,IAAM,CACX,GAAc,MAEf,CAAC,GAAa,IAGf,MAAM,cAAc,MAAO,CAAE,IAAK,EAAa,UAAW,EAAQ,MAC9D,MAAM,cAAc,OAAQ,CAC5B,cAAe,OACf,QAAS,GACT,YAAa,GACb,WAAY,GACZ,YAAa,EAAS,CAAE,UAAS,MAAO,GAAU,UAAS,SAC3D,UAAW,EAAQ,SAEnB,IAAe,GACf,MAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,aAAe,IAE/D,MAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,SAC5C,MAAM,GAAS,MAAQ,GAAG,KAAW,MCjIjD,KAAM,IAAY,QAChB,CACE,KAAM,CACJ,OAAQ,OACR,MAAO,MAGX,CAAE,KAAM,uBASH,YAAmB,EAAO,CAC/B,KAAM,GAAU,GAAU,GACpB,CACJ,QACA,YACA,WACA,UACA,WACA,cACA,OACA,UACA,aACE,EAEE,GAAa,CACjB,UACA,cACA,YACA,MAAO,GAGT,MACE,OAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,MAC5C,MAAM,cAAc,SAAU,CAC9B,MAAO,EACP,UAAW,EACX,SAAU,EACV,QAAS,EACT,KAAM,GAEJ,MAAM,cAAc,MAAO,IAAK,OCrDnC,YAAqB,EAAO,CACjC,KAAM,CAAE,QAAO,WAAW,kBAAqB,EACzC,CAAE,WAAY,WACpB,GAAI,MAAM,GACR,MAAO,MAET,GAAI,GAAU,KAAK,MAAM,EAAQ,IAAM,KAAO,IAC1C,EAAU,KACZ,GAAU,KAEZ,KAAM,GAAc,EAAS,CAC3B,UACA,MAAO,EACP,QAAS,GACT,IAAK,MAEP,MACE,OAAM,cAAc,QAAS,CAAE,MAAO,GAAG,MACrC,MAAM,cAAc,OAAQ,KAC1B,MAAM,cAAc,KAAM,CAC1B,QAAS,EACT,YAAa,EACb,WAAY,EACZ,YAAa,M,kGChCvB,KAAM,IAAY,QAChB,IACE,QAAa,CACX,KAAM,CACJ,SAAU,WACV,MAAO,MACP,cAAe,UAGrB,CAAE,KAAM,4BAmBV,OAhBuB,IAAM,CAC3B,KAAM,GAAU,KAChB,MACE,iBAAoB,KAAS,CAC3B,UAAW,EAAQ,KACnB,KAAM,OACN,MAAO,8BAEL,gBAAoB,OAAQ,CAC5B,EAAG,4EACH,KAAM,cCvBd,KAAM,IAAY,QAChB,IACE,QAAa,CACX,KAAM,CACJ,SAAU,WACV,MAAO,MACP,cAAe,UAGrB,CAAE,KAAM,4BAmBV,OAhBuB,IAAM,CAC3B,KAAM,GAAU,KAChB,MACE,iBAAoB,KAAS,CAC3B,UAAW,EAAQ,KACnB,KAAM,OACN,MAAO,8BAEL,gBAAoB,OAAQ,CAC5B,EAAG,oFACH,KAAM,cCNd,KAAM,IAAiB,QACpB,GACC,QAAa,CACX,KAAM,CACJ,YAAa,CACX,UAAW,EAAM,QAAQ,KAG7B,MAAO,CACL,aAAc,EACd,SAAU,WACV,gBAAiB,EAAM,QAAQ,WAAW,MAC1C,OAAQ,oBACR,SAAU,GACV,QAAS,sBACT,WAAY,EAAM,YAAY,OAAO,CAAC,eAAgB,eACtD,WAAY,iBACZ,UAAW,CACT,WAAY,EAAM,QAAQ,WAAW,MACrC,aAAc,MAItB,CAAE,KAAM,6BACR,MAWI,GAAY,QACf,GACC,QAAa,CACX,YAAa,CACX,OAAQ,GAAG,EAAM,QAAQ,SACzB,SAAU,KAEZ,MAAO,CACL,UAAW,UACX,WAAY,OACZ,SAAU,GACV,WAAY,EAAM,WAAW,WAC7B,MAAO,EAAM,QAAQ,KAAK,QAC1B,gBAAiB,CACf,MAAO,EAAM,QAAQ,KAAK,UAG9B,MAAO,CACL,QAAS,OACT,SAAU,QAEZ,KAAM,CACJ,OAAQ,GAEV,SAAU,GAEV,KAAM,CACJ,QAAS,OACT,cAAe,YAGrB,CAAE,KAAM,oBAyBH,YAAyB,EAAO,CACrC,KAAM,CACJ,WACA,QACA,QACA,cACA,WACA,WACA,eACA,SAAS,GACT,WAAW,IACT,EACE,GAAU,KACV,CAAC,GAAO,IAAY,eACxB,GAAa,GAAW,GAAK,KAEzB,CAAC,GAAQ,IAAW,eAAS,IAEnC,gBAAU,IAAM,CACd,GAAS,EAAW,GAAK,KACxB,CAAC,EAAc,IAElB,gBAAU,IAAM,CACV,IAAa,QACf,GAAS,IAEV,CAAC,IAEJ,KAAM,IAAgB,IAAU,CAC9B,GAAS,GAAM,OAAO,OACtB,EAAS,GAAM,OAAO,QAGlB,GAAe,IAAU,CAC7B,GAAI,EAAU,CACZ,GAAM,iBACN,OAEF,GAAQ,IACF,GAAY,CAAE,IAAM,iBAAkB,cACjC,GAEF,CAAC,KAIN,GAAkB,IAAM,CAC5B,GAAQ,KAGJ,GAAgB,IAAkB,IAAM,CAC5C,KAAM,IAAY,GAAQ,OAAO,IAAQ,KAAS,IAClD,GAAS,IACT,EAAS,KAGX,MACE,iBAAoB,MAAO,CAAE,UAAW,GAAQ,MAC5C,gBAAoB,KAAY,CAAE,QAAS,UAAY,GACvD,gBAAoB,KAAmB,CAAE,YAAa,IACpD,gBAAoB,KAAa,CAAE,UAAW,GAAQ,aACpD,gBAAoB,KAAQ,CAC5B,MAAO,GACP,OAAQ,EACR,SAAU,EACV,cAAe,SACf,aAAc,GACd,SAAU,EACV,SAAU,GACV,QAAS,GACT,KAAM,GACN,MAAO,gBAAoB,GAAgB,MAC3C,YAAa,IAAE,C,OACb,UAAa,GAAQ,SAAW,EAC9B,gBAAoB,MAAO,CAAE,UAAW,GAAQ,OAC3C,GAAI,IAAI,IAAc,C,UACvB,uBAAoB,KAAM,CACxB,IAAK,MAAM,KAAK,IAAM,GAAG,QAAU,MAA9B,eAA8C,MACnD,MACE,MAAM,KAAK,IAAM,GAAG,QAAU,MAA9B,eAA8C,MAEhD,UAAW,GACX,SAAU,GAAa,IACvB,UAAW,GAAQ,UAKzB,gBAAoB,KAAY,KAC3B,GAAQ,SAAW,EAClB,GAAe,GACf,MAAM,KAAK,IAAM,GAAG,QAAU,MAA9B,eAAkC,QAI5C,cAAe,IACZ,GAAsD,gBAAoB,GAAgB,MAAjF,gBAAoB,GAAgB,MAEhD,UAAW,CACT,aAAc,CACZ,SAAU,SACV,WAAY,QAEd,gBAAiB,CACf,SAAU,MACV,WAAY,QAEd,mBAAoB,OAGpB,GAAe,CAAC,GAChB,gBAAoB,KAAU,CAAE,MAAO,IAAM,GAE7C,EACE,GACA,EAAM,IAAI,IACR,gBAAoB,SAAU,CAAE,MAAO,GAAK,MAAO,IAAK,GAAK,OACzD,GAAK,QAGX,GACA,EAAM,IAAI,IACR,gBAAoB,KAAU,CAAE,IAAK,GAAK,MAAO,MAAO,GAAK,OACzD,GACA,gBAAoB,KAAU,CAC5B,MAAO,UACP,QAAU,GAAQ,SAAS,GAAK,QAAU,GAC1C,UAAW,GAAQ,WAGrB,GAAK,YCjO3B,KAAM,IAAO,IAAM,GACN,GAAyB,gBAAoB,CACxD,cAAe,EACf,UAAW,EACX,aAAc,GACd,YAAa,GACb,eAAgB,GAChB,aAAc,KAST,YAAuB,EAAO,CACnC,KAAM,CAAE,WAAU,WAAU,eAAc,aAAa,GAAM,EACvD,CAAC,EAAW,GAAgB,SAAS,GACrC,CAAC,EAAa,GAAkB,SAAS,CAAC,IAEhD,UAAU,IAAM,CACd,EAAa,IACZ,CAAC,IAEJ,KAAM,GAAQ,GACd,GAAI,IACJ,gBAAS,QAAQ,EAAU,IAAS,CAC9B,eAAe,KACjB,CAAI,GAAM,MAAM,IACd,GAAU,GAEV,EAAM,KAAK,OAMf,MAAM,cAAc,MAAM,SAAU,KAChC,MAAM,cAAc,GAAuB,SAAU,CACrD,MAAO,CACL,YACA,eACA,cACA,iBACA,eACA,cAAe,SAAS,MAAM,KAG9B,MAAM,cAAc,WAAY,CAChC,WAAY,EACZ,YAAa,WACb,UAAW,EAAW,EAAI,GAExB,IAGJ,GAAa,SAAS,MAAM,GAAY,GAAK,ICnErD,KAAM,IAAY,QAChB,GAAU,EACR,KAAM,CACJ,UAAW,EAAM,QAAQ,GACzB,WAAY,CACV,YAAa,EAAM,QAAQ,OAIjC,CAAE,KAAM,iCAmBG,GAAa,CAAC,CAAE,OAAM,iBACjC,MAAM,cAAc,OAAQ,CAAE,QAAS,GAAe,GAAQ,SAG1D,GAAU,CAAC,CACf,OACA,cACA,WACA,OACA,eAEA,MAAM,cAAc,OAAQ,CAC1B,QAAS,YACT,MAAO,UACP,SAAU,EACV,cAAe,cAAc,IAC7B,QAAS,GAEP,GAAS,GAAO,SAAW,SAI3B,GAAU,CAAC,CAAE,OAAM,cAAa,WAAU,eAC9C,MAAM,cAAc,OAAQ,CAC1B,QAAS,EACT,cAAe,cAAc,IAC7B,SAAU,GAER,GAAQ,QASD,GAAsB,CAAC,CAClC,UAAU,GACV,cACI,CACJ,KAAM,GAAU,KACV,CACJ,gBACA,YACA,eACA,cACA,iBACA,gBACE,WAAW,wBAET,EAAW,CAAC,GAAU,KAAa,CACnC,IACF,KAEE,GACF,EAAa,EAAW,IAG1B,EAAa,KAGT,GAAa,IAAM,CACvB,KAAM,IAAW,EAAQ,SACrB,EAAQ,SAAS,EAAW,EAAgB,GAC5C,EAAY,EAChB,EAAS,GAAU,EAAQ,QAC3B,EAAe,CAAC,GAAG,EAAa,MAE5B,GAAa,IAAM,CACvB,EAAY,MACZ,EAAS,EAAY,EAAY,OAAS,GAAI,EAAQ,QACtD,EAAe,CAAC,GAAG,KAEf,GAAgB,IAAM,CAC1B,EAAS,EAAG,EAAQ,WACpB,EAAe,CAAC,KAGlB,MACE,OAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,MAC5C,CAAC,OAAW,IAAM,SAAS,EAAQ,WAAa,IAAc,GAC9D,MAAM,cAAc,GAAS,CAC3B,KAAM,EAAQ,SACd,YAAa,GACb,SAAU,IAAc,EACxB,UAAW,IAGb,CAAC,OAAW,IAAM,SAAS,EAAQ,WACnC,MAAM,cAAc,GAAS,CAC3B,KAAM,EAAQ,SACd,YAAa,GACb,SACG,CAAC,CAAC,GAAiB,GAAa,GAChC,CAAC,CAAC,EAAQ,SAAW,CAAC,EAAQ,UAEjC,UAAW,IAGb,EAAQ,aAAe,IAAc,GACrC,MAAM,cAAc,GAAY,CAC9B,KAAM,EAAQ,YACd,YAAa,GACb,UAAW,IAGb,ICpIF,EAAY,QAChB,GAAU,EACR,IAAK,CACH,QAAS,EAAM,QAAQ,MAG3B,CAAE,KAAM,sBAGH,WAA2B,EAAO,CACvC,KAAM,CAAE,QAAO,WAAU,MAAK,aAAY,GAAa,EACjD,EAAU,IAIhB,MAAO,GACL,MAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,KAC5C,MAAM,cAAc,WAAY,CAAE,QAAS,MAAQ,GACnD,EACA,MAAM,cAAc,oBAAqB,CAAE,QAAS,IAAM,GAAW,GAAK,SAAU,OAGxF,MAAM,cAAc,QAAS,IAAK,GAC9B,MAAM,cAAc,UAAW,KAC7B,MAAM,cAAc,WAAY,CAAE,QAAS,MAAQ,IAErD,MAAM,cAAc,YAAa,KAC/B,EACA,MAAM,cAAc,oBAAqB,CAAE,QAAS,MCxB9D,KAAM,GAAY,QAChB,GAAU,EACR,OAAQ,CACN,WAAY,IACZ,YAAa,CACX,MAAO,QACP,OAAQ,QACR,QAAS,eACT,YAAa,EACb,aAAc,MACd,QAAS,OAGb,GAAI,CACF,YAAa,CACX,gBAAiB,EAAM,QAAQ,OAAO,KAG1C,QAAS,CACP,YAAa,CACX,gBAAiB,EAAM,QAAQ,OAAO,UAG1C,MAAO,CACL,YAAa,CACX,gBAAiB,EAAM,QAAQ,OAAO,QAG1C,QAAS,CACP,YAAa,CACX,gBAAiB,EAAM,QAAQ,OAAO,UAG1C,QAAS,CACP,YAAa,CACX,gBAAiB,EAAM,QAAQ,OAAO,UAG1C,QAAS,CACP,YAAa,CACX,gBAAiB,EAAM,QAAQ,OAAO,YAI5C,CAAE,KAAM,oBAGH,YAAkB,EAAO,CAC9B,KAAM,GAAU,EAAU,GAC1B,MACE,OAAM,cAAc,OAAQ,CAC1B,UAAW,WAAW,EAAQ,OAAQ,EAAQ,IAC9C,aAAc,YACd,cAAe,UACZ,IAKF,YAAuB,EAAO,CACnC,KAAM,GAAU,EAAU,GAC1B,MACE,OAAM,cAAc,OAAQ,CAC1B,UAAW,WAAW,EAAQ,OAAQ,EAAQ,SAC9C,aAAc,iBACd,cAAe,UACZ,IAKF,YAAqB,EAAO,CACjC,KAAM,GAAU,EAAU,GAC1B,MACE,OAAM,cAAc,OAAQ,CAC1B,UAAW,WAAW,EAAQ,OAAQ,EAAQ,OAC9C,aAAc,eACd,cAAe,UACZ,IAKF,YAAuB,EAAO,CACnC,KAAM,GAAU,EAAU,GAC1B,MACE,OAAM,cAAc,OAAQ,CAC1B,UAAW,WAAW,EAAQ,OAAQ,EAAQ,SAC9C,aAAc,iBACd,cAAe,UACZ,IAKF,YAAuB,EAAO,CACnC,KAAM,GAAU,EAAU,GAC1B,MACE,OAAM,cAAc,OAAQ,CAC1B,UAAW,WAAW,EAAQ,OAAQ,EAAQ,SAC9C,aAAc,iBACd,cAAe,UACZ,IAKF,YAAuB,EAAO,CACnC,KAAM,GAAU,EAAU,GAC1B,MACE,OAAM,cAAc,OAAQ,CAC1B,UAAW,WAAW,EAAQ,OAAQ,EAAQ,SAC9C,aAAc,iBACd,cAAe,UACZ,I,4BClHT,KAAM,IAAwB,GAC5B,QAAa,CACX,KAAM,CACJ,WAAY,SACZ,WAAY,SACZ,aAAc,EAAM,QAAQ,GAC5B,OAAQ,IACR,cAAe,SAMf,GAAyB,CAC7B,KAAM,CACJ,OAAQ,IACR,cAAe,QAMb,GAAc,GAClB,QAAa,CACX,KAAM,CACJ,UAAW,OACX,OAAQ,EAAM,QAAQ,EAAG,EAAG,GAAI,GAChC,QAAS,OAMT,GAAkB,GACtB,QAAa,CACX,KAAM,CACJ,QAAS,EAAM,QAAQ,EAAG,EAAG,EAAG,IAElC,OAAQ,KAGN,GAAY,QAAW,GAAsB,CACjD,KAAM,oCACL,MACG,GAAc,QAAW,GAAwB,CACrD,KAAM,+BACL,MAEU,GAAgB,CAAC,CAC5B,QACA,cAKA,MAAM,cAAc,MAAO,CAAE,KAAM,EAAQ,QAAU,UACjD,MAAM,cAAc,UAAW,KAAM,IAI9B,GAAoB,CAAC,CAChC,QACA,cACG,KAKH,MAAM,cAAc,SAAU,KAC1B,GAAS,MAAM,cAAc,GAAW,KAAM,GAC9C,MAAM,cAAc,GAAa,CAAE,QAAS,EAAQ,EAAI,KAAM,GAC5D,IASK,GAAe,QAAW,GAAY,CACjD,KAAM,+BACL,CAAC,CAAE,UAAS,cACb,gBAAoB,KAAM,CAAE,UAAW,EAAQ,MAAQ,IAG5C,GAAmB,QAAW,GAAgB,CACzD,KAAM,mCACL,CAAC,CAAE,UAAS,cACb,gBAAoB,KAAM,CAAE,UAAW,EAAQ,MAAQ,ICrFnD,GAAY,QAAa,CAC7B,KAAM,CACJ,OAAQ,MACR,cAAe,UAMb,GAAmB,GACvB,QAAa,CACX,KAAM,IACD,GAAU,KACb,YAAa,EAAM,QAAQ,MAQ3B,GAAa,QAAW,GAAW,CACvC,KAAM,yCACL,CAAC,CAAE,UAAS,cACb,gBAAoB,GAAc,CAAE,QAAS,GAAW,IAEpD,GAAmB,QAAW,GAAiB,CACnD,KAAM,+CACL,CAAC,CAAE,UAAS,cACb,gBAAoB,GAAc,CAAE,QAAS,GAAW,IAG1D,YAAoB,EAAM,EAAQ,CAChC,KAAM,GAAS,EAAK,IAAI,CAAC,EAAM,IAC7B,MAAM,cAAc,iBAAkB,CAAE,IAAK,GAAS,GAAQ,KAEhE,MAAO,GACL,MAAM,cAAc,GAAkB,KAAM,GAE5C,MAAM,cAAc,GAAY,KAAM,GAI1C,YACE,EACA,EACA,EACA,CACA,KAAM,GAAS,OAAO,KAAK,GAAK,IAAI,GAAO,CACzC,KAAM,GAAQ,GAAQ,EAAI,GAAM,IAC1B,EACJ,GAAW,EAAQ,YACf,EAAQ,YAAY,GACpB,UAAU,GAChB,MACE,OAAM,cAAc,iBAAkB,CAAE,IAAK,GACzC,GAAG,MACH,KAKR,MAAO,GACL,MAAM,cAAc,GAAkB,KAAM,GAE5C,MAAM,cAAc,GAAY,KAAM,GAI1C,YACE,EACA,EACA,EACA,CACA,MAAI,OAAM,eAAe,GAChB,MAAM,cAAc,SAAU,KAAM,GAGzC,MAAO,IAAU,UAAY,CAAC,MAAM,QAAQ,GACvC,GAAU,EAAO,EAAS,GAG/B,MAAM,QAAQ,GACT,GAAW,EAAO,GAGvB,MAAO,IAAU,UACZ,MAAM,cAAc,SAAU,KAAM,EAAQ,SAAM,UAGpD,MAAM,cAAc,SAAU,KAAM,GAE7C,KAAM,IAAY,CAAC,CAAE,QAAO,aAC1B,MAAM,cAAc,SAAU,KAAM,GAAQ,EAAO,IAG/C,GAAY,CAAC,CACjB,QACA,QACA,aAOE,MAAM,cAAc,kBAAmB,CACrC,MACE,GAAW,EAAQ,YACf,EAAQ,YAAY,GACpB,UAAU,IAGd,MAAM,cAAc,GAAW,CAAE,MAAO,EAAO,QAAS,KAKhE,YAAoB,EAAM,EAAS,CACjC,MAAO,QAAO,KAAK,GAAM,IAAI,GAC3B,MAAM,cAAc,GAAW,CAAE,IAAK,EAAK,MAAO,EAAK,MAAO,EAAK,GAAM,QAAS,KAU/E,YAAiC,EAAO,CAC7C,KAAM,CAAE,WAAU,QAAQ,GAAM,WAAY,EACtC,EAAgB,GAAW,EAAU,GAAW,IACtD,MAAO,OAAM,cAAc,cAAe,CAAE,MAAO,GAAS,G,uFCjJ9D,YAAmB,EAAa,CAI9B,MAAO,gBAAa,EAAa,CAC/B,mBAAoB,KAIxB,YAAe,EAAa,CAC1B,MAAO,YAAS,EAAa,CAC3B,kBAAmB,GACnB,mBAAoB,KAIxB,YAAsB,EAAa,EAAW,CAG5C,MAAO,IAFmB,GAEP,GAGrB,YACE,EACA,EACA,EACA,CACA,KAAM,GAAc,IACf,GAAM,IACR,GAAY,GAEf,MAAO,IAAU,GAKZ,YACL,EAEA,EAAe,IACf,CACA,KAAM,CAAC,EAAc,GAAmB,WAClC,EAAqB,EAAa,WAClC,CAAC,EAAiB,GAAsB,eAC5C,GAAa,EAAoB,IAGnC,sBAAU,IAAM,CACd,KAAM,GAAW,GAAa,EAAoB,GAElD,EAAmB,GACjB,eAAQ,EAAU,GAAY,EAAW,IAE1C,CAAC,EAAoB,EAAoB,IAE5C,SACE,IAAM,CACJ,KAAM,GAAc,GAClB,EACA,EACA,GAGE,IAAuB,GACzB,EAAgB,EAAa,CAAE,QAAS,MAG5C,EACA,CAAC,EAAiB,EAAiB,EAAoB,IAGlD,CAAC,EAAiB,GC3D3B,KAAM,IAAyB,CAC7B,IAAK,gDACL,MAAO,CACL,CACE,MAAO,yBACP,KAAM,UACN,MAAO,CACL,CAEE,MAAO,+BACP,IAAK,6EAOR,aAA4B,CAEjC,KAAM,GAAS,GADG,kBACO,IAAI,gBACvB,EAAgB,iBAAQ,kBAAkB,eAEhD,MAAK,GAIE,CACL,IAAK,EAAc,UAAU,OAC7B,MAAO,EAAc,eAAe,SAAS,QAAQ,GAAS,C,MAAI,OAChE,MAAO,EAAS,UAAU,SAC1B,KAAM,EAAS,kBAAkB,QACjC,MAAQ,MAAS,uBAAuB,WAAhC,OAA4C,IAAI,QACtD,GAAa,EACX,IAAK,EAAS,UAAU,OACxB,MAAO,EAAS,UAAU,gBAXzB,G,gBCnCX,YAAuB,EAAK,EAAO,CAEjC,KAAM,GAAO,GADD,YACK,cAAc,GAC/B,MAAO,GAAO,gBAAoB,EAAM,IAAK,IAAY,gBAAoB,KAAoB,IAAK,IAUjG,YAAyB,EAAO,CACrC,MAAO,IAAc,cAAe,GAG/B,YAAqB,EAAO,CACjC,MAAO,IAAc,UAAW,GAG3B,YAAkB,EAAO,CAC9B,MAAO,IAAc,OAAQ,GAGxB,YAAuB,EAAO,CACnC,MAAO,IAAc,YAAa,GAG7B,YAAkB,EAAO,CAC9B,MAAO,IAAc,OAAQ,GAGxB,YAAmB,EAAO,CAC/B,MAAO,IAAc,QAAS,GAGzB,YAAoB,EAAO,CAChC,MAAO,IAAc,SAAU,GAG1B,YAAmB,EAAO,CAC/B,MAAO,IAAc,QAAS,GAGzB,YAAkB,EAAO,CAC9B,MAAO,IAAc,OAAQ,GAGxB,YAAkB,EAAO,CAC9B,MAAO,IAAc,OAAQ,GAGxB,YAAqB,EAAO,CACjC,MAAO,IAAc,UAAW,GClClC,KAAM,IAAY,QAChB,CACE,YAAa,CACX,SAAU,IACV,SAAU,MAGd,CAAE,KAAM,2BAGJ,GAAc,CAAC,CAAE,UAAW,C,MAChC,KAAM,GAAM,eACN,EAAO,GAAO,KAAI,cAAc,KAAlB,OAAsC,GAC1D,MAAO,iBAAoB,EAAM,OAG7B,GAAc,CAAC,CAAE,UAAQ,C,MAC7B,uBAAoB,EAAM,CAAE,GAAI,EAAK,KAAO,KAAK,QAAL,OAAc,EAAK,MAG3D,GAAkB,CAAC,CAAE,UAAW,C,MACpC,MACE,iBAAoB,KAAU,KAC1B,gBAAoB,KAAc,KAChC,gBAAoB,GAAa,CAAE,KAAM,EAAK,QAEhD,gBAAoB,KAAc,CAClC,QAAS,EAAK,MACd,UAAW,KAAK,QAAL,cAAY,OACrB,CAAC,EAAM,EAAM,IAAQ,CACnB,GAAG,EACH,EAAM,GAAK,gBAAoB,KAAM,CAAE,IAAK,IAC5C,gBAAoB,GAAa,CAAE,KAAM,EAAM,IAAK,EAAK,OAE3D,QAOH,YAAuB,EAAO,CACnC,KAAM,CAAE,QAAO,YAAa,EACtB,CAAE,SAAU,KAEZ,CAAC,EAAa,GAAkB,eAAS,IACzC,CAAC,EAAU,GAAe,eAAS,MACnC,EAAU,KACV,EAAgB,SAAc,IAClC,GAAM,YAAY,KAAK,OAGnB,GAAiB,IAAS,CAC9B,EAAY,GAAM,eAClB,EAAe,KAGX,GAAsB,IAAM,CAChC,EAAe,KAGjB,MACE,iBAAoB,WAAgB,KAChC,gBAAoB,IAAK,CAAE,QAAS,OAAQ,GAAI,GAC9C,EACA,gBAAoB,IAAY,CAC9B,MAAO,UACP,KAAM,QACN,QAAS,GACT,cAAe,kBAEb,gBAAoB,GAAU,OAGlC,gBAAoB,IAAQ,CAC1B,cAAe,iBACf,MAAO,UACP,QAAS,GACT,UAAW,gBAAoB,GAAU,OACzC,YAKJ,gBAAoB,MAAS,CAC7B,cAAe,yBACf,KAAM,EACN,SAAU,EACV,aAAc,CACZ,SAAU,SACV,WAAY,SAEd,gBAAiB,CACf,SAAU,MACV,WAAY,SAEd,QAAS,IAEP,gBAAoB,KAAM,CAAE,UAAW,EAAQ,aAC7C,GACA,gBAAoB,KAAU,CAAE,WAAY,cACxC,gBAAoB,KAAY,CAAE,QAAS,aAAe,IAG9D,eAAmB,EAAU,CAAC,GAAO,KACrC,gBAAoB,KAAU,CAAE,WAAY,aAAc,IAAK,SAAS,MACpE,KAGJ,GACA,EAAM,IAAI,CAAC,GAAM,KACf,gBAAoB,GAAiB,CAAE,KAAM,GAAM,IAAK,QAAQ,SAGpE,gBAAoB,KAAe,KACjC,gBAAoB,IAAQ,CAAE,MAAO,UAAW,QAAS,IAAuB,Y,4BC3I5F,KAAM,IAAoB,GACpB,GAAc,GACd,GAAmB,GAEZ,GAAgB,CAC3B,qBACA,gBAAiB,IAGjB,mBAAoB,IACpB,oBAAqB,EACrB,oBAAqB,IACrB,WAAY,GACZ,mBAAoB,GACpB,SAAU,GAAoB,GAAc,EAC5C,eACA,uBAAwB,EACxB,oBACA,kBAAmB,GAAoB,GAAmB,EAC1D,oBAAqB,IAGV,GAAgB,CAC3B,kBAAmB,EACnB,gBAAiB,IACjB,mBAAoB,GAAc,mBAAqB,KAG5C,GACX,0CAaW,GAAiB,oBAAc,CAC1C,OAAQ,GACR,QAAS,IAAM,KAQJ,GACX,oBAAc,CACZ,YAAa,GACb,eAAgB,IAAM,KCzD1B,GAAI,IAAmB,UAAU,EAAkB,CACjD,KAAM,GAAoB,kBAAmB,EAAiB,kBAAuB,IACpF,IAAqB,IAAmB,KAEpC,KAAM,IAAe,CAC1B,oBAAqB,CACnB,GAAI,GACJ,GAAI,CACF,EAAQ,KAAK,MACX,OAAO,aAAa,QAAQ,GAAiB,oBAC3C,aAEJ,CACA,MAAO,GAET,MAAO,CAAC,CAAC,GAEX,mBAAmB,EAAO,CACxB,MAAO,QAAO,aAAa,QACzB,GAAiB,kBACjB,KAAK,UAAU,MCFf,GAAY,QAChB,GAAU,EACR,KAAM,CACJ,MAAO,OACP,WAAY,6BACZ,UAAW,WACV,EAAM,YAAY,GAAG,OAAQ,CAC5B,YAAa,CAAC,CAAE,cACd,EACI,GAAc,gBACd,GAAc,oBAErB,EAAM,YAAY,KAAK,OAAQ,CAC9B,cAAe,GAAc,sBAGjC,QAAS,CACP,OAAQ,EACR,UAAW,UACX,UAAW,CACT,QAAS,MAIf,CAAE,KAAM,yBA4BG,GAAyB,oBACpC,CACE,SAAU,GACV,sBAAuB,IAAM,GAC7B,SAAU,KAUR,GAAc,oBAAc,CAChC,QAAS,CACP,WAAY,UAGT,YAAqB,EAAO,CACjC,KAAM,CAAC,EAAU,GAAe,eAAS,IACvC,GAAa,sBAGT,EAAa,aAAO,MAEpB,EAAc,cAClB,IAAO,EACL,QAAS,CACP,gBAGJ,CAAC,IAGH,gBAAU,IAAM,CACd,GAAa,mBAAmB,IAC/B,CAAC,IAEJ,KAAM,GAAW,SACf,GAAS,EAAM,YAAY,KAAK,MAChC,CAAE,MAAO,KAGL,EAAwB,IAAM,EAAY,CAAC,GAE3C,EAAU,GAAU,CAAE,aAE5B,MACE,iBAAoB,GAAuB,SAAU,CACnD,MAAO,CACL,WACA,wBACA,aAGA,gBAAoB,GAAY,SAAU,CAAE,MAAO,GACjD,gBAAoB,MAAO,CAAE,UAAW,EAAQ,MAAQ,EAAM,YA8BjE,aAAsB,CAC3B,KAAM,CAAE,WAAY,iBAAW,IAM/B,MAAO,CAAE,aAJY,kBAAY,IAAM,C,QACrC,uBAAS,aAAT,cAAqB,UAArB,QAA8B,SAC7B,CAAC,IAEmB,WAAY,iBAAS,Y,+DClI9C,KAAM,IAAY,QAAW,GAAU,EACrC,KAAM,CACJ,SAAU,EACV,OAAQ,EAAM,QAAQ,EAAG,GACzB,MAAO,EAAM,QAAQ,WAAW,OAGlC,SAAU,CACR,MAAO,GAAG,EAAM,QAAQ,WAAW,0BACnC,UAAW,SAAS,GAAc,4BAA4B,EAAM,QAAQ,WAAW,YACvF,UAAW,QAGb,MAAO,CACL,QAAS,WAWP,GAAsB,GAAU,CACpC,KAAM,CAAE,KAAI,QAAO,OAAM,SAAU,EAC7B,EAAU,KACV,EAAW,YACX,CAAE,wBAAuB,4BAC7B,iBAAW,IAEP,EAAW,CAAC,GAAG,KAAU,CAE3B,EADE,KAAU,EACa,GAEA,KAIvB,GACH,IAAU,GAAyB,GAAyB,GAC1D,IAAU,GACX,CAAE,IAAyB,IAC3B,IAAO,EAAS,SAEpB,MAEE,iBAAoB,KAAwB,CAC1C,MAAO,EACP,KAAM,EACN,UAAW,EACX,GAAK,GAAU,EAAS,SACxB,SAAU,EACV,MAAO,EACP,SAAU,GACV,QAAS,KAaF,GAAgB,GAAU,CACrC,KAAM,CAAE,WAAU,KAAI,QAAO,OAAM,SAAU,EACvC,CAAE,YAAa,iBAAW,IAEhC,MAAO,GACL,gBAAoB,GAAoB,CAAE,GAAI,EAAI,MAAO,EAAO,KAAM,EAAM,MAAO,IAEnF,gBAAoB,WAAgB,KAAM,IChExC,GAAY,QAAW,GAAU,EACrC,KAAM,CACJ,SAAU,QACV,gBAAiB,EAAM,QAAQ,WAAW,WAC1C,MAAO,EAAM,QAAQ,WAAW,MAChC,OAAQ,EACR,KAAM,EACN,MAAO,EACP,OAAQ,EAAM,OAAO,SAErB,UAAW,qBAGb,QAAS,CACP,WAAY,EAAM,QAAQ,WAAW,WACrC,MAAO,OACP,OAAQ,GAAG,GAAc,wBACzB,OAAQ,eAAe,GAAc,yBACrC,KAAM,WACN,SAAU,QAGZ,cAAe,CACb,QAAS,OACT,MAAO,EAAM,QAAQ,OAAO,UAC5B,WAAY,SACZ,eAAgB,gBAChB,QAAS,EAAM,QAAQ,EAAG,IAG5B,mBAAoB,CAClB,MAAO,EAAM,QAAQ,OAAO,WAG9B,oBAAqB,CACnB,aAAc,GAAG,GAAc,4BAI7B,GAAgC,GACpC,eACE,EACA,CAAC,CAAE,MAAO,CAAE,eAAkB,OAAO,UAAU,GAAY,EAAW,GACtE,QAGE,GAAmB,gBAAoB,IAAc,KAErD,GAAc,CAAC,CACnB,WACA,QAAQ,OACR,OACA,aACI,CACJ,KAAM,GAAU,KAEhB,MACE,iBAAoB,MAAQ,CAC1B,OAAQ,SACR,KAAM,EACN,QAAS,EACT,WAAY,CACV,cAAe,CAAE,QAAS,CAAE,KAAM,EAAQ,uBAE5C,QAAS,CACP,KAAM,EAAQ,oBACd,kBAAmB,EAAQ,UAG3B,gBAAoB,IAAK,CAAE,UAAW,EAAQ,eAC5C,gBAAoB,KAAY,CAAE,QAAS,MAAQ,GACnD,gBAAoB,IAAY,CAChC,QAAS,EACT,QAAS,CAAE,KAAM,EAAQ,qBAEvB,gBAAoB,KAAW,QAGnC,gBAAoB,IAAK,KAAM,KAU1B,GAAuB,oBAAc,CAChD,sBAAuB,GACvB,yBAA0B,IAAM,KAYrB,GAAiB,GAAU,CACtC,KAAM,CAAE,YAAa,EACf,EAAU,KACV,EAAW,YACX,CAAC,EAAuB,GAC5B,eAAS,IAEX,gBAAU,IAAM,CACd,EAAyB,KACxB,CAAC,EAAS,WAQb,GAAI,GAAgB,uBAAiB,EAAU,GAC7C,EAAS,cAAc,OAAO,GAAS,EAAM,OAAS,KAGxD,GAAK,EAGO,EAAc,OAUxB,EAAgB,GAA6B,GAP7C,EAAc,KACZ,gBAAoB,GAAc,CAAE,IAAK,eAAgB,KAAM,gBAAoB,KAAU,OACzF,QANN,OAAO,MAcT,KAAM,GACJ,GAAyB,GACzB,CAAC,EAAc,GAAuB,MAAM,GAE9C,MACE,iBAAoB,YAAyB,CAAE,MAAO,CAAE,OAAQ,GAAM,QAAS,IAAM,KACjF,gBAAoB,GAAqB,SAAU,CACnD,MAAO,CAAE,wBAAuB,6BAE9B,gBAAoB,GAAa,CACjC,MACE,EAAc,IACb,EAAc,GAAuB,MAAM,MAE9C,KAAM,EACN,QAAS,IAAM,EAAyB,KAEtC,EAAc,IACb,EAAc,GAAuB,MACnC,UAEL,gBAAoB,KAAkB,CACtC,UAAW,EAAQ,KACnB,cAAe,uBAEb,MCnMN,GAAY,QAChB,GAAU,EACR,OAAQ,CACN,QAAS,OACT,SAAU,gBACV,WAAY,aACZ,SAAU,QACV,KAAM,EACN,IAAK,EACL,OAAQ,EACR,OAAQ,EAAM,OAAO,OACrB,WAAY,EAAM,QAAQ,WAAW,WACrC,UAAW,SACX,gBAAiB,OACjB,eAAgB,OAChB,MAAO,GAAc,kBACrB,WAAY,EAAM,YAAY,OAAO,QAAS,CAC5C,OAAQ,EAAM,YAAY,OAAO,MACjC,SAAU,EAAM,YAAY,SAAS,WAEvC,QAAS,CACP,WAAY,GAEd,uBAAwB,CACtB,QAAS,SAGb,WAAY,CACV,MAAO,GAAc,gBACrB,WAAY,EAAM,YAAY,OAAO,QAAS,CAC5C,OAAQ,EAAM,YAAY,OAAO,MACjC,SAAU,EAAM,YAAY,SAAS,WAGzC,eAAgB,CACd,IAAK,EACL,SAAU,WACV,OAAQ,IACR,UAAW,oBACX,UAAW,CACT,UAAW,sBAIjB,CAAE,KAAM,qBAGV,GAAI,IAAQ,UAAU,EAAO,CACT,EAAM,EAAM,OAAY,GAAU,SACpD,KAAM,GAAO,EAAS,EAAG,EAAM,EAAM,KAAU,GAAQ,OACvD,KAAM,GAAO,EAAO,EAAG,EAAM,EAAM,KAAU,GAAQ,SACpD,IAAU,IAAQ,KAoBrB,KAAM,IAAkB,GAAU,CAChC,KAAM,CACJ,cAAc,GAAc,mBAC5B,eAAe,GAAc,oBAC7B,uBACA,YACE,EACE,EAAU,KACV,EAAgB,SACpB,IAAS,GAAM,YAAY,KAAK,MAChC,CAAE,MAAO,KAEL,CAAC,EAAO,GAAY,eAAS,GAAM,QACnC,EAAgB,eAChB,CAAE,YAAU,0BAA0B,iBAC1C,IAGI,GAAa,IAAM,CACnB,IAAY,GAGZ,GAAc,SAChB,cAAa,EAAc,SAC3B,EAAc,QAAU,QAEtB,IAAU,GAAM,MAAQ,CAAC,GAC3B,GAAc,QAAU,OAAO,WAAW,IAAM,CAC9C,EAAc,QAAU,OACxB,EAAS,GAAM,OACd,GAEH,EAAS,GAAM,SAIb,GAAc,IAAM,CACpB,IAAY,GAGZ,GAAc,SAChB,cAAa,EAAc,SAC3B,EAAc,QAAU,QAEtB,IAAU,GAAM,KAClB,EAAS,GAAM,QACN,IAAU,GAAM,MACzB,GAAc,QAAU,OAAO,WAAW,IAAM,CAC9C,EAAc,QAAU,OACxB,EAAS,GAAM,SACd,MAID,GAAU,IAAU,GAAM,MAAQ,CAAC,GAAkB,GAKrD,GAAW,IAAS,CACpB,GACF,GAAS,GAAM,MACf,MAEA,GAAS,GAAM,QACf,OAIJ,MACE,iBAAoB,MAAO,CAAE,MAAO,IAChC,gBAAoB,GAAiB,MACrC,gBAAoB,YAAyB,CAC7C,MAAO,CACL,UACA,aAGA,gBAAoB,MAAO,CAC3B,UAAW,EAAQ,KACnB,cAAe,eACf,aAAc,EAAuB,IAAM,GAAK,GAChD,QAAS,EAAuB,IAAM,GAAK,GAC3C,aAAc,EAAuB,IAAM,GAAK,GAChD,OAAQ,EAAuB,IAAM,GAAK,IAExC,gBAAoB,MAAO,CAC3B,UAAW,KAAW,EAAQ,OAAQ,EACnC,EAAQ,YAAa,MAGtB,OAaD,GAAW,GAAU,CAChC,KAAM,CAAE,WAAU,cAAa,eAAc,wBAAyB,EAChE,CAAE,YAAa,iBAAW,IAEhC,MAAO,GACL,gBAAoB,GAAe,KAAM,GAEzC,gBAAoB,GAAgB,CAClC,YAAa,EACb,aAAc,EACd,qBAAsB,GAEpB,IAKR,aAA2B,CACzB,KAAM,CAAE,eAAc,cAAe,KAC/B,EAAU,KAEhB,MAAK,kBAAY,SAIf,gBAAoB,IAAQ,CAC1B,QAAS,EACT,QAAS,YACT,UAAW,KAAW,EAAQ,iBAC9B,mBAPK,KChNJ,YAAyB,EAAiB,EAAY,CAC3D,KAAM,GAAkB,GAAI,iBAAgB,EAAW,QAAQ,WACzD,EAAoB,WAAS,GAE7B,EAAuB,GAAI,iBAC/B,EAAgB,QAChB,WACI,EAAyB,WAAS,GAMxC,MAHE,eAAQ,EAAW,SAAU,EAAgB,WAC7C,eAAQ,EAAwB,GCEpC,KAAM,IAAY,QAAW,GAAU,EACrC,KAAM,CACJ,OAAQ,GACR,MAAO,OACP,UAAW,CACT,WAAY,UACZ,MAAO,EAAM,QAAQ,WAAW,eAElC,QAAS,OACT,WAAY,SACZ,MAAO,EAAM,QAAQ,WAAW,MAChC,QAAS,GACT,OAAQ,UACR,SAAU,WACV,WAAY,OACZ,OAAQ,QAEV,cAAe,CACb,MAAO,QAET,SAAU,CACR,WAAY,UACZ,MAAO,QAET,MAAO,CACL,OAAQ,GACR,WAAY,EACZ,SAAU,IAEZ,cAAe,CACb,SAAU,WACV,MAAO,IAET,SAAU,CACR,QAAS,OACT,cAAe,SACf,WAAY,OAEd,aAAc,CACZ,MAAO,OACP,QAAS,iBAEX,YAAa,CACX,MAAO,EAAM,QAAQ,WAAW,MAChC,QAAS,OACT,eAAgB,UACf,EAAM,YAAY,KAAK,OAAQ,CAC9B,QAAS,QACT,YAAa,EAAM,QAAQ,IAE7B,SAAU,WAqCD,GAAsB,GAAU,CAC3C,KAAM,CAAE,QAAO,KAAI,KAAM,EAAM,iBAAkB,EAC3C,EAAU,KACV,CAAE,kBAAmB,WAAW,+BAChC,EAAe,IAAM,CACzB,EAAe,KAEX,EAAa,gBAAgB,GAC7B,EAAkB,cACxB,GAAI,IAAW,gBAAgB,EAAiB,GAEhD,KAAM,CAAC,GAAc,IAAmB,SAAS,IAC3C,GAAsB,IAAM,CAChC,GAAgB,CAAC,KAEnB,MAAI,KAAkB,OACpB,GAAc,KAAK,IAAQ,CACzB,KAAM,IAAe,YAAY,GAAK,IACtC,UAAW,gBAAgB,EAAiB,IACrC,KAGP,MAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,eAC5C,MAAM,cAAc,SAAU,CAC9B,QAAS,GACT,aAAc,IAAK,GAAE,kBACrB,UAAW,WACT,EAAQ,KACR,GAAW,EAAQ,SAAW,SAG9B,MAAM,cAAc,EAAM,CAAE,SAAU,UACtC,MAAM,cAAc,WAAY,CAAE,QAAS,YAAa,UAAW,EAAQ,OACzE,GAEF,GACA,MAAM,cAAc,gBAAiB,CAAE,UAAW,EAAQ,gBAE1D,MAAM,cAAc,kBAAmB,CAAE,UAAW,EAAQ,iBAG9D,GAAiB,IACjB,MAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,UAC5C,EAAc,IAAI,CAAC,GAAQ,KAC3B,MAAM,cAAc,KAAM,CACxB,UAAW,QACX,GAAI,GAAO,GACX,UAAW,OACX,UAAW,EAAQ,aACnB,QAAS,EACT,aAAc,IAAK,GAAE,kBACrB,IAAK,IAEH,MAAM,cAAc,WAAY,CAAE,UAAW,EAAQ,aACnD,GAAO,YAWvB,MAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,eAC5C,MAAM,cAAc,KAAM,CAC1B,UAAW,QACX,GAAI,EACJ,UAAW,OACX,UAAW,WACT,EAAQ,KACR,GAAW,EAAQ,SAAW,QAEhC,QAAS,EACT,aAAc,IAAK,GAAE,mBAEnB,MAAM,cAAc,EAAM,CAAE,SAAU,UACtC,MAAM,cAAc,WAAY,CAAE,QAAS,YAAa,UAAW,EAAQ,OACzE,MC5KN,GAAa,GACjB,QAAW,GAAM,C,QAAI,OACnB,KAAM,CACJ,OAAQ,IACR,SAAU,WACV,SAAU,UACV,MAAO,EAAM,QAAQ,GAAK,GAE5B,OAAQ,CACN,QAAS,OACT,SAAU,gBACV,WAAY,aACZ,SAAU,SACT,EAAM,YAAY,GAAG,OAAQ,CAC5B,WAAY,EAAM,KAClB,WAAY,EAAM,YAAY,OAAO,cAAe,CAClD,OAAQ,EAAM,YAAY,OAAO,MACjC,SAAU,EAAM,YAAY,SAAS,YAGzC,IAAK,EACL,OAAQ,EACR,QAAS,EACT,WAAY,QAAM,QAAQ,WAAW,UAAzB,cAAkC,aAAlC,OAAgD,UAC5D,UAAW,SACX,gBAAiB,OACjB,eAAgB,OAChB,OAAQ,UACR,MAAO,GAAc,kBACrB,gBAAiB,GAAG,GAAc,uBAClC,QAAS,CACP,WAAY,GAEd,uBAAwB,CACtB,QAAS,SAGb,WAAY,CACV,MAAO,GAAc,iBACpB,EAAM,YAAY,KAAK,OAAQ,CAC9B,MAAO,OACP,SAAU,WACV,YAAa,EAAM,QAAQ,GAC3B,KAAM,EACN,IAAK,IAGT,MAAO,CACL,SAAU,GACV,WAAY,IACZ,MAAO,OACP,QAAS,IACR,EAAM,YAAY,KAAK,OAAQ,CAC9B,QAAS,YAqBJ,GAAkB,GAAU,CACvC,KAAM,CAAE,UAAW,iBAAW,IACxB,EAAO,EACT,GAAc,gBACd,GAAc,kBACZ,EAAU,GAAU,CAAE,WAEtB,CAAE,eAAgB,iBAAW,IAC7B,CAAC,EAAe,GAAoB,eAAS,IAEnD,sBAAU,IAAM,CACd,EAAiB,IAChB,CAAC,IAGF,gBAAoB,MAAO,CACzB,UAAW,KAAW,EAAQ,OAAQ,EACnC,EAAQ,YAAa,KAGtB,gBAAoB,KAAY,CAAE,QAAS,KAAM,UAAW,EAAQ,OAClE,EAAM,OAER,EAAM,W,gECxGd,KAAM,IAAY,QAAW,CAC3B,cAAe,CACb,QAAS,OACT,SAAU,WACV,MAAO,QAET,OAAQ,CACN,MAAO,MACP,SAAU,cAIR,GAAkB,IAAM,CAC5B,KAAM,GAAU,KAEhB,MACE,OAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,eAC5C,MAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,QAC9C,MAAM,cAAc,iBAAkB,CAAE,MAAO,CAAE,SAAU,WAE7D,MAAM,cAAc,MAAO,KACzB,MAAM,cAAc,iBAAkB,CAAE,MAAO,CAAE,SAAU,aAMrE,OAAe,KC3Bf,KAAM,IAAY,QAAW,CAC3B,cAAe,CACb,QAAS,OACT,SAAU,WACV,MAAO,QAET,OAAQ,CACN,MAAO,MACP,SAAU,cAIR,GAAmB,IAAM,CAC7B,KAAM,GAAU,KAEhB,MACE,OAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,eAC5C,MAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,QAC9C,MAAM,cAAc,oBAAqB,CAAE,MAAO,CAAE,SAAU,WAEhE,MAAM,cAAc,MAAO,KACzB,MAAM,cAAc,oBAAqB,CAAE,MAAO,CAAE,SAAU,aAMxE,OAAe,KCgCf,KAAM,IAAY,QAChB,GAAS,C,YACP,KAAM,CACJ,yBACA,oBACA,kBACA,sBACE,GACJ,MAAO,CACL,KAAM,CACJ,MAAO,EAAM,QAAQ,WAAW,MAChC,QAAS,OACT,SAAU,aACV,WAAY,SACZ,OAAQ,GACR,OAAQ,WAEV,WAAY,CACV,WAAY,OACZ,OAAQ,OACR,MAAO,OACP,OAAQ,EACR,QAAS,EACT,UAAW,UACX,KAAM,WAER,OAAQ,CACN,MAAO,EACP,eAAgB,UAElB,KAAM,EACH,EAAM,YAAY,GAAG,OAAQ,CAC5B,MAAO,IAGX,cAAe,CACb,UAAW,CACT,WACE,QAAM,QAAQ,WAAW,UAAzB,cAAkC,kBAAlC,OAAqD,YAG3D,YAAa,CACX,WACE,QAAM,QAAQ,WAAW,UAAzB,cAAkC,kBAAlC,OAAqD,WAEzD,MAAO,CAEL,WAAY,OACZ,WAAY,SACZ,WAAY,OACZ,KAAM,WACN,MAAO,QACP,SAAU,SACV,gBAAiB,YAEnB,cAAe,CACb,UAAW,aACX,OAAQ,OACR,MAAO,EACP,YAAa,CAAC,EAAM,QAAQ,GAC5B,QAAS,OACT,WAAY,SACZ,eAAgB,UAElB,WAAY,CACV,aAAc,IAEhB,YAAa,CACX,MAAO,UACP,WAAY,OACZ,SAAU,EAAM,WAAW,UAE7B,qBAAsB,CACpB,QAAS,EAAM,QAAQ,EAAG,EAAG,IAE/B,gBAAiB,CACf,MAAO,EAAkB,GAE3B,gBAAiB,CACf,MAAO,EAAM,QAAQ,GACrB,UAAW,SACX,YAAa,EAAM,QAAQ,IAE7B,eAAgB,CACd,MAAO,OACP,eAAgB,UAElB,aAAc,CACZ,QAAS,QAEX,aAAc,CACZ,WAAY,OACZ,OAAQ,OACR,MAAO,EAAM,QAAQ,WAAW,MAChC,MAAO,OACP,OAAQ,UACR,SAAU,WACV,OAAQ,IAEV,OAAQ,CACN,SAAU,WACV,MAAO,IAET,SAAU,CACR,SAAU,CACR,WAAY,SAAS,OAA4B,EAAM,QAAQ,WAAW,YAC1E,MAAO,EAAM,QAAQ,WAAW,eAElC,WAAY,CACV,MAAO,GAET,oBAAqB,CACnB,aAAc,GAEhB,mBAAoB,CAClB,WAAY,CAAC,MAKrB,CAAE,KAAM,yBAWJ,GAAmB,CACvB,EACA,IAEA,uBACE,EAAQ,MAAM,SACd,GAAY,CACV,GAAI,GAAS,GACb,SACG,cACA,QACC,CAAC,CACC,MAAO,CAAE,KAAI,oBAGpB,CACO,GAAI,CAAC,EAAQ,CACX,GAAI,iBAAe,OAAQ,CACzB,EAAc,QACZ,CAAC,CAAE,GAAI,KACJ,EACC,GAAU,GAAgB,EAAU,UAAY,KAEtD,OAEE,GACF,GAAS,GAAgB,EAAU,UAAY,QAKlD,GAET,CAAC,EAAS,WAqCd,YACE,EACA,CACA,MAAQ,GAAQ,KAAO,OAGzB,KAAM,IAAqB,gBAAoB,IAAgB,KAKlD,GAAoB,aAGhC,SACC,CACE,KACA,MACA,QACA,YACA,cACA,gBACA,kBAAkB,SAClB,eAAgB,EAAkB,UAC/B,GAEL,GACA,CACA,GAAI,CAAE,SAAU,IAAqB,YACjC,CAAE,SAAU,IAAe,UAAgB,GAE1C,GACH,IAAmB,GAAiB,kBAAkB,SACtD,GAAa,GAAW,kBAAkB,UAG5C,GAAI,IAAW,KAAqB,GAChC,CAAC,IAAY,CAAC,GAEhB,IAAW,GAAiB,WAAW,GAAG,QAG5C,KAAM,IAAc,GAAW,EAAkB,OAEjD,MACE,iBAAoB,KAAM,IACrB,EACH,GAAI,EACJ,IAAK,GACL,eAAgB,GAChB,MAAO,IAAK,KAAW,GAAW,EAAc,QAChD,UAAW,KAAW,CACpB,EACA,GAAW,EAAkB,aAS/B,GAAkB,iBAAW,CAAC,EAAO,IAAQ,CACjD,KAAM,CACJ,KAAM,EACN,OACA,mBAAmB,GACnB,mBAAmB,GACnB,UACA,WACA,eACG,GACD,EACE,GAAU,KAIV,CAAE,WAAW,iBAAW,IAExB,GACJ,gBAAoB,KAAO,CACzB,MAAO,YACP,QAAS,MACT,QAAS,WACT,UAAW,CAAC,EACZ,UAAW,KAAW,EAAG,GAAQ,gBAAiB,CAAC,MAEjD,gBAAoB,EAAM,CAAE,SAAU,WAItC,GACJ,gBAAoB,WAAgB,KAChC,gBAAoB,MAAO,CAAE,cAAe,eAAgB,UAAW,GAAQ,eAC7E,IAEF,GACA,gBAAoB,KAAY,CAAE,QAAS,YAAa,UAAW,GAAQ,OACvE,GAGJ,gBAAoB,MAAO,CAAE,UAAW,GAAQ,iBAAmB,IAInE,GAAU,GAAS,GAAc,GAEjC,GAAa,CACjB,UACA,UAAW,KACT,EACA,GAAQ,KACR,GAAS,GAAQ,KAAO,GAAQ,OAChC,GAAa,IAAU,GAAQ,WAC/B,EAAG,GAAQ,eAAgB,CAAC,KAIhC,MAAI,IAAa,GAEb,gBAAoB,SAAU,CAAE,aAAc,KAAS,GAAY,IAAK,GACpE,IAMN,gBAAoB,GAAmB,IAClC,GACH,gBAAiB,GAAQ,SACzB,GAAI,EAAM,GAAK,EAAM,GAAK,GAC1B,IAAK,EACL,aAAc,GAAc,EAAM,MAC/B,GAED,MAKF,GAAyB,CAAC,CAC9B,cACG,KAGA,CACH,KAAM,GAAU,KACV,CAAC,EAAa,GAAkB,eAAS,IACzC,EAAW,YACX,EAAW,GAAiB,EAAU,GACtC,EAAgB,SAAe,IACnC,GAAM,YAAY,KAAK,OAGnB,EAAmB,IAAM,CAC7B,EAAe,KAEX,EAAmB,IAAM,CAC7B,EAAe,KAGX,GAAY,IACZ,EACK,EACL,gBAAoB,KAAa,CAAE,SAAU,QAAS,UAAW,EAAQ,eAEzE,gBAAoB,KAAe,CAAE,SAAU,QAAS,UAAW,EAAQ,eAI7E,CAAC,GACC,gBAAoB,KAAgB,CAAE,SAAU,QAAS,UAAW,EAAQ,eAKlF,MACE,iBAAoB,YAAwC,CAC1D,MAAO,CACL,cACA,mBAGA,gBAAoB,MAAO,CAC3B,cAAe,oBACf,aAAc,EACd,aAAc,EAAc,EAAmB,EAC/C,aAAc,EACd,UAAW,KAAW,GAAe,EAAQ,cAE3C,gBAAoB,GAAiB,CACrC,UAAW,EAAW,EAAQ,SAAW,MACtC,GAED,MAEF,GAAe,KAWZ,GAAc,iBAAW,CAAC,EAAO,IAAQ,CAEpD,KAAM,CAAC,GAAW,uBAAiB,EAAM,SAAU,GAKjD,EAAS,cAAc,OAAO,GAAS,EAAM,OAAS,KAGxD,MAAI,GAEA,gBAAoB,GAAwB,IAAK,GAC7C,GAKD,gBAAoB,GAAiB,IAAK,EAAO,IAAK,MASxD,YAA4B,EAAO,CACxC,KAAM,CAAC,EAAO,GAAY,SAAS,IAC7B,EAAU,KACV,EAAO,EAAM,KAAO,EAAM,KAAO,WAEjC,EAAS,IAAM,CACnB,EAAM,SAAS,GACf,EAAS,KAGL,EAAc,IAAM,CACpB,GAAG,MAAQ,SACb,IAAG,iBACH,MAIE,EAAe,IAAO,CAC1B,EAAS,GAAG,OAAO,QAGf,EAAoB,IAAO,CAE/B,GAAG,iBACH,GAAG,mBAGC,EAAmB,IAAO,CAE9B,IACA,GAAG,kBAGL,MACE,OAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,YAC5C,MAAM,cAAc,GAAa,CACjC,KAAM,EACN,GAAI,EAAM,GACV,QAAS,EACT,iBAAkB,IAEhB,MAAM,cAAc,UAAW,CAC/B,YAAa,SACb,MAAO,EACP,QAAS,EACT,SAAU,EACV,UAAW,EACX,UAAW,EAAQ,gBACnB,WAAY,CACV,iBAAkB,GAClB,UAAW,EAAQ,aAErB,WAAY,CACV,UAAW,EAAQ,0BAUxB,KAAM,IAAe,SAAO,OACjC,CACE,KAAM,GAER,CAAE,KAAM,0BAKG,GAAgB,SAAO,OAClC,CACE,OAAQ,GAEV,CAAE,KAAM,2BAKG,GAAiB,SAAO,MACnC,CACE,OAAQ,EACR,MAAO,OACP,WAAY,UACZ,OAAQ,OACR,OAAQ,YAEV,CAAE,KAAM,4BAGJ,GAAmB,GAAW,EAClC,UAAW,OACX,uBAAwB,CACtB,gBAAiB,EAAM,QAAQ,WAAW,QAC1C,MAAO,MACP,aAAc,OAEhB,6BAA8B,CAC5B,gBAAiB,EAAM,QAAQ,KAAK,KACpC,aAAc,SAIL,GAAuB,SAAO,OAAO,CAAC,CAAE,WAAY,CAC/D,KAAM,GAAkB,GAAgB,GACxC,MAAO,CACL,KAAM,WACN,UAAW,SAEX,MAAO,mBAGP,UAAW,OACX,UAAW,SACX,uBAAwB,EACxB,UAAW,KAYF,GAAsB,IAAM,CACvC,KAAM,GAAU,KACV,CAAE,SAAQ,WAAY,WAAW,gBAMvC,GALsB,cACpB,GAAS,EAAM,YAAY,KAAK,MAChC,CAAE,MAAO,KAIT,MAAO,MAGT,KAAM,GAAc,IAAM,CACxB,EAAQ,CAAC,IAGX,MACE,OAAM,cAAc,SAAU,CAC5B,QAAS,EACT,UAAW,EAAQ,aACnB,aAAc,iBACd,cAAe,yBAEb,MAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,QAC9C,EAAS,MAAM,cAAc,gBAAiB,MAAS,MAAM,cAAc,iBAAkB,SCpnBjG,GAAY,QAChB,GAAU,EACR,UAAW,CACT,MAAO,UAEP,SAAU,GACV,MAAO,GAAc,gBACrB,UAAW,GACX,aAAc,GACd,YAAa,GAAc,YAC3B,aAAc,GAAc,aAE9B,aAAc,CACZ,QAAS,OACT,eAAgB,WAChB,WAAY,SACZ,UAAW,IAEb,iBAAkB,CAChB,MAAO,UACP,QAAS,OACT,WAAY,SACZ,aAAc,EACd,UAAW,CACT,MAAO,EAAM,QAAQ,UACrB,WAAY,EAAM,YAAY,OAAO,QAAS,CAC5C,OAAQ,EAAM,YAAY,OAAO,MACjC,SAAU,EAAM,YAAY,SAAS,aAI3C,iBAAkB,CAChB,SAAU,SACV,WAAY,OACZ,cAAe,YACf,cAAe,GAEjB,iBAAkB,CAChB,MAAO,GACP,OAAQ,GACR,YAAa,MAGjB,CAAE,KAAM,0BAeH,YAAmB,EAAO,CAC/B,KAAM,GAAU,KACV,CAAE,OAAM,WAAY,EACpB,EAAc,IAAM,IAE1B,MACE,OAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,WAC5C,MAAM,cAAc,WAAY,CAAE,QAAS,aAAe,GAC1D,MAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,cAC9C,MAAM,cAAc,KAAM,CAC1B,UAAW,SACX,QAAS,EACT,UAAW,OACX,UAAW,EAAQ,kBAEjB,MAAM,cAAc,UAAW,CAAE,UAAW,EAAQ,mBACpD,MAAM,cAAc,WAAY,CAAE,UAAW,OAAQ,UAAW,EAAQ,kBAAoB,cAmBxG,KAAM,IAAoB,GAAU,CAClC,KAAM,CAAE,OAAM,aAAc,EACtB,CAAC,EAAY,GAAiB,SAAS,IACvC,EAAkB,IAAM,CAC5B,EAAc,KAEhB,MACE,OAAM,cAAc,SAAU,CAAE,GAAI,CAAC,EAAY,SAAU,GACvD,MAAM,cAAc,GAAW,CAAE,KAAM,EAAM,QAAS,MAKxD,GAAmB,KAEnB,GACJ,qDAEK,YAAsB,EAAQ,CACnC,KAAM,CAAE,UAAW,WAAW,gBACxB,EAAe,CACnB,sBAAuB,GACvB,6BAA8B,IAE1B,CAAC,EAAgB,GACrB,gBAAgB,6BAEZ,CAAE,wBAAuB,gCAC7B,UAAkB,GAEd,EAAiB,IAAM,CAC3B,EAAkB,GAAU,KACvB,KACA,EACH,sBAAuB,OAGrB,EAAwB,IAAM,CAClC,EAAkB,GAAU,KACvB,KACA,EACH,6BAA8B,OAIlC,MAAK,GAKH,MAAM,cAAc,MAAM,SAAU,KAChC,CAAC,GACD,MAAM,cAAc,MAAM,SAAU,KAChC,MAAM,cAAc,GAAkB,CACtC,KAAM,GACN,UAAW,IAEX,MAAM,cAAc,eAAgB,OAGxC,CAAC,GACD,MAAM,cAAc,GAAkB,CACpC,KAAM,GACN,UAAW,KAjBV,KC1JX,KAAM,IAAY,QACf,GAAW,EACV,KAAM,CACJ,SAAU,cACV,SAAU,EACV,WAAY,EAAM,QAAQ,GAC1B,cAAe,EAAM,QAAQ,GAC7B,YAAa,EAAM,QAAQ,GAC3B,aAAc,EAAM,QAAQ,IAC3B,EAAM,YAAY,GAAG,OAAQ,CAC5B,YAAa,EAAM,QAAQ,GAC3B,aAAc,EAAM,QAAQ,KAGhC,QAAS,CACP,QAAS,OACT,cAAe,SACf,SAAU,GAEZ,UAAW,CACT,QAAS,KAGb,CAAE,KAAM,qBAgBH,YAAiB,EAAO,CAC7B,KAAM,CAAE,YAAW,UAAS,YAAW,cAAa,GAAc,EAE5D,CAAE,cAAe,KAEjB,EAAU,KAChB,MACE,iBAAoB,UAAW,CAC7B,IAAK,EACL,SAAU,MACP,EACH,UAAW,KAAW,EAAQ,KAAM,EAAW,EAC5C,EAAQ,SAAU,GAClB,EAAQ,WAAY,KAGrB,G,2BChDR,KAAM,IAAY,QAChB,GAAU,EACR,YAAa,CACX,SAAU,gBACV,gBAAiB,EAAM,QAAQ,WAAW,MAC1C,YAAa,EAAM,QAAQ,IAE7B,WAAY,CACV,QAAS,EAAM,QAAQ,EAAG,MACvB,EAAM,WAAW,QACpB,cAAe,YACf,WAAY,OACZ,MAAO,EAAM,QAAQ,KAAK,WAE5B,SAAU,CACR,MAAO,EAAM,QAAQ,KAAK,SAE5B,QAAS,CACP,UAAW,CACT,gBAAiB,EAAM,QAAQ,WAAW,QAC1C,MAAO,EAAM,QAAQ,KAAK,YAIhC,CAAE,KAAM,wBAqBH,YAAoB,EAAO,CAChC,KAAM,CAAE,OAAM,WAAU,iBAAkB,EACpC,CAAC,EAAa,GAAkB,eAAS,UAAiB,GAC1D,EAAS,KAET,EAAe,CAAC,EAAG,IAAU,CAC7B,IAAkB,QACpB,EAAe,GAEb,GAAU,EAAS,IAGzB,sBAAU,IAAM,CACV,IAAkB,QACpB,EAAe,IAEhB,CAAC,IAGF,gBAAoB,MAAO,CAAE,UAAW,EAAO,aAC3C,gBAAoB,KAAM,CAC1B,sBAAuB,GACvB,eAAgB,UAChB,UAAW,UACX,QAAS,aACT,cAAe,OACf,aAAc,+BACd,SAAU,EACV,MAAO,GAEL,EAAK,IAAI,CAAC,EAAK,IACf,gBAAoB,KAAO,IACtB,EAAI,SACP,cAAe,cAAc,IAC7B,MAAO,EAAI,MACX,IAAK,EAAI,GACT,MAAO,EACP,UAAW,EAAO,WAClB,QAAS,CAAE,SAAU,EAAO,SAAU,KAAM,EAAO,cC5FxD,YAA6B,EAInC,C,UACC,KAAM,GAAS,YAST,EAAe,EAPI,IAAI,CAAC,CAAE,QAAM,eAAgB,EACpD,cAAe,GACf,KAAM,GAAG,OACT,QAAS,MAIiB,KAAK,CAAC,GAAG,KAEnC,GAAE,KAAK,QAAQ,QAAS,IAAI,cAAc,GAAE,KAAK,QAAQ,QAAS,MAG9D,EAAU,G,GAAA,OAAU,KAAV,OAA2B,EAAU,GAAG,SAElD,CAAC,GAAgB,G,GAAA,OAAY,EAAc,IAAI,EAAO,UAArC,OAAgD,GACjE,EAAa,EACf,EAAU,UAAU,IAAK,GAAG,GAAE,WAAa,EAAa,MAAM,MAC9D,EAEJ,MAAO,CACL,MAAO,IAAe,GAAK,EAAI,EAC/B,UACA,MAAO,KAAU,KAAV,OAAyB,EAAU,IAIvC,YAAoB,EAAO,CAChC,KAAM,CAAE,UAAW,EACb,EAAW,YACX,CAAE,QAAO,QAAO,WAAY,GAAoB,GAChD,EAAa,cACjB,IACE,EAAO,IAAI,GAAM,EACf,GAAI,EAAE,KACN,MAAO,EAAE,MACT,SAAU,EAAE,YAEhB,CAAC,IAGG,EAAe,GAKnB,EAAS,EAAO,GAAU,KAAK,QAAQ,QAAS,IAAI,QAAQ,MAAO,KAErE,MACE,iBAAoB,WAAgB,KAChC,gBAAoB,GAAY,CAChC,KAAM,EACN,cAAe,EACf,SAAU,IAEV,gBAAoB,GAAS,KAC3B,gBAAoB,KAAQ,CAAE,MAAO,EAAM,QAC3C,ICnDV,KAAM,IAAQ,IAAM,KAGpB,0BAAoB,GAAO,yBAA0B,IAE9C,YACL,EACA,CAIA,KAAM,GACJ,gBAAoB,GAAO,CAAE,KAAM,GAAI,MAAO,IAC1C,gBAAoB,MAAO,OAE/B,KAEF,MAAO,oBAAiB,GAAe,QAAQ,GAAS,CACtD,GAAI,CAAC,qBAAe,GAClB,MAAO,GAGT,GAAI,EAAM,OAAS,WACjB,MAAO,IAA4B,EAAM,MAAM,UAGjD,GAAI,EAAM,OAAS,EACjB,KAAM,IAAI,OAAM,uDAGlB,KAAM,CAAE,OAAM,QAAO,WAAU,YAAa,EAAM,MAClD,MAAO,CAAC,CAAE,OAAM,QAAO,WAAU,eAmB9B,YAAsB,EAAO,CAClC,KAAM,GAAS,GAA4B,EAAM,UAEjD,MAAO,iBAAoB,GAAY,CAAE,OAAQ,IAGnD,GAAa,MAAQ,GCpErB,KAAM,IAAwB,QAC5B,GAAU,EACR,MAAO,CACL,aAAc,OAEhB,SAAU,CACR,MAAO,EAAM,QAAQ,WACrB,WAAY,YAGhB,CAAE,KAAM,0BAQH,YAAsB,EAAO,CAClC,KAAM,CAAE,QAAO,YAAa,EACtB,EAAU,KAEhB,MACE,iBAAoB,WAAgB,KAChC,gBAAoB,MAAO,CAAE,UAAW,EAAQ,OAAS,GACzD,gBAAoB,MAAO,CAAE,UAAW,EAAQ,UAAY,I,uLCtBpE,KAAM,IAAkB,QACtB,GAAU,EACR,KAAM,CACJ,OAAQ,OACR,MAAO,QACP,QAAS,OACT,cAAe,SACf,YAAa,EAAM,QAAQ,IAE7B,MAAO,CACL,WAAY,OACZ,SAAU,IAEZ,OAAQ,CACN,QAAS,OACT,WAAY,SACZ,OAAQ,OACR,eAAgB,gBAChB,aAAc,aAAa,EAAM,QAAQ,KAAK,QAEhD,QAAS,CACP,QAAS,OACT,cAAe,SACf,QAAS,CACP,UAAW,EAAM,QAAQ,OAI/B,CAAE,KAAM,0BAoBG,GAAW,GAAU,C,MAChC,KAAM,GAAU,KAEV,CAAE,mBAAoB,EAEtB,CAAC,EAAiB,GAAsB,eAAS,IAClD,EAAM,kBAEL,CAAC,EAAO,GAAgB,eAAS,IAGjC,EAAc,IAAM,CACxB,EAAmB,IACnB,EAAa,GAAM,CAAC,IAGtB,sBAAU,IAAM,CACd,EAAgB,IACf,CAAC,EAAiB,IAInB,gBAAoB,MAAO,CAAE,UAAW,EAAQ,MAC5C,gBAAoB,MAAO,CAAE,UAAW,EAAQ,QAC9C,gBAAoB,MAAO,CAAE,UAAW,EAAQ,OAAS,WACzD,gBAAoB,IAAQ,CAAE,MAAO,UAAW,QAAS,GAAe,cAI1E,gBAAoB,MAAO,CAAE,UAAW,EAAQ,SAC9C,MAAM,UAAN,cAAe,SACf,EAAM,QAAQ,IAAI,GAChB,gBAAoB,GAAQ,CAC1B,aAAc,EACd,IAAK,EAAO,QAAQ,SAChB,EAAO,QACX,SAAU,EAAgB,EAAO,QAAQ,OACzC,SAAU,IACR,EAAmB,IACd,GACF,EAAO,QAAQ,OAAQ,WCzDpC,GAAa,CACjB,IAAK,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAQ,IAAK,EAAO,IAAK,KAC7E,MAAO,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAO,IAAK,EAAO,IAAK,KAC9E,MAAO,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAO,IAAK,EAAO,IAAK,KAC9E,OAAQ,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAe,IAAK,EAAO,IAAK,KACvF,YAAa,iBAAW,CAAC,EAAO,IAC9B,gBAAoB,KAAc,IAAK,EAAO,IAAK,KAErD,KAAM,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAM,IAAK,EAAO,IAAK,KAC5E,OAAQ,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAS,IAAK,EAAO,IAAK,KACjF,OAAQ,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAY,IAAK,EAAO,IAAK,KACpF,UAAW,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAW,IAAK,EAAO,IAAK,KACtF,SAAU,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAU,IAAK,EAAO,IAAK,KACpF,SAAU,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAc,IAAK,EAAO,IAAK,KACxF,aAAc,iBAAW,CAAC,EAAO,IAC/B,gBAAoB,KAAa,IAAK,EAAO,IAAK,KAEpD,YAAa,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAO,IAAK,EAAO,IAAK,KACpF,OAAQ,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAY,IAAK,EAAO,IAAK,KACpF,UAAW,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAa,IAAK,EAAO,IAAK,KACxF,gBAAiB,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAQ,IAAK,EAAO,IAAK,KACzF,WAAY,iBAAW,CAAC,EAAO,IAAQ,gBAAoB,KAAY,IAAK,EAAO,IAAK,MAI1F,YAA6B,EAAM,EAAO,CACxC,KAAM,GAAO,EAAM,MAAM,KACzB,GAAI,GAAQ,EAAK,EAAK,IAEtB,OAAS,GAAI,EAAG,EAAI,EAAK,OAAQ,EAAE,EAAG,CACpC,GAAI,IAAU,OACZ,MAAO,GAGT,KAAM,GAAI,EAAK,GACf,EAAQ,EAAM,GAGhB,MAAO,GAKT,KAAM,IAAqB,QACzB,GAAU,EACR,OAAQ,CACN,QAAS,EAAM,QAAQ,EAAG,EAAG,EAAG,KAChC,UAAW,aAAa,EAAM,QAAQ,KAAK,OAC3C,aAAc,aAAa,EAAM,QAAQ,KAAK,OAE9C,MAAQ,EAAQ,QAAQ,WACxB,WAAY,EAAM,WAAW,eAC7B,SAAU,SACV,UAAW,YAGf,CAAE,KAAM,yBACR,OAII,GAAsB,QAC1B,GAAU,EACR,KAAM,CACJ,QAAS,EAAM,QAAQ,EAAG,EAAG,IAAK,MAEpC,MAAO,CACL,SAAU,CACR,WAAY,SAGhB,YAAa,CACX,aAAc,EAAM,QAAQ,MAGhC,CAAE,KAAM,0BACR,OAKI,GAAkB,QACtB,IAAO,EACL,KAAM,CACJ,QAAS,OACT,WAAY,SACZ,eAAgB,iBAElB,MAAO,CACL,WAAY,OACZ,SAAU,GACV,WAAY,YAGhB,CAAE,KAAM,mCAKJ,GAAiB,QACrB,IAAO,EACL,KAAM,CACJ,QAAS,OACT,WAAY,WAGhB,CAAE,KAAM,mBAGV,YACE,EACA,EACA,CACA,MAAO,GAAQ,IAAI,GAAU,CAC3B,KAAM,GAAc,GAEpB,GAAI,GAAY,EAAO,WAAa,GAEpC,GAAI,EAAO,UAGT,GAFA,EAAY,MAAQ,EAAM,QAAQ,aAE9B,MAAO,IAAc,SACtB,EAAY,WACX,EAAM,WAAW,mBACd,CACL,KAAM,GAAc,EAKpB,EAAY,CAAC,EAAM,EAAS,IAEnB,KADO,EAAY,EAAM,EAAS,GACtB,WAAY,EAAM,WAAW,iBAKtD,MAAO,IACF,EACH,cACA,eAKN,YAA6B,EAAO,EAAc,CAChD,MAAO,iBAAU,EAAO,CAAC,EAAQ,EAAO,IAAQ,CACzC,eAAQ,EAAO,EAAa,KAC/B,GAAO,GAAO,KAKpB,KAAM,IAAsB,CAC1B,OAAQ,GACR,YAAa,GACb,QAAS,IA6BJ,YAAsB,EAO3B,CACA,KAAM,CACJ,aACA,YACA,aACA,wBACA,iBACE,EACE,EAAiB,KACjB,EAAkB,kBACrB,GAAe,CACd,EAAa,gBAAgB,GAC7B,EAAU,IAEZ,CAAC,EAAc,IAGjB,MAAI,GAEA,gBAAoB,MAAO,CAAE,UAAW,EAAe,MACnD,gBAAoB,MAAO,CAAE,UAAW,EAAe,MACrD,gBAAoB,IAAY,CAAE,QAAS,EAAe,aAAc,eACtE,gBAAoB,KAAY,OAElC,gBAAoB,KAAY,CAAE,UAAW,EAAe,OAAS,YAClE,EAAuB,MAG5B,gBAAoB,GAAqB,IACtC,EACH,IAAK,EACL,gBAAiB,KAOvB,gBAAoB,GAAqB,IACpC,EACH,IAAK,EACL,gBAAiB,IAKhB,YAAe,EAAO,CAC3B,KAAM,CACJ,OACA,UACA,UACA,QACA,WACA,UACA,eACA,eACA,mBACG,IACD,EACE,GAAe,KAEf,GAAQ,UAER,GAAyB,IAAK,MAAwB,GAEtD,CAAC,GAAa,IAAkB,eACpC,GAAuB,aAEnB,GAAgB,kBACpB,IAAM,GAAe,IAAK,CAAC,IAC3B,CAAC,KAEG,CAAC,GAAuB,IAA4B,eAAS,GAC7D,CAAC,GAAW,IAAgB,eAAS,GACrC,CAAC,GAAiB,IAAsB,eAC5C,GAAuB,SAGnB,GAAY,GAAe,EAAS,IAEpC,CAAC,GAAQ,IAAa,eAAS,GAAuB,QAE5D,gBAAU,IAAM,CACd,GAAI,EAAe,CACjB,KAAM,IAAQ,GACZ,CACE,UACA,eACA,QAAS,IAEX,IAGF,EAAc,MAEf,CAAC,GAAQ,GAAa,GAAiB,IAE1C,KAAM,IAAiB,CACrB,YAAa,CACX,cAAe,cAIb,GAAkB,kBACrB,IAAY,C,OACX,YAAQ,KAAK,IAAM,GAAG,QAAU,MAAhC,eAA6C,OAC/C,CAAC,IAGH,gBAAU,IAAM,CACd,GAAI,MAAO,IAAS,WAClB,OAEF,GAAI,CAAC,GAAiB,CACpB,GAAa,GACb,OAGF,KAAM,IAAuB,OAAO,OAAO,IAC3C,GAAI,GAAQ,GAAqB,OAAO,OAAQ,CAC9C,KAAM,IAAW,EAAO,OACtB,IACE,CAAC,CAAC,OAAO,QAAQ,IACd,OAAO,CAAC,CAAC,CAAE,MAAW,CAAC,CAAC,GAAM,QAC9B,MAAM,CAAC,CAAC,GAAK,MAAiB,CAC7B,KAAM,IAAa,GACjB,GACA,GAAgB,KAGlB,MAAI,OAAM,QAAQ,KAAe,MAAM,QAAQ,IACtC,GAAW,KAAK,IAAK,GAAY,SAAS,KACxC,MAAM,QAAQ,IAChB,GAAW,SAAS,IAClB,MAAM,QAAQ,IAChB,GAAY,SAAS,IAGvB,KAAe,MAG9B,GAAa,QAEb,IAAa,GAEf,GAAyB,GAAqB,OAAO,SACpD,CAAC,EAAM,GAAiB,KAE3B,KAAM,IAAmB,CACvB,GACA,KACG,CACH,KAAM,IAAyB,IAAU,CACvC,KAAM,IAAiB,GAAI,KACrB,GAAY,IAAU,CACC,IAAU,MACnC,GAAe,IAAI,KAIvB,MAAI,KACF,GAAU,QAAQ,IAAM,CACtB,KAAM,IAAQ,GACZ,GACA,GAAgB,KAGd,MAAM,QAAQ,IACf,GAAQ,QAAQ,IAEjB,GAAS,MAKR,IAGH,GACJ,IAEO,EACL,YAAa,cACb,MAAO,GAAO,OACd,SAAU,GAAO,OAAS,kBAC1B,MAAO,CAAC,GAAG,GAAsB,GAAO,SAAS,OAAO,IAAI,IAAU,EACpE,MAAO,GACP,cAKN,MAAO,IAAa,IAAI,IAAW,EACjC,KAAM,GAAO,KACb,QAAS,GAAgB,QAIvB,GAAa,CAAC,CAAC,kBAAS,QACxB,GAAU,kBACd,IAEI,gBAAoB,GAAc,CAChC,UAAW,GACX,WAAY,GACZ,sBAAuB,GACvB,cAAe,MACZ,KAIT,CAAC,GAAe,GAAY,GAAuB,KAG/C,GAAY,MAAO,IAAS,YAAc,EAAK,SAAW,EAC1D,GAAc,EAAQ,OACtB,GAAO,kBACX,IACM,GAAgB,GAEhB,gBAAoB,QAAS,KACzB,gBAAoB,KAAM,KACxB,gBAAoB,KAAM,CAAE,QAAS,IAAe,KAMvD,gBAAoB,MAAY,IAAK,KAE9C,CAAC,GAAW,EAAc,KAG5B,MACE,iBAAoB,MAAO,CAAE,UAAW,GAAa,MACjD,IAAe,GAAQ,MAAO,IAAS,YAAc,kBAAS,SAC9D,gBAAoB,GAAS,CAC3B,QAAS,GAAiB,EAAS,GACnC,gBAAiB,GACjB,gBAAiB,KAGnB,gBAAoB,MAAQ,CAC5B,WAAY,CACV,OAAQ,GACR,WACA,SAEF,QAAS,IAAK,MAAmB,GACjC,QAAS,GACT,MAAO,GACP,MACE,gBAAoB,WAAgB,KAChC,gBAAoB,KAAY,CAAE,QAAS,KAAM,UAAW,MAC1D,GAEF,GACA,gBAAoB,KAAY,CAAE,MAAO,gBAAiB,QAAS,SAC/D,IAKV,KAAM,MAAO,IAAS,WAAa,EAAO,GAC1C,MAAO,CAAE,MAAO,QAChB,aAAc,CAAE,QAAS,CAAE,kBAAmB,cAC3C,MC1eJ,KAAM,IAAY,GAAU,CACjC,KAAM,CAAE,WAAU,QAAO,WAAU,GAAU,EAE7C,MACE,OAAM,cAAc,MAAO,CACzB,KAAM,WACN,OAAQ,IAAU,EAClB,kBAAmB,uBAAuB,OACvC,GAED,IAAU,GAAS,MAAM,cAAc,IAAK,CAAE,EAAG,GAAK,KCJxD,GAAY,QAChB,IAAO,EACL,KAAM,CACJ,MAAO,UACP,SAAU,UACV,SAAU,SACV,UAAW,SACX,aAAc,MACd,gBAAiB,UACjB,WAAY,GAAU,EAAM,OAAS,OAAS,IAC9C,YAAa,GAAU,EAAM,OAAS,IAAM,OAC5C,UAAW,CACT,gBAAiB,UACjB,QAAS,QAIf,CAAE,KAAM,qBAGG,GAAc,GAAU,CACnC,KAAM,GAAU,GAAU,GACpB,CAAE,YAAW,WAAY,EAC/B,MACE,OAAM,cAAc,WAAY,CAC9B,QAAS,EACT,UAAW,EAAQ,KACnB,KAAM,QACN,cAAe,GACf,mBAAoB,GACpB,aAAc,GAEZ,EAAM,WCjCR,GAAgB,CAAC,EAAY,IAC7B,EACE,EACK,OAEF,IAEF,OAGH,GAAY,QAAW,GAAU,EACrC,KAAM,CACJ,cAAe,OACf,OAAQ,OACR,WAAY,EAAM,WAAW,eAC7B,SAAU,EAAM,WAAW,QAAQ,IACnC,MAAO,EAAM,QAAQ,WACrB,WAAY,GACV,GAAc,EAAM,WAAa,EAAM,cACzC,MAAO,QACP,SAAU,QACV,UAAW,CACT,QAAS,OACT,gBAAiB,cACjB,MAAO,EAAM,QAAQ,gBAKd,GAAa,GAAU,CAClC,KAAM,GAAU,GAAU,GACpB,CAAE,aAAY,kBAAiB,GAAS,EAC9C,MAAO,OAAM,cAAc,IAAK,CAAE,UAAW,EAAQ,KAAM,cAAe,MAAS,KChC/E,GAAY,QAChB,GAAU,EACR,UAAW,CACT,QAAS,OACT,eAAgB,SAChB,gBAAiB,EAAM,QAAQ,OAAO,UACtC,OAAQ,OAEV,cAAe,CACb,WAAY,UAEd,KAAM,CACJ,eAAgB,CACd,WAAY,WAIlB,CAAE,KAAM,oBAGG,GAAc,GAAU,CACnC,KAAM,GAAU,GAAU,GAC1B,MACE,OAAM,cAAc,KAAM,CACxB,QAAS,KACN,EACH,kBAAmB,CAAE,SAAU,MAAM,cAAc,OAAQ,UCT3D,GAAY,QAChB,GAAU,EACR,KAAM,CACJ,SAAU,EACV,MAAO,QAET,WAAY,CACV,gBAAiB,EAAM,QAAQ,WAAW,OAE5C,OAAQ,CACN,UAAW,OACX,gBAAiB,EAAM,QAAQ,WAAW,MAC1C,YAAa,OACb,aAAc,UAGlB,CAAE,KAAM,kBAGH,YAAc,EAAO,CAC1B,KAAM,CAAE,QAAS,EACX,EAAU,KACV,CAAC,EAAO,GAAY,SAAS,CAAC,EAAG,IACjC,CAAC,EAAU,GAAe,SAAS,GACnC,CAAC,EAAwB,GAA6B,SAAS,GAC/D,CAAC,EAAa,IAAkB,SAAS,CAAC,KAC1C,GAAU,SAEV,CAAE,UAAU,gBAEZ,GAAe,CAAC,GAAG,KAAa,CACpC,EAAS,CAAC,EAAU,MAGhB,GAAsB,IAAM,CAChC,EAAY,EAAW,IAGnB,GAAsB,IAAM,CAChC,EAAY,EAAW,IAGnB,GAAkB,IAAM,EAAW,EAAI,EAAY,OAEzD,UAAU,IAAM,CAId,KAAM,IAAmB,IAAa,EAAI,EAAI,EACxC,GACJ,GAAQ,QAAQ,YAAc,GAAU,GAAmB,GACvD,GAAe,EAAM,GAAK,EAAyB,EAAM,GACzD,GAAwB,KAAK,MAAM,GAAe,KAExD,EAA0B,IAC1B,GAAe,WAAW,EAAM,KAChC,EAAS,CACP,KAAK,MAAM,GAAe,IAC1B,GAAe,MAGhB,CAAC,GAAO,IAEX,KAAM,IAAe,IAAa,EAAM,GAAK,EAAM,GAAK,GAExD,MACE,OAAM,cAAc,MAAO,CAAE,UAAW,EAAQ,MAC5C,MAAM,cAAc,OAAQ,CAAE,IAAK,GAAS,UAAW,EAAQ,OAAQ,SAAU,UAC/E,MAAM,cAAc,MAAO,KACzB,MAAM,cAAc,WAAY,CAChC,MAAO,GACP,SAAU,GACV,sBAAuB,IAErB,IAAa,GACb,MAAM,cAAc,WAAY,CAC9B,QAAS,GACT,UAAW,mBAET,MAAM,cAAc,mBAAoB,OAG5C,EAAY,GAAU,IAAI,CAAC,GAAK,KAChC,MAAM,cAAc,UAAW,CAC7B,MAAO,GACP,aAAc,KAAU,EACxB,WAAY,IAAa,EACzB,IAAK,GACL,KAAM,GAAI,MAAQ,OAClB,MAAO,GAAI,OAAS,UAGtB,MACA,MAAM,cAAc,WAAY,CAC9B,OAAQ,GACR,QAAS,GACT,UAAW,iBAET,MAAM,cAAc,iBAAkB,UAMhD,KAAiB,GACjB,EAAY,GAAU,IAAI,CAAC,GAAK,KAC9B,MAAM,cAAc,SAAU,CAAE,IAAK,GAAO,MAAO,GAAO,MAAO,IAC7D,GAAI,UAKV,MAAM,cAAc,SAAU,CAC5B,IAAK,8BACL,MAAO,EAAM,GACb,MAAO,EAAM,IAEX,EAAY,EAAM,IAAI,EAAM,IAAI,U,gBCzI5C,YAAe,EAAM,EAAO,CAC1B,KAAM,GAAU,EAAK,EAAK,OAAS,GACnC,GAAI,EAAC,EACL,MAAI,IAAW,GAAY,EAAM,QAAQ,OAAO,GAC5C,GAAW,GAAY,EAAM,QAAQ,OAAO,QACzC,EAAM,QAAQ,OAAO,MAGvB,YACL,EAEA,C,MACA,KAAM,GAAQ,WAEd,MAAK,GAAM,KAET,MAAM,cAAc,WAAY,CAAE,MAAO,IAAK,OAAQ,GAAI,IAAK,EAAG,IAAK,KAAM,GACzE,EAAM,OAAS,MAAM,cAAc,QAAS,KAAM,EAAM,OACxD,MAAM,cAAc,eAAgB,CAAE,MAAO,KAAM,QAAN,OAAe,GAAM,EAAM,KAAM,MAJ5D,KCP1B,KAAM,IAAa,GACjB,QACE,GAAU,EACR,UAAW,CACT,MAAO,OACP,QAAS,OACT,cAAe,MACf,SAAU,OACV,eAAgB,WAChB,WAAY,SACZ,aAAc,EAAM,QAAQ,GAC5B,UAAW,EAAM,WAEnB,aAAc,CACZ,KAAM,WACN,SAAU,EACV,SAAU,WAEZ,cAAe,CACb,KAAM,WACN,QAAS,OACT,cAAe,MACf,SAAU,OACV,WAAY,SACZ,WAAY,EAAM,QAAQ,GAC1B,SAAU,EACV,SAAU,WAEZ,YAAa,GACb,MAAO,CACL,QAAS,cACT,aAAc,KAGlB,CAAE,KAAM,2BAQN,GAAqB,CAAC,CAC1B,QAAQ,eACR,eAEA,gBAAoB,KAAY,CAC9B,QAAS,KACT,UAAW,KACX,UAAW,EACX,cAAe,gBAEb,GAkBC,YAAuB,EAAO,CACnC,KAAM,CACJ,cACA,QACA,eAAgB,EAAiB,OACjC,WACA,YAAY,QACV,EACE,EAAU,GAAU,CAAE,gBAEtB,EAAgB,GAGpB,gBAAoB,GAAoB,CAAE,MAAO,EAAO,UAAW,EAAQ,QAG7E,MACE,iBAAoB,WAAgB,KAChC,gBAAoB,KAAQ,CAAE,MAAO,IACrC,gBAAoB,MAAO,CAAE,UAAW,EAAQ,WAC9C,gBAAoB,MAAO,CAAE,UAAW,EAAQ,cAC9C,EACA,GACA,gBAAoB,KAAY,CAAE,UAAW,EAAQ,YAAa,QAAS,SACvE,IAIN,gBAAoB,MAAO,CAAE,UAAW,EAAQ,eAAiB,K,gBC/G3E,KAAM,IAAY,QAChB,GAAU,EACR,QAAS,CACP,SAAU,MACV,SAAU,WACV,OAAQ,EAAM,QAAQ,GACtB,MAAO,EAAM,QAAQ,IACpB,EAAM,YAAY,KAAK,OAAQ,CAC9B,SAAU,MACV,SAAU,WACV,OAAQ,QACR,MAAO,QACP,OAAQ,GAAG,EAAM,QAAQ,cAAc,EAAM,QAAQ,WAI3D,CAAE,KAAM,8BAKG,GAAU,IAAM,CAC3B,KAAM,GAAU,KAChB,MACE,iBAAoB,MAAO,CACzB,IAAK,GACL,UAAW,EAAQ,QACnB,IAAK,sCCXL,GAAY,QAChB,GAAU,EACR,UAAW,CACT,QAAS,EAAM,QAAQ,IACtB,EAAM,YAAY,KAAK,OAAQ,CAC9B,QAAS,EAAM,QAAQ,KAG3B,MAAO,CACL,cAAe,EAAM,QAAQ,IAC5B,EAAM,YAAY,KAAK,OAAQ,CAC9B,cAAe,EAAM,QAAQ,GAC7B,SAAU,KAGd,SAAU,CACR,MAAO,EAAM,QAAQ,cAGzB,CAAE,KAAM,uBASH,YAAmB,EAAO,CAC/B,KAAM,CAAE,SAAQ,gBAAe,iBAAgB,cAAe,EACxD,EAAU,KACV,EAAW,YACX,EAAU,KAEhB,MACE,iBAAoB,KAAM,CAAE,UAAW,GAAM,QAAS,EAAG,UAAW,EAAQ,WACxE,gBAAoB,GAAS,MAC7B,gBAAoB,KAAM,CAAE,KAAM,GAAM,GAAI,GAAI,GAAI,EAAG,GAAI,GACzD,gBAAoB,KAAY,CAChC,cAAe,QACf,QAAS,QACT,UAAW,EAAQ,UACnB,SACG,EAAQ,KAAO,GAElB,gBAAoB,KAAY,CAAE,QAAS,QAAS,UAAW,EAAQ,UACrE,GAEF,gBAAoB,KAAY,CAAE,QAAS,KAAM,UAAW,EAAQ,OAAS,uCAG7E,gBAAoB,KAAY,CAAE,QAAS,MACzC,gBAAoB,EAAM,CAAE,GAAI,IAAK,cAAe,eAAgB,QAAS,IAAM,EAAS,KAAO,WAElG,gBACC,IACF,gBAAoB,EAAM,CAAE,GAAI,GAAc,EAAQ,KAAO,mBAAqB,kC,gBC9D9F,KAAM,IAAgB,QACpB,CACE,KAAM,CACJ,eAAgB,YAChB,OAAQ,YAGZ,CAAE,KAAM,sCACR,MAKI,GAAY,QAChB,CACE,KAAM,CACJ,eAAgB,YAChB,MAAO,YAGX,CAAE,KAAM,kCACR,KAQK,YAAqB,EAAO,CACjC,KAAM,CAAE,cAAa,GAAc,EAC7B,CAAC,EAAU,GAAe,WAC9B,MAGI,EAAgB,mBAAuB,GAEvC,CAAC,EAAW,KAAe,GAAmB,EAC9C,EAAc,EAAgB,OAChC,EAAgB,MAChB,EAAc,EAAc,OAAS,GACnC,GAAuB,EAAc,OAAS,EAE9C,GAAe,IAAU,CAC7B,EAAY,GAAM,gBAGd,GAAc,IAAM,CACxB,EAAY,OAGR,GAAO,QAAQ,GACrB,MACE,iBAAoB,WAAU,KAC1B,gBAAoB,KAAqB,CAAE,aAAc,gBAAiB,GACxE,EAAc,OAAS,GAAK,gBAAoB,GAAW,CAAE,MAAO,IAAQ,GAC5E,EAAc,OAAS,GAAK,gBAAoB,GAAW,CAAE,MAAO,IAAQ,GAC5E,IACA,gBAAoB,GAAe,CAAE,QAAS,IAAe,OAE7D,gBAAoB,IAAK,CAAE,MAAO,CAAE,UAAW,WAAc,IAE/D,gBAAoB,MAAS,CAC7B,KAAM,GACN,SAAU,EACV,QAAS,GACT,aAAc,CACZ,SAAU,SACV,WAAY,QAEd,gBAAiB,CACf,SAAU,MACV,WAAY,SAGZ,gBAAoB,KAAM,KACxB,EAAgB,IAAI,CAAC,GAAU,KAC/B,gBAAoB,KAAU,CAAE,IAAK,GAAO,OAAQ,IAChD,gBAAoB,GAAW,CAAE,MAAO,IAAQ,SCpEhE,KAAM,IAAY,QAChB,GAAU,EACR,OAAQ,CACN,SAAU,aACV,QAAS,EAAM,QAAQ,GACvB,MAAO,OACP,UAAW,EAAM,QAAQ,GACzB,SAAU,WACV,OAAQ,IACR,QAAS,OACT,cAAe,MACf,WAAY,SACZ,gBAAiB,EAAM,KAAK,gBAC5B,mBAAoB,SACpB,eAAgB,SACf,EAAM,YAAY,KAAK,OAAQ,CAC9B,SAAU,SAGd,aAAc,CACZ,SAAU,OACV,SAAU,GAEZ,cAAe,CACb,MAAO,QAET,MAAO,CACL,MAAO,EAAM,QAAQ,OAAO,UAC5B,UAAW,YACX,SAAU,EAAM,WAAW,GAAG,SAC9B,aAAc,GAEhB,SAAU,CACR,MAAO,EAAM,QAAQ,OAAO,UAC5B,QAAS,GACT,QAAS,eACT,UAAW,EAAM,QAAQ,GACzB,SAAU,QAEZ,KAAM,CACJ,cAAe,YACf,SAAU,GACV,QAAS,GACT,aAAc,EAAM,QAAQ,GAC5B,MAAO,EAAM,QAAQ,OAAO,WAE9B,WAAY,CACV,MAAO,EAAM,QAAQ,OAAO,WAE9B,eAAgB,CACd,SAAU,UACV,QAAS,GACT,YAAa,CAAC,EAAM,QAAQ,IAC5B,aAAc,EAAM,QAAQ,KAE9B,gBAAiB,CACf,SAAU,UACV,WAAY,CAAC,EAAM,QAAQ,IAC3B,aAAc,EAAM,QAAQ,OAGhC,CAAE,KAAM,oBAkCJ,GAAe,CAAC,CACpB,OACA,WACA,UACA,eAEK,EAIA,EAKH,gBAAoB,GAAa,CAAE,UAAW,EAAQ,YAClD,gBAAoB,EAAM,CAAE,GAAI,GAAY,GAC5C,gBAAoB,KAAY,KAAM,IANnC,gBAAoB,KAAY,CAAE,UAAW,EAAQ,MAAQ,GAJ7D,KAeL,GAAgB,CAAC,CAAE,YAAW,UAAS,aAAc,CACzD,KAAM,GACJ,gBAAoB,KAAY,CAAE,UAAW,EAAQ,MAAO,QAAS,MACjE,GAIN,MAAK,GAKH,gBAAoB,KAAS,CAAE,MAAO,EAAS,UAAW,aACtD,GALG,GAUL,GAAmB,CAAC,CAAE,UAAS,cAC9B,EAID,MAAO,IAAa,SACf,gBAAoB,WAAgB,KAAM,GAIjD,gBAAoB,KAAY,CAC9B,UAAW,EAAQ,SACnB,QAAS,YACT,UAAW,QAET,GAbG,KAuBJ,YAAgB,EAAO,CAC5B,KAAM,CACJ,WACA,oBACA,QACA,WACA,QACA,UACA,OACA,YACE,EACE,EAAU,KAEV,GAAW,GADC,UAAO,gBACE,kBAAkB,cAAgB,YACvD,GAAgB,GAAqB,EACrC,GAAY,GAAS,EACrB,GAAgB,GAAG,aAAwB,KAC3C,GAAe,GAAG,QAAmB,KAE3C,MACE,iBAAoB,WAAgB,KAChC,gBAAoB,KAAQ,CAAE,cAAe,GAAe,aAAc,KAC1E,gBAAoB,SAAU,CAAE,MAAO,EAAO,UAAW,EAAQ,QAC/D,gBAAoB,IAAK,CAAE,UAAW,EAAQ,cAC5C,gBAAoB,GAAc,CAClC,QAAS,EACT,KAAM,EACN,SAAU,EACV,UAAW,KAEX,gBAAoB,GAAe,CACnC,QAAS,EACT,UAAW,GACX,QAAS,IAET,gBAAoB,GAAkB,CAAE,QAAS,EAAS,SAAU,KAEtE,gBAAoB,KAAM,CAAE,UAAW,GAAM,UAAW,EAAQ,cAAe,QAAS,GACtF,KCrNZ,KAAM,IAAY,QAChB,GAAU,EACR,KAAM,CACJ,UAAW,QAEb,MAAO,CACL,MAAO,EAAM,QAAQ,OAAO,MAC5B,WAAY,OACZ,cAAe,EACf,SAAU,EAAM,WAAW,SAC3B,aAAc,EAAM,QAAQ,GAAK,EACjC,WAAY,GAEd,MAAO,CACL,MAAO,2BACP,SAAU,EAAM,WAAW,SAC3B,WAAY,KAGhB,CAAE,KAAM,yBAQJ,GAAqB,CAAC,CAAE,QAAO,eACnC,gBAAoB,KAAY,CAAE,UAAW,GAAa,GAerD,YAAqB,EAAO,CACjC,KAAM,CAAE,QAAO,QAAO,OAAQ,EACxB,EAAU,KACV,EACJ,gBAAoB,GAAoB,CACtC,UAAW,EAAQ,MACnB,MAAO,GAAS,cAGpB,MACE,iBAAoB,KAAM,CAAE,KAAM,IAC9B,gBAAoB,OAAQ,CAAE,UAAW,EAAQ,MAC/C,gBAAoB,KAAY,CAAE,UAAW,EAAQ,OAAS,GAC9D,EAAM,gBAAoB,EAAM,CAAE,GAAI,GAAO,GAAW,IC7DlE,KAAM,IAAa,CACjB,KAAM,UACN,OAAQ,WAQV,YAAkB,EAAW,CAC3B,KAAM,GAAI,GAAI,MACR,EAAO,OAAO,UAAU,SAExB,EAAS,GAEf,GAAI,CAAC,EAAU,IAAI,mBACjB,MAAO,GAGT,KAAM,GAAe,EAAU,eAAe,mBAE9C,SAAW,KAAS,GAClB,GAAI,EAAM,IAAI,UAAY,EAAM,IAAI,YAAa,CAC/C,GAAI,GAAQ,EAAM,UAAU,SAE5B,KAAM,GAAU,CACd,SAAU,EAAM,UAAU,eACvB,IAGL,GAAI,CACF,GAAI,QAAO,eAAe,EAAM,QAChC,CAEA,QAAQ,KACN,gBAAgB,EAAQ,0CAE1B,EAAQ,SAAW,MACnB,EAAQ,MAGV,KAAM,GAAO,EAAE,mBAAmB,EAAM,GACxC,EAAO,KAAK,CAAE,OAAM,UAGxB,MAAO,GASF,YAAuB,EAAQ,CACpC,KAAM,GAAY,OAAO,cAEnB,EAAe,GACf,CAAC,EAAQ,GAAY,MAAM,SAAS,GAc1C,MAZA,OAAM,UAAU,IAAM,CACpB,EAAS,GAAS,IAElB,KAAM,GAAa,YAAY,IAAM,CACnC,EAAS,GAAS,KACjB,KAEH,MAAO,IAAM,CACX,cAAc,KAEf,CAAC,IAEA,EAAO,SAAW,EAElB,MAAM,cAAc,MAAM,SAAU,KAChC,EAAO,IAAI,GACX,MAAM,cAAc,YAAa,CAC/B,MAAO,EAAM,MACb,MAAO,EAAM,KACb,IAAK,EAAM,UAMd,KClFT,KAAM,IAAU,GACd,QAAa,CACX,KAAM,CACJ,MAAO,EAAM,QAAQ,OAAO,MAC5B,QAAS,EAAM,QAAQ,EAAG,EAAG,GAC7B,gBAAiB,EAAM,QAAQ,OAAO,SAAS,OAC/C,mBAAoB,EACpB,eAAgB,aAIhB,GAAY,QAAW,GAAQ,CAAE,KAAM,4BAuCtC,YAAwB,EAAO,CACpC,KAAM,CAAE,QAAO,WAAU,YAAa,EAChC,EAAU,GAAU,GAC1B,MACE,iBAAoB,MAAO,CAAE,UAAW,EAAQ,MAC5C,GACA,gBAAoB,KAAY,CAAE,QAAS,YAAa,UAAW,MAC/D,GAGJ,GACA,gBAAoB,KAAY,CAAE,QAAS,KAAM,UAAW,MACxD,GAGJ,GC5BD,YAAkB,EAAO,CAC9B,KAAM,CAAE,cAAa,OAAM,QAAO,OAAM,WAAU,QAAO,UAAS,QAChE,EACF,MACE,OAAM,cAAc,KAAM,KACtB,MAAM,cAAc,UAAW,KAC7B,MAAM,cAAc,eAAgB,CAAE,MAAO,EAAO,SAAU,GAAY,KAE5E,MAAM,cAAc,YAAa,KAC/B,kBAAM,QACN,MAAM,cAAc,IAAK,KACrB,EAAK,IAAI,CAAC,EAAK,KACf,MAAM,cAAc,KAAM,CAAE,KAAM,QAAS,MAAO,EAAK,IAAK,OAG9D,KACF,GAEF,MAAM,cAAc,YAAa,KAC/B,CAAC,GACD,MAAM,cAAc,OAAQ,CAAE,GAAI,IAAK,QAAS,EAAS,MAAO,WAC5D,GAGJ,GACA,MAAM,cAAc,OAAQ,CAAE,GAAI,EAAM,MAAO,WAC3C,KC5Dd,KAAM,IAAU,GACd,QAAa,CACX,KAAM,CACJ,QAAS,OACT,oBAAqB,uCACrB,aAAc,MACd,QAAS,EAAM,QAAQ,MAIvB,GAAY,QAAW,GAAQ,CAAE,KAAM,0BAyBtC,YAAsB,EAAO,CAClC,KAAM,CAAE,cAAa,GAAe,EAC9B,EAAU,GAAU,GAC1B,MACE,iBAAoB,MAAO,CAAE,UAAW,EAAQ,QAAS,GACrD,G,gBC5CR,KAAM,IAAY,QAChB,IAAO,EACL,KAAM,CAAC,CAAE,cAAgB,EACvB,QAAS,OACT,kBACE,mHACF,iBAAkB,uBAClB,oBAAqB,gBACrB,OAAQ,EAAW,OAAS,QAC5B,UAAW,WAGf,CAAE,KAAM,kBAQH,YAAc,EAAO,CAC1B,KAAM,CAAE,UAAS,YAAa,EACxB,CAAE,YAAa,iBAAW,IAC1B,EAAU,GAAU,CAAE,aAC5B,MACE,iBAAoB,KAAe,CACjC,MAAQ,GAAe,KAClB,EACH,KAAM,EAAU,aAAa,CAAE,eAG/B,gBAAoB,MAAO,CAAE,UAAW,EAAQ,MAAQ,IC7BzD,YAAwB,EAAO,CACpC,KAAM,CAAE,UAAS,cAAa,GAAc,EAC5C,MACE,iBAAoB,GAAM,CAAE,QAAS,GACjC,gBAAoB,GAAQ,IAAK,IACjC,G,gBCRD,KAAM,IAAuB,YAAS,CAC3C,aAAc,YAAS,IAAI,SAAS,gBAAa,WACjD,QAAS,YAAS,CAChB,MAAO,cAAW,WAClB,YAAa,cAAW,WACxB,QAAS,cAAW,aAEtB,kBAAmB,YAAS,CAC1B,MAAO,cACP,SAAU,YAAS,CACjB,KAAM,aAAU,QAChB,cAAe,cACf,oBAAqB,WAAQ,qBCTtB,GAAW,CAGtB,yBAA0B,EAAI,GAAK,IAGnC,wBAAyB,EAAI,GAAK,KAI7B,YAAuB,EAAU,CACtC,KAAM,GAAW,GAAI,MAAK,KAAK,MAAQ,GAAS,0BAChD,GAAI,CAAC,EACH,MAAO,GAGT,KAAM,CAAC,EAAS,EAAY,GAAc,EAAS,MAAM,KACnD,EAAU,KAAK,MAAM,KAAK,IAChC,MAAI,OAAO,GAAQ,KAAQ,SAClB,EAGF,GAAI,MAAK,EAAQ,IAAM,IAAO,GAAS,yBA+BzC,QAA6B,CAKlC,YAAY,EAAS,CAJnB,kBACA,0BACD,gBAGC,KAAK,QAAU,EACf,KAAK,gBAAkB,GAAI,iBAC3B,KAAK,MAAQ,CAAE,KAAM,cAGjB,QAAQ,CAEZ,KAAM,MAAK,kBAIb,WAAY,CACV,KAAM,CAAE,qBAAsB,KAAK,iBAC7B,EAAM,EAAkB,SAAS,cACjC,EAAQ,kCAAkC,KAAK,GACrD,GAAI,CAAC,EACH,KAAM,IAAI,WAAU,kCAAkC,MAGxD,MAAO,GAAM,QAIT,aAAa,CAEjB,MAAO,MADe,MAAK,mBACZ,kBAAkB,MAInC,YAAa,CAEX,MAAO,MADc,iBACN,aAIX,iBAAiB,CAErB,MAAO,MADe,MAAK,mBACZ,aAIX,uBAAuB,CAE3B,MAAO,MADe,MAAK,mBACZ,kBAAkB,cAI7B,iBAAiB,CAErB,MAAO,CACL,MAAO,MAFa,MAAK,mBAEV,kBAAkB,YAK/B,UAAU,CACd,KAAK,gBAAgB,QAGvB,gBAAiB,CACf,GAAI,KAAK,MAAM,OAAS,SACtB,MAAO,MAAK,MAAM,QACb,GAAI,KAAK,MAAM,OAAS,YAAc,KAAK,MAAM,SACtD,MAAO,MAAK,MAAM,SAEpB,KAAM,IAAI,OAAM,+DAGZ,kBAAkB,CACtB,GAAI,KAAK,MAAM,OAAS,WACtB,MAAO,MAAK,MAAM,QACb,GACL,KAAK,MAAM,OAAS,UACpB,GAAI,MAAS,KAAK,MAAM,UAExB,MAAO,MAAK,MAAM,QAGpB,KAAM,GACJ,KAAK,MAAM,OAAS,SAAW,KAAK,MAAM,QAAU,OAEhD,EAAU,KAAK,eAAe,KAClC,GACE,MAAK,MAAQ,CACX,KAAM,SACN,UACA,UAAW,GAAc,EAAQ,kBAAkB,QAE9C,GAET,GAAS,CACP,WAAK,MAAQ,CACX,KAAM,SACN,SAEI,IAIV,YAAK,MAAQ,CACX,KAAM,WACN,UACA,YAGK,OAGH,eAAe,CACnB,KAAM,GAAU,KAAM,MAAK,QAAQ,aAAa,WAAW,QAKrD,EAAW,KAAM,OACrB,GAAG,KAAW,KAAK,QAAQ,mBAC3B,CACE,OAAQ,KAAK,gBAAgB,OAC7B,QAAS,CAAE,mBAAoB,kBAC/B,YAAa,YAIjB,GAAI,CAAC,EAAS,GACZ,KAAM,MAAM,eAAc,aAAa,GAGzC,MAAO,sBAAqB,MAAM,KAAM,GAAS,SC5J9C,KAAM,IAAqB,GAAU,CAC1C,KAAM,GAAe,OAAO,iBAEtB,CAAE,UAAS,SAAU,SAAS,SAAY,CAC9C,KAAM,GAAW,GAAI,uBAAsB,CACzC,SAAU,EAAM,SAChB,iBAGF,KAAM,GAAS,QAEf,EAAM,gBAAgB,IACrB,IAEH,MAAI,GACK,MAAM,cAAc,SAAU,MAC5B,EAEP,MAAM,cAAc,WAAY,CAC9B,MAAO,4EACP,MAAO,IAKN,MC3DI,GAAY,QACvB,CACE,UAAW,CACT,QAAS,EACT,UAAW,QAEb,KAAM,CACJ,QAAS,OACT,cAAe,SACf,MAAO,OACP,SAAU,QACV,OAAQ,EACR,QAAS,IAGb,CAAE,KAAM,wBAGG,GAAW,CAAC,CAAE,cAAe,CACxC,KAAM,GAAU,KAEhB,MACE,iBAAoB,KAAM,CAAE,UAAW,KAAM,KAAM,GAAM,QAAS,GAC9D,ICtBD,QAAyB,CAC9B,WAAY,CACV,MAAO,aAGH,aAAa,EAInB,YAAa,CACX,MAAO,CACL,MAAO,oBACP,YAAa,cAIX,iBAAiB,CACrB,MAAO,CACL,MAAO,oBACP,YAAa,cAIX,uBAAuB,CAC3B,KAAM,GAAgB,qBACtB,MAAO,CACL,KAAM,OACN,gBACA,oBAAqB,CAAC,SAIpB,iBAAiB,CACrB,MAAO,QAGH,UAAU,GCpClB,YAAyB,EAAO,CAC9B,KAAM,CAAC,EAAS,EAAS,GAAc,EAAM,MAAM,KACnD,MAAO,MAAK,MAAM,KAAK,IAWlB,QAA0B,CAC9B,YAAc,EAAQ,CAAE,KAAK,OAAS,EAEvC,WAAY,CACV,MAAO,MAAK,OAAO,aAGd,YAAW,EAAQ,CACxB,MAAO,IAAI,IAAmB,QAG1B,aAAa,C,QACjB,MAAO,WAAK,QAAO,aAAZ,sBAGT,YAAa,CACX,MAAO,MAAK,OAAO,aAGf,iBAAiB,CACrB,MAAO,MAAK,OAAO,aAGf,uBAAuB,CAC3B,KAAM,GAAQ,KAAM,MAAK,aAEzB,GAAI,CAAC,EAAO,CACV,KAAM,GAAgB,gBAAgB,KAAK,cAC3C,MAAO,CACL,KAAM,OACN,gBACA,oBAAqB,CAAC,IAI1B,KAAM,CAAE,MAAK,OAAQ,GAAgB,GACrC,MAAO,CACL,KAAM,OACN,cAAe,EACf,oBAAqB,UAAO,SAI1B,iBAAiB,C,QAErB,MAAO,CAAE,MADK,KAAM,YAAK,QAAO,aAAZ,6BAIhB,UAAU,C,QACd,MAAO,WAAK,QAAO,UAAZ,uBC5CJ,QAAoB,CA0DxB,YACG,EACA,EAGA,EACF,CA/DD,yBA+DG,KAAK,SAAW,EAAS,KAAK,QAAU,EAAQ,KAAK,QAAU,QAzD5D,cAAc,CACnB,MAAO,IAAI,UAQN,YAAW,EAiBlB,CACE,MAAO,IAAmB,WAAW,SAShC,QAAO,EAWd,CACE,MAAO,IAAI,IAAa,EAAQ,SAAU,EAAQ,QAAS,EAAQ,SAYrE,WAAY,CACV,KAAM,GAAM,KAAK,SAAS,cACpB,EAAQ,kCAAkC,KAAK,GACrD,GAAI,CAAC,EACH,KAAM,IAAI,WAAU,kCAAkC,MAGxD,MAAO,GAAM,QAIT,aAAa,CAEjB,MAAO,MADgB,MAAK,QAAQ,wBACpB,MAIlB,YAAa,CACX,GAAI,CAAC,KAAK,QACR,KAAM,IAAI,OACR,kGAGJ,MAAO,MAAK,aAIR,iBAAiB,CACrB,GAAI,KAAK,eACP,MAAO,MAAM,MAAK,eAGpB,GAAI,CACF,YAAK,eAAiB,KAAK,QAAQ,aAC5B,KAAM,MAAK,qBACX,EAAP,CACA,WAAK,eAAiB,OAChB,QAKJ,uBAAuB,CAC3B,MAAO,MAAK,cAIR,iBAAiB,CAErB,MAAO,CAAE,MAAO,MADO,MAAK,QAAQ,wBACX,YAIrB,UAAU,CACd,MAAO,MAAK,QAAQ,WC/DjB,KAAM,IAAiB,CAAE,UAnEd,CAAC,CAAE,SAAQ,qBAAsB,CACjD,KAAM,CAAE,SAAQ,QAAO,WAAY,EAC7B,EAAU,aAAO,GACjB,EAAW,aAAO,eAElB,EAAc,SAAY,CAC9B,GAAI,CACF,KAAM,GAAmB,KAAM,GAAQ,qBAAqB,CAC1D,aAAc,KAEhB,GAAI,CAAC,EACH,KAAM,IAAI,OACR,OAAO,mDAIX,KAAM,GAAU,KAAM,GAAQ,aAE9B,EACE,UAAoB,CAClB,SAAU,EAAiB,SAC3B,UACA,mBAGG,EAAP,CACA,EAAS,KAAK,GAAI,OAAe,eAAgB,MAIrD,MACE,iBAAoB,GAAU,KAC1B,gBAAoB,GAAU,CAC9B,QAAS,aACT,MAAO,EACP,QACE,gBAAoB,IAAQ,CAAE,MAAO,UAAW,QAAS,WAAY,QAAS,GAAe,YAK7F,gBAAoB,KAAY,CAAE,QAAS,SAAW,MA0BrB,OApB5B,MAAO,EAAM,IAAW,CACrC,KAAM,GAAU,EAAK,IAAI,GAEnB,EAAmB,KAAM,GAAQ,qBAAqB,CAC1D,SAAU,KAGZ,GAAI,CAAC,EACH,OAGF,KAAM,GAAU,KAAM,GAAQ,aAE9B,MAAO,WAAoB,CACzB,SAAU,EAAiB,SAC3B,UACA,cCxCS,GAAgB,CAAE,UA9Bb,CAAC,CAAE,qBACnB,gBAAoB,GAAU,KAC1B,gBAAoB,GAAU,CAC9B,MAAO,QACP,QAAS,aACT,QACE,gBAAoB,IAAQ,CAC1B,MAAO,UACP,QAAS,WACT,QAAS,IAAM,EAAgB,GAAI,MACnC,UAKF,gBAAoB,KAAY,CAAE,QAAS,SAAW,yBAEpD,gBAAoB,KAAM,MAAQ,yCAElC,gBAAoB,KAAM,MAAQ,iDAWJ,OAJzB,SACN,GAAI,K,+DCpBb,KAAM,IAAiB,8CAKjB,GAAgB,QACpB,GAAU,EACR,KAAM,CACJ,QAAS,OACT,SAAU,iBAEZ,OAAQ,CACN,UAAW,SACX,UAAW,EAAM,QAAQ,MAG7B,CAAE,KAAM,4BAQJ,GAAc,GAAiB,CACnC,KAAM,CAAE,SAAQ,GAAS,EACzB,MAAO,CACL,SAAU,KACP,IAkFM,GAAiB,CAAE,UA9Ed,CAAC,CAAE,qBAAsB,CACzC,KAAM,GAAU,KACV,CAAE,WAAU,eAAc,aAAc,UAAQ,CACpD,KAAM,aAGF,CAAE,UAAW,EAEb,EAAe,CAAC,CAAE,YAAa,CACnC,EACE,cAAwB,CACtB,SACA,QAAS,CACP,MAAO,GAAG,qBAMlB,MACE,iBAAoB,GAAU,KAC1B,gBAAoB,GAAU,CAAE,MAAO,cAAgB,QAAS,cAC9D,gBAAoB,KAAY,CAAE,QAAS,SAAW,0CAEpD,gBAAoB,KAAM,MAAQ,sCAIpC,gBAAoB,OAAQ,CAAE,UAAW,EAAQ,KAAM,SAAU,EAAa,IAC5E,gBAAoB,KAAa,KAC/B,gBAAoB,KAAW,IAC5B,GAAW,EAAS,SAAU,CAAE,SAAU,MAC7C,MAAO,UACP,OAAQ,SACR,MAAO,QAAQ,EAAO,UAEtB,EAAO,QACP,gBAAoB,KAAgB,CAAE,MAAO,IAAQ,EAAO,OAAO,UAGrE,gBAAoB,KAAa,KAC/B,gBAAoB,KAAW,IAC5B,GACD,EAAS,UAAW,CAClB,SAAU,GACV,SAAU,GACR,CAAC,GACD,GAAe,KAAK,IACpB,mDAGN,MAAO,sBACP,OAAQ,SACR,aAAc,MACd,MAAO,QAAQ,EAAO,WAEtB,EAAO,SACP,gBAAoB,KAAgB,CAAE,MAAO,IAAQ,EAAO,QAAQ,UAGtE,gBAAoB,IAAQ,CAC5B,KAAM,SACN,MAAO,UACP,QAAS,WACT,UAAW,EAAQ,OACnB,SAAU,CAAC,kBAAW,UAAW,CAAC,KAAQ,IAC1C,gBAY6B,OAF1B,SAAS,ICzGlB,GAAuB,sCAUvB,GAAkB,CACtB,MAAO,GACP,OAAQ,GACR,OAAQ,IAGV,YAAqB,EAAI,EAAW,CAClC,GAAI,IAAM,GACR,KAAM,IAAI,OACR,IAAI,qEAIH,YACL,EACA,CAoBA,MAnBkB,GAAkB,OAClC,CAAC,EAAK,IAAW,CACf,GAAI,MAAO,IAAW,SACpB,UAAY,EAAQ,GACpB,EAAI,GAAU,CAAE,WAAY,GAAgB,GAAS,GAAI,GAElD,EAGT,KAAM,CAAE,MAAO,EACf,UAAY,EAAI,GAEhB,EAAI,GAAM,CAAE,WAAY,GAAgB,OAAQ,KAAI,UAE7C,GAET,IAMG,KAAM,IAAqB,CAChC,EACA,IACG,CACH,KAAM,GAAW,OAAO,aAClB,EAAY,eACZ,CAAC,EAAS,GAAc,SAAS,IAGjC,EAAsB,YACzB,GAAgB,CACf,EACE,wBAAwB,KAAK,CAC3B,cACA,QAAS,SAAY,C,MACnB,aAAa,WAAW,IACxB,KAAM,MAAY,UAAZ,4BAKd,CAAC,IAKH,gBAAgB,IAAM,C,OACpB,GAAI,CAAC,EACH,OAIF,KAAM,GAAqB,aAAa,QACtC,IAIF,GAAI,IAAuB,KAAM,CAC/B,EAAW,IACX,OAGF,KAAM,GAAW,EAAU,GAC3B,GAAI,CAAC,EAAU,CACb,EAAW,IACX,OAGF,GAAI,IAAY,GAEhB,SAAS,WACN,OAAO,EAAW,MAAS,SAAT,eAAiB,QACnC,KAAK,IAAU,CACV,IAGJ,CAAI,GACF,EAAoB,IAEpB,EAAW,OAGd,MAAM,IAAS,CACV,IAGJ,cAAa,WAAW,IACxB,EAAS,KAAK,IACd,EAAW,OAGR,IAAM,CACX,GAAY,KAEb,CACD,EACA,EACA,EACA,EACA,EACA,IAIF,KAAM,GAAW,QACf,IACE,OAAO,KAAK,GAAW,IAAI,GAAO,CAChC,KAAM,GAAW,EAAU,GAErB,CAAE,cAAc,EAAS,WAEzB,GAAuB,IAAW,CACtC,aAAa,QAAQ,GAAsB,EAAS,IAEpD,EAAoB,KAGtB,MACE,OAAM,cAAc,GAAW,CAC7B,IAAK,EAAS,GACd,OAAQ,EAAS,OACjB,gBAAiB,OAIzB,CAAC,EAAW,IAGd,MAAO,CAAC,EAAS,IC3IN,GAAkB,CAAC,CAC9B,kBACA,YAAY,GACZ,QACA,QAAQ,UACJ,CACJ,KAAM,GAAY,OAAO,cACnB,EAAU,YAEV,EAAkB,mBAAmB,GACrC,CAAC,EAAS,GAAoB,mBAClC,EACA,GAGF,MAAI,GACK,MAAM,cAAc,SAAU,MAIrC,MAAM,cAAc,KAAM,CAAE,QAAS,QACjC,MAAM,cAAc,OAAQ,CAAE,MAAO,EAAU,UAAU,eACzD,MAAM,cAAc,QAAS,KAC3B,GAAS,MAAM,cAAc,cAAe,CAAE,MAAO,EAAO,UAAW,IACvE,MAAM,cAAc,KAAM,CAC1B,UAAW,GACX,eAAgB,IAAU,SAAW,EAAQ,aAC7C,QAAS,EACT,UAAW,KACX,QAAS,GAEP,MAOC,GAAmB,CAAC,CAC/B,WACA,OACA,qBACI,CACJ,KAAM,GAAU,YACV,EAAU,OAAO,EAAS,QAC1B,EAAY,OAAO,cAEnB,CAAC,EAAO,GAAY,WAKpB,CAAC,EAAe,GAAoB,SAAS,IAG7C,GAAQ,MAAO,CAAE,iBAAe,gBAAgB,CACpD,GAAI,CACF,GAAI,IASJ,GARI,IAEF,IAAmB,KAAM,GAAQ,qBAAqB,CACpD,SAAU,MAKV,CAAC,IAAqB,KAAa,IAGrC,GAAiB,IACjB,GAAmB,KAAM,GAAQ,qBAAqB,CACpD,aAAc,KAEZ,CAAC,IACH,KAAM,IAAI,OACR,OAAO,EAAS,uDAKtB,GAAI,CAAC,GAAkB,CACrB,EAAiB,IACjB,OAGF,KAAM,IAAU,KAAM,GAAQ,aAC9B,EACE,aAAa,OAAO,CAClB,SAAU,GAAiB,SAC3B,UACA,oBAGG,GAAP,CAEA,EAAS,IACT,EAAiB,MAIrB,gBAAS,IAAM,GAAM,CAAE,cAAe,MAE/B,EACL,MAAM,cAAc,KAAM,CAAE,QAAS,QACjC,MAAM,cAAc,OAAQ,CAAE,MAAO,EAAU,UAAU,eACzD,MAAM,cAAc,QAAS,KAC3B,MAAM,cAAc,KAAM,CAC1B,UAAW,GACX,eAAgB,SAChB,QAAS,EACT,UAAW,KACX,QAAS,GAEP,MAAM,cAAc,SAAU,KAC5B,MAAM,cAAc,SAAU,CAC9B,QAAS,aACT,MAAO,EAAS,MAChB,QACE,MAAM,cAAc,OAAQ,CAC1B,MAAO,UACP,QAAS,WACT,QAAS,IAAM,CACb,GAAM,CAAE,UAAW,OAErB,YAKF,MAAM,cAAc,WAAY,CAAE,QAAS,SAAW,EAAS,SAC/D,GAAS,EAAM,OAAS,sBACxB,MAAM,cAAc,WAAY,CAAE,QAAS,QAAS,MAAO,SACvD,EAAM,cAStB,MAAM,cAAc,SAAU,OAI3B,YAAoB,EAAO,CAChC,MAAI,YAAc,GACT,MAAM,cAAc,GAAkB,IAAK,IAG7C,MAAM,cAAc,GAAiB,IAAK,ICvKnD,KAAM,IAAgB,QACpB,GAAU,EACR,KAAM,CACJ,QAAS,EAAM,QAAQ,EAAG,EAAG,EAAG,KAChC,UAAW,EAAM,QAAQ,IAE3B,UAAW,CACT,gBAAiB,EAAM,QAAQ,KAAK,KACpC,OAAQ,EAAM,QAAQ,OAG1B,CAAE,KAAM,wBAMJ,GAAa,QACjB,GAAU,EACR,KAAM,CAAE,QAAS,EAAM,QAAQ,EAAG,EAAG,EAAG,KAAM,QAAS,gBACvD,MAAO,CAAE,WAAY,KACrB,UAAW,CAAE,WAAY,EAAM,QAAQ,MAEzC,CAAE,KAAM,kCACR,KAaK,YAAoB,EAAO,CAChC,KAAM,CACJ,eACA,qBACA,WACA,QACA,WACA,QACA,YACE,EACE,EAAc,KACd,CAAC,EAAe,IAAe,SAAS,GAExC,GAAe,GAEjB,EAAC,GAAK,KAAqB,GAAY,KAE3C,GAAI,IACC,EAKH,MAAM,SAAS,IAAI,EAAU,IAAS,CAChC,oBAAO,MAAM,SAAU,GACzB,IAAqB,mBAAO,MAAM,YANtC,MAAM,SAAS,IAAI,EAAU,CAAC,GAAO,KAAU,CACzC,KAAU,GAAe,IAAqB,mBAAO,MAAM,YASnE,KAAM,IACJ,GAAuB,GAAe,CAAE,gBAAiB,IAE3D,MACE,OAAM,cAAc,KAAM,KACtB,MAAM,cAAc,cAAe,IAAK,IACtC,GAAS,MAAM,cAAc,GAAY,CAAE,MAAO,IAClD,MAAM,cAAc,KAAM,CAC1B,sBAAuB,GACvB,QAAS,EACT,MAAO,GAAS,EAChB,SAAU,IAER,GAEF,MAAM,cAAc,QAAS,MAC7B,MAAM,cAAc,YAAa,KAAM,IACvC,GAAY,MAAM,cAAc,WAAY,IAAK,MAS3D,KAAM,IAAmB,QACvB,GAAU,EACR,KAAM,CACJ,SAAU,EAAM,QAAQ,GACxB,UAAW,EAAM,QAAQ,GACzB,OAAQ,EAAM,QAAQ,EAAG,EAAG,EAAG,GAC/B,QAAS,EAAM,QAAQ,GAAK,EAAG,GAAK,GACpC,cAAe,OACf,UAAW,CACT,QAAS,EACT,gBAAiB,cACjB,MAAO,EAAM,QAAQ,KAAK,UAG9B,SAAU,CACR,WAAY,UAGhB,CAAE,KAAM,qBAaH,YAAiB,EAAO,CAC7B,KAAM,CAAE,cAAa,GAAc,EAC7B,EAAU,KAEhB,MAAO,OAAM,cAAc,IAAK,CAAE,cAAe,GAAM,QAAS,KAAY,M,qHC1I9E,KAAM,GACJ,SAAuB,qBAQZ,EAAsB,IAAM,CACvC,KAAM,GAAa,iBAAW,GAG9B,GAAI,IAAe,OACjB,MAAO,CACL,SAAU,UACV,SAAU,OACV,UAAW,OAKf,KAAM,GAAW,EAAW,UAAU,GACtC,GAAI,IAAa,OACf,KAAM,IAAI,OAAM,mCAGlB,MAAO,IAcI,EAAoB,GAG5B,CACH,KAAM,CAAE,aAAY,YAAa,EAG3B,EAAgB,IADD,OAGhB,GAGC,EAAyB,SAAwB,CAAE,EAAG,IAC5D,MACE,iBAAoB,EAAsB,SAAU,CAAE,MAAO,GACzD,IAaD,WACL,EACA,EACA,CACA,KAAM,GAAiC,GAEnC,MAAM,cAAc,EAAkB,CAAE,WAAY,GAChD,MAAM,cAAc,EAAW,IAAK,KAI5C,SAA8B,YAAc,wBAC1C,EAAU,aAAe,EAAU,MAAQ,eAEtC,I,iICnFF,OAAe,CACpB,YACI,EACD,EAAU,CACT,SAAU,UACV,SAAU,OACV,UAAW,OAEb,CAAE,KAAK,aAAe,EAAa,KAAK,QAAU,EAEpD,WAAW,EAAS,CAClB,KAAK,QAAU,EAGjB,aACE,EACA,EACA,CACE,QACA,cACE,GACJ,CACA,GAAI,CACF,KAAK,aAAa,aAAa,CAC7B,SACA,UACA,QACA,aACA,QAAS,KAAK,gBAET,EAAP,CAEA,QAAQ,KAAK,2CAA4C,KC7B/D,YAA2B,CACzB,GAAI,CACF,MAAO,aAAO,wBACd,CACA,MAAO,CAAE,aAAc,IAAM,KAS1B,YAAwB,CAC7B,KAAM,GAAa,aAAO,MACpB,EAAU,WAIV,EAAe,IAErB,YAAsB,CACpB,MAAI,GAAW,UAAY,MACzB,GAAW,QAAU,GAAI,GAAQ,IAE5B,EAAW,QAGpB,KAAM,GAAU,IAChB,SAAQ,WAAW,GAEZ,I,spBC4ME,EAAe,UAAU,GAAc,CAIhD,KAAM,IAAW,WAAY,GAAa,SAAc,GAIxD,KAAM,IAAY,YAAa,GAAa,UAAe,KAC1D,GAAiB,GAAe,KAoC5B,KAAM,GAMV,SAAa,CACd,GAAI,qBAaO,EAEV,SAAa,CACd,GAAI,qBAaO,EAMV,SAAa,CACd,GAAI,mBAaO,EAEV,SAAa,CACd,GAAI,qBAcO,EAEV,SAAa,CACd,GAAI,oBAcO,EAMV,SAAa,CACd,GAAI,wBASO,EAMV,SAAa,CACd,GAAI,qBASO,EAMV,SAAa,CACd,GAAI,mBASO,EAEV,SAAa,CACd,GAAI,mBAQO,EAMV,SAAa,CACd,GAAI,uBAYO,EAEV,SAAa,CACd,GAAI,wBAYO,EAEV,SAAa,CACd,GAAI,wBCxbO,EAAc,SAAa,CACtC,GAAI,eC+EO,EAAkB,SAAa,CAC1C,GAAI,mBCjDO,EAAiB,SAAa,CACzC,GAAI,kBCtDO,EAAe,SAAa,CACvC,GAAI,gBCoBO,EAAkB,SAAa,CAC1C,GAAI,mBCmCO,EAAc,SAAa,CACtC,GAAI,eCxDC,GAAI,GAAmB,UAAU,GAAkB,CAIxC,GAAiB,GAAiB,KAAU,GAAQ,OAIpE,KAAM,IAAS,EAAG,GAAiB,GAAiB,OAAY,IAAU,WACzE,GAAqB,GAAmB,KAgEpC,KAAM,GAAqB,SAAa,CAC7C,GAAI,sBClEO,GAAc,SAAa,CACtC,GAAI,eCWO,GAAiB,SAAa,CACzC,GAAI,kBC8EO,GAAqB,SAAa,CAC7C,GAAI,sBCPO,GAAgB,SAAa,CACxC,GAAI,kB,s5ICpGN,OAAiB,CACf,YAAc,EAAQ,CAKpB,GALsB,KAAK,OAAS,EAKhC,CAJU,EAAO,GAClB,MAAM,KACN,QAAQ,GAAQ,EAAK,MAAM,MAC3B,MAAM,GAAQ,EAAK,MAAM,qBAE1B,KAAM,IAAI,OACR,yFAAyF,EAAO,UAKlG,KAAK,CACP,MAAO,MAAK,OAAO,MAIjB,IAAI,CACN,KAAM,IAAI,OAAM,6BAA6B,QAG/C,UAAW,CACT,MAAO,UAAU,KAAK,OAAO,OAW1B,WAAsB,EAAQ,CACnC,MAAO,IAAI,GAAW,K,mECLjB,WAKL,EACA,EACA,CACA,MAAI,MAAQ,GACH,CACL,IAAK,EACL,KAAM,GACN,QAAS,IAAM,GAGZ,I,ukHC/CF,YAAwB,CAC7B,KAAM,GAAkB,SAAoB,eAC5C,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,gCAGlB,KAAM,GAAY,EAAgB,UAAU,GAC5C,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,+BAElB,MAAO,GASF,WAAgB,EAAQ,CAG7B,KAAM,GAAM,IAAU,IAAI,GAC1B,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,mCAAmC,KAErD,MAAO,GASF,WAAkB,EAAM,CAC7B,MAAO,UACL,EACA,CACA,KAAM,GAAO,GAAU,CACrB,KAAM,GAAY,IAEZ,EAAQ,GAEd,SAAW,KAAO,GAChB,GAAI,EAAK,eAAe,GAAM,CAC5B,KAAM,GAAM,EAAK,GAEX,EAAM,EAAU,IAAI,GAC1B,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,mCAAmC,KAErD,EAAM,GAAO,EAIjB,MAAO,OAAM,cAAc,EAAkB,IAAM,KAAY,KAE3D,EACJ,EAAiB,aAAe,EAAiB,MAAQ,YAE3D,SAAI,YAAc,YAAY,KAEvB,K,47CChEJ,KAAM,GAAS,IAAM,CAC1B,KAAM,GACJ,SAAoB,eACtB,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,gCAGlB,KAAM,GAAa,EAAiB,UAAU,GAC9C,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,+BAElB,MAAO,K,mLCVT,KAAM,GAAc,SAClB,uBACA,IAAM,GAAI,UAMN,EAAmB,mBAsBlB,WACL,EACA,EACA,EACA,C,OACA,KAAM,GAAgB,EAEtB,GAAI,GAAY,MAAc,KAAd,QAAmC,EAAY,IAAI,GAYnE,GAXK,GACH,GAAY,CAAE,IAAK,GAAI,MACvB,OAAO,eAAe,EAAe,EAAkB,CACrD,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,IAET,EAAY,IAAI,EAAW,IAGzB,EAAU,IAAI,IAAI,GAAO,CAC3B,KAAM,IAAO,EAAU,aAAe,EAAU,KAChD,KAAM,IAAI,OACR,uCAAuC,oBAAuB,OAIlE,EAAU,IAAI,IAAI,EAAM,GAenB,WACL,EACA,EACA,C,MACA,GAAI,CAAC,EACH,OAGF,KAAM,GAAa,EAAO,KAC1B,GAAI,CAAC,EACH,OAGF,KAAM,GAAY,KAAU,KAAV,OAA+B,EAAY,IAAI,GACjE,GAAI,EAAC,EAIL,MAAO,GAAU,IAAI,IAAI,G,+CCvFpB,eAAkC,YAAgB,CAAlD,a,CAAA,oBAKL,eAAQ,CAAE,MAAO,SAEjB,0BAAmB,IAAM,CACvB,KAAK,SAAS,CAAE,MAAO,iBAPlB,0BAAyB,EAAO,CACrC,MAAO,CAAE,SASX,QAAS,CACP,KAAM,CAAE,SAAU,KAAK,MACjB,CAAE,MAAK,UAAW,KAAK,MACvB,CAAE,yBAA0B,EAAI,gBAEtC,MAAI,GAEA,gBAAoB,EAAuB,CACzC,MAAO,EACP,WAAY,KAAK,iBACjB,OAAQ,IAKP,KAAK,MAAM,UCHf,WAEN,EAuBC,CACA,KAAM,CAAE,YAAW,aAAY,QAAS,EACxC,MAAO,GAAqB,CAC1B,UAAW,CACT,KAAM,IACJ,IAAY,KACV,GAAkB,CAChB,KAAM,IAA4B,IAAU,CAE1C,GAAI,CACF,SAAY,SACL,GAAP,CACA,GAAI,MAAO,KAAU,UAAY,KAAU,KAAM,CAC/C,KAAM,CAAE,YAAY,GACpB,GACE,MAAO,KAAY,UACnB,GAAQ,WAAW,gBAEnB,KAAM,IAAI,OACR,iDAAiD,uMAMvD,KAAM,IAER,MAAO,iBAAoB,EAAgB,IAAK,MAG5C,GACJ,GACC,EAAiB,aAClB,EAAe,MACf,gBAEF,UAAyB,YAAc,qBAAqB,MAErD,IAET,GACoC,IAAM,CACtC,KAAM,IAAM,UACN,CAAE,kBAAkB,GAAI,gBAE9B,MAAO,iBAAoB,GAAe,CAAE,KAAM,aAAc,MAAO,OAMjF,KAAM,CACJ,kBAAmB,GAErB,SAiBG,WAEN,EAcC,CACA,KAAM,CAAE,YAAW,QAAS,EAC5B,MAAO,GAAqB,CAAE,YAAW,SAgBpC,WAEN,EAmBC,CACA,KAAM,CAAE,OAAO,GAAI,QAAS,EACvB,GAEH,QAAQ,KACN,4KAKJ,GAAI,GACJ,GAAI,QAAU,GAAQ,UAAW,CAC/B,KAAM,IAAa,EAAQ,UAAU,KACrC,EAAY,WAAK,IACf,KAAa,KAAK,IAAc,EAAE,QAAS,WAG7C,GAAY,EAAQ,UAAU,KAEhC,KAAM,GACJ,GACC,EAAY,aACb,EAAU,MACV,YAEF,MAAO,CACL,OAAO,GAAQ,CACb,KAAM,IAAU,IAAU,CACxB,KAAM,IAAM,UACN,CAAE,aAAa,GAAI,gBAGnB,GAAa,iBAAO,mBAI1B,MACE,iBAAoB,WAAU,CAAE,SAAU,gBAAoB,GAAU,OACpE,gBAAoB,EAAqB,CAAE,IAAK,GAAK,OAAQ,IAC3D,gBAAoB,KAAkB,CACtC,WAAY,CACV,SAAU,GAAO,WACb,GAAQ,CAAE,UAAW,MACrB,IAAc,CAAE,SAAU,GAAW,MAGzC,gBAAoB,EAAW,IAAK,SAOhD,EAAoB,GAAQ,cAAe,IAC3C,SAAW,CAAC,GAAK,KAAU,QAAO,QAAQ,GACxC,EAAoB,GAAQ,GAAK,IAGnC,UAAO,YAAc,aAAa,KAC3B,K,eC1Ob,WACE,EACA,EACA,EACA,EACA,CACA,MAAO,oBAAiB,GAAU,QAAQ,GAAQ,CAChD,GAAI,CAAC,qBAAe,GAClB,MAAO,GAGT,GAAI,EAAK,OAAS,WAChB,MAAO,GACL,EAAK,MAAM,SACX,EACA,EACA,GAIJ,GAAI,EAAiB,EAAM,uBAAwB,CACjD,KAAM,IAAQ,EAAK,MAKnB,MAHE,SAAU,IACN,EAAgB,SAAS,GAAM,MAC/B,CAAC,EAAgB,SAAS,GAAM,UAE7B,EACL,EAAK,MAAM,SACX,EACA,EACA,GAGG,GAGT,GAAI,IAAa,QAAa,EAAS,GACrC,MAAO,CAAC,GAGV,GAAI,EACF,KAAM,IAAI,OAAM,GAGlB,MAAO,GACL,EAAK,MAAM,SACX,EACA,EACA,KA6DN,OAAkB,CAChB,YACI,EACA,EACF,CAAE,KAAK,KAAO,EAAK,KAAK,gBAAkB,EAE5C,sBAAsB,EAAO,CAC3B,KAAM,GAAY,EAChB,KAAK,KACL,KAAK,gBACL,GAAQ,EAAiB,EAAM,EAAM,OAAS,OAC9C,EAAM,iBAER,MAAO,IAAI,GAAW,EAAW,KAAK,iBAGxC,kBAAkB,EAAO,CAMvB,MAAO,GAJL,KAAK,KACL,KAAK,gBACL,GAAQ,EAAiB,EAAM,EAAM,OAAS,QAG7C,IAAI,GAAQ,EAAiB,EAAM,EAAM,MACzC,OAAQ,GAAS,IAAS,QAG/B,aAED,CACG,MAAO,GAAe,KAAK,KAAM,KAAK,kBA4BnC,WACL,EACA,EACA,EAAe,GACf,CACA,KAAM,GAAkB,aAAO,sBACzB,EAAW,GAAI,GAAW,EAAM,GAEtC,MAAO,cAAQ,IAAM,EAAS,GAAW,CAAC,EAAM,GAAG,M,2yKC7K9C,OAIP,CACE,YAAc,EAAQ,CAAE,KAAK,OAAS,EAEtC,OAAQ,CACN,MAAO,MAAK,OAAO,GAGrB,SAAU,C,MACR,MAAO,QAAK,OAAO,OAAZ,OAAoB,GAG7B,iBAAkB,C,QAChB,MAAO,WAAK,OAAO,eAAZ,cAA0B,UAA1B,OAAqC,MAG1C,SAAS,C,MACX,MAAO,QAAK,OAAO,SAAZ,OAAuB,MAG5B,iBAAiB,C,MACnB,MAAO,QAAK,OAAO,iBAAZ,OAA+B,GAGxC,QAAQ,EAAW,CACjB,MAAO,GAAU,OAAO,MAG1B,UAAW,CACT,MAAO,UAAU,KAAK,OAAO,OAU1B,WAIL,EACA,CACA,MAAO,IAAI,GAAW,K,qKCTjB,KAAM,GAAe,SAC1B,iBACA,IAAM,OAAO,mBC3CR,OAEP,CAKE,YACI,EACD,EACD,CALA,SAAgB,YAKd,KAAK,GAAK,EAAG,KAAK,OAAS,KAE3B,QAAQ,CACV,MAAO,MAAK,GAGd,UAAW,CACT,MAAO,6BAA6B,KAAK,OAZzC,IAsBG,WAQN,EAKC,C,MACA,MAAO,IAAI,GACT,EAAO,GACN,KAAO,SAAP,OAAiB,IC5CtB,KAAM,GAAgB,QAKf,OAEP,CAKE,YACI,EACD,EACA,EACA,EACD,CAPA,SAAgB,OAOd,KAAK,GAAK,EAAG,KAAK,KAAO,EAAK,KAAK,OAAS,EAAO,KAAK,OAAS,EAErE,UAAW,CACT,MAAO,wBAAwB,KAAK,OAVpC,IAiEG,WAGN,EAIC,CACA,KAAM,CAAE,KAAI,OAAM,UAAW,EAIvB,EAAa,EAChB,MAAM,KACN,OAAO,IAAK,GAAE,WAAW,MACzB,IAAI,IAAK,GAAE,UAAU,IAClB,EAAS,CAAC,GAAG,EAAO,OAAQ,GAAG,GAErC,GAAI,EAAO,OAAO,KAAK,IAAK,EAAW,SAAS,KAC9C,KAAM,IAAI,OACR,gEAGJ,GAAI,CAAC,EAAK,WAAW,KACnB,KAAM,IAAI,OAAM,8CAA8C,MAEhE,GAAI,EAAK,SAAS,KAChB,KAAM,IAAI,OAAM,gDAAgD,MAElE,SAAW,MAAS,GAClB,GAAI,CAAC,EAAc,KAAK,IACtB,KAAM,IAAI,OAAM,4CAA4C,OAchE,MAToB,IAAI,GACtB,EACA,EACA,EACA,GClHG,OAIP,CAKE,YACI,EACD,EACA,EACD,CANA,SAAgB,YAMd,KAAK,GAAK,EAAG,KAAK,OAAS,EAAO,KAAK,SAAW,EAEtD,UAAW,CACT,MAAO,6BAA6B,KAAK,OATzC,IAuBG,WAIN,EAkBC,C,MACA,MAAO,IAAI,GACT,EAAQ,GACP,KAAQ,SAAR,OAAkB,GACnB,QAAQ,EAAQ,W,yBCFb,WACL,EAIA,CACA,KAAM,GAAiB,WACjB,EACJ,SAAoB,mBACtB,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,oCAGlB,KAAM,GAAW,EAAiB,UAAU,GACtC,EAAY,cAChB,IAAM,GAAY,EAAS,QAAQ,EAAU,GAC7C,CAAC,EAAU,EAAU,IAGvB,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,+CAElB,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,mCAGlB,KAAM,GAAa,YAAc,IAAY,EAAS,SACtD,GAAI,CAAC,GAAa,CAAC,EACjB,KAAM,IAAI,OAAM,eAAe,KAGjC,MAAO,GCxFF,WACL,EACA,CACA,MAAO,a,4ICSF,WAAiB,EAAO,CAC7B,GAAI,MAAO,IAAU,UAAY,IAAU,MAAQ,MAAM,QAAQ,GAC/D,MAAO,GAET,KAAM,GAAQ,EAId,MAHI,QAAO,GAAM,MAAS,UAAY,EAAM,OAAS,IAGjD,MAAO,GAAM,SAAY,UAexB,WAAqB,EAAO,CACjC,GAAI,MAAO,IAAU,UAAY,IAAU,MAAQ,MAAM,QAAQ,GAC/D,KAAM,IAAI,OAAM,kDAAkD,MAEpE,KAAM,GAAQ,EACd,GAAI,MAAO,GAAM,MAAS,UAAY,EAAM,OAAS,GACnD,KAAM,IAAI,OAAM,iDAAiD,MAEnE,GAAI,MAAO,GAAM,SAAY,SAC3B,KAAM,IAAI,OACR,oDAAoD,M,eCvBnD,WACL,EACA,EAIA,CACA,KAAM,GAAa,uBAAuB,GACpC,EAAS,CACb,KAAM,UACN,QAAS,uBACN,GAGL,MAAK,kBAAS,eACZ,MAAO,GAAO,MAGT,EAQF,WACL,EACA,CACA,KAAM,GAAS,uBAAyB,GACxC,MAAK,GAAK,OACR,GAAO,MAAQ,QAEV,EASF,WAAwB,EAAO,CACpC,GAAI,EAAQ,GAAQ,CAElB,KAAM,GAAM,OAAO,GACnB,MAAO,KAAQ,kBAAoB,EAAM,GAAG,EAAM,SAAS,EAAM,UAGnE,MAAO,kBAAkB,KC7DpB,eAA8B,MAAM,CAMzC,YAAY,EAAS,EAAO,C,MAC1B,GAAI,GAAc,EAClB,GAAI,IAAU,OAAW,CACvB,KAAM,GAAW,EAAe,GAC5B,EACF,GAAe,eAAe,IAE9B,EAAc,aAAa,IAI/B,MAAM,GAbP,gBAeC,SAAM,oBAAN,mBAA0B,KAAM,KAAK,aAErC,KAAK,KAAO,KAAK,YAAY,KAC7B,KAAK,MAAQ,EAAQ,GAAS,EAAQ,QCrBnC,eAAyB,KAAe,EAOxC,eAAkC,KAAe,EAOjD,eAA8B,KAAe,EAU7C,eAA4B,EAAgB,EAQ5C,eAA4B,KAAe,EAO3C,eAA+B,KAAe,EAU9C,eAA6B,EAAgB,CAClD,YAAY,EAAS,EAAO,CAC1B,MAAM,EAAS,GAEf,KAAK,KAAO,EAAQ,GAAS,EAAM,KAAO,SClCvC,iBACL,EACA,C,MACA,GAAI,CACF,KAAM,GAAO,KAAM,GAAS,OAC5B,GAAI,EAAM,CACR,GACE,KAAS,QAAQ,IAAI,kBAArB,cAAsC,WAAW,oBAEjD,GAAI,CACF,KAAM,GAAO,KAAK,MAAM,GACxB,GAAI,EAAK,OAAS,EAAK,SACrB,MAAO,QAET,EAKJ,MAAO,CACL,MAAO,CACL,KAAM,QACN,QAAS,8BAA8B,EAAS,UAAU,EAAS,eAAe,KAEpF,SAAU,CACR,WAAY,EAAS,eAI3B,EAIF,MAAO,CACL,MAAO,CACL,KAAM,QACN,QAAS,8BAA8B,EAAS,UAAU,EAAS,cAErE,SAAU,CACR,WAAY,EAAS,SChEpB,eAA4B,MAAM,CAgDtC,YAAY,EAKb,CACE,MAAM,EAAM,SA/Cb,mBAKA,eAWA,gBAgCC,KAAK,KAAO,gBACZ,KAAK,SAAW,EAAM,SACtB,KAAK,KAAO,EAAM,KAClB,KAAK,MAAQ,EAAM,kBA1BR,cAAa,EAAU,CAClC,KAAM,GAAO,KAAM,GAAuB,GAEpC,EAAS,EAAK,SAAS,YAAc,EAAS,OAC9C,EAAa,EAAK,MAAM,MAAQ,EAAS,WACzC,EAAU,uBAAuB,KAAU,IAC3C,GAAQ,EAAiB,EAAK,OAEpC,MAAO,IAAI,GAAc,CACvB,UACA,WACA,OACA,c,iJCuBC,KAAM,GAAgB,mBAAa,CACxC,GAAI,iBCxDN,OAAkB,CAGhB,YAAY,EAAW,CAFvB,kBAGE,QAAK,EAAa,QAGd,gBACJ,EACA,CACA,KAAM,GAAM,GAAI,KAAI,EAAQ,KACtB,EAAW,QAAK,GAAW,KAAK,GAAK,EAAE,eAAe,IAC5D,GAAI,CAAC,EACH,KAAM,IAAI,OACR,uDAAuD,EAAQ,QAInE,MAAO,GAAS,eAAe,IAjBjC,cA8CK,aAAe,CAkKnB,YACC,EACA,EACA,EACA,EACA,CAVF,kBACA,kBACA,kBACA,kBAQE,QAAK,EAAO,GACZ,QAAK,EAAQ,GACb,QAAK,EAAgB,GACrB,QAAK,EAAgB,SAvKhB,0BAA0B,CAC/B,MAAO,kBAAiB,CACtB,IAAK,cACL,KAAM,CACJ,OAAQ,iBACR,OAAQ,iBACR,MAAO,oBACP,UAAW,qBAEb,QAAS,CAAC,CAAE,SAAQ,SAAQ,QAAO,eACjC,EAAQ,MACN,EAAQ,UAAU,GAClB,EAAQ,UAAU,GAClB,EAAQ,SAAS,GACjB,EAAQ,aAAa,YAQtB,YACL,EACA,EAOA,CACA,MAAO,IAAI,GAAQ,UAAW,EAAS,EAAQ,KAAM,EAAQ,oBAgBxD,WACL,EACA,EAGA,C,MACA,KAAM,GAAO,oBAAS,OAAT,OAAiB,aAC9B,MAAO,IAAI,GAAQ,SAAU,EAAe,EAAM,CAChD,QAAS,CAAC,OAAQ,WAAY,aAC9B,UAAW,CAAC,gBAiBT,WACL,EACA,EAGA,C,MACA,KAAM,GAAO,oBAAS,OAAT,OAAiB,aAC9B,MAAO,IAAI,GAAQ,SAAU,EAAe,EAAM,CAChD,QAAS,CAAC,YAAa,WAAY,mBACnC,UAAW,CAAC,mBAAoB,eAiB7B,UACL,EACA,EAGA,C,MACA,KAAM,GAAO,oBAAS,OAAT,OAAiB,gBAC9B,MAAO,IAAI,GAAQ,QAAS,EAAkB,EAAM,CAClD,QAAS,CACP,YACA,WACA,YACA,cACA,eAEF,UAAW,CAAC,2BAiBT,cACL,EACA,EAGA,C,MACA,KAAM,GAAO,oBAAS,OAAT,OAAiB,gBAC9B,MAAO,IAAI,GAAQ,YAAa,EAAkB,EAAM,CACtD,QAAS,CAAC,UAAW,OAAQ,cAAe,UAAW,SACvD,UAAW,CAAC,oBAAqB,gBAAiB,uBAQ/C,UAAS,EAAW,CACzB,MAAO,IAAI,GAAW,GAuBxB,eAAe,EAAK,CAClB,MAAO,GAAI,OAAS,QAAK,GAG1B,+BACC,EACA,C,QACA,MAAI,CAAC,kBAAkB,eAAgB,QAAK,KAAkB,UACrD,GAGF,QAAiB,eAAjB,cAAgC,QAAK,MAArC,OAAuD,QAM1D,gBACJ,EACA,CACA,KAAM,CAAE,MAAK,qBAAoB,GAAgB,EAE3C,EAAS,QAAK,GAAc,QAAQ,QACtC,kBAAiB,YACnB,EAAO,KAAK,GAAG,QAAK,GAAc,WAGpC,KAAM,IACJ,KAAK,+BAA+B,GAElC,GAAiB,QACnB,EAAO,KAAK,GAAG,IAGjB,KAAM,IAAe,CAAC,GAAG,GAAI,KAAI,IAE3B,GAAQ,KAAM,SAAK,GAAK,eAAe,GAAc,GAE3D,MAAO,CACL,SACA,QAAS,CACP,cAAe,UAAU,SA1N1B,QA6JL,cACA,cACA,cACA,c,eC5NK,OAAyB,OAMvB,YAAW,EAAQ,CACxB,MAAO,iBAA2B,IAS/B,KAAM,GACX,mBAAa,CACX,GAAI,gC,yBCVD,KAAM,GAAsB,GAAU,C,MAC3C,KAAM,CAAE,QAAS,EACX,EAAM,eACN,EAAc,IACd,EAAO,GAAO,KAAI,cAAc,KAAlB,OAAyC,EAC7D,MAAO,iBAAoB,EAAM,Q,0JCpB5B,WAAqB,EAAM,CAChC,KAAM,GAAQ,GAAI,KAAI,sBACtB,SAAM,KAAO,EACN,EAAM,OAAS,EAIjB,WAAoB,EAAK,CAC9B,GAAI,CAEF,UAAI,KAAI,GACD,QACP,CACA,MAAO,IAIJ,WACL,EACA,EACA,CACA,MAAO,CACL,MAAO,CACL,MAAO,IAET,MAAM,EAAK,CACT,GAAI,CACF,KAAM,GAAS,MAAO,IAAQ,SAAW,GAAI,KAAI,GAAO,EACxD,MAAO,GAAa,KAAK,IAAK,EAAQ,MAAO,EAAO,WACpD,CACA,SAGJ,OAAO,EAAM,CACX,MAAO,GAAa,KAAK,GAAK,EAAQ,KAAO,KAW5C,WAA8B,EAInC,CACA,KAAM,CAAE,MAAK,OAAM,cAAe,EAGlC,GAAI,CAEF,UAAI,KAAI,GACD,OACP,EAIF,GAAI,IAEJ,GAAI,EAAI,WAAW,KAAM,CAEvB,KAAM,CAAE,aAAa,IAAY,GACjC,GAAU,GAAI,KAAI,GAClB,KAAM,IAAe,cACnB,GAAQ,SAAS,UAAU,EAAG,GAAQ,SAAS,OAAS,GAAS,QACjE,KAEF,GAAQ,SAAW,GAAG,KAAe,QAKrC,IAAU,GAAI,KAAI,EAAK,GAGzB,UAAQ,OAAS,GAAI,KAAI,GAAM,OAC3B,GACF,IAAQ,KAAO,IAAI,KAEd,GAAQ,WCxFjB,KAAM,GAA4B,KAE3B,QAAe,CAiDnB,YACC,EACA,EACA,EACA,GACA,GACA,GACA,CAdF,mBACA,mBACA,mBACA,mBACA,mBACA,mBAkBA,WAAW,IAAI,IAAU,CACvB,KAAM,GAAM,GAAI,KAAI,QAAK,KACzB,SAAI,SAAW,EAAM,IAAI,GAAQ,mBAAmB,IAAO,KAAK,KACzD,IAXP,QAAK,GAAU,GACf,QAAK,GAAS,GACd,QAAK,GAAW,GAChB,QAAK,GAAQ,IACb,QAAK,GAAQ,IACb,QAAK,GAAO,UAxDP,aAAY,EAAS,C,OAC1B,KAAM,GAAM,GAAI,KAAI,GAEpB,GAAI,GACA,GACA,GAEJ,KAAM,IAAQ,EAAI,SAAS,MAAM,KAAK,IAAI,IAAQ,mBAAmB,KAUrE,GATI,GAAM,KAAO,OACf,GAAQ,GAAM,GACd,GAAU,GAAO,GAAM,IACd,GAAM,KAAO,QACtB,GAAQ,GAAM,GACd,GAAU,GAAM,GAChB,GAAO,GAAM,IAGX,CAAC,GAAS,CAAC,IAAW,CAAC,GACzB,KAAM,IAAI,OAAM,4CAGlB,KAAM,IAAO,MAAI,aAAa,IAAI,UAArB,QAAgC,OAE7C,GAAI,IACJ,KAAM,IAAU,EAAI,aAAa,IAAI,WACrC,GAAI,GAAS,CAEX,GAAI,GADmB,MAAM,EAAG,KACjB,KACb,KAAM,IAAI,OAAM,gDAElB,GAAM,GAAQ,MAAM,GAGtB,MAAO,IAAI,IAAS,EAAI,OAAQ,EAAO,GAAS,GAAM,GAAM,IAqC9D,WAAY,CACV,GAAI,GACJ,MAAI,SAAK,MAAa,QAAK,IACzB,EAAM,QAAK,IAAL,UAAc,QAAK,IAAQ,OAAQ,QAAK,KAE9C,EAAM,QAAK,IAAL,UAAc,QAAK,IAAQ,QAAK,IAAU,OAAQ,QAAK,KAG3D,QAAK,KACP,EAAI,aAAa,IAAI,OAAQ,QAAK,KAEhC,QAAK,KACP,EAAI,aAAa,IAAI,UAAW,EAA4B,QAAK,KAG5D,EAAI,WAQb,WAAY,CACV,GAAI,CAAC,QAAK,IACR,KAAM,IAAI,OACR,yEAIJ,KAAM,GAAM,QAAK,IAAL,UACV,QAAK,IACL,QAAK,IACL,QACA,MACA,eACA,QAAK,IACL,SAEF,SAAI,aAAa,IAAI,cAAe,OACpC,EAAI,aAAa,IAAI,OAAQ,QAAK,KAE9B,QAAK,KACP,EAAI,aAAa,IAAI,UAAW,QAAK,KAGhC,EAAI,WAQb,cAAe,CACb,KAAM,GAAM,QAAK,IAAL,UACV,QAAK,IACL,QAAK,IACL,QACA,MACA,eACA,QAAK,IACL,SAEF,SAAI,aAAa,IAAI,iBAAkB,QACvC,EAAI,aAAa,IAAI,WAAY,QACjC,EAAI,aAAa,IAAI,cAAe,OAEhC,QAAK,KACP,EAAI,aAAa,IAAI,YAAa,QAAK,KAErC,QAAK,KACP,EAAI,aAAa,IAAI,UAAW,QAAK,KAGhC,EAAI,WAQb,cAAe,CACb,KAAM,GAAM,QAAK,IAAL,UACV,QAAK,IACL,QAAK,IACL,QACA,MACA,eACA,QAAK,IACL,WAEF,SAAI,aAAa,IAAI,cAAe,OAEhC,QAAK,KACP,EAAI,aAAa,IAAI,qCAAsC,QAAK,KAG3D,EAAI,WAMb,UAAW,CACT,MAAO,SAAK,IAMd,YAAa,CACX,MAAO,SAAK,IAMd,SAAU,CACR,MAAO,SAAK,IAMd,SAAU,CACR,MAAO,SAAK,IAMd,QAAS,CACP,MAAO,SAAK,MAlNT,SA0CL,eACA,eACA,eACA,eACA,eACA,eAkBA,eChEF,KAAM,GAAa,gBA6BZ,WACL,EACA,C,MACA,KAAM,GAAO,KAAO,kBAAkB,UAAzB,OAAoC,EAC3C,EAAQ,EAAO,kBAAkB,SAEvC,GAAI,CAAC,EAAY,GACf,KAAM,IAAI,OACR,sCAAsC,0BAI1C,MAAO,CAAE,OAAM,SAUV,WACL,EACA,CAEA,KAAM,GAAS,EAAQ,IAAI,GAI3B,MAAK,GAAO,KAAK,GAAK,EAAE,OAAS,IAC/B,EAAO,KAAK,CAAE,KAAM,IAGf,ECxDF,cAAwB,CAW7B,YAAc,EAAmB,CAAE,KAAK,kBAAoB,KAExD,OAAO,CACT,MAAO,WAGL,QAAQ,CACV,MAAO,MAAK,kBAAkB,QAG5B,SAAS,CACX,MAAO,MAAK,kBAQd,WAAW,EAIX,C,OACE,KAAM,CAAE,MAAK,QAAS,EAGtB,GAAI,EAAW,GACb,MAAO,GAGT,GAAI,CACF,KAAM,IAAW,cAAqB,GAChC,GAAS,GAAI,KAAI,GAGjB,GAAc,GAAI,KAAI,gBAAgB,OAAS,YAAT,QAAsB,MAC5D,GAAc,GAAI,KAAI,EAAK,IAAa,SAC9C,UAAO,aAAa,IAAI,OAAQ,IAE5B,EAAQ,YACV,IAAO,aAAa,IAAI,OAAQ,OAAO,EAAQ,aAC/C,GAAO,aAAa,IAAI,UAAW,OAAO,EAAQ,WAAa,IAC/D,GAAO,aAAa,IAAI,kBAAmB,KAC3C,GAAO,aAAa,IAAI,gBAAiB,MAGpC,GAAO,gBACd,CAEA,MAAO,IAAI,KAAI,EAAK,GAAM,YAI9B,eAAe,EAAK,CAGlB,MAAO,KApEJ,SACE,EADF,EACE,UAAU,CAAC,CAAE,YAAa,C,MAC/B,KAAM,GAAU,EACd,KAAO,uBAAuB,wBAA9B,OAAuD,IAEzD,MAAO,GACL,EAAQ,IAAI,IAAK,GAAI,IAAiB,KACtC,IAAK,GAAE,OAAO,Q,sBCDb,WAA8B,EAAK,CACxC,MAAO,UAAS,YAAY,GAAK,YAU5B,WAA6B,EAAK,CACvC,MAAO,UAAS,YAAY,GAAK,eAS5B,WAA4B,EAAK,CACtC,MAAO,UAAS,YAAY,GAAK,eAS5B,WACL,EACA,EACA,CACA,KAAM,GAAU,EACZ,IAAK,GACL,GAEJ,GAAI,EAAO,MAAO,CAChB,KAAM,GAAS,EAAO,KAAK,IAAI,EAAO,QAAS,QAC/C,EAAQ,cAAgB,SAAS,EAAO,SAAS,YAGnD,MAAO,CAAE,WCxDX,KAAM,GAAiB,gBACjB,EAAyB,gCAoDxB,WACL,EACA,C,OACA,KAAM,GAAO,MAAO,kBAAkB,UAAzB,QAAoC,EACjD,GAAI,GAAa,EAAO,kBAAkB,cAC1C,KAAM,GAAQ,EAAO,kBAAkB,SACjC,GAAW,EAAO,kBAAkB,YACpC,GAAc,EAAO,kBAAkB,eAE7C,GAAI,CAAC,EAAY,GACf,KAAM,IAAI,OACR,0CAA0C,0BAI9C,MAAI,GACF,EAAa,cAAQ,EAAY,KACxB,IAAS,GAClB,GAAa,GAGR,CACL,OACA,aACA,QACA,YACA,gBAWG,WACL,EACA,CAEA,KAAM,GAAS,EAAQ,IAAI,GAI3B,MAAK,GAAO,KAAK,GAAK,EAAE,OAAS,IAC/B,EAAO,KAAK,CACV,KAAM,EACN,WAAY,IAIT,EChGF,cAA4B,CAajC,YAAc,EAAmB,CAAE,KAAK,kBAAoB,KAExD,OAAO,CACT,MAAO,eAGL,QAAQ,CACV,MAAO,MAAK,kBAAkB,QAG5B,SAAS,CACX,MAAO,MAAK,kBAGd,WAAW,EAIX,CACE,KAAM,GAAW,EAAqB,GAGtC,GAAI,EAAQ,WAAY,CACtB,KAAM,GAAM,GAAI,KAAI,GAEd,GAAW,EAAI,SAAS,MAAM,KAAK,MAAM,IAAI,GACnD,SAAI,KAAO,GAAG,MAAY,EAAQ,aAC3B,EAAI,WAGb,MAAO,GAGT,eAAe,EAAK,CAClB,KAAM,GAAU,IAAY,GACtB,EAAU,GAAI,KAAI,GAExB,SAAQ,aAAa,IAAI,OAAQ,QAGjC,EAAQ,aAAa,IAAI,MAAO,KAChC,EAAQ,aAAa,IAAI,KAAM,EAAQ,KAChC,EAAQ,aAvDZ,UACE,EADF,GACE,UAAU,CAAC,CAChB,YACI,C,MACJ,KAAM,GAAU,EACd,KAAO,uBAAuB,4BAA9B,OAA2D,IAE7D,MAAO,GACL,EAAQ,IAAI,IAAK,GAAI,IAAqB,KAC1C,IAAK,GAAE,OAAO,Q,mCCXb,kBACL,EACA,EACA,CACA,KAAM,CAAE,KAAM,EAAU,MAAO,EAAS,aAAa,YAAY,GAE3D,GAAW,KAAa,gBAE9B,GAAI,IAAY,GACZ,GAAG,EAAO,2BAA2B,KAAW,IAChD,GAAG,EAAO,uBAAuB,WAAiB,mBAElD,GAAW,KAAM,OAAM,GAAW,GAA2B,IASjE,GAPI,GAAS,SAAW,KAAO,CAAC,IAG9B,IAAY,GAAG,EAAO,uBAAuB,WAAiB,qBAC9D,GAAW,KAAM,OAAM,GAAW,GAA2B,KAG3D,CAAC,GAAS,GAAI,CAChB,KAAM,IAAU,0CAA0C,OAAc,GAAS,UAAU,GAAS,aACpG,KAAM,IAAI,OAAM,IAGlB,GAAI,IACJ,GAAI,GAEF,GAAgB,MADO,IAAS,QACP,WAAW,SAC/B,CACL,KAAM,CAAE,cAAc,KAAM,IAAS,OACrC,GAAgB,GAElB,GAAI,CAAC,GACH,KAAM,IAAI,OACR,sCAAsC,gBACxB,GAAS,UAAU,GAAS,UAG9C,MAAO,IAWF,kBACL,EACA,EACA,CACA,KAAM,CACJ,KAAM,EACN,MAAO,EACP,OACA,YACA,YACA,aACE,YAAY,GAEV,GAAW,KAAa,gBAE9B,GAAI,IAAS,GACR,IACH,IAAS,KAAM,IAA0B,EAAK,IAKhD,KAAM,IAAO,GAAW,SAAS,mBAAmB,MAAc,GAKlE,MAJmB,IACf,GAAG,QAAc,MAAY,KAAW,SAAgB,YACxD,GAAG,EAAO,uBAAuB,WAAiB,2BAAkC,aAAiB,KAAW,IAAW,KAmB1H,YACL,EACA,EACA,CACA,GAAI,CACF,KAAM,CAAE,QAAO,OAAM,OAAK,gBAAc,aAAa,YAAY,GACjE,GACE,CAAC,GACD,CAAC,GACA,KAAiB,UAChB,KAAiB,OACjB,KAAiB,MAEnB,KAAM,IAAI,OAAM,sCAGlB,KAAM,IAAmB,GAAS,QAAQ,MAAO,IAEjD,GAAI,EAAO,OAAS,gBAAiB,CACnC,GAAI,CAAC,GACH,KAAM,IAAI,OAAM,sCAElB,MAAO,GAAG,EAAO,2BAA2B,KAAS,SAAY,MAAO,KAE1E,MAAO,GAAG,EAAO,uBAAuB,WAAe,SAAY,SAAuB,WACnF,EAAP,CACA,KAAM,IAAI,OAAM,kBAAkB,MAAQ,MAUvC,YACL,EACA,CACA,KAAM,GAAU,GAEhB,GAAI,EAAO,MACT,EAAQ,cAAgB,UAAU,EAAO,gBAChC,EAAO,UAAY,EAAO,YAAa,CAChD,KAAM,GAAS,GAAO,KACpB,GAAG,EAAO,YAAY,EAAO,cAC7B,QAEF,EAAQ,cAAgB,SAAS,EAAO,SAAS,YAGnD,MAAO,CACL,WC1JJ,KAAM,IAAc,aACd,GAAsB,yBACtB,GAAsB,oCAiGrB,YACL,EACA,C,UACA,KAAM,GAAO,MAAO,kBAAkB,UAAzB,QAAoC,GACjD,GAAI,GAAa,EAAO,kBAAkB,cACtC,EAAa,EAAO,kBAAkB,cAC1C,KAAM,IAAQ,EAAO,kBAAkB,SACjC,GAAO,MAAO,uBAAuB,UAA9B,eAAuC,IAAI,IAAM,EAC5D,MAAO,GAAE,UAAU,SACnB,SAAU,GAAE,UAAU,YACtB,aAAc,GAAE,UAAU,gBAC1B,cAAe,GAAE,UAAU,iBAC3B,WAAY,GAAE,UAAU,cACxB,0BAA2B,GAAE,uBAC3B,gCAIJ,GAAI,CAAC,EAAY,GACf,KAAM,IAAI,OACR,uCAAuC,0BAI3C,MAAI,GACF,EAAa,cAAQ,EAAY,KACxB,IAAS,IAClB,GAAa,IAGX,EACF,EAAa,cAAQ,EAAY,KACxB,IAAS,IAClB,GAAa,IAGR,CAAE,OAAM,aAAY,aAAY,SAAO,SAUzC,YACL,EACA,CAEA,KAAM,GAAS,EAAQ,IAAI,IAI3B,MAAK,GAAO,KAAK,GAAK,EAAE,OAAS,KAC/B,EAAO,KAAK,CACV,KAAM,GACN,WAAY,GACZ,WAAY,KAIT,EClJF,YACL,EACA,EACA,EACA,CACA,GAAI,CACF,KAAM,CAAE,QAAO,QAAM,OAAK,gBAAc,aAAa,YAAY,GACjE,GACE,CAAC,GACD,CAAC,IACD,CAAC,IAGA,KAAiB,QAChB,KAAiB,OACjB,KAAiB,OAEnB,KAAM,IAAI,OAAM,mCAGlB,KAAM,IAAmB,GAAS,QAAQ,MAAO,IACjD,MAAI,IAAe,EAAQ,KAAiB,MACnC,GAAG,EAAO,oBAAoB,KAAS,eAAiB,UAAwB,KAElF,GAAG,EAAO,cAAc,KAAS,MAAQ,MAAO,WAChD,EAAP,CACA,KAAM,IAAI,OAAM,kBAAkB,MAAQ,MAWvC,YACL,EACA,EACA,CACA,KAAM,GAAU,GAEhB,MAAI,IAAe,EAAQ,KAAiB,OAC1C,GAAQ,OAAS,iCAGf,EAAY,OACd,GAAQ,cAAgB,SAAS,EAAY,SAGxC,CAAE,WAGJ,YACL,EACA,EACA,CACA,MAAI,GAAO,YAAe,GAAY,OAAS,CAAC,EAAO,YAC9C,MAEF,MChET,QAAY,CAAZ,a,CACI,oBAAa,GAAI,MAoBlB,sBAAgB,GACf,EAAK,KAAK,SAAS,QAAS,WAAW,QAAU,SAhB7C,kBACJ,EACA,EACA,CACA,KAAM,GAAO,KAAK,WAAW,IAAI,GACjC,GAAI,GAAQ,KAAK,aAAa,EAAK,WACjC,MAAO,CAAE,YAAa,EAAK,OAG7B,KAAM,IAAS,KAAM,KACrB,YAAK,WAAW,IAAI,EAAK,IAClB,CAAE,YAAa,GAAO,QAajC,KAAM,IAAU,CACd,OAAQ,mDAMV,QAAuB,CAOrB,YAAY,EAAQ,EAAS,CAN3B,oBACA,kBACA,yBACA,eAAQ,GAAI,KACZ,oCAGA,KAAK,0BAA4B,EAAO,0BACxC,KAAK,QAAU,EACf,KAAK,eAAiB,CACpB,MAAO,EAAO,MACd,WAAY,EAAO,WAAW,QAAQ,QAAS;AAAA,IAEjD,KAAK,UAAY,GAAI,SAAQ,CAC3B,UACA,QAAS,GACT,aAAc,cACd,KAAM,KAAK,sBAIT,4BACJ,EACA,EACA,C,OACA,KAAM,CAAE,iBAAgB,cAAc,KAAM,MAAK,oBAAoB,GACrE,GAAI,KAAK,2BACH,CAAC,UAAK,4BAAL,eAAgC,SAAS,IAC5C,MAAO,CAAE,YAAa,QAG1B,GAAI,GACF,KAAM,IAAI,OAAM,8BAA8B,kBAGhD,KAAM,IAAW,EAAO,GAAG,KAAS,IAAS,EAG7C,MAAO,MAAK,MAAM,iBAAiB,GAAU,SAAY,CACvD,KAAM,IAAS,KAAM,MAAK,UAAU,KAAK,8BAA8B,CACrE,gBAAiB,EACjB,QAAS,KAEX,GAAI,GAAQ,GAAO,KAAK,uBAAyB,WAAY,CAC3D,KAAM,IAAqB,GAAI,SAAQ,CACrC,QAAS,KAAK,QACd,KAAM,GAAO,KAAK,QAQpB,GAAI,CAHY,MAHI,IAAmB,SACrC,GAAmB,KAAK,oCAEJ,KAAK,IAClB,GAAW,OAAS,GAG3B,KAAM,IAAI,OACR,gDAAgD,qEAAyE,KAI/H,MAAO,CACL,MAAO,GAAO,KAAK,MACnB,UAAW,SAAS,QAAQ,GAAO,KAAK,eAK9C,kBAED,CACG,MAAO,MAAK,UAAU,SAAS,KAAK,UAAU,KAAK,wBAG9C,qBAAoB,EAAO,CAEhC,KAAM,GAAe,MADU,MAAK,oBACE,KACpC,IAAK,C,UACH,kBAAK,UAAL,eAAc,QAAd,eAAqB,kBAAkB,YACvC,EAAM,kBAAkB,WAE5B,GAAI,EACF,MAAO,CACL,eAAgB,EAAa,GAC7B,UAAW,QAAQ,EAAa,eAGpC,KAAM,IAAgB,GAAI,OACxB,iCAAiC,QAAY,KAAK,eAAe,SAEnE,SAAc,KAAO,gBACf,IASH,QAA8B,CAGnC,YAAY,EAAQ,CAFlB,e,QAGA,KAAK,KACH,QAAO,OAAP,cAAa,IAAI,IAAM,GAAI,IAAiB,GAAI,EAAO,eAAvD,OAAuE,QAGrE,sBAEP,CACG,MAAK,MAAK,KAAK,OAQR,MAJgB,SAAQ,IAC7B,KAAK,KAAK,IAAI,GAAO,EAAI,sBAGX,OAPP,QAUL,aAAY,EAAO,EAAM,CAC7B,GAAI,KAAK,KAAK,SAAW,EACvB,OAGF,KAAM,GAAU,KAAM,SAAQ,IAC5B,KAAK,KAAK,IAAI,IACZ,GAAI,2BAA2B,EAAO,GAAM,KAC1C,IAAgB,EAAE,eAAa,MAAO,SACtC,IAAU,EAAE,YAAa,OAAW,cAKpC,GAAS,EAAQ,KAAK,IAAc,GAAW,aACrD,GAAI,GACF,MAAO,IAAO,YAAY,YAI5B,KAAM,IAAmB,EADF,IAAI,IAAK,GAAE,OACF,KAAK,IAAO,GAAI,OAAS,iBACzD,GAAI,GACF,KAAM,KAeL,QAEP,CAUG,YACG,EACA,EACF,CAAE,KAAK,wBAA0B,EAAwB,KAAK,MAAQ,OAsBlE,gBAAe,EAAM,CACzB,KAAM,GAAS,YAAY,EAAK,KAE1B,EAAQ,EAAO,OAAS,EAAO,KAC/B,GAAO,EAAO,MAAQ,EAAO,KAAO,OAE1C,GAAI,IAAO,MACP,GAAQ,KAAM,MAAK,wBAAwB,YAAY,EAAO,IAClE,MAAK,KACH,IAAO,QACP,GAAQ,KAAK,OAGR,CACL,QAAS,GAAQ,CAAE,cAAe,UAAU,MAAY,OACxD,SACA,UAlDG,EAHF,GAGE,SAEN,MC7MI,QAEP,OACS,kBAAiB,EAAc,CACpC,KAAM,GACJ,GAAI,KAEN,SAAa,OAAO,OAAO,QAAQ,GAAe,CAChD,KAAM,IACJ,wCAAwC,OAAO,EAAY,QAC7D,EAAqB,IAAI,EAAY,OAAO,KAAM,MAE7C,GAAI,IAAiC,GAG7C,YACG,EACF,CAAE,KAAK,UAAY,OA0Bf,gBAAe,EAAM,CACzB,KAAM,GAAS,GAAI,KAAI,EAAK,KACtB,EAAW,KAAK,UAAU,IAAI,EAAO,MAE3C,GAAI,CAAC,EACH,KAAM,IAAI,OACR,+CAA+C,EAAK,uDAIxD,MAAO,GAAS,eAAe,ICrD5B,cAAyB,CAW9B,YAAc,EAAmB,CAAE,KAAK,kBAAoB,KAExD,OAAO,CACT,MAAO,YAGL,QAAQ,CACV,MAAO,MAAK,kBAAkB,QAG5B,SAAS,CACX,MAAO,MAAK,kBAGd,WAAW,EAIX,CAIE,MAAO,IAAqB,EAAqB,GAAU,QAG7D,eAAe,EAAK,CAClB,MAAO,IAAqB,EAAK,UArC9B,UACE,EADF,GACE,UAAU,CAAC,CAAE,YAAa,C,MAC/B,KAAM,GAAU,GACd,KAAO,uBAAuB,yBAA9B,OAAwD,IAE1D,MAAO,GACL,EAAQ,IAAI,IAAK,GAAI,IAAkB,KACvC,IAAK,GAAE,OAAO,QAyCb,YACL,EACA,EACA,CACA,MAAO,GAAI,QACT,oDACA,CAAC,EAAG,EAAM,GAAO,KACR,KAAK,KAAQ,MAAS,MAAQ,MC/D3C,KAAM,IAAc,aACd,GAAsB,4BA2CrB,YACL,EACA,CACA,KAAM,GAAO,EAAO,UAAU,QAC9B,GAAI,GAAa,EAAO,kBAAkB,cAC1C,KAAM,GAAQ,EAAO,kBAAkB,SACvC,GAAI,IAAU,EAAO,kBAAkB,WAcvC,GAZI,EACF,EAAa,cAAQ,EAAY,KACxB,IAAS,IAClB,GAAa,IAGX,GACF,GAAU,cAAQ,GAAS,KAE3B,GAAU,WAAW,IAGnB,EAAK,SAAS,KAChB,KAAM,IAAI,OACR,4CAA4C,kEAEzC,GAAK,EAAY,GAIjB,IAAI,CAAC,GAAc,CAAC,EAAW,GACpC,KAAM,IAAI,OACR,uCAAuC,gCAEpC,GAAI,CAAC,EAAW,IACrB,KAAM,IAAI,OACR,uCAAuC,kCATzC,MAAM,IAAI,OACR,uCAAuC,0BAY3C,MAAO,CAAE,OAAM,QAAO,aAAY,YAU7B,YACL,EACA,CAEA,KAAM,GAAS,EAAQ,IAAI,IAI3B,MAAK,GAAO,KAAK,GAAK,EAAE,OAAS,KAC/B,EAAO,KAAK,CACV,KAAM,GACN,WAAY,GACZ,QAAS,WAAW,OAIjB,EC5FF,kBACL,EACA,EACA,CAIA,GAAI,EAAI,SAAS,YAAa,CAC5B,KAAM,GAAY,KAAM,GAAa,EAAK,GAC1C,MAAO,GAAgB,EAAK,GAAW,WAEzC,MAAO,IAAY,GAAK,WASnB,YAAiC,EAEvC,CACC,KAAM,CAAE,QAAQ,IAAO,EACvB,MAAO,CACL,QAAS,CACP,gBAAiB,IAQhB,YAAqB,EAAQ,CAClC,GAAI,CACF,KAAM,GAAM,GAAI,KAAI,GAEd,CAAC,EAAO,EAAW,GAAU,MAAgB,IACjD,EAAI,SAAS,MAAM,KAErB,GACE,IAAU,IACV,IAAc,IACd,KAAa,IACb,KAAgB,QAChB,CAAC,GAAW,KAAK,KAAK,MAAM,iBAE5B,KAAM,IAAI,OAAM,oBAIlB,SAAI,SAAW,CAAC,EAAO,EAAW,GAAU,MAAO,GAAG,IAAY,KAAK,KAEhE,QACA,EAAP,CACA,KAAM,IAAI,OAAM,kBAAkB,MAAW,MAO1C,WAAyB,EAAQ,EAAW,CACjD,GAAI,CACF,KAAM,GAAM,GAAI,KAAI,GAEd,EAAoB,EAAI,SAAS,MAAM,YAAY,GACnD,CAAC,MAAW,IAAY,EAAkB,MAAM,KAEtD,SAAI,SAAW,CACb,mBACA,EACA,mBACA,mBAAmB,mBAAmB,GAAS,KAAK,OACpD,OACA,KAAK,KACP,EAAI,OAAS,QAAQ,KAEd,QACA,EAAP,CACA,KAAM,IAAI,OAAM,kBAAkB,MAAW,MAO1C,iBACL,EACA,EACA,CACA,KAAM,GAAM,GAAI,KAAI,GAEpB,GAAI,CAAC,EAAI,SAAS,SAAS,YACzB,KAAM,IAAI,OAAM,qDAGlB,GAAI,CACF,KAAM,GAAO,EAAI,SAAS,MAAM,YAAY,GAItC,GAAe,GAAI,KACvB,GAAG,EAAI,SAAW,EAAI,4BAA4B,mBAChD,EAAK,QAAQ,MAAO,QAGlB,GAAW,KAAM,OACrB,GAAa,WACb,GAAwB,IAEpB,GAAO,KAAM,IAAS,OAE5B,GAAI,CAAC,GAAS,GACZ,KAAM,IAAI,OACR,iBAAiB,GAAK,WAAW,GAAK,qBAI1C,MAAO,QAAO,GAAK,UACZ,EAAP,CACA,KAAM,IAAI,OAAM,wCAAwC,MAAW,MClIhE,cAAyB,CAW9B,YAAc,EAAmB,CAAE,KAAK,kBAAoB,KAExD,OAAO,CACT,MAAO,YAGL,QAAQ,CACV,MAAO,MAAK,kBAAkB,QAG5B,SAAS,CACX,MAAO,MAAK,kBAGd,WAAW,EAIX,CACE,MAAO,GAAqB,GAG9B,eAAe,EAAK,CAClB,MAAO,GAAe,EAAK,UAlCxB,SACE,EADF,EACE,UAAU,CAAC,CAAE,YAAa,C,MAC/B,KAAM,GAAU,GACd,KAAO,uBAAuB,yBAA9B,OAAwD,IAE1D,MAAO,GACL,EAAQ,IAAI,IAAK,GAAI,IAAkB,KACvC,IAAK,GAAE,OAAO,QA+Bb,WACL,EACA,EACA,CACA,MAAO,GAAI,QAAQ,2BAA4B,MAAM,MCpDvD,KAAM,GAAkB,gBAoDjB,YACL,EACA,C,OACA,KAAM,GAAW,EAAO,kBAAkB,YACpC,EACJ,MAAO,mBAAmB,sBAA1B,QAAiD,GACnD,GAAI,GACA,GACJ,GAAI,EAAU,CACZ,GAAI,CACF,KAAM,IAAM,GAAI,KAAI,GACpB,EAAO,GAAI,KACX,GAAW,GAAI,cACf,CACA,KAAM,IAAI,OACR,+CAA+C,yBAGnD,GAAI,KAAa,IACf,KAAM,IAAI,OACR,yEAAyE,UAI7E,GAAO,EAGT,KAAM,IAAc,EAAO,kBAAkB,eACvC,GAAkB,EAAO,kBAAkB,mBAC3C,GAAU,EAAO,kBAAkB,WAEzC,MAAO,CACL,OACA,WACA,mBACA,eACA,mBACA,YAWG,YACL,EACA,CAEA,KAAM,GAAS,EAAQ,IAAI,IAI3B,MAAK,GAAO,KAAK,GAAK,EAAE,OAAS,IAC/B,EAAO,KAAK,CACV,KAAM,IAGH,EC1GF,cAAwB,IAWzB,OAAO,CACT,MAAO,WAGL,QAAQ,CACV,MAAO,MAAK,kBAAkB,QAG5B,SAAS,CACX,MAAO,MAAK,kBAGd,YAAc,EAAmB,CAAE,KAAK,kBAAoB,EAE5D,WAAW,EAIX,CAEE,MADiB,GAAqB,GAIxC,eAAe,EAAK,CAElB,MAAO,KApCJ,UACE,EADF,GACE,UAAU,CAAC,CAAE,YAAa,C,MAC/B,KAAM,GAAU,GACd,KAAO,uBAAuB,wBAA9B,OAAuD,IAEzD,MAAO,GACL,EAAQ,IAAI,IAAK,GAAI,IAAiB,KACtC,IAAK,GAAE,OAAO,QCYb,QAAuB,CAa5B,YAAY,EAAoB,CAZ9B,iBAaA,KAAK,OAAS,QAXT,YAAW,EAAQ,CACxB,MAAO,IAAI,IAAgB,CACzB,MAAO,GAAiB,QAAQ,CAAE,WAClC,MAAO,EAAiB,QAAQ,CAAE,WAClC,UAAW,GAAqB,QAAQ,CAAE,WAC1C,OAAQ,GAAkB,QAAQ,CAAE,WACpC,OAAQ,EAAkB,QAAQ,CAAE,gBAQpC,QAAQ,CACV,MAAO,MAAK,OAAO,SAGjB,QAAQ,CACV,MAAO,MAAK,OAAO,SAGjB,YAAY,CACd,MAAO,MAAK,OAAO,aAGjB,SAAS,CACX,MAAO,MAAK,OAAO,UAGjB,SAAS,CACX,MAAO,MAAK,OAAO,OAGrB,MAAO,CACL,MAAO,QAAO,OAAO,KAAK,QAAQ,QAChC,GAAK,EAAE,QAIX,MAAM,EAAK,CACT,MAAO,QAAO,OAAO,KAAK,QACvB,IAAI,GAAK,EAAE,MAAM,IACjB,KAAK,SAGV,OAAO,EAAM,CACX,MAAO,QAAO,OAAO,KAAK,QACvB,IAAI,GAAK,EAAE,OAAO,IAClB,KAAK,SAGV,WAAW,EAIX,CACE,KAAM,GAAc,KAAK,MAAM,EAAQ,MACvC,MAAK,GAIE,EAAY,WAAW,GAHrB,EAAqB,GAMhC,eAAe,EAAK,CAClB,KAAM,GAAc,KAAK,MAAM,GAC/B,MAAK,GAIE,EAAY,eAAe,GAHzB,K,sKC9CN,KAAM,GAAO,CAClB,uBAAiB,CACf,IAAK,kBACL,KAAM,CAAE,UAAW,gBACnB,QAAS,CAAC,CAAE,eACV,8BACE,GAAG,EAAU,UAAU,2CAG7B,uBAAiB,CACf,IAAK,cACL,KAAM,GACN,QAAS,IAAM,GAAI,uBAErB,uBAAiB,CACf,IAAK,kBACL,KAAM,GACN,QAAS,IAAM,GAAI,sBAErB,uBAAiB,CACf,IAAK,cACL,KAAM,CAAE,SAAU,eAClB,QAAS,CAAC,CAAE,cAAe,CACzB,KAAM,GAAW,GAAI,gBAAa,EAAU,GAAI,sBAChD,yCAAgC,EAAU,CAAE,OAAQ,KAC7C,KAGX,uBAAiB,CACf,IAAK,gBACL,KAAM,CAAE,SAAU,eAClB,QAAS,CAAC,CAAE,cAAe,oBAAkB,CAAE,eAEjD,uBAAiB,CACf,IAAK,cACL,KAAM,CACJ,UAAW,eACX,YAAa,iBACb,aAAc,mBAEhB,QAAS,CAAC,CAAE,YAAW,cAAa,kBAC3B,qBAAe,CACpB,WAAY,CACV,yCAAuC,CACrC,iBAEF,sCAAoC,CAClC,cACA,OAAQ,SAMlB,uBAAiB,CACf,IAAK,qBACL,KAAM,GACN,QAAS,IAAM,GAAI,yBAErB,uBAAiB,CACf,IAAK,mBACL,KAAM,CACJ,aAAc,kBACd,gBAAiB,qBACjB,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,kBAAiB,eACzC,oBAAkB,CAChB,eACA,kBACA,YAAa,EAAU,kBAAkB,wBAG/C,uBAAiB,CACf,IAAK,sBACL,KAAM,CACJ,aAAc,kBACd,gBAAiB,qBACjB,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,kBAAiB,eACzC,uBAAqB,CACnB,eACA,kBACA,YAAa,EAAU,kBAAkB,wBAG/C,uBAAiB,CACf,IAAK,mBACL,KAAM,CACJ,aAAc,kBACd,gBAAiB,qBACjB,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,kBAAiB,eACzC,oBAAkB,CAChB,eACA,kBACA,cAAe,CAAC,aAChB,YAAa,EAAU,kBAAkB,wBAG/C,uBAAiB,CACf,IAAK,iBACL,KAAM,CACJ,aAAc,kBACd,gBAAiB,qBACjB,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,kBAAiB,eACzC,kBAAgB,CACd,eACA,kBACA,YAAa,EAAU,kBAAkB,wBAG/C,uBAAiB,CACf,IAAK,mBACL,KAAM,CACJ,aAAc,kBACd,gBAAiB,qBACjB,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,kBAAiB,eACzC,oBAAkB,CAChB,eACA,kBACA,YAAa,EAAU,kBAAkB,wBAG/C,uBAAiB,CACf,IAAK,kBACL,KAAM,CACJ,aAAc,kBACd,gBAAiB,qBACjB,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,kBAAiB,eACzC,mBAAiB,CACf,eACA,kBACA,YAAa,EAAU,kBAAkB,wBAG/C,uBAAiB,CACf,IAAK,eACL,KAAM,CACJ,aAAc,kBACd,gBAAiB,qBACjB,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,kBAAiB,eACzC,gBAAc,CACZ,eACA,kBACA,YAAa,EAAU,kBAAkB,wBAG/C,uBAAiB,CACf,IAAK,iBACL,KAAM,CACJ,aAAc,kBACd,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,eACxB,kBAAgB,CACd,eACA,YAAa,EAAU,kBAAkB,wBAG/C,uBAAiB,CACf,IAAK,qBACL,KAAM,CACJ,aAAc,kBACd,gBAAiB,qBACjB,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,kBAAiB,eACzC,sBAAoB,CAClB,eACA,kBACA,YAAa,EAAU,kBAAkB,wBAG/C,uBAAiB,CACf,IAAK,iBACL,KAAM,CACJ,aAAc,kBACd,gBAAiB,qBACjB,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,kBAAiB,eACzC,gBAAc,CACZ,eACA,kBACA,SAAU,CACR,GAAI,OACJ,MAAO,yBACP,KAAM,IAAM,MAEd,YAAa,EAAU,kBAAkB,wBAG/C,uBAAiB,CACf,IAAK,sBACL,KAAM,CACJ,aAAc,kBACd,gBAAiB,qBACjB,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,kBAAiB,eACzC,uBAAqB,CACnB,eACA,kBACA,cAAe,CAAC,QAChB,YAAa,EAAU,kBAAkB,wBAG/C,uBAAiB,CACf,IAAK,sBACL,KAAM,CACJ,aAAc,kBACd,gBAAiB,qBACjB,UAAW,gBAEb,QAAS,CAAC,CAAE,eAAc,kBAAiB,eAClC,uBAAqB,CAC1B,eACA,kBACA,YAAa,EAAU,kBAAkB,wBAI/C,uBAAiB,CACf,IAAK,KACL,KAAM,CACJ,UAAW,kBACX,SAAU,iBACV,OAAQ,gBAEV,QAAS,CAAC,CAAE,SAAQ,YAAW,cAC7B,YAA6B,CAAE,SAAQ,YAAW,gB,oCCxRjD,WAAgC,CAAE,YAAY,CACnD,MAAI,WACK,gBAAoB,WAAgB,KAAM,GAE5C,gBAAoB,KAAc,KAAM,GAGjD,KAAM,GAAsB,IAC1B,gBAAoB,YAAW,CAAE,OAAQ,MAAO,cAAe,mBAG3D,EAAuB,CAAC,CAAE,OAAM,WAAY,CAChD,GAAI,GAAU,GACd,MAAI,KAAS,cACX,EAAU,+EAA+E,EAAM,UACtF,IAAS,cAClB,GAAU,6DAA6D,EAAM,WAI7E,gBAAoB,EAAwB,KACxC,gBAAoB,YAAW,CAAE,OAAQ,MAAO,cAAe,MAKjE,EAA+B,CAAC,CACpC,QACA,aACA,YAGE,gBAAoB,aAAY,CAC9B,MAAO,YAAY,iBAAQ,UAC3B,gBAAiB,GACjB,MAAO,GAEL,gBAAoB,IAAQ,CAAE,QAAS,WAAY,QAAS,GAAc,UAYrE,EAAa,CACxB,SAAQ,WACR,OAAQ,KACR,kBAAmB,EACnB,cAAe,EACf,sBAAuB,G,iOC/ClB,KAAM,IAAQ,CACnB,YAAa,IAEb,QAAS,KACT,WAAY,IACZ,SAAU,IACV,OAAQ,IACR,KAAM,KACN,UAAW,KACX,KAAM,KACN,MAAO,KACP,OAAQ,KACR,MAAO,KACP,KAAM,KACN,WAAY,KACZ,iBAAkB,KAClB,cAAe,IACf,aAAc,KACd,gBAAiB,KACjB,cAAe,IACf,YAAa,KACb,KAAM,KACN,QAAS,M,4BC1BJ,KAAM,IAAS,CACpB,KAAM,qpDACN,MAAO,y1CACP,MAAO,+8DAQI,GAAgB,CAC3B,SAAU,CAAC,UAAW,WACtB,WAAY,CAAC,UAAW,WACxB,SAAU,CAAC,UAAW,WACtB,QAAS,CAAC,UAAW,WACrB,aAAc,CAAC,UAAW,WAC1B,UAAW,CAAC,UAAW,WACvB,WAAY,CAAC,UAAW,WACxB,KAAM,CAAC,WACP,QAAS,CAAC,UAAW,YAYhB,YAAsB,EAAQ,EAAO,CAE1C,KAAM,IAAW,0BAA0B,GADb,SAAW,EAAI,CAAC,EAAO,GAAI,EAAO,IAAM,GACZ,KAAK,SACzD,GAAkB,GAAG,OAAW,KAEtC,MAAO,CAAE,SAAQ,QAAO,oBAQnB,KAAM,IAAY,CACvB,KAAM,GAAa,GAAc,KAAM,GAAO,MAC9C,cAAe,GAAa,GAAc,QAAS,GAAO,OAC1D,KAAM,GAAa,GAAc,UAAW,GAAO,OACnD,QAAS,GAAa,GAAc,WAAY,GAAO,MACvD,QAAS,GAAa,GAAc,SAAU,GAAO,MACrD,QAAS,GAAa,GAAc,QAAS,GAAO,MACpD,MAAO,GAAa,GAAc,SAAU,GAAO,MACnD,IAAK,GAAa,GAAc,aAAc,GAAO,MACrD,KAAM,GAAa,GAAc,KAAM,GAAO,QC7D1C,GACJ,yDAOK,YACL,EACA,CACA,KAAM,CACJ,UACA,aAAa,GACb,oBACA,aAAY,IACV,EAEJ,GAAI,CAAC,GAAU,IACb,KAAM,IAAI,OAAM,GAAG,mCAGrB,MAAO,CACL,UACA,MAAO,CACL,QAAS,CACP,QAAS,GAEX,UAAW,CACT,MAAO,YAGX,WAAY,CACV,aACA,GAAI,CACF,WAAY,KAEd,GAAI,CACF,WAAY,IACZ,SAAU,GACV,aAAc,GAEhB,GAAI,CACF,SAAU,GACV,WAAY,IACZ,aAAc,GAEhB,GAAI,CACF,SAAU,GACV,WAAY,IACZ,aAAc,GAEhB,GAAI,CACF,SAAU,GACV,WAAY,IACZ,aAAc,KAGlB,KAAM,GAAU,IAChB,aAAc,CAAC,CAAE,cAAW,C,OAC1B,aAAU,MAAV,QAAsB,GAAU,MAS/B,YAA8B,EAAO,CAC1C,MAAO,CACL,eAAgB,CACd,UAAW,CACT,KAAM,CACJ,OAAQ,OACR,WAAY,EAAM,WAAW,YAE/B,KAAM,CACJ,OAAQ,OACR,WAAY,EAAM,WAAW,WAC7B,wBAAyB,QAE3B,EAAG,CACD,MAAO,UACP,eAAgB,UAItB,YAAa,CAEX,KAAM,CACJ,qBAAsB,CACpB,gBAAiB,EAAM,QAAQ,WAAW,UAI9C,MAAO,CACL,UAAW,CACT,OAAQ,YAIZ,KAAM,CACJ,qBAAsB,CACpB,gBAAiB,EAAM,QAAQ,WAAW,SAKhD,aAAc,CACZ,KAAM,CACJ,UAAW,aACX,SAAU,SACV,cAAe,SACf,WAAY,IACZ,OAAQ,EACR,QAAS,EAAM,QAAQ,EAAG,EAAG,EAAG,KAChC,aAAc,GAEhB,UAAW,CACT,QAAS,EAAM,QAAQ,IAAK,EAAG,IAAK,MAEtC,KAAM,CACJ,UAAW,aACX,SAAU,SACV,MAAO,qBACP,WAAY,SACZ,WAAY,MAGhB,QAAS,CAEP,KAAM,CACJ,UAAW,KAGf,OAAQ,CAEN,KAAM,CACJ,MAAO,EAAM,QAAQ,KACrB,UAAW,GACX,cAAe,UACf,cAAe,SACf,UAAW,CACT,MAAO,cAAO,EAAM,QAAQ,KAAM,IAClC,WAAY,eAAQ,EAAM,QAAQ,KAAM,OAEzC,EAAM,YAAY,GAAG,OAAQ,CAC5B,SAAU,IACV,SAAU,EAAM,WAAW,QAAQ,IACnC,WAAY,MAGhB,iBAAkB,CAChB,MAAO,EAAM,QAAQ,OAGzB,kBAAmB,CAEjB,KAAM,CACJ,MAAO,UACP,UAAW,CACT,MAAO,WAET,UAAW,CACT,MAAO,YAIX,OAAQ,CACN,WAAY,OACZ,MAAO,YAGX,gBAAiB,CACf,MAAO,CAEL,WAAY,SACZ,SAAU,SACV,aAAc,aAGlB,UAAW,CACT,KAAM,CAEJ,QAAS,SAGb,QAAS,CACP,KAAM,CACJ,gBAAiB,UAEjB,YAAa,EAAM,QAAQ,GAC3B,aAAc,EAAM,QAAQ,GAC5B,MAAO,EAAM,QAAQ,KAAK,MAE5B,SAAU,CACR,MAAO,EAAM,QAAQ,KAAK,SAE5B,MAAO,CACL,WAAY,GAAG,EAAM,QAAQ,SAC7B,WAAY,EAAM,WAAW,iBAC7B,SAAU,GAAG,EAAM,QAAQ,WAE7B,WAAY,CACV,SAAU,GAAG,EAAM,QAAQ,UAE7B,WAAY,CACV,MAAO,EAAM,QAAQ,KAAK,KAC1B,MAAO,GAAG,EAAM,QAAQ,OACxB,OAAQ,GAAG,EAAM,QAAQ,OACzB,OAAQ,KAAK,EAAM,QAAQ,aAAc,EAAM,QAAQ,UAEzD,gBAAiB,CACf,MAAO,GAAG,EAAM,QAAQ,OACxB,OAAQ,GAAG,EAAM,QAAQ,OACzB,OAAQ,KAAK,EAAM,QAAQ,YAAa,EAAM,QAAQ,UAG1D,QAAS,CACP,KAAM,CAKJ,QAAS,OACT,cAAe,WAGnB,cAAe,CACb,KAAM,CAEJ,cAAe,IAGnB,eAAgB,CACd,KAAM,CAKJ,SAAU,EACV,eAAgB,CACd,cAAe,UAIrB,eAAgB,CACd,KAAM,CAEJ,eAAgB,cAYjB,YAAqB,EAAS,CACnC,KAAM,GAAe,GAAmB,GAClC,EAAY,SAAe,GAC3B,GAAY,GAAqB,GAEvC,MADc,IAAK,EAAW,c,gBC3QzB,KAAM,IAAa,GAAY,CACpC,QAAS,CACP,KAAM,QACN,WAAY,CACV,QAAS,WAEX,OAAQ,CACN,GAAI,UACJ,QAAS,UACT,MAAO,UACP,QAAS,UACT,QAAS,UACT,QAAS,WAEX,OAAQ,CACN,UAAW,UACX,iBAAkB,OAClB,gBAAiB,CACf,QAAS,WAEX,SAAU,CACR,OAAQ,uDAGZ,QAAS,CACP,KAAM,WAER,OAAQ,CACN,KAAM,UACN,MAAO,UACP,KAAM,UACN,KAAM,UACN,QAAS,WAEX,OAAQ,UACR,aAAc,UACd,eAAgB,OAChB,WAAY,UACZ,UAAW,UACX,gBAAiB,UACjB,kBAAmB,UACnB,eAAgB,UAChB,UAAW,UACX,SAAU,UACV,YAAa,UACb,UAAW,UACX,KAAM,UACN,KAAM,UACN,WAAY,CACV,WAAY,UACZ,UAAW,UACX,MAAO,UACP,cAAe,OACf,QAAS,CACP,gBAAiB,WAEnB,QAAS,CACP,WAAY,YAGhB,iBAAkB,CAChB,KAAM,UACN,WAAY,WAEd,OAAQ,CACN,UAAW,YAGf,iBAAkB,OAClB,UAAS,KAQE,GAAY,GAAY,CACnC,QAAS,CACP,KAAM,OACN,WAAY,CACV,QAAS,WAEX,OAAQ,CACN,GAAI,UACJ,QAAS,UACT,MAAO,UACP,QAAS,UACT,QAAS,UACT,QAAS,WAEX,OAAQ,CACN,UAAW,UACX,iBAAkB,OAClB,gBAAiB,CACf,QAAS,WAEX,SAAU,CACR,OAAQ,uDAGZ,QAAS,CACP,KAAM,UACN,KAAM,WAER,UAAW,CACT,KAAM,WAER,OAAQ,CACN,KAAM,UACN,MAAO,UACP,KAAM,UACN,KAAM,UACN,QAAS,WAEX,OAAQ,UACR,aAAc,UACd,eAAgB,UAChB,WAAY,UACZ,UAAW,UACX,gBAAiB,UACjB,kBAAmB,UACnB,eAAgB,UAChB,UAAW,UACX,SAAU,UACV,YAAa,UACb,UAAW,UACX,KAAM,UACN,KAAM,UACN,WAAY,CACV,WAAY,UACZ,UAAW,UACX,MAAO,UACP,cAAe,OACf,QAAS,CACP,gBAAiB,WAEnB,QAAS,CACP,WAAY,YAGhB,iBAAkB,CAChB,KAAM,UACN,WAAY,WAEd,OAAQ,CACN,UAAW,YAGf,iBAAkB,OAClB,UAAS,K,mDCvJJ,KAAM,GAAS,CACpB,CACE,GAAI,QACJ,MAAO,cACP,QAAS,QACT,KAAM,gBAAoB,KAAW,MACrC,SAAU,CAAC,CAAE,cACX,gBAAoB,KAAe,CAAE,MAAO,IACxC,gBAAoB,KAAa,KAAM,KAI/C,CACE,GAAI,OACJ,MAAO,aACP,QAAS,OACT,KAAM,gBAAoB,KAAU,MACpC,SAAU,CAAC,CAAE,cACX,gBAAoB,KAAe,CAAE,MAAO,IACxC,gBAAoB,KAAa,KAAM,MCR1C,WACL,EACA,C,WACA,MAAO,2BAAqB,IACvB,EACH,KAAM,oBAAS,OAAT,OAAiB,GACvB,WAAY,iBAAS,WACrB,WAAY,IACP,KACA,iBAAS,YAEd,aAAc,iBAAS,aACvB,YAAa,EACb,MAAO,IACF,MACA,iBAAS,OAEd,QAAU,oBAAS,UAAT,OAAsB,GAChC,OAAQ,qBAAS,SAAT,QAAmB,I,sCC1B/B,KAAM,IAAY,SAAW,CAC3B,cAAe,CACb,SAAU,QAEZ,SAAU,CACR,MAAO,OACP,UAAW,YACX,aAAc,UAIL,GAAwB,CAAC,CAAE,YAAa,CACnD,KAAM,GAAU,KAChB,MACE,OAAM,cAAc,KAAM,CAAE,GAAI,EAAO,UACnC,MAAM,cAAc,SAAU,CAAE,WAAY,aAAc,UAAW,EAAQ,eAC3E,MAAM,cAAc,aAAc,CAClC,UAAW,EAAQ,SACnB,uBAAwB,CAAE,QAAS,MACnC,QAAS,EAAO,MAChB,UAAW,EAAO,OAElB,MAAM,cAAc,IAAK,KACvB,EAAO,MAAQ,MAAM,cAAc,KAAM,CAAE,MAAO,SAAS,EAAO,OAAQ,KAAM,UAChF,EAAO,WACP,MAAM,cAAc,KAAM,CAAE,MAAO,cAAc,EAAO,YAAa,KAAM,YAI/E,MAAM,cAAc,QAAS,CAAE,UAAW,S,uLClC3C,KAAM,GAA+B,iBAU/B,EAA8B,CACzC,KAAM,sBACN,WAAY,CACV,OAAQ,QAEV,aAAc,GASH,EAAgC,CAC3C,KAAM,wBACN,WAAY,CACV,OAAQ,UAEV,aAAc,GAQH,GAAgC,CAC3C,KAAM,wBACN,WAAY,CACV,OAAQ,UAEV,aAAc,GAQH,GAAiC,CAC5C,KAAM,yBACN,WAAY,CACV,OAAQ,UAEV,aAAc,GAWH,GAAgC,CAC3C,KAAM,wBACN,WAAY,CACV,OAAQ,SASC,GAAkC,CAC7C,KAAM,0BACN,WAAY,CACV,OAAQ,WASC,GAAkC,CAC7C,KAAM,0BACN,WAAY,CACV,OAAQ,WCjFN,GAAY,SAAW,CAC3B,OAAQ,CACN,MAAO,WAuBE,GAAoB,CAAC,CAChC,iCACA,8BACA,wBACI,C,OACJ,KAAM,CAAC,GAAU,IAAe,iBAC1B,GAAU,KACV,GAAuB,2BAC3B,IAGI,GAAU,IAAU,CACxB,GAAY,GAAM,gBAGd,GAAU,IAAM,CACpB,GAAY,SAGR,GAAa,GAAkC,CACnD,GAAG,EAA+B,IAAI,IACpC,gBAAoB,KAAU,CAC5B,IAAK,GAAK,MACV,QAAS,IAAM,CACb,KACA,GAAK,YAGL,gBAAoB,KAAc,KAChC,gBAAoB,GAAK,KAAM,CAAE,SAAU,WAE7C,gBAAoB,KAAc,CAAE,QAAS,GAAK,UAGxD,gBAAoB,KAAS,CAAE,IAAK,0BAGhC,GACH,KAAC,GAAqB,SACrB,kBAA6B,qBAD9B,QAED,GAEF,MACE,iBAAoB,WAAgB,KAChC,gBAAoB,KAAY,CAChC,aAAc,OACd,gBAAiB,YACjB,gBAAiB,OACjB,QAAS,GACT,cAAe,cACf,UAAW,GAAQ,QAEjB,gBAAoB,IAAU,OAEhC,gBAAoB,MAAS,CAC7B,KAAM,QAAQ,IACd,QAAS,GACT,SAAU,GACV,aAAc,CAAE,SAAU,SAAU,WAAY,SAChD,gBAAiB,CAAE,SAAU,MAAO,WAAY,UAE9C,gBAAoB,KAAU,KAC5B,GACA,gBAAoB,KAAU,CAC9B,QAAS,IAAM,CACb,KACA,KAEF,SAAU,IAER,gBAAoB,KAAc,KAChC,gBAAoB,KAAQ,CAAE,SAAU,WAE1C,gBAAoB,KAAc,CAAE,QAAS,2BC1ErD,GAAU,mCAEV,EAAQ,IAAM,KACpB,0BAAoB,EAAO,GAAS,IAGpC,0BAAoB,EAAO,yBAA0B,IAErD,KAAM,GAAoB,CAAC,CACzB,SACA,WAME,gBAAoB,KAAK,CAAE,QAAS,cAAe,WAAY,SAAU,OAAQ,MAAO,SAAU,QAC9F,gBAAoB,KAAK,CACzB,UAAW,OACX,aAAc,WACd,WAAY,SACZ,SAAU,UAER,GAEF,GAAU,gBAAoB,kBAAgB,CAAE,OAAQ,KAK1D,GAAc,CAClB,EACA,EACA,EACA,KACG,C,mBACH,KAAM,IAAO,cAAa,mBAAQ,OAArB,QAA6B,GACpC,GAAY,cAAkB,mBAAQ,SAAS,YAAnC,QAAgD,GAGlE,MAAO,CACL,YAAa,GAFb,+BAAQ,SAAS,QAAjB,QAA0B,IAA1B,QAAuC,mBAAQ,SAAS,OAAxD,QAAgE,KAG9D,IAAa,KAAc,MACvB,OAAO,KACP,KAEN,WAAa,KAAM,CACjB,GAAI,IAAI,GAAK,kBAAkB,SAC/B,MAAI,KAAU,GAAO,MAAQ,QAAU,IAAO,MAC5C,KAAK,WACL,IAAM,GAAO,KAAO,KAAK,kBAAkB,UAEtC,SAKP,GAAe,CAAC,CAAE,YAAa,C,MACnC,KAAM,GAAmB,0BAAmB,EAAQ,OACpD,MACE,iBAAoB,WAAgB,KAChC,EAAiB,OAAS,GAC1B,gBAAoB,cAAa,CAC/B,MAAO,QACP,MACE,gBAAoB,kBAAgB,CAClC,WAAY,EACZ,YAAa,QACb,MAAO,cAKb,MAAO,OAAP,cAAa,YACb,gBAAoB,cAAa,CAAE,MAAO,YAAa,MAAO,EAAO,KAAK,cAwCrE,GAAe,CAAC,CAC3B,iCACA,8BACA,cACI,C,aACJ,KAAM,CAAE,QAAM,aAAW,SAAS,+BAC5B,CAAE,UAAQ,WAAS,UAAU,iBAAW,kBACxC,GAAS,uBACb,EACA,IACE,GACG,sBAAsB,CACrB,IAAK,GACL,gBACE,wDAEH,cACA,QAAQ,CAAC,CAAE,YACN,GAAM,IAAM,IAAU,CAAC,GAAM,GAAG,IAC3B,GAGF,CACL,CACE,KAAM,GAAM,KACZ,MAAO,GAAM,MACb,SAAU,GAAM,SAChB,SAAU,GAAM,YAI1B,CAAC,KAGG,CAAE,eAAa,eAAe,GAClC,GACA,GACA,GACA,IAGI,CAAC,GAAwB,IAA6B,eAAS,IAC/D,GAAW,WACX,GAAsB,SAAY,CACtC,GAA0B,IAC1B,GAAS,MAGL,GAAoB,IAAM,GAA0B,IAE1D,MACE,iBAAoB,OAAM,CAAE,QAAS,+BAAQ,OAAR,eAAc,OAAd,eAAoB,aAApB,QAAkC,QACnE,gBAAoB,SAAQ,CAC5B,MAAO,gBAAoB,EAAmB,CAAE,MAAO,GAAa,OAAQ,KAC5E,kBAAmB,GACnB,KAAM,IAEJ,IACA,gBAAoB,WAAgB,KAChC,gBAAoB,GAAc,CAAE,OAAQ,KAC5C,gBAAoB,GAAmB,CACvC,+BAAgC,EAChC,4BAA6B,EAC7B,mBAAoB,OAM1B,IAAW,gBAAoB,WAAU,MAEzC,IAAU,gBAAoB,aAAY,CAAE,OAAQ,KAEpD,IACA,gBAAoB,UAAS,KACzB,gBAAoB,KAAO,CAAE,SAAU,SAAW,GAAM,aAI5D,CAAC,IAAW,CAAC,IAAS,CAAC,IACvB,gBAAoB,UAAS,KACzB,gBAAoB,eAAc,CAAE,MAAO,oBAAwB,eAC9D,GAAM,sBAA0B,IACnC,gBAAoB,OAAM,CAAE,GAAI,kEAAoE,6BAEnG,MAMP,gBAAoB,0BAAwB,CAC5C,KAAM,GACN,OAAQ,GACR,UAAW,GACX,QAAS,IAAM,GAA0B,QAMjD,GAAa,MAAQ,E,gBCnPd,KAAM,IAAqB,CAAC,CACjC,OACA,UACA,YACA,aACI,CACJ,KAAM,CAAC,GAAM,IAAW,SAAS,IAC3B,GAAa,OAAO,eACpB,GAAW,OAAO,aAElB,GAAW,SAAY,CAC3B,GAAQ,IACR,GAAI,CACF,KAAM,IAAM,GAAO,SAAS,IAC5B,KAAM,IAAW,kBAAkB,IACnC,UACO,GAAP,CACA,YAAY,IACZ,GAAS,KAAK,CAAE,QAAS,GAAI,iBAC7B,CACA,GAAQ,MAIZ,MACE,OAAM,cAAc,OAAQ,CAAE,KAAM,EAAM,QAAS,GAC/C,MAAM,cAAc,YAAa,CAAE,GAAI,2BAA6B,gDAGpE,MAAM,cAAc,cAAe,KACjC,MAAM,cAAc,OAAQ,CAC5B,QAAS,YACT,MAAO,YACP,SAAU,GACV,QAAS,IACT,UAGA,MAAM,cAAc,OAAQ,CAAE,QAAS,EAAS,MAAO,WAAa,aC5CjE,GAAY,GAAQ,C,QAC/B,8BAAQ,WAAR,cAAkB,cAAlB,cAAgC,0BAA2B,QAKhD,GAAsB,IAAM,CACvC,KAAM,GAAW,cACX,EAAc,YAAY,iBAC1B,CAAC,EAAwB,IAA6B,SAAS,IAC/D,CAAE,WAAW,YAEb,GAAsB,SAAY,CACtC,GAA0B,IAC1B,EAAS,MAGX,MACE,OAAM,cAAc,MAAM,SAAU,KAChC,MAAM,cAAc,MAAO,CAAE,SAAU,UAAW,QAAS,IAAM,GAA0B,KAAS,+GAIpG,MAAM,cAAc,mBAAoB,CACxC,KAAM,EACN,OAAQ,GACR,UAAW,GACX,QAAS,IAAM,GAA0B,Q,gBCZjD,KAAM,IAAe,GACnB,EAAE,OACF,EAAE,QAAU,SACZ,EAAE,OAAS,sCASb,kBACE,EACA,EACA,CAYA,MAAO,CAAE,MAVK,MADU,GAAW,mBAAmB,CAAE,eAChC,MACrB,IAAI,IAAQ,C,UAMX,MAAO,CAAE,OAJM,YADQ,OAAS,SAAd,eAAsB,QAAtB,QAA+B,IAE9C,OAAO,IACP,IAAI,IAAK,GAAE,OACX,OAAQ,IAAM,QAAQ,KACA,OAAQ,GAAK,UAEvC,OAAO,IAAQ,GAAK,OAAO,OAAS,IAIlC,KAAM,IAA6B,MACxC,EACA,IACG,CACH,KAAM,GAAa,EAAQ,KAAK,IAAI,eACpC,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,mCAAmC,iBAOrD,MAAO,MAJc,IACnB,mBAAmB,GACnB,IAEY,MAAM,OAAS,GAMlB,GAA8B,IAAM,CAC/C,KAAM,CAAE,UAAW,YACb,EAAY,mBAAmB,GAC/B,EAAa,OAAO,eACpB,CAAE,WAAS,SAAO,UAAU,SAAS,SAClC,GAAyB,EAAW,GAC1C,CAAC,EAAW,IAEf,MAAI,IAEA,MAAM,cAAc,IAAK,CAAE,GAAI,GAC3B,MAAM,cAAc,mBAAoB,CAAE,MAAO,MAKrD,IAAW,CAAC,GACP,KAIP,MAAM,cAAc,MAAM,SAAU,KAChC,GAAM,MAAM,IAAI,CAAC,GAAe,KAChC,MAAM,cAAc,IAAK,CAAE,IAAK,GAAO,GAAI,GACvC,CAAC,mBACD,EACA,mBAAmB,GAAc,UAEjC,MAAM,cAAc,IAAK,CAAE,EAAG,GAAK,kCAC3B,IACJ,MAAM,cAAc,cAAe,CAAE,UAAW,GAAc,UAGlE,GAAc,OAAO,IAAI,CAAC,GAAG,KAC7B,MAAM,cAAc,mBAAoB,CAAE,IAAK,GAAG,MAAO,U,gBC7FrE,KAAM,IAA4B,CAChC,EACA,EACA,EAAe,IACZ,CACH,GAAI,CAAC,EAAc,MAAO,GAC1B,KAAM,IAAW,EAAK,UAAU,IAAK,GAAE,KAAO,EAAa,MAAM,MACjE,MAAO,CAAC,GAAW,GAAW,GAoBnB,GAAS,CACpB,OAAQ,CAAC,CAAE,cAAe,C,aACxB,KAAM,GAAS,GACT,EAAO,GACP,GAAS,WACT,GAAW,WAEjB,mBAAuB,EAAU,IAAS,CACxC,GAAI,CAAC,iBAAqB,IAExB,OAEF,GAAI,GAAM,OAAS,GAAO,QACxB,KAAM,IAAI,OACR,sGAGJ,KAAM,IAAa,GAAQ,MAAM,KAGjC,EAAK,KAAK,CACR,GAAI,GACJ,MAAQ,GAAQ,MAAM,QAGxB,EAAO,KAAK,CACV,KAAM,GACN,QAAS,GAAM,MAAM,YAKpB,0BAAS,KAAT,eAAa,OAAb,QAAqB,MAAQ,IAChC,EAAO,KAAK,CACV,KAAM,KACN,QAAS,gBAAoB,KAAU,CAAE,GAAI,EAAO,GAAG,SAG3D,KAAM,CAAC,IACL,I,GAAA,MAAY,EAAS,IAAI,GAAO,UAAhC,QAA2C,GACvC,GAAgB,GAA0B,GAAc,GACxD,GAAa,EAAK,IAClB,GAAQ,mBAAY,MAEpB,GAAe,IAKnB,GAAS,EAAK,IAAO,GAAG,QAAQ,QAAS,IAAI,QAAQ,MAAO,KAExD,GAAsB,SAAU,GAEtC,MAAK,IAEH,gBAAoB,WAAgB,KAChC,gBAAoB,aAAY,CAChC,KAAM,EACN,cAAe,GACf,SAAU,KAEV,gBAAoB,UAAS,KAC3B,gBAAoB,KAAQ,CAAE,MAAO,KACrC,KAVgB,MAe1B,QAAU,GACR,MC9EE,GAAkB,CAAC,CACvB,SACA,WAKA,gBAAoB,KAAK,CAAE,QAAS,cAAe,WAAY,SAAU,OAAQ,OAC7E,EACA,GAAU,gBAAoB,kBAAgB,CAAE,OAAQ,KAIxD,GAAe,CAAC,CAAE,YAAa,C,MACnC,KAAM,GAAmB,0BAAmB,EAAQ,OACpD,MACE,iBAAoB,WAAgB,KAChC,EAAiB,OAAS,GAC1B,gBAAoB,cAAa,CAC/B,MAAO,QACP,MACE,gBAAoB,kBAAgB,CAClC,WAAY,EACZ,YAAa,QACb,MAAO,cAKb,MAAO,OAAP,cAAa,YACb,gBAAoB,cAAa,CAAE,MAAO,YAAa,MAAO,EAAO,KAAK,cAM5E,GAAc,CAClB,EACA,EACA,EACA,KAEO,EACL,YAAa,GAAG,IACd,GAAa,IAAc,MACvB,OAAO,IACP,KAEN,WAAa,KAAM,CACjB,GAAI,IAAI,EAAK,kBAAkB,SAC/B,MAAI,KAAU,GAAO,MAAQ,QAAU,IAAO,MAC5C,KAAK,WACL,IAAM,GAAO,KAAO,KAAK,kBAAkB,UAEtC,SAwBA,GAAmB,CAAC,CAC/B,WACA,iCACA,iCACI,C,aACJ,KAAM,CAAE,QAAM,aAAW,SAAS,+BAC5B,CAAE,UAAQ,WAAS,UAAU,iBAAW,kBACxC,CAAE,eAAa,eAAe,GAClC,GACA,GACA,GACA,IAGI,CAAC,GAAwB,IAA6B,eAAS,IAC/D,GAAW,WACX,GAAsB,SAAY,CACtC,GAA0B,IAC1B,GAAS,MAGL,GAAoB,IAAM,GAA0B,IAE1D,MACE,iBAAoB,OAAM,CAAE,QAAS,+BAAQ,OAAR,eAAc,OAAd,eAAoB,aAApB,QAAkC,QACnE,gBAAoB,SAAQ,CAC5B,MAAO,gBAAoB,GAAiB,CAAE,MAAO,GAAa,OAAQ,KAC1E,kBAAmB,GACnB,KAAM,IAGJ,IACA,gBAAoB,WAAgB,KAChC,gBAAoB,GAAc,CAAE,OAAQ,KAC5C,gBAAoB,GAAmB,CACvC,+BAAgC,EAChC,4BAA6B,EAC7B,mBAAoB,OAM1B,IACA,gBAAoB,UAAS,KACzB,gBAAoB,WAAU,OAIlC,IAAU,gBAAoB,GAAO,OAAQ,KAAM,GAEnD,IACA,gBAAoB,UAAS,KACzB,gBAAoB,qBAAoB,CAAE,MAAO,MAIrD,CAAC,IAAW,CAAC,IAAS,CAAC,IACvB,gBAAoB,UAAS,KACzB,gBAAoB,eAAc,CAAE,MAAO,oBAAwB,eAC9D,GAAM,sBAA0B,IACnC,gBAAoB,OAAM,CAAE,GAAI,kEAAoE,6BAEnG,MAMP,gBAAoB,0BAAwB,CAC5C,KAAM,GACN,OAAQ,GACR,UAAW,GACX,QAAS,IAAM,GAA0B,QAMjD,GAAiB,QAAU,GAAO,Q,gBCjLlC,KAAM,IAAoB,8BAEpB,GAAoB,GAMrB,KAEL,0BAAoB,GAAkB,GAAmB,IAelD,KAAM,IAAe,CAAC,CAAE,cAAe,C,UAC5C,KAAM,CAAE,UAAW,mBACb,EAAO,qBACP,GAAU,uBACd,EACA,IACE,GACG,sBAAsB,CACrB,IAAK,GACL,gBAAiB,sDAElB,cACA,QAAS,IAAY,C,OACpB,KAAM,CAAE,GAAI,GAAW,SAAU,IAC/B,GAAQ,MACV,MAAO,CACL,CACE,GAAI,uBAAY,EAAQ,CAAE,WAAtB,QAAiC,GACrC,SAAU,OAIpB,CAAC,EAAM,IAMT,MAJsB,IAAQ,KAC5B,IAAK,MAAO,IAAE,IAAO,UAAY,QAAU,IAAE,IAItC,gBAAoB,GAAmB,CAAE,QAAS,KAGpD,WAAQ,KAAK,IAAK,GAAE,MAApB,eAAyB,WAAzB,QAAqC,MAG9C,YAA2B,CAAE,WAAW,CACtC,KAAM,CAAE,UAAS,SAAU,eAAS,SAAY,C,OAC9C,KAAM,IAAW,EAAQ,IACvB,MAAO,CAAE,GAAI,GAAW,SAAU,MAAa,CAC7C,GAAI,CACF,GAAI,KAAM,IACR,MAAO,SAET,EAIF,MAAO,QAGX,MAAQ,UAAM,SAAQ,IAAI,KAAW,KAAK,WAAlC,QAA8C,MACrD,CAAC,IAEJ,MAAI,IAAW,CAAC,EACP,KAGF,EAGT,GAAa,KAAO,G,qCC5FpB,KAAM,IAAY,SAAW,GAAU,EACrC,KAAM,CACJ,SAAU,MACV,IAAK,IACL,MAAO,GACP,SAAU,YACT,EAAM,YAAY,KAAK,OAAQ,CAC9B,SAAU,MACV,SAAU,WACV,IAAK,QACL,MAAO,QACP,OAAQ,GAAG,EAAM,QAAQ,cAAc,EAAM,QAAQ,YAK9C,GAAO,IAAM,CACxB,KAAM,GAAU,KAChB,MACE,OAAM,cAAc,MAAO,CACzB,IAAK,WACL,UAAW,EAAQ,KACnB,IAAK,2CCnBL,GAAY,SAAW,GAAU,EACrC,UAAW,CACT,WAAY,EAAM,QAAQ,IAC1B,YAAa,EAAM,QAAQ,IAC1B,EAAM,YAAY,KAAK,OAAQ,CAC9B,QAAS,EAAM,QAAQ,KAG3B,MAAO,CACL,cAAe,EAAM,QAAQ,IAC5B,EAAM,YAAY,KAAK,OAAQ,CAC9B,SAAU,KAGd,KAAM,CACJ,cAAe,EAAM,QAAQ,IAC5B,EAAM,YAAY,KAAK,OAAQ,CAC9B,cAAe,EAAM,QAAQ,QAKtB,GAAiB,IAAM,CAClC,KAAM,GAAU,KAEhB,MACE,OAAM,cAAc,KAAM,CAAE,UAAW,GAAM,QAAS,EAAG,UAAW,EAAQ,WACxE,MAAM,cAAc,KAAM,MAC1B,MAAM,cAAc,KAAM,CAAE,KAAM,GAAM,GAAI,GAAI,GAAI,GAClD,MAAM,cAAc,WAAY,CAAE,QAAS,KAAM,UAAW,EAAQ,OAAS,wBAG7E,MAAM,cAAc,WAAY,CAAE,QAAS,QAAS,UAAW,EAAQ,MAAQ,4EAI/E,MAAM,cAAc,OAAQ,CAC5B,QAAS,YACT,MAAO,UACP,KAAM,6BACN,WClCJ,GAAoB,IACxB,MAAM,cAAc,iBAAkB,KAClC,MAAM,cAAc,iBAAiB,QAAS,CAC9C,KAAM,IACN,MAAO,WACP,QACE,MAAM,cAAc,QAAS,KACzB,MAAM,cAAc,WAAY,CAAE,QAAS,MAAQ,oCACnD,MAAM,cAAc,WAAY,CAAE,QAAS,SAAW,2EAEnD,IACD,MAAM,cAAc,KAAM,CAAE,GAAI,6BAA+B,0BAQvE,GAAmB,CAAC,CAAE,gBAAiB,CAC3C,KAAM,CAAE,SAAQ,UAAS,UAAU,YAEnC,MAAI,GAAgB,MAAM,cAAc,iBAAkB,MACtD,IAAS,CAAC,EAAe,MAAM,cAAc,eAAgB,MAI1D,MAAM,cAAc,EAAY,OAGnC,GAAyB,IAAM,C,OACnC,KAAM,CAAE,2BAA0B,IAAK,GAAS,YAC1C,CAAC,EAAM,IAAa,EAAyB,MAAM,KAAK,UACxD,GACJ,uBAAW,kBAAkB,WAA7B,QAAyC,yBACrC,GAAgB,EAAO,IAAI,IAAS,GAC1C,MACE,OAAM,cAAc,SAAU,CAC5B,GAAI,SAAS,gBAA4B,IAAO,QAKzC,GAAgB,GAC3B,MAAM,cAAc,oBAAqB,IAAK,sBAAuB,IAM1D,GAAS,CAAC,CACrB,aAAa,MAIb,MAAM,cAAc,OAAQ,KACxB,MAAM,cAAc,MAAO,CAAE,KAAM,IAAK,QAAS,MAAM,cAAc,YAAa,QAClF,MAAM,cAAc,MAAO,CAC3B,KAAM,0BACN,QACE,MAAM,cAAc,GAAc,KAC9B,MAAM,cAAc,GAAkB,CAAE,WAAY,OAI1D,MAAM,cAAc,MAAO,CAC3B,KAAM,wCACN,QAAS,MAAM,cAAc,GAAwB,S,gBC7DpD,KAAM,IAAgB,mBAAa,CACxC,GAAI,UACJ,KAAM,CACJ,uBAAiB,CACf,IAAK,MACL,KAAM,CACJ,aAAc,kBACd,SAAU,eAEZ,QAAS,CAAC,CAAE,eAAc,cACxB,GAAI,OAAc,CAAE,eAAc,eAEtC,uBAAiB,CACf,IAAK,yBACL,KAAM,CAAE,WAAY,iBACpB,QAAS,CAAC,CAAE,gBACV,GAAI,8BAA0B,CAAE,kBAGtC,OAAQ,CACN,aAAc,MACd,cAAe,OAEjB,eAAgB,CACd,gBAAiB,KACjB,YAAa,QAIJ,GAAmB,GAAc,QAC5C,8BAAwB,CACtB,KAAM,mBACN,UAAW,IACT,uCAAmC,KAAK,GAAK,EAAE,aACjD,WAAY,SAIH,GAAoB,GAAc,QAC7C,8BAAwB,CACtB,KAAM,oBACN,UAAW,IACT,gCAAyC,KAAK,GAAK,EAAE,mBACvD,WAAY,SAIH,GAAkB,GAAc,QAC3C,+BAAyB,CACvB,KAAM,kBACN,UAAW,CACT,KAAM,IAAM,wCAAiC,KAAK,GAAK,EAAE,eAKlD,GAAkB,GAAc,QAC3C,+BAAyB,CACvB,KAAM,kBACN,UAAW,CACT,KAAM,IACJ,gCAAuC,KAAK,GAAK,EAAE,qBAK9C,GAAuB,GAAc,QAChD,+BAAyB,CACvB,KAAM,uBACN,UAAW,CACT,KAAM,IACJ,+BAAsC,KAAK,GAAK,EAAE,oBAK7C,GAA0B,GAAc,QACnD,+BAAyB,CACvB,KAAM,0BACN,UAAW,CACT,KAAM,IACJ,+BAAyC,KAAK,GAAK,EAAE,uBAKhD,GAA6B,GAAc,QACtD,+BAAyB,CACvB,KAAM,6BACN,UAAW,CACT,KAAM,IACJ,gCAA4C,KAC1C,GAAK,EAAE,0BAMJ,GAAyB,GAAc,QAClD,+BAAyB,CACvB,KAAM,yBACN,UAAW,CACT,KAAM,IACJ,gCAAwC,KAAK,GAAK,EAAE,sBAK/C,GAAgC,GAAc,QACzD,+BAAyB,CACvB,KAAM,gCACN,UAAW,CACT,KAAM,IACJ,gCAA+C,KAC7C,GAAK,EAAE,6BAMJ,GAAmC,GAAc,QAC5D,+BAAyB,CACvB,KAAM,mCACN,UAAW,CACT,KAAM,IACJ,gCAAkD,KAChD,GAAK,EAAE,gCAMJ,GAA+B,GAAc,QACxD,+BAAyB,CACvB,KAAM,+BACN,UAAW,CACT,KAAM,IACJ,gCAA8C,KAC5C,GAAK,EAAE,4BAUJ,GAA0B,GAAc,QACnD,+BAAyB,CACvB,KAAM,0BACN,UAAW,CACT,KAAM,IACJ,gCAAyC,KAAK,GAAK,EAAE,uBAKhD,GAAsB,GAAc,QAC/C,+BAAyB,CACvB,KAAM,sBACN,UAAW,CACT,KAAM,IACJ,gCAA2C,KACzC,GAAK,EAAE,yB,2BCtKV,QAAsB,CAK3B,YAAY,EAIZ,CARC,oBACA,uBACA,mBAOC,KAAK,UAAY,EAAQ,UACzB,KAAK,aAAe,EAAQ,aAC5B,KAAK,SAAW,EAAQ,cAGpB,eAAe,C,MACnB,MACE,QAAK,UAAU,kBAAkB,yBAAjC,OACC,KAAM,MAAK,aAAa,WAAW,iBAalC,qBAAoB,EAAU,CAClC,KAAM,CAAE,OAAM,aAAW,SAAS,EAG5B,GAAa,GADD,KAAM,MAAK,oCACwB,MAAa,KAAQ,KACpE,GAAU,KAAM,MAAK,SAAS,MAAM,GAAG,MAC7C,GAAI,CAAC,GAAQ,GACX,KAAM,MAAM,oBAA2B,IAGzC,MAAO,MAAM,IAAQ,YAWjB,mBACJ,EACA,CACA,KAAM,CAAE,OAAM,aAAW,SAAS,EAG5B,GAAa,GADD,KAAM,MAAK,kCACsB,MAAa,KAAQ,KAElE,GAAU,KAAM,MAAK,SAAS,MAAM,GAAG,MAC7C,GAAI,CAAC,GAAQ,GACX,KAAM,MAAM,oBAA2B,IAGzC,MAAO,MAAM,IAAQ,QASlB,QAA6B,CAMlC,YAAY,EAKZ,CAVC,oBACA,uBACA,sBACA,mBAQC,KAAK,UAAY,EAAQ,UACzB,KAAK,aAAe,EAAQ,aAC5B,KAAK,YAAc,EAAQ,YAC3B,KAAK,SAAW,EAAQ,cAGpB,eAAe,C,MACnB,MACE,QAAK,UAAU,kBAAkB,yBAAjC,OACC,KAAM,MAAK,aAAa,WAAW,iBAIlC,gBAAgB,C,MACpB,MACE,QAAK,UAAU,kBAAkB,yBAAjC,OACA,GAAG,KAAM,MAAK,aAAa,WAAW,+BAIpC,aAAa,CACjB,MAAO,MAAK,UAAU,UAAU,yBAW5B,eAAc,EAAU,EAAM,CAClC,KAAM,CAAE,QAAM,aAAW,SAAS,EAG5B,GAAM,GADO,KAAM,MAAK,mBACD,MAAa,MAAQ,MAAQ,IAEpD,GAAU,KAAM,MAAK,SAAS,MAClC,GAAG,GAAI,SAAS,KAAO,GAAM,GAAG,mBAGlC,GAAI,IAAe,GACnB,OAAQ,GAAQ,YACT,KACH,SAAe,mBAEV,GACH,KACE,yGAEE,GAAI,OAAc,QACrB,KACH,SACE,yEACI,GAAI,OAAM,YAGhB,MAGJ,MAAO,IAAQ,YAWX,gBACJ,EACA,EAAa,IAAM,GACnB,CACA,KAAM,CAAE,QAAM,aAAW,SAAS,EAG5B,GAAM,GADM,KAAM,MAAK,uBACI,MAAa,MAAQ,KAChD,CAAE,UAAU,KAAM,MAAK,YAAY,iBAEzC,MAAO,IAAI,SAAQ,CAAC,GAAS,KAAW,CAEtC,KAAM,IAAS,GAAI,wBAAoB,GAAK,CAC1C,gBAAiB,GACjB,QAAS,GAAQ,CAAE,cAAe,UAAU,MAAY,KAG1D,GAAO,iBAAiB,MAAQ,IAAM,CAChC,GAAE,MACJ,EAAW,KAAK,MAAM,GAAE,SAI5B,GAAO,iBAAiB,SAAW,IAAM,CACvC,GAAI,IAAU,GAEV,GAAE,MACH,EAAE,YAAY,KAAK,MAAM,GAAE,OAG9B,GAAQ,GAAU,UAAY,YAGhC,GAAO,QAAW,IAAM,CAGtB,OAFA,GAAO,QAEC,GAAE,YAEH,KACH,GAAO,GAAI,OAAc,GAAE,UAC3B,eAKA,GAAO,GAAI,OAAM,GAAE,OACnB,gBAMJ,YACJ,EACA,EACA,GACA,CACA,KAAM,CAAE,QAAM,aAAW,SAAS,EAG5B,GAAa,GADD,KAAM,MAAK,8BACkB,MAAa,MAAQ,MAAQ,KAE5E,MAAO,IAAI,KACT,EACA,GAAW,SAAS,KAAO,GAAa,GAAG,OAC3C,Y,2EC9NC,KAAM,GAAsB,CAAC,CAClC,UACA,aAIG,C,UACH,KAAM,CAAE,UAAS,SAAO,YAAU,YAAY,+BACxC,CAAE,mBAAiB,wBAAwB,4BAC3C,CAAC,CAAE,IAAmB,WAEtB,GAAQ,kBAAW,WAAQ,OAAR,eAAc,QAAd,QAAuB,OAE1C,GAAiB,CACrB,2BAAwC,IACxC,0BACE,GACA,KAIJ,MAAI,IAEA,gBAAoB,eAAc,CAChC,SAAU,QACV,MAAO,2CAEL,gBAAoB,cAAa,CAAE,SAAU,OAAQ,KAAM,GAAM,cAMvE,gBAAoB,aAAW,CAC7B,MAAO,GACP,SAAU,GACV,QAAS,EACT,QAAS,GAAW,GACpB,QAAS,KAKf,EAAoB,QAAU,EAC9B,EAAoB,QAAU,G,cCtD9B,OAAsB,CACpB,mBAAoB,CAClB,MAAO,CACL,iDAAkD,QASjD,KAAM,IAAiB,IAAM,CAClC,KAAM,CAAE,iBAAkB,+BAE1B,sBAAU,IAAM,CACd,EAAc,CACZ,SAAU,GAAI,MAEf,CAAC,IAEG,MCJI,GAAsB,CAAC,CAClC,gBAAgB,MAChB,UACA,aAOE,gBAAoB,IAAqB,KACrC,gBAAoB,UAAS,KAC3B,gBAAoB,gBAAe,CAAE,MAAO,IAC1C,gBAAoB,gBAAe,KAAM,8CAI3C,gBAAoB,sBAAoB,KACtC,gBAAoB,MAAsB,KACxC,gBAAoB,MAAiB,KACnC,gBAAoB,GAAgB,MACpC,gBAAoB,kBAAgB,CAAE,cAAe,IACrD,gBAAoB,qBAAmB,MACvC,gBAAoB,mBAAiB,OAEvC,gBAAoB,MAAqB,KACvC,gBAAoB,EAAqB,CAAE,QAAS,EAAS,QAAS,S,gBC3C/E,KAAM,IAAqB,IAAM,CACtC,KAAM,CAAE,UAAS,QAAO,YAAa,wBAErC,MAAI,GAEA,MAAM,cAAc,aAAc,CAChC,SAAU,QACV,MAAO,2CAEL,MAAM,cAAc,YAAa,CAAE,SAAU,OAAQ,KAAM,EAAM,cAKrE,GAAW,CAAC,EACP,MAAM,cAAc,SAAU,MAGvC,GAAS,KAAK,CAAC,GAAG,KAAG,C,UAClB,cAAE,SAAS,QAAX,QAAoB,GAAE,SAAS,MAAM,cACpC,OAAE,SAAS,QAAX,QAAoB,GAAE,SAAS,QAI5B,MAAM,cAAc,aAAc,CAAE,SAAU,M,gBCdhD,KAAM,IAAiB,mBAAa,CACzC,GAAI,WACJ,KAAM,CACJ,uBAAiB,CACf,IAAK,KACL,KAAM,CACJ,UAAW,eACX,aAAc,kBACd,YAAa,iBACb,SAAU,eAEZ,QAAS,CAAC,CAAE,YAAW,eAAc,cAAa,eAChD,GAAI,IAAsB,CACxB,YACA,eACA,cACA,gBAGN,uBAAiB,CACf,IAAK,KACL,KAAM,CACJ,UAAW,eACX,aAAc,kBACd,SAAU,eAEZ,QAAS,CAAC,CAAE,YAAW,eAAc,cACnC,GAAI,IAAe,CACjB,YACA,eACA,gBAIR,OAAQ,CACN,KAAM,MACN,QAAS,MACT,cAAe,SAIN,GAAe,GAAe,QACzC,8BAAwB,CACtB,KAAM,eACN,UAAW,IAAM,wCAAmB,KAAK,GAAK,EAAE,QAChD,WAAY,SAIH,GAAwB,GAAe,QAClD,8BAAwB,CACtB,KAAM,wBACN,UAAW,IAAM,wCAAmB,KAAK,GAAK,EAAE,oBAChD,WAAY,SAKH,GAAe,GAAe,QACzC,+BAAyB,CACvB,KAAM,eACN,UAAW,CACT,KAAM,IACJ,wCAAyC,KAAK,GAAK,EAAE,kBAMhD,GAAY,GAAe,QACtC,+BAAyB,CACvB,KAAM,YACN,UAAW,CACT,KAAM,IAAM,wCAAsC,KAAK,GAAK,EAAE,eAMvD,GAAqB,GAAe,QAC/C,8BAAwB,CACtB,KAAM,qBACN,UAAW,IACT,wCAA+C,KAC7C,GAAK,EAAE,oBAEX,WAAY,SAIH,GAAoB,GAAe,QAC9C,8BAAwB,CACtB,KAAM,oBACN,UAAW,IACT,wCAA8C,KAC5C,GAAK,EAAE,mBAEX,WAAY,SAIH,GAAqB,GAAe,QAC/C,8BAAwB,CACtB,KAAM,qBACN,UAAW,IACT,wCAA2C,KAAK,GAAK,EAAE,cACzD,WAAY,S,wCC9FhB,QAA6B,CAK3B,YAAY,CACV,YACA,eACA,gBAKF,CAZC,oBACA,uBACA,sBAWC,KAAK,UAAY,EACjB,KAAK,aAAe,EACpB,KAAK,YAAc,QAGf,eAAe,C,MACnB,MACE,QAAK,UAAU,kBAAkB,yBAAjC,OACC,KAAM,MAAK,aAAa,WAAW,iBAIlC,gBAAgB,C,MACpB,MACE,QAAK,UAAU,kBAAkB,yBAAjC,OACA,GAAG,KAAM,MAAK,aAAa,WAAW,+BAIpC,aAAa,CACjB,MAAO,MAAK,UAAU,UAAU,yBAG5B,eAAc,EAAW,EAAM,CAGnC,KAAM,IAAM,GAFM,KAAM,MAAK,kBAED,IAEtB,GAAU,KAAM,OACpB,GAAG,GAAI,SAAS,KAAO,GAAM,GAAG,mBAGlC,GAAI,GAAQ,SAAW,IACrB,KAAM,IAAI,OAAM,kBAGlB,MAAO,IAAQ,YAGX,gBAAe,EAAG,CAGtB,MAAO,cAIH,YACJ,EACA,EACA,GACA,CACA,KAAM,IAAY,KAAM,MAAK,eAC7B,MAAO,IAAI,KAAI,EAAY,GAAG,MAAa,MAAQ,YAIvD,QAAsB,CAKpB,YAAY,CACV,YACA,eACA,gBAKF,CAZC,oBACA,uBACA,sBAWC,KAAK,UAAY,EACjB,KAAK,aAAe,EACpB,KAAK,YAAc,QAGf,eAAe,C,MACnB,MACE,QAAK,UAAU,kBAAkB,yBAAjC,OACC,KAAM,MAAK,aAAa,WAAW,iBAIlC,mBAAkB,EAAW,CACjC,MAAO,CACL,WAAY,wBACZ,KAAM,YACN,SAAU,CACR,KAAM,SAER,KAAM,CACJ,MAAO,OACP,UAAW,sBAKX,qBAAoB,EAAW,CACnC,MAAO,CACL,UAAW,2BACX,iBAAkB,KAKjB,KAAM,IAAO,CAClB,uBAAiB,CACf,IAAK,KACL,KAAM,CACJ,UAAW,eACX,aAAc,kBACd,YAAa,kBAEf,QAAS,CAAC,CAAE,YAAW,eAAc,iBACnC,GAAI,IAAsB,CACxB,YACA,eACA,kBAGN,uBAAiB,CACf,IAAK,KACL,KAAM,CACJ,UAAW,eACX,aAAc,kBACd,YAAa,kBAEf,QAAS,CAAC,CAAE,YAAW,eAAc,iBACnC,GAAI,IAAe,CACjB,YACA,eACA,kBAGN,uBAAiB,CACf,IAAK,MACL,KAAM,CAAE,UAAW,gBACnB,QAAS,CAAC,CAAE,eAAgB,iBAA8B,M,4BCjL9D,KAAM,IAAY,SAAW,CAC3B,IAAK,CACH,MAAO,OACP,OAAQ,IAEV,KAAM,CACJ,KAAM,aAoBV,OAjBiB,IAAM,CACrB,KAAM,GAAU,KAEhB,MACE,iBAAoB,MAAO,CACzB,UAAW,EAAQ,IACnB,MAAO,6BACP,QAAS,sBAEP,gBAAoB,OAAQ,CAC5B,UAAW,EAAQ,KACnB,EAAG,45YCpBX,KAAM,IAAY,SAAW,CAC3B,IAAK,CACH,MAAO,OACP,OAAQ,IAEV,KAAM,CACJ,KAAM,aAqBV,OAjBiB,IAAM,CACrB,KAAM,GAAU,KAEhB,MACE,iBAAoB,MAAO,CACzB,UAAW,EAAQ,IACnB,MAAO,6BACP,QAAS,oBAEP,gBAAoB,OAAQ,CAC5B,UAAW,EAAQ,KACnB,EAAG,mvFCTX,KAAM,IAAuB,SAAW,CACtC,KAAM,CACJ,MAAO,kCACP,OAAQ,EAAI,2BACZ,QAAS,OACT,SAAU,aACV,WAAY,SACZ,aAAc,KAEhB,KAAM,CACJ,MAAO,kCACP,WAAY,MAIV,GAAc,IAAM,CACxB,KAAM,GAAU,KACV,CAAE,UAAW,iBAAW,kBAE9B,MACE,iBAAoB,MAAO,CAAE,UAAW,EAAQ,MAC5C,gBAAoB,KAAM,CAC1B,UAAW,KACX,GAAI,iCACJ,UAAW,OACX,UAAW,EAAQ,MAEjB,EAAS,gBAAoB,GAAU,MAAS,gBAAoB,GAAU,SAM3E,GAAO,CAAC,CAAE,cACrB,gBAAoB,cAAa,KAC7B,gBAAoB,UAAS,KAC3B,gBAAoB,GAAa,MACjC,gBAAoB,iBAAgB,MAEpC,gBAAoB,cAAa,CACjC,KAAM,KACN,GAAI,gCACJ,KAAM,kBAIR,GCnDA,GAAsB,IAAM,CAChC,KAAM,GAAmB,CACvB,UAAW,2BACX,iBAAkB,IAGpB,MACE,iBAAoB,MAAc,KAC9B,CAAC,CAAE,YAAW,aACd,gBAAoB,WAAgB,KAChC,gBAAoB,MAAoB,CACxC,iBAAkB,EAClB,UAAW,IAEX,gBAAoB,UAAS,CAAE,cAAe,oBAC5C,gBAAoB,MAAQ,CAC5B,QAAS,EACT,UAAW,EACX,WAAY,SASb,GAAe,gBAAoB,GAAqB,MCnC/D,GAAoB,CACxB,QAAS,CACP,QAAS,yBAEX,SAAU,CACR,QAAS,WACT,WAAY,8BAIV,GAAqB,CACzB,QAAS,CACP,QAAS,yBAEX,SAAU,CACR,QAAS,WACT,WAAY,8BAIhB,mBAAmC,CACjC,KAAM,GAAM,KAAM,OAAM,YACxB,MAAK,GAAI,GAIF,MADY,GAAI,QACX,SAAW,sBAHd,GAMJ,mBAA8B,CACnC,KAAM,GAAiB,KAAM,4BACvB,EAAe,KAAM,MAE3B,MAAO,CACL,GAAG,EACH,CACE,QAAS,WACT,KAAM,EAAe,GAAoB,KCtB/C,KAAM,IAAM,EAAU,CACpB,KAAI,GACJ,aAAY,GACZ,QAAS,OAAO,OAAO,KAGnB,GAAc,GAAI,cAClB,GAAY,GAAI,YAEhB,GACJ,gBAAoB,aAAY,KAC5B,gBAAoB,KAAU,CAAE,IAAK,IAAK,GAAI,mCAE9C,gBAAoB,KAAO,CAC3B,KAAM,kCACN,QAAS,gBAAoB,GAAmB,QAEhD,gBAAoB,KAAO,CAAE,KAAM,QAAS,QAAS,gBAAoB,GAAmB,OAC1F,gBAAoB,GAAqB,OAE3C,gBAAoB,KAAO,CAC3B,KAAM,iCACN,QAAS,gBAAoB,GAAoB,OAE/C,KAaR,OARY,IACV,gBAAoB,GAAa,KAC7B,gBAAoB,GAAW,KAC7B,gBAAoB,GAAM,KAAM,MC5CxC,SAAgB,gBAAoB,GAAK,MAAQ,SAAS,eAAe,U,4ICJzE,YAA2B,CACzB,MAAI,OAAO,SAAW,aAAe,OAAO,OAAS,KAC5C,OAEL,MAAO,OAAS,aAAe,KAAK,OAAS,KACxC,KAGF,SAAS,iBAGlB,KAAM,GAAe,IAEf,EAAW,GAAO,gBAAgB,MAOjC,WACL,EACA,EACA,CACA,KAAM,GAAM,EAAQ,GAEpB,GAAI,GAAQ,EAAa,GACzB,MAAI,IAIJ,GAAQ,IACR,EAAa,GAAO,EACb,G,cCZF,WAEN,EAAK,CACJ,MAAO,GAA2B,EAAK,IACrC,oBAAc,SAwBX,WAEN,EAAK,CACJ,MAAO,iBAAW,EAAuB,IAyBpC,WAA0C,EAAK,CACpD,MAAO,CACL,IAAI,EAAU,CACX,WAAa,gBAAgB,OAAW,cACvC,wBAAwB,KAG5B,OAAQ,CACN,MAAQ,YAAa,gBAAgB,SCpEpC,WAEN,EAAU,CACT,cAAO,OAAO,GACP,CACL,UAAU,EAAS,CACjB,MAAO,GAAS,O,u1DCrBf,KAAM,GAAgB,mBAAa,CACxC,GAAI,2B,8CCSC,iBAA8C,CACnD,cAGA,C,OACA,KAAM,GAAS,EAAW,UAAU,YAC9B,EAAS,EAAW,UAAU,mBAE9B,EAAqB,EAAO,IAAI,mBAEtC,GAAI,CAAC,cAAQ,GAEX,OAEF,KAAM,IAAiB,GAAI,KAAI,MAAO,IAAI,gBAAX,QAA4B,IAE3D,EACG,OAAO,YAEP,IAAI,IAAO,GAAI,MAAM,MAErB,OAAO,IAAS,GAAM,SAAW,GAAK,GAAM,KAAO,UAEnD,IAAI,CAAC,CAAC,GAAG,GAAM,GAAW,MACzB,SAAmB,CAAE,QAAM,aAAW,WAEvC,QAAQ,IAAK,GAAe,IAAI,KAEnC,KAAM,GAAO,IAAI,aAAc,MAAM,KAAK,KAE1C,KAAM,GAAO,OAAO,mBChCf,OAAiC,CAItC,YAAY,EAAM,CAHhB,wBACD,0BAyCC,qBAAc,GAAI,MAIlB,oBAAa,GAAI,MAAe,GAEhC,GAAW,KAAK,KAAK,iBAErB,KAAK,YAAY,IAAI,GACd,IAAM,CACX,KAAK,YAAY,OAAO,O,MA/C1B,EAA+B,GAAM,OAErC,KAAK,cAAgB,EAAK,WAAW,UAAU,mBAE/C,KAAK,gBAAkB,GAAI,KACzB,QAAK,cAAc,IAAI,gBAAvB,OAAwC,IAG1C,KAAK,cAAc,SAAS,cAAc,UAAU,CAClD,KAAM,GAAQ,C,OACZ,KAAK,gBAAkB,GAAI,KAAI,MAAK,WAAL,QAAiB,IAChD,KAAK,wBAKL,eAAc,EAAW,CACzB,KAAK,gBAAgB,IAAI,GAC3B,KAAK,gBAAgB,OAAO,GAE5B,KAAK,gBAAgB,IAAI,GAG3B,KAAM,MAAK,cAAc,IACvB,aACA,MAAM,KAAK,KAAK,kBAIpB,iBAAkB,CAChB,MAAO,MAAK,WAGd,UAAU,EAAW,CACnB,MAAO,MAAK,gBAAgB,IAAI,GAiBjC,eAAgB,CACf,SAAW,KAAgB,MAAK,YAC9B,EAAa,KAAK,KAAK,kBC9DtB,KAAM,GAAwB,mBAAa,CAChD,GAAI,mC,+CCMC,KAAM,GAPY,qBAAe,CACtC,GAAI,YAiBO,EAAiB,SAC5B,2BACA,IACE,qBAAe,CACb,GAAI,iBACJ,OAAQ,CAAC,YAAa,OAAQ,WAOvB,EAAc,KAIpB,WAA2B,EAAQ,C,QACxC,MAAO,CACL,KAAM,EAAO,KAAK,kBAAkB,SACpC,UACE,QAAO,SAAS,YAAhB,cAA2B,kBAAkB,WAA7C,OACA,yBACF,KAAM,EAAO,SAAS,MC3CnB,KAAM,GAAwB,IAAM,CACzC,KAAM,CAAE,OAAM,YAAW,QAAS,wBAAkB,GACpD,MAAO,CAAE,OAAM,YAAW,SCsBf,EACX,oBAAc,CACZ,OAAQ,OACR,QAAS,GACT,MAAO,OACP,QAAS,IAAM,KAGb,GAAoB,EAAc,SAKlC,GACJ,SAAuB,kBAoBZ,GAAsB,CAAC,CAClC,WACA,SACA,UACA,QACA,cACI,CACJ,KAAM,IAAQ,CAAE,SAAQ,UAAS,QAAO,YAGxC,MACE,iBAAoB,GAAmB,CAAE,MAAO,IAC5C,gBAAoB,GAAiB,SAAU,CAAE,MAAO,SAAwB,CAAE,EAAG,MACnF,KAqBG,GAAiB,CAAC,CAAE,SAAQ,cACvC,MAAM,cAAc,GAAqB,CACvC,OAAQ,EACR,QAAS,CAAC,QAAQ,GAClB,MAAO,OACP,QAAS,OACT,SAAU,IAKR,GAAwB,CAAC,CAC7B,QACA,cAKO,gBAAoB,GAAqB,IAAK,EAAO,SAAU,IAExE,EAAc,SAAW,GAElB,KAAM,IAAmB,IAAM,CACpC,KAAM,CAAE,OAAM,YAAW,QAAS,IAC5B,EAAW,WACX,GAAW,aAAO,eAClB,GAAa,aAAO,GAEpB,CACJ,MAAO,GACP,SACA,WACA,MAAO,IACL,QACF,IAAM,GAAW,gBAAgB,CAAE,OAAM,YAAW,SACpD,CAAC,GAAY,EAAM,EAAW,IAGhC,sBAAU,IAAM,CACT,GACH,IAAS,KAAK,GAAI,OAAM,sBACxB,EAAS,OAEV,CAAC,GAAU,EAAU,GAAO,GAAS,GAAQ,IAEzC,CAAE,UAAQ,WAAS,SAAO,aAQ5B,aAAqB,CAC1B,KAAM,GACJ,SAAoB,kBAEtB,GAAI,CAAC,EAIH,MAAO,CACL,OAAQ,OACR,QAAS,GACT,MAAO,OACP,QAAS,IAAM,IAInB,KAAM,GAAQ,EAAgB,UAAU,GACxC,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,kCAGlB,KAAM,CAAE,SAAQ,UAAS,SAAO,YAAY,EAC5C,MAAO,CAAE,OAAQ,EAAS,UAAS,SAAO,Y,+DCzKrC,YACL,EACA,CACA,MAAO,GAAQ,OAAO,CAAC,EAAgB,IAC9B,KACF,KACC,EAAO,kBAAoB,EAAO,oBAAsB,KAE7D,IAGE,YACL,EACA,CACA,MAAQ,IACN,EAAQ,MACN,GAAU,CAAC,EAAO,cAAgB,EAAO,aAAa,ICbrD,YAAkC,EAAQ,C,MAC/C,MAAO,KAAO,SAAS,cAAhB,cAA8B,MAGhC,YAAkC,EAAQ,C,MAC/C,MAAO,KAAO,SAAS,cAAhB,cAA8B,MCNhC,YACL,EACA,EACA,EACA,C,UACA,GAAI,GACF,0BAAQ,YAAR,eACI,OAAO,IAAK,GAAE,OAAS,KAD3B,eAEI,IAAI,IAAK,GAAE,UAAW,GAE5B,MAAI,kBAAQ,OACV,GAAc,iBAAa,OACzB,IACE,GAAE,KAAK,kBAAkB,WACzB,EAAO,KAAK,kBAAkB,WAI7B,ECXF,YACL,EACA,EACA,C,MACA,KAAM,GACJ,KAAO,SAAS,cAAhB,cAA8B,MAEhC,GAAI,EAAC,EAIL,GAAI,CACF,KAAM,IAAoB,SAAuB,GAC3C,GAAc,EAAmB,MAAM,GAAkB,QAC/D,MAAO,CACL,kBAAmB,GAAkB,OACrC,gBAAiB,mBAAa,WAEhC,CACA,QCnBG,YAAmB,EAAO,EAAO,CACtC,KAAM,GAAiB,GAAI,KACzB,CACE,GAAG,GAAmB,EAAO,KAAoB,CAAE,KAAM,UACzD,GAAI,EAAQ,CAAC,SAAc,IAAU,IACrC,IAAI,OAGF,EAAS,GAAmB,EAAO,MAAmB,IAC1D,MAGF,SAAW,MAAa,GACtB,GAAI,EAAe,IAAI,IACrB,MAAO,GAIX,MAAO,GC+CF,KAAM,IAAoB,oBAEhC,QAQY,GAAqB,CAAC,CACjC,cACI,CACJ,KAAM,GAAY,iBACZ,EAAa,aAAO,GACpB,CAAC,EAAkB,IAAuB,eAC9C,IAOI,GAAW,WACX,GAAkB,cACtB,IAAG,C,OACA,qBAAS,GAAS,OAAQ,CACzB,kBAAmB,KAClB,UAFF,QAEa,IAChB,CAAC,KAGG,CAAC,GAAa,IAAkB,eACpC,IACS,EACL,eAAgB,GAChB,SAAU,GACV,gBAAiB,MAQjB,CAAC,CAAE,WAAS,UAAS,IAAW,eACpC,SAAY,C,OACV,KAAM,IAAY,cAAQ,OAAO,OAAO,IAClC,GAAe,GAAoB,IACnC,GAAgB,GAAqB,IACrC,GAAwB,GAC5B,cAAQ,OAAO,OAAO,GAAY,kBAG9B,GAAc,OAAO,KAAK,GAAkB,OAChD,CAAC,GAAQ,KAAQ,CACf,KAAM,IACJ,EAAiB,IACnB,MAAI,oBAAQ,eACV,IAAO,IAAO,GAAO,gBAEhB,IAET,IAMF,GAAK,cAAQ,GAAuB,IAYlC,GAAe,CACb,eAAgB,EAChB,gBAAiB,GAAY,gBAC7B,SAAU,GAAY,gBAAgB,OAAO,UAfG,CAGlD,KAAM,IAAW,KAAM,GAAW,YAAY,CAC5C,OAAQ,KAEV,GAAe,CACb,eAAgB,EAChB,gBAAiB,GAAS,MAC1B,SAAU,GAAS,MAAM,OAAO,MAUpC,GAAI,IAAa,CACf,KAAM,IAAY,WAAS,GAAS,OAAQ,CAC1C,kBAAmB,KAEf,GAAY,eAChB,IAAK,GAAW,QAAS,IACzB,CAAE,eAAgB,KAEd,GAAS,GAAG,OAAO,SAAS,WAAW,KAM7C,WAAO,UAAP,SAAgB,aAAa,KAAM,SAAS,MAAO,MAGvD,CAAC,EAAY,GAAiB,EAAkB,IAChD,CAAE,QAAS,KAKb,SAAY,GAAS,GAAI,CAAC,IAE1B,KAAM,IAAgB,kBAElB,IAGG,CACH,GAAoB,IAAe,CACjC,KAAM,IACJ,MAAO,KAAW,WAAa,GAAO,IAAe,GACvD,MAAO,IAAK,MAAgB,OAGhC,IAGI,GAAQ,cACZ,IAAO,EACL,QAAS,GAAY,eACrB,SAAU,GAAY,SACtB,gBAAiB,GAAY,gBAC7B,iBACA,mBACA,WACA,WAEF,CAAC,GAAa,GAAe,GAAiB,GAAS,KAGzD,MACE,iBAAoB,GAAkB,SAAU,CAAE,MAAO,IACrD,IAKD,aAEJ,CACD,KAAM,GAAU,iBAAW,IAC3B,GAAI,CAAC,EACH,KAAM,IAAI,OACR,gEAEJ,MAAO,G,uCClOF,YACL,EACA,EACA,CACA,KAAM,GAAc,iBAAM,YAC1B,GAAI,GACA,GACA,GAEJ,MAAI,YAAc,GAChB,GAAO,EAAU,KACjB,GAAY,EAAU,SAAS,UAC/B,GAAO,EAAU,SAAS,MAE1B,GAAO,EAAU,KACjB,GAAY,EAAU,UACtB,GAAO,EAAU,MAGf,KAAc,MAChB,IAAY,QAGd,EAAO,EAAK,kBAAkB,SAEvB,GAAG,SAAmB,CAC3B,KACE,GAAe,EAAY,kBAAkB,WAAa,EACtD,OACA,EACN,QACA,iB,2BCTG,KAAM,IAAgB,iBAC3B,CAAC,EAAO,IAAQ,C,OACd,KAAM,CAAE,YAAW,cAAa,SAAO,eAAa,IAAc,EAC5D,GAAc,kBAAY,GAEhC,GAAI,IACA,GACA,GAEA,YAAc,GAChB,IAAO,EAAU,KACjB,GAAY,EAAU,SAAS,UAC/B,GAAO,EAAU,SAAS,MAE1B,IAAO,EAAU,KACjB,GAAY,EAAU,UACtB,GAAO,EAAU,MAGnB,GAAO,GAAK,kBAAkB,SAE9B,KAAM,IAAc,CAClB,QACA,UACE,uBAAW,kBAAkB,WAA7B,QAAyC,KAC3C,SAEI,GAA0B,GAAqB,EAAW,CAC9D,gBAGI,GACJ,gBAAoB,QAAM,IAAK,GAAW,IAAK,EAAK,GAAI,GAAY,KAChE,GACA,CAAC,IAAa,aAAS,KAI7B,MAAO,IACL,gBAAoB,MAAS,CAAE,MAAO,IAA2B,IAEjE,KClDO,GAAiB,CAAC,CAC7B,aACA,iBACG,KAEH,gBAAoB,WAAgB,KAChC,EAAW,IAAI,CAAC,EAAG,KACnB,gBAAoB,WAAgB,CAAE,IAAK,IACvC,GAAI,GAAK,KACT,gBAAoB,GAAe,IAAK,EAAW,UAAW,EAAG,YAAa,OCxBjF,OAAwB,CAC7B,YAAa,EAAO,CAAE,KAAK,MAAQ,EAEnC,mBAAoB,CAClB,MAAO,CAAE,KAAM,KAAK,OAGtB,cAAe,CACb,MAAO,MAAK,OAIT,OAAwB,CAC7B,YAAa,EAAO,CAAE,KAAK,MAAQ,EAGnC,UAAW,CACT,MAAO,OAAM,QAAQ,KAAK,OAAS,KAAK,MAAQ,CAAC,KAAK,OAGxD,mBAAoB,CAClB,MAAO,CAAE,YAAa,KAAK,YAG7B,cAAe,CACb,MAAO,MAAK,YAIT,OAAuB,CAC5B,YAAa,EAAQ,CAAE,KAAK,OAAS,EAErC,aAAa,EAAQ,CACnB,MAAO,MAAK,OAAO,MAAM,GAAE,C,MAAI,YAAO,SAAS,OAAhB,OAAwB,IAAI,SAAS,KAGtE,cAAe,CACb,MAAO,MAAK,QAIT,OAAwB,CAC7B,YAAa,EAAO,CAAE,KAAK,MAAQ,EAEnC,aAAa,EAAQ,C,MACnB,KAAM,GAAiB,KAAK,MAAM,kBAAkB,SAEpD,MACE,GAAO,SAAS,KACb,kBAAkB,SAClB,SAAS,IACZ,GAAG,EAAO,SAAS,QAChB,kBAAkB,SAClB,SAAS,IACZ,MAAO,SAAS,OAAhB,cACI,KAAK,IACN,kBAAkB,SAClB,QAAQ,MAAoB,IAK9B,OAAyB,CAC9B,YAAa,EAAQ,CAAE,KAAK,OAAS,EAErC,aAAa,EAAQ,CACnB,MAAO,MAAK,OAAO,KAAK,GACtB,GAAmB,EAAQ,MAAmB,KAC5C,GAAK,GAAqB,EAAG,CAAE,YAAa,YAAe,IAKjE,cAAe,CACb,MAAO,MAAK,QAIT,QAA6B,CAClC,YAAa,EAAQ,CAAE,KAAK,OAAS,EAErC,aAAa,EAAQ,CACnB,MAAO,MAAK,OAAO,KAAK,GAAE,C,MAAG,YAAO,OAAP,cAAa,aAAc,IAG1D,cAAe,CACb,MAAO,MAAK,QAIT,QAAsB,CAC3B,YACG,EACA,EACA,EACD,CAAE,KAAK,MAAQ,EAAM,KAAK,cAAgB,EAAc,KAAK,gBAAkB,EAEjF,aAAa,EAAQ,CACnB,OAAQ,KAAK,WACN,QACH,MAAO,MAAK,cAAc,OACvB,UACH,MAAO,MAAK,gBAAgB,WAE5B,MAAO,IAIb,cAAe,CACb,MAAO,MAAK,OC9FT,aAA+B,C,OACpC,KAAM,GAAa,aAAO,GACpB,CACJ,QAAS,CAAE,KAAM,EAAY,KAAM,GACnC,kBACA,kBACE,KAEE,GAAkB,cACtB,IAAM,CAAC,EAAgB,MAAM,OAAO,OAAO,SAC3C,CAAC,IAGG,CAAC,GAAe,IAAoB,eACxC,GAAgB,OAAS,GAAkB,qBAAY,aAAZ,QAA0B,IAKvE,gBAAU,IAAM,CACV,GAAgB,QAClB,GAAiB,KAElB,CAAC,KAEJ,KAAM,CAAC,GAAgB,IAAqB,eAAS,IAC/C,GAAO,cAAQ,IAAM,iBAAY,MAAO,CAAC,IAIzC,CACJ,SACA,WACA,MAAO,IACL,eAAS,SACP,GACY,KAAM,GACjB,YAAY,CACX,OAAQ,CAAE,SACV,OAAQ,CAAC,eAEV,KAAK,IAAY,GAAS,OAGxB,GACN,CAAC,GAAM,IAEJ,GAAc,aAAO,IAC3B,sBAAU,IAAM,CACd,KAAM,IAAc,GAAY,QAYhC,GAXA,GAAY,QAAU,GAKlB,IAAW,CAAC,IAAQ,KAAgB,IAMpC,CAAC,GAAU,OAGf,KAAM,IAAc,GAAS,OAAO,CAAC,GAAK,KAAW,C,OACnD,GAAI,MAAO,QAAO,OAAP,eAAa,OAAS,SAAU,MAAO,IAElD,KAAM,IAAa,GAAO,KAAK,KAAK,kBAAkB,SACtD,MAAK,IAAI,KACP,IAAI,IAAc,GAEpB,GAAI,KAAe,EACZ,IACN,IAEG,GAAW,OAAO,QAAQ,IAC7B,KAAK,CAAC,CAAC,CAAE,IAAS,CAAC,CAAE,MAAY,GAAS,IAC1C,IAAI,CAAC,CAAC,MAAU,IACnB,GAAkB,IAGlB,KAAM,IAAkB,GAAc,OAAO,IAC3C,GAAS,SAAS,KAEf,KAAQ,GAAe,KAC1B,GAAiB,KAElB,CAAC,GAAS,GAAM,GAAe,GAAkB,KAEpD,gBAAU,IAAM,CACd,GAAc,CACZ,KAAM,GAAc,OAChB,GAAI,GAAiB,IACrB,UAEL,CAAC,GAAe,KAEZ,CACL,WACA,SACA,kBACA,iBACA,qBCrHG,aAA0B,CAC/B,KAAM,GAAa,aAAO,GAEpB,CACJ,QACA,UACA,MAAO,GACL,eAAS,SAAY,CACvB,KAAM,IAAW,KAAM,GACpB,YAAY,CAAE,OAAQ,CAAC,UACvB,KAAK,IAAY,GAAS,OAE7B,MAAO,CAAC,GAAG,GAAI,KAAI,GAAS,IAAI,IAAK,GAAE,QAAQ,SAEjD,MAAO,CAAE,QAAO,UAAS,SCPpB,aAAsB,CAC3B,KAAM,GAAa,aAAO,GACpB,EAAc,aAAO,kBAE3B,MAAO,eAAS,SAAY,CAC1B,KAAM,GAAW,KAAM,GAAY,uBACnC,MAAO,GAAW,gBAChB,SAAe,EAAS,cAAe,CACrC,YAAa,OACb,iBAAkB,SAGrB,CAAC,EAAY,ICnBlB,KAAM,IAAa,GAEZ,YACL,EACA,CAAE,OAAM,QAKT,CACC,KAAM,GAAa,aAAO,GACpB,CACJ,WACA,MAAO,GACP,UACE,eAAS,SAAY,CACvB,KAAM,IACJ,EAAO,WACP,EAAO,UAAU,OACf,IACG,EAAC,GACA,GAAE,KAAK,kBAAkB,WACvB,EAAK,kBAAkB,WAC1B,EAAC,GACA,GAAE,OAAO,KAAK,kBAAkB,WAC9B,EAAK,kBAAkB,WAGjC,GAAI,CAAC,GACH,MAAO,GAQT,KAAM,IAA8B,OAAO,OACzC,cAAQ,GAAW,CAAC,CAAE,aACb,GAAG,GAAO,QAAQ,GAAO,YAAY,kBAAkB,WAK5D,GAIP,GACC,SAAW,MAAM,IACf,GAAmC,KAAK,CAEtC,KAAM,GAAG,GAAG,OAAO,KACnB,UAAW,GAAG,GAAG,OAAO,UACxB,YAAa,YACX,GAAG,IAAI,IAAK,GAAE,OAAO,MACrB,MAmBN,MAAO,MAde,SAAQ,IAC5B,GAAmC,QAAQ,IAClC,GAAG,YAAY,IAAI,IACjB,EAAW,YAAY,CAC5B,OAAQ,CACN,KAAM,GAAG,KACT,qBAAsB,GAAG,UACzB,gBAAiB,UAOZ,QAAQ,IAAK,GAAE,QAC7B,CAAC,EAAQ,IAEZ,MAAO,CACL,YACA,WACA,U,gBC5EJ,YAAsB,EAAa,CACjC,MAAO,OAAO,IAAgB,SAC1B,EACA,SAAmB,GAGlB,aAIN,CACC,KAAM,GAAqB,aAAO,GAE5B,EAAkB,SACtB,EAAmB,kBACnB,GAAI,MAGA,EAAkB,kBACrB,IACC,EAAgB,IAAI,GAAa,KACnC,CAAC,IAGG,EAAsB,kBACzB,IACC,EAAmB,cAAc,GAAa,KAAc,OAC9D,CAAC,IAGH,MAAO,CACL,kBACA,sBACA,mBClCJ,YAAsB,EAAa,CACjC,MAAO,OAAO,IAAgB,SAC1B,EACA,SAAmB,GAGlB,YAA0B,EAGhC,CACC,KAAM,GAAqB,aAAO,GAE5B,CAAC,EAAiB,GAAsB,eAAS,IAEvD,sBAAU,IAAM,CACd,KAAM,IAAe,EAAmB,kBAAkB,UAAU,CAClE,KAAK,GAAiB,CACpB,EAAmB,GAAgB,IAAI,GAAa,QAIxD,MAAO,IAAM,CACX,GAAa,gBAEd,CAAC,EAAa,IAOV,CACL,oBAN0B,kBAC1B,IAAM,EAAmB,cAAc,GAAa,IAAc,OAClE,CAAC,EAAa,IAKd,mBCZG,kBACL,EACA,CAEA,MAAO,MADgB,GAAY,wBACnB,oBAcX,kBACL,EACA,EACA,CACA,KAAM,GAAS,GAAI,OAEb,EAAiB,EAAkB,KAAK,IAAO,GAAI,WAAW,UACpE,GAAI,EAAgB,CAClB,KAAM,IAAS,KAAM,GAAW,gBAC9B,SAAe,IAEjB,GAAI,GAAQ,CACV,KAAM,IAAW,GAAmB,GAAQ,KAAoB,CAC9D,KAAM,UAER,SAAW,MAAS,IAClB,EAAO,KAAK,SAAmB,MAKrC,MAAO,GAaF,aAGN,CACC,KAAM,GAAc,aAAO,kBACrB,EAAa,aAAO,GAGpB,CAAE,UAAS,MAAO,GAAS,eAAS,SAAY,CACpD,KAAM,CAAE,wBAAwB,KAAM,GAAY,uBAC5C,GAAc,KAAM,IACxB,EACA,IAEF,MAAO,IAAI,KAAI,CAAC,GAAG,GAAqB,GAAG,MAC1C,IAEG,GAAgB,cAAQ,IAAM,CAClC,KAAM,IAAc,GAAI,KAAI,UAAQ,IACpC,MAAQ,KAAW,CACjB,KAAM,IACJ,aAAc,IACV,GAAmB,GAAQ,MAC3B,CAAC,KACL,IAAI,MACN,SAAW,MAAO,IAChB,GAAI,GAAY,IAAI,IAClB,MAAO,GAGX,MAAO,KAER,CAAC,IAEJ,MAAO,cAAQ,IAAO,EAAE,UAAS,mBAAkB,CAAC,EAAS,KChGxD,YAA0B,EAGhC,CACC,KAAM,GAAc,OAAO,gBACrB,EAAa,OAAO,eAEpB,CAAE,UAAS,MAAO,IAAS,SAAS,SAAY,CACpD,KAAM,IAAe,KAAM,uBAAsB,GAC3C,GAAc,KAAM,sBAAqB,EAAY,IAiB3D,MAhBiB,MAAM,GAAW,YAChC,EACI,CACE,OAAQ,CACN,KAAM,GACL,aAAa,qBACZ,CAAC,GAAG,GAAc,GAAG,MAG3B,CACE,OAAQ,EACL,aAAa,qBACZ,CAAC,GAAG,GAAc,GAAG,QAKhC,IAEG,GAAgB,QAAQ,IACrB,GACN,CAAC,KAEJ,MAAO,SAAQ,IAAO,EAAE,UAAS,mBAAkB,CAAC,EAAS,K,gBCrCxD,WAA6B,EAInC,CACC,KAAM,CAAE,SAAQ,QAAS,EAAe,MAAO,GAAgB,KACzD,CACJ,WACA,QAAS,GACT,MAAO,IACL,UACF,EACA,EAAS,SAAmB,GAAU,QAGxC,MAAI,IAAiB,GACZ,CAAE,QAAS,GAAM,QAAS,IAE/B,EACK,CAAE,QAAS,GAAO,QAAS,GAAO,MAAO,GAE3C,CAAE,QAAS,GAAO,WAAS,MAAO,ICrBpC,KAAM,GAAoB,GAAU,C,OACzC,KAAM,CAAE,gBAAe,UAAW,EAE5B,CAAE,gBAAe,oBAAoB,wBACrC,CAAC,IAAgB,SACrB,KAAC,GAAgB,MAAM,OAAO,KAA9B,QAAoC,GAStC,MANA,WAAU,IAAM,CACd,EAAc,CACZ,KAAM,GAAe,GAAI,kBAAiB,IAAgB,UAE3D,CAAC,GAAc,IAEd,EAAe,KAKZ,MAAM,cAAc,MAAO,CAAE,SAAU,WAAa,kC,yHCf7D,KAAM,GAAY,QAChB,CACE,MAAO,IAET,CACE,KAAM,sCAIJ,EAAO,gBAAoB,KAA0B,CAAE,SAAU,UACjE,GAAc,gBAAoB,KAAc,CAAE,SAAU,UAGrD,GAAwB,IAAM,C,UACzC,KAAM,GAAU,IACV,CAAE,gBAAe,kBAAiB,UAAS,oBAC/C,KAEI,GAAuB,cAC3B,IAAM,CAAC,GAAgB,YAAY,OAAO,OAAO,SACjD,CAAC,KAGG,CAAC,GAAoB,IAAyB,eAClD,GAAqB,OACjB,GACA,UAAQ,aAAR,eAAoB,SAApB,QAA8B,IAKpC,gBAAU,IAAM,CACV,GAAqB,QACvB,GAAsB,KAEvB,CAAC,KAEJ,gBAAU,IAAM,CACd,EAAc,CACZ,WAAY,GAAmB,OAC3B,GAAI,IAAsB,IAC1B,UAEL,CAAC,GAAoB,IAExB,KAAM,IAAsB,cAC1B,IACE,CACE,GAAG,GAAI,KACL,EACG,IAAK,IAAG,C,OAAG,aAAE,OAAF,eAAQ,YACnB,OAAO,WAEZ,OACJ,CAAC,IAGH,MAAK,IAAoB,OAGvB,gBAAoB,IAAK,CAAE,GAAI,EAAG,GAAI,GAClC,gBAAoB,KAAY,CAAE,QAAS,UAAY,aACvD,gBAAoB,MAAc,CAClC,aAAc,YACd,SAAU,GACV,QAAS,GACT,MAAO,GACP,SAAU,CAAC,GAAG,KAAU,GAAsB,IAC9C,aAAc,CAAC,GAAQ,CAAE,eACvB,gBAAoB,KAAkB,CACpC,QACE,gBAAoB,KAAU,CAC5B,KAAM,EACN,YAAa,GACb,QAAS,KAGb,MAAO,KAGX,KAAM,QACN,UAAW,gBAAoB,KAAgB,CAAE,cAAe,4BAChE,YAAa,IACX,gBAAoB,KAAW,IAAK,GAAQ,UAAW,EAAQ,MAAO,QAAS,gBA1B/C,MCvDpC,GAAY,QAChB,CACE,MAAO,IAET,CACE,KAAM,kCAIJ,GAAO,gBAAoB,KAA0B,CAAE,SAAU,UACjE,GAAc,gBAAoB,KAAc,CAAE,SAAU,UAGrD,GAAoB,IAAM,C,UACrC,KAAM,GAAU,KACV,CAAE,gBAAe,kBAAiB,UAAS,oBAC/C,KAEI,GAAmB,cACvB,IAAM,CAAC,GAAgB,QAAQ,OAAO,OAAO,SAC7C,CAAC,KAGG,CAAC,GAAgB,IAAqB,eAC1C,GAAiB,OAAS,GAAmB,UAAQ,SAAR,eAAgB,SAAhB,QAA0B,IAKzE,gBAAU,IAAM,CACV,GAAiB,QACnB,GAAkB,KAEnB,CAAC,KAEJ,gBAAU,IAAM,CACd,EAAc,CACZ,OAAQ,GAAe,OACnB,GAAI,GAAkB,IACtB,UAEL,CAAC,GAAgB,IAEpB,KAAM,IAAkB,cACtB,IACE,CACE,GAAG,GAAI,KACL,EACG,QAAS,IACR,GAAmB,GAAG,MAAmB,IAAI,IAC3C,GAAqB,GAAG,CAAE,YAAa,YAG1C,OAAO,WAEZ,OACJ,CAAC,IAGH,MAAK,IAAgB,OAGnB,gBAAoB,IAAK,CAAE,GAAI,EAAG,GAAI,GAClC,gBAAoB,KAAY,CAAE,QAAS,UAAY,SACvD,gBAAoB,MAAc,CAClC,SAAU,GACV,aAAc,QACd,QAAS,GACT,MAAO,GACP,SAAU,CAAC,GAAG,KAAU,GAAkB,IAC1C,aAAc,CAAC,GAAQ,CAAE,eACvB,gBAAoB,KAAkB,CACpC,QACE,gBAAoB,KAAU,CAC5B,KAAM,GACN,YAAa,GACb,QAAS,KAGb,MAAO,KAGX,KAAM,QACN,UAAW,gBAAoB,KAAgB,CAAE,cAAe,wBAChE,YAAa,IACX,gBAAoB,KAAW,IAAK,GAAQ,UAAW,EAAQ,MAAO,QAAS,gBA1BnD,MC/DhC,GAAY,QAChB,GAAW,EACT,cAAe,CACb,YAAa,EACb,aAAc,GAEhB,MAAO,KAET,CACE,KAAM,gCAKG,GAAkB,IAAM,C,UACnC,KAAM,GAAU,KAEV,CAAE,UAAS,iBAAkB,wBAC7B,CAAC,EAAQ,IAAa,SAAS,UAAQ,OAAR,eAAc,QAAd,QAAuB,IAE5D,mBACE,IAAM,CACJ,EAAc,CACZ,KAAM,EAAO,OAAS,GAAI,kBAAiB,GAAU,UAGzD,IACA,CAAC,EAAQ,IAIT,MAAM,cAAc,QAAS,CAAE,UAAW,EAAQ,eAC9C,MAAM,cAAc,YAAa,KAC/B,MAAM,cAAc,MAAO,CAC3B,GAAI,4BACJ,UAAW,EAAQ,MACnB,YAAa,SACb,aAAc,MACd,SAAU,IAAS,GAAU,GAAM,OAAO,OAC1C,MAAO,EACP,eACE,MAAM,cAAc,eAAgB,CAAE,SAAU,SAC5C,MAAM,cAAc,OAAQ,OAGlC,aACE,MAAM,cAAc,eAAgB,CAAE,SAAU,OAC5C,MAAM,cAAc,WAAY,CAChC,aAAc,eACd,QAAS,IAAM,GAAU,IACzB,KAAM,MACN,SAAU,EAAO,SAAW,GAE1B,MAAM,cAAc,MAAO,aCvDtC,YAA+B,EAEpC,CACA,KAAM,CAAE,eAAgB,EACxB,WAAuB,EAAQ,C,OAC7B,MACE,OAAO,WAAP,eAAiB,QACjB,GAAqB,EAAQ,CAC3B,gBAKN,MAAO,CACL,MAAO,OACP,UAAW,GACX,sBAAsB,EAAQ,GAAQ,CAOpC,MAAO,GAAc,IAAQ,SAAS,IAExC,WAAW,EAAS,GAAS,CAG3B,MAAO,GAAc,GAAS,cAAc,EAAc,MAE5D,OAAQ,GAAO,C,OACb,uBAAoB,GAAe,CACjC,UAAW,EACX,YAAa,EACb,MAAO,MAAO,WAAP,eAAiB,UAOzB,YAAoC,CACzC,QACA,WACA,cACA,OAAQ,GAMR,CACA,YAAsB,GAAQ,CAC5B,MAAO,IAAmB,GAAQ,EAAU,GAG9C,YAAuB,GAAQ,CAC7B,MAAO,IAAa,IACjB,IAAI,IAAK,GAAqB,GAAG,CAAE,iBACnC,KAAK,MAGV,MAAO,CACL,QACA,sBAAsB,GAAQ,GAAQ,CACpC,MAAO,IAAc,IAAQ,SAAS,KAExC,WAAW,GAAS,GAAS,CAC3B,MAAO,IAAc,IAAS,cAAc,GAAc,MAE5D,OAAQ,IAEJ,gBAAoB,GAAgB,CAClC,WAAY,GAAa,IACzB,YAAa,KAQhB,aAA6B,CAClC,MAAO,IAA2B,CAChC,MAAO,QACP,SAAU,KACV,YAAa,UAKV,aAA8B,CACnC,MAAO,IAA2B,CAChC,MAAO,SACP,SAAU,KACV,YAAa,SACb,OAAQ,CACN,KAAM,YAML,aAA8B,CACnC,MAAO,IAA2B,CAChC,MAAO,SACP,SAAU,KACV,YAAa,SACb,OAAQ,CACN,KAAM,YAML,aAEJ,CACD,MAAO,CACL,MAAO,cACP,MAAO,uBACP,OAAQ,GACN,gBAAoB,mBAAiB,CACnC,KAAM,EAAO,SAAS,YACtB,UAAW,eACX,KAAM,IAGV,MAAO,QAKJ,aAAqC,CAC1C,MAAO,CACL,MAAO,YACP,MAAO,kBAKJ,aAAgC,CACrC,MAAO,CACL,MAAO,OACP,MAAO,aCpJJ,KAAM,IAAsB,CACjC,GAAsB,CAAE,YAAa,WACrC,KACA,KACA,MAGW,GAAyB,CACpC,GAAsB,CAAE,YAAa,cACrC,KACA,KACA,KACA,KACA,MCLI,GAAY,QAAW,GAAU,EACrC,MAAO,CACL,QAAS,EAAM,QAAQ,GACvB,QAAS,OACT,eAAgB,aAUb,YAAqB,EAAO,CACjC,KAAM,CACJ,WACA,QACA,eACA,WAAU,WACV,YACE,EAEE,GAAU,KACV,GAAa,CACjB,SAAU,IACV,MAAO,QAGT,MAAI,MAAY,YACd,IAAW,OAAS,qBAIpB,gBAAoB,SAAO,CACzB,QAAS,GACT,MAAO,EACP,MAAO,GACP,aACE,GAAgB,gBAAoB,MAAO,CAAE,UAAW,GAAQ,OAAS,GAE3E,QAAS,CAEP,OAAQ,GACR,OAAQ,GACR,mBAAoB,GACpB,QAAS,SAEX,KAAM,IAKZ,GAAY,QAAU,EAEtB,GAAY,oBAAsB,GAElC,GAAY,uBAAyB,GCzDrC,KAAM,IAAY,QAChB,CACE,MAAO,IAET,CACE,KAAM,gCAIJ,GAAO,gBAAoB,KAA0B,CAAE,SAAU,UACjE,GAAc,gBAAoB,KAAc,CAAE,SAAU,UAGrD,GAAkB,IAAM,C,UACnC,KAAM,GAAU,KACV,CAAE,gBAAe,kBAAiB,UAAS,oBAC/C,KAEI,GAAiB,cACrB,IAAM,CAAC,GAAgB,MAAM,OAAO,OAAO,SAC3C,CAAC,KAGG,CAAC,GAAc,IAAmB,eACtC,GAAe,OAAS,GAAiB,UAAQ,OAAR,eAAc,SAAd,QAAwB,IAKnE,gBAAU,IAAM,CACV,GAAe,QACjB,GAAgB,KAEjB,CAAC,KAEJ,gBAAU,IAAM,CACd,EAAc,CACZ,KAAM,GAAa,OAAS,GAAI,GAAgB,IAAgB,UAEjE,CAAC,GAAc,IAElB,KAAM,IAAgB,cACpB,IACE,CACE,GAAG,GAAI,KACL,EACG,QAAS,IAAM,GAAE,SAAS,MAC1B,OAAO,WAEZ,OACJ,CAAC,IAGH,MAAK,IAAc,OAGjB,gBAAoB,IAAK,CAAE,GAAI,EAAG,GAAI,GAClC,gBAAoB,KAAY,CAAE,QAAS,UAAY,QACvD,gBAAoB,MAAc,CAClC,SAAU,GACV,aAAc,OACd,QAAS,GACT,MAAO,GACP,SAAU,CAAC,GAAG,KAAU,GAAgB,IACxC,aAAc,CAAC,GAAQ,CAAE,eACvB,gBAAoB,KAAkB,CACpC,QACE,gBAAoB,KAAU,CAC5B,KAAM,GACN,YAAa,GACb,QAAS,KAGb,MAAO,KAGX,KAAM,QACN,UAAW,gBAAoB,KAAgB,CAAE,cAAe,sBAChE,YAAa,IACX,gBAAoB,KAAW,IAAK,GAAQ,UAAW,EAAQ,MAAO,QAAS,gBA1BrD,M,2BCtD7B,KAAM,IAAoB,GAAU,C,OACzC,KAAM,CAAE,SAAQ,iBAAkB,EAC5B,EAAW,aAAO,eAClB,CAAE,SAAO,kBAAgB,iBAAe,qBAC5C,KAcF,GAZA,gBAAU,IAAM,CACV,IACF,EAAS,KAAK,CACZ,QAAS,8BACT,SAAU,UAGV,GACF,GAAiB,CAAC,KAEnB,CAAC,GAAO,EAAU,EAAe,KAEhC,GAAe,SAAW,GAAK,GAAO,MAAO,MAEjD,KAAM,IAAQ,CACZ,CAAE,MAAO,MAAO,MAAO,OACvB,GAAG,GAAe,IAAK,IAAU,EAC/B,MAAO,GACP,MAAO,KAAW,QAItB,MAAO,GAAS,KACd,gBAAoB,IAAK,CAAE,GAAI,EAAG,GAAI,GAClC,gBAAoB,UAAQ,CAC5B,MAAO,OACP,MAAO,GACP,SAAW,OAAM,OAAS,EAAI,GAAc,GAAK,SAAtC,QAAoD,MAC/D,SAAU,IACR,GAAiB,KAAU,MAAQ,GAAK,CAAC,OAAO,U,oDC7C1D,KAAM,IAAa,SAAW,CAC5B,KAAM,CACJ,MAAO,aAER,MAEU,GAAyB,GACpC,EAAY,wBAA0B,mBAE3B,GAAsB,GACjC,EAAY,gBAAoB,GAAY,MAAS,gBAAoB,KAAY,MAM1E,GAAkB,GAAU,CACvC,KAAM,CAAE,sBAAqB,mBAAoB,GAC/C,EAAM,QAER,MACE,iBAAoB,KAAY,CAC9B,MAAO,aACJ,EACH,QAAS,IAAM,KAEb,gBAAoB,MAAS,CAAE,MAAO,GAAsB,IAC1D,GAAmB,M,mGCMtB,YACL,EACA,C,OACA,KAAM,GAAa,aAAO,GACpB,EAAc,MAAO,SAAS,cAAhB,eAA8B,MAC5C,EAAM,EAAO,SAAS,IACtB,GAAc,IAAgB,sBAI9B,GAAgB,eAAS,SAAY,CACzC,KAAM,IAAkB,EAAW,0BAA0B,GAE7D,GAAI,IACJ,GAAI,CAAC,EACH,GAA2B,QAAQ,QAAQ,QACtC,CACL,KAAM,IAA2B,wBAAwB,OACzD,GAA2B,EACxB,YAAY,CACX,OAAQ,EAAG,IAA2B,GACtC,OAAQ,CACN,OACA,eACA,gBACA,wBAGH,KAAK,IAAY,GAAS,OAG/B,MAAO,SAAQ,IAAI,CAAC,GAAiB,KAA2B,KAC9D,CAAC,CAAC,GAAU,MAAwB,EAClC,YACA,yBAGH,CAAC,EAAY,IAKV,GAAqB,kBACzB,gBAAsC,CACpC,KAAM,CAAE,YAAU,sBAAsB,GAAc,MACtD,KAAM,GAAW,mBAAmB,GAAS,IAC7C,KAAM,SAAQ,WACZ,GAAkB,IAAI,IACpB,EAAW,kBAAkB,GAAE,SAAS,QAI9C,CAAC,EAAY,KAIT,GAAe,kBACnB,gBAAgC,CAC9B,KAAM,GAAW,kBAAkB,IAErC,CAAC,EAAY,IAMf,GAAI,GACF,MAAO,CAAE,KAAM,YAAa,SAAU,EAAa,iBAIrD,KAAM,CAAE,WAAS,SAAO,UAAU,GAClC,GAAI,GACF,MAAO,CAAE,KAAM,WACV,GAAI,GACT,MAAO,CAAE,KAAM,QAAS,UAG1B,KAAM,CAAE,YAAU,sBAAsB,GACxC,MAAK,IAGE,CACL,KAAM,aACN,SAAU,EACV,kBAAmB,GAAkB,IAAI,MACzC,sBACA,iBAPO,CAAE,KAAM,cAAe,iB,gBCrGlC,KAAM,IAAY,QAAW,CAC3B,eAAgB,CACd,SAAU,WAWR,GAAW,CAAC,CAChB,SACA,eAIG,C,OACH,KAAM,GAAW,aAAO,eAClB,EAAY,aAAO,gBACnB,GAAU,KACV,GAAQ,GAA+B,GACvC,CAAC,GAAY,IAAiB,eAAS,IACvC,CAAC,GAAM,IAAW,eAAS,IAC3B,GAAW,MAAU,kBAAkB,eAA5B,QAA4C,YAEvD,GAAe,kBACnB,gBAAgC,CAC9B,GAAI,sBAAwB,IAAO,CACjC,GAAQ,IACR,GAAI,CACF,KAAM,IAAM,qBACZ,UACO,GAAP,CACA,UAAY,IACZ,EAAS,KAAK,CAAE,QAAS,GAAI,iBAC7B,CACA,GAAQ,OAId,CAAC,EAAU,EAAW,KAGlB,GAAW,kBACf,gBAA4B,CAC1B,GAAI,gBAAkB,IAAO,CAC3B,GAAQ,IACR,GAAI,CACF,KAAM,IAAM,eACZ,UACO,GAAP,CACA,UAAY,IACZ,EAAS,KAAK,CAAE,QAAS,GAAI,iBAC7B,CACA,GAAQ,OAId,CAAC,EAAU,EAAW,KAGxB,MAAI,IAAM,OAAS,UACV,gBAAoB,YAAU,MAGnC,GAAM,OAAS,QACV,gBAAoB,sBAAoB,CAAE,MAAO,GAAM,QAG5D,GAAM,OAAS,YAEf,gBAAoB,WAAgB,KAChC,gBAAoB,KAAO,CAAE,SAAU,QAAU,8GAE3C,GAAM,SAAU,2DACX,GAAU,IAAK,eAI1B,gBAAoB,IAAK,CAAE,UAAW,GACpC,CAAC,IACD,gBAAoB,KAAQ,CAC1B,QAAS,OACT,KAAM,QACN,MAAO,UACP,UAAW,GAAQ,eACnB,QAAS,IAAM,GAAc,KAC7B,oBAKF,IACA,gBAAoB,WAAgB,KAChC,gBAAoB,KAAmB,KAAM,oTAO7C,gBAAoB,KAAQ,CAC5B,QAAS,YACT,MAAO,YACP,SAAU,GACV,QAAS,IACT,oBAUV,GAAM,OAAS,cAEf,gBAAoB,WAAgB,KAChC,gBAAoB,KAAmB,KAAM,iJAI7C,gBAAoB,KAAQ,CAC5B,QAAS,YACT,MAAO,YACP,SAAU,GACV,QAAS,IACT,kBAOJ,GAAM,OAAS,aAEf,gBAAoB,WAAgB,KAChC,gBAAoB,KAAmB,KAAM,uDAG7C,gBAAoB,KAAmB,CAAE,UAAW,MAClD,GAAM,kBAAkB,IAAI,IAC5B,gBAAoB,KAAM,CAAE,IAAK,GAAG,GAAE,QAAQ,GAAE,aAAa,GAAE,QAC3D,gBAAoB,GAAe,CAAE,UAAW,QAItD,gBAAoB,KAAmB,KAAM,sCAG7C,gBAAoB,KAAmB,CAAE,UAAW,MAClD,gBAAoB,KAAM,KAAM,GAAM,WAExC,gBAAoB,KAAmB,KAAM,2CACpC,GAAU,KAEnB,gBAAoB,IAAK,CAAE,UAAW,GACpC,gBAAoB,KAAQ,CAC5B,QAAS,YACT,MAAO,YACP,SAAU,GACV,QAAS,IACT,uBAGA,CAAC,IACD,gBAAoB,IAAK,CAAE,UAAW,OAAQ,WAAY,GACtD,gBAAoB,KAAQ,CAC5B,QAAS,OACT,KAAM,QACN,MAAO,UACP,UAAW,GAAQ,eACnB,QAAS,IAAM,GAAc,KAC7B,sBAON,IACA,gBAAoB,WAAgB,KAChC,gBAAoB,IAAK,CAAE,WAAY,EAAG,cAAe,GACvD,gBAAoB,KAAS,OAE/B,gBAAoB,KAAmB,KAAM,yTAO7C,gBAAoB,KAAQ,CAC5B,QAAS,YACT,MAAO,YACP,SAAU,GACV,QAAS,IACT,mBASL,gBAAoB,KAAO,CAAE,SAAU,SAAW,kCAG9C,GAAyB,CAAC,CACrC,OACA,YACA,UACA,YAEA,gBAAoB,KAAQ,CAAE,KAAM,EAAM,QAAS,GAC/C,gBAAoB,KAAa,CAAE,GAAI,2BAA6B,oDAGpE,gBAAoB,KAAe,KACjC,gBAAoB,GAAU,CAAE,OAAQ,EAAQ,UAAW,KAE7D,gBAAoB,KAAe,KACjC,gBAAoB,KAAQ,CAAE,QAAS,EAAS,MAAO,WAAa,Y,uFCnN5E,KAAM,IAAY,QAChB,GAAU,EACR,KAAM,CACJ,gBAAiB,qBACjB,UAAW,OACX,OAAQ,EAAM,QAAQ,EAAG,EAAG,EAAG,IAEjC,MAAO,CACL,OAAQ,EAAM,QAAQ,EAAG,EAAG,EAAG,GAC/B,cAAe,YACf,SAAU,GACV,WAAY,QAEd,SAAU,CACR,SAAU,GACV,MAAO,EAAM,QAAQ,KAAK,SAE5B,SAAU,CACR,UAAW,EAAM,QAAQ,IAE3B,aAAc,CACZ,OAAQ,EAAM,QAAQ,EAAG,EAAG,EAAG,MAGnC,CACE,KAAM,+BAaV,YAAyB,EAAS,CAChC,MAAO,CACL,CACE,KAAM,WACN,MAAO,CACL,CACE,GAAI,QACJ,MAAO,QACP,KAAM,MAER,CACE,GAAI,UACJ,MAAO,UACP,KAAM,QAIZ,CACE,KAAM,UAAW,UACjB,MAAO,CACL,CACE,GAAI,MACJ,MAAO,UAYV,KAAM,IAAiB,CAAC,CAC7B,gBACA,sBACI,C,OACJ,KAAM,GAAU,KAEV,GAAU,IADE,aAAO,gBACC,kBAAkB,uBAA5B,QAAoD,UAC9D,CAAE,WAAS,iBAAe,mBAAiB,mBAAiB,YAChE,KAII,GAAwB,CAAC,UAAW,OACpC,GAAe,GAAgB,IAClC,IAAI,IAAgB,KAChB,GACH,MAAO,GAAY,MAAM,OAAO,CAAC,CAAE,SAEjC,CAAC,QAAS,QAAQ,KAAK,IAAQ,KAAS,GAAgB,MACpD,GAAsB,SAAS,IAC/B,CAAC,GAAoB,EAAiB,SAAS,QAGtD,OAAO,CAAC,CAAE,YAAY,CAAC,CAAC,GAAM,QAE3B,CAAE,oBAAoB,KACtB,CAAE,kBAAkB,KAGpB,GAAc,cAClB,IAAM,GAAI,IAAe,QAAS,GAAe,IACjD,CAAC,GAAe,KAEZ,GAAgB,cACpB,IAAM,GAAI,IAAe,UAAW,GAAe,IACnD,CAAC,GAAe,KAGZ,GAAuB,cAC3B,IAAM,CAAC,GAAgB,MAAM,OAAO,GACpC,CAAC,KAGG,CAAC,GAAoB,IAAyB,eAClD,YAAwB,GAKpB,GAA4B,cAChC,IACE,GAAgB,OACd,GACE,cAAQ,OAAO,OAAO,IAAK,GAAS,KAAM,YAGhD,CAAC,GAAS,KAGN,GAAe,cACnB,IAAO,EACL,IAAK,GAA0B,OAC/B,QAAS,GAA0B,OAAO,IACxC,GAAc,aAAa,KAC3B,OACF,MAAO,GAA0B,OAAO,IACtC,GAAY,aAAa,KACzB,SAEJ,CAAC,GAA2B,GAAe,KAK7C,sBAAU,IAAM,CACV,IACF,GAAsB,KAEvB,CAAC,KAEJ,gBAAU,IAAM,CAEZ,CAAC,IACD,CAAC,CAAC,IACF,KAAuB,OACvB,GAAa,MAAwB,GAErC,GAAsB,QAEvB,CAAC,GAAS,GAAc,GAAoB,KAE/C,gBAAU,IAAM,CACd,GAAc,CACZ,KAAM,GACF,GAAI,IACF,GACA,GACA,IAEF,UAEL,CAAC,GAAoB,GAAe,GAAiB,KAGtD,gBAAoB,KAAM,CAAE,UAAW,EAAQ,MAC3C,GAAa,IAAI,IACjB,gBAAoB,WAAU,CAAE,IAAK,GAAM,MACvC,gBAAoB,KAAY,CAAE,QAAS,YAAa,UAAW,EAAQ,OACzE,GAAM,MAER,gBAAoB,KAAM,CAAE,UAAW,EAAQ,cAC7C,gBAAoB,KAAM,CAAE,eAAgB,GAAM,MAAO,IACvD,GAAM,MAAM,IAAI,IAAK,C,UACrB,uBAAoB,KAAU,CAC5B,IAAK,GAAK,GACV,OAAQ,GACR,QAAS,GACT,QAAS,IAAM,GAAsB,GAAK,IAC1C,SAAU,GAAK,KAAO,QAAQ,OAAR,eAAc,OACpC,UAAW,EAAQ,SACnB,SAAU,GAAa,GAAK,MAAQ,EACpC,cAAe,eAAe,GAAK,MAEjC,GAAK,MACL,gBAAoB,KAAc,CAAE,UAAW,EAAQ,UACnD,gBAAoB,GAAK,KAAM,CAAE,SAAU,WAG/C,gBAAoB,KAAc,KAChC,gBAAoB,KAAY,CAAE,QAAS,SAAW,GAAK,QAE7D,gBAAoB,KAAyB,KAC3C,OAAa,GAAK,MAAlB,QAAyB,cCrOlC,GAAgC,CAAC,CAC5C,WACA,WAGG,C,OAGH,KAAM,CAAC,EAAS,GAAc,SAC5B,qBAAO,UAAP,QAAkB,IAGd,GAAgB,YAElB,IAKG,CACH,EAAW,IAAe,CACxB,KAAM,IACJ,MAAO,KAAW,WAAa,GAAO,IAAe,GACvD,MAAO,IAAK,MAAgB,OAGhC,IAKI,GAAgB,QACpB,IAAO,EACL,SAAU,GACV,gBAAiB,GACjB,gBAAiB,KAEnB,IAGI,GAAgB,QACpB,IAAG,C,mBAAI,OACL,SAAU,qBAAO,WAAP,QAAmB,GAAc,SAC3C,gBAAiB,qBAAO,kBAAP,QAA0B,GAAc,gBACzD,cAAe,qBAAO,gBAAP,QAAwB,GACvC,UACA,QAAS,qBAAO,UAAP,QAAkB,GAC3B,gBAAiB,qBAAO,kBAAP,QAA0B,GAAc,gBACzD,MAAO,iBAAO,QAEhB,CAAC,EAAO,GAAe,EAAS,KAGlC,MACE,OAAM,cAAc,kBAAkB,SAAU,CAAE,MAAO,IACrD,I,4YC/DR,KAAM,GAAY,QAAW,IAAU,EACrC,MAAO,CACL,WAAY,OACZ,SAAU,SACV,WAAY,OACZ,UAAW,cAEb,MAAO,CACL,MAAO,GAAM,QAAQ,KAAK,UAC1B,cAAe,YACf,SAAU,OACV,WAAY,OACZ,cAAe,GACf,SAAU,SACV,WAAY,aAWH,EAAa,CAAC,CAAE,SAAO,SAAO,aAAW,eAAe,CACnE,KAAM,IAAU,IAEV,GAAgB,uBAAiB,GAAU,IAAK,GAAE,eAGlD,GACJ,GAAc,OAAS,EACrB,GAEA,gBAAoB,IAAY,CAAE,QAAS,QAAS,UAAW,GAAQ,OACnE,IAAS,WAGjB,MACE,iBAAoB,IAAM,CAAE,KAAM,MAAS,IACvC,gBAAoB,IAAY,CAAE,QAAS,YAAa,UAAW,GAAQ,OACzE,IAEF,KCnCF,EAAY,QAAW,CAC3B,YAAa,CACX,UAAW,gBAQF,GAAe,CAAC,CAAE,aAAa,C,sBAC1C,KAAM,IAAU,IACV,GAAW,GAAO,KAAK,kBAAkB,WAAa,SACtD,GAAa,GAAO,KAAK,kBAAkB,WAAa,WACxD,GAAc,GAAO,KAAK,kBAAkB,WAAa,YACzD,GAAQ,GAAO,KAAK,kBAAkB,WAAa,MACnD,GAAa,GAAO,KAAK,kBAAkB,WAAa,WACxD,GAAa,GAAO,KAAK,kBAAkB,WAAa,WACxD,GAAU,GAAO,KAAK,kBAAkB,WAAa,QAErD,GAAwB,yBAAmB,GAAQ,KAAkB,CACzE,KAAM,WAEF,GAA2B,yBAC/B,GACA,KACA,CACE,KAAM,cAGJ,GAAwB,yBAAmB,GAAQ,KAAkB,CACzE,KAAM,WAEF,GAAmB,yBAAmB,GAAQ,MAEpD,MACE,iBAAoB,IAAM,CAAE,UAAW,IACnC,gBAAoB,EAAY,CAAE,MAAO,cAAe,UAAW,CAAE,GAAI,KACvE,gBAAoB,IAAY,CAAE,QAAS,QAAS,UAAW,GAAM,UAAW,GAAQ,aACtF,wBAAQ,WAAR,eAAkB,cAAe,mBAGrC,gBAAoB,EAAY,CAChC,MAAO,QACP,MAAO,WACP,UAAW,CAAE,GAAI,GAAI,GAAI,EAAG,GAAI,IAE9B,GAAiB,OAAS,GAC1B,gBAAoB,iBAAgB,CAAE,WAAY,GAAkB,YAAa,WAGlF,KAAY,GAAsB,OAAS,IAC5C,gBAAoB,EAAY,CAC9B,MAAO,SACP,MAAO,YACP,UAAW,CAAE,GAAI,GAAI,GAAI,EAAG,GAAI,IAE9B,GAAsB,OAAS,GAC/B,gBAAoB,iBAAgB,CAClC,WAAY,GACZ,YAAa,YAKlB,KACD,IACA,IACA,GAAsB,OAAS,IAC/B,gBAAoB,EAAY,CAC9B,MAAO,SACP,MAAO,YACP,UAAW,CAAE,GAAI,GAAI,GAAI,EAAG,GAAI,IAE9B,GAAsB,OAAS,GAC/B,gBAAoB,iBAAgB,CAClC,WAAY,GACZ,YAAa,YAKnB,IAAe,GAAyB,OAAS,GACjD,gBAAoB,EAAY,CAC9B,MAAO,mBACP,MAAO,sBACP,UAAW,CAAE,GAAI,GAAI,GAAI,EAAG,GAAI,IAE9B,gBAAoB,iBAAgB,CACpC,WAAY,GACZ,YAAa,eAIhB,KACD,IACA,IACA,IACA,IACA,IACA,MAAO,wBAAQ,OAAR,eAAc,OAAS,WAC9B,gBAAoB,EAAY,CAC9B,MAAO,OACP,MAAO,uBAAQ,OAAR,eAAc,KACrB,UAAW,CAAE,GAAI,GAAI,GAAI,EAAG,GAAI,KAGjC,KACD,IACA,MAAO,wBAAQ,OAAR,eAAc,YAAc,WACnC,gBAAoB,EAAY,CAC9B,MAAO,YACP,MAAO,uBAAQ,OAAR,eAAc,UACrB,UAAW,CAAE,GAAI,GAAI,GAAI,EAAG,GAAI,KAGlC,gBAAoB,EAAY,CAChC,MAAO,OACP,MAAO,UACP,UAAW,CAAE,GAAI,GAAI,GAAI,EAAG,GAAI,IAE7B,yBAAQ,WAAR,eAAkB,OAAQ,IAAI,IAAI,IACnC,gBAAoB,IAAM,CAAE,IAAK,GAAG,KAAM,QAAS,MAAO,SCjG9D,GAAY,QAAW,CAC3B,aAAc,CACZ,QAAS,OACT,cAAe,SACf,OAAQ,oBACR,aAAc,QAEhB,eAAgB,CACd,QAAS,OACT,cAAe,SACf,OAAQ,QAEV,oBAAqB,CACnB,KAAM,GAER,sBAAuB,CACrB,KAAM,KAUH,YAAmB,CAAE,YAAW,C,UACrC,KAAM,IAAU,KACV,CAAE,WAAW,kBACb,GAAqB,aAAO,MAC5B,GAAa,aAAO,MACpB,GAAW,aAAO,eAClB,GAAkB,kBAAY,KAE9B,GAAuB,8BAC3B,GACA,IAEI,GAAwB,+BAAyB,IAEjD,GAAe,CACnB,MAAO,cACP,SAAU,CAAC,GACX,KAAM,gBAAoB,KAAoB,CAAE,KAAM,mBAAsB,kBAC5E,KAAM,mBAAsB,mBAExB,GAAiB,CACrB,MAAO,gBACP,SACE,CAAC,QAAO,SAAS,cAAhB,eAA8B,+BAC/B,CAAC,GACH,KAAM,gBAAoB,IAAU,MACpC,KACE,IACA,GAAgB,CACd,UAAW,GAAO,SAAS,WAAa,KACxC,KAAM,GAAO,KACb,KAAM,GAAO,SAAS,QAI5B,GAAI,IAAY,GACZ,KAAY,WACd,GAAY,GAAQ,aACX,KAAY,cACrB,IAAY,GAAQ,gBAGtB,GAAI,IAAmB,GACnB,KAAY,WACd,GAAmB,GAAQ,oBAClB,KAAY,cACrB,IAAmB,GAAQ,uBAG7B,KAAM,IAAiB,OAAO,SAAS,cAAhB,eAA8B,MAE/C,GACJ,oBAAgB,WAAW,UAAW,oBAAgB,WAAW,UAC7D,GAAgB,kBAAY,SAAY,CAC5C,KAAM,IAAW,cAAc,SAAmB,KAClD,GAAS,KAAK,CAAE,QAAS,oBAAqB,SAAU,UACvD,CAAC,GAAY,GAAU,KAE1B,MACE,iBAAoB,IAAM,CAAE,UAAW,IACnC,gBAAoB,IAAY,CAChC,MAAO,QACP,OACE,gBAAoB,WAAgB,KAChC,IACA,gBAAoB,IAAY,CAC9B,aAAc,UACd,MAAO,0BACP,QAAS,IAEP,gBAAoB,IAAY,OAGpC,gBAAoB,IAAY,CAChC,UAAW,OACX,aAAc,OACd,SAAU,CAAC,GACX,MAAO,gBACP,GAAI,YAAyB,KAE3B,gBAAoB,IAAU,QAItC,UAAW,gBAAoB,oBAAmB,CAAE,MAAO,CAAC,GAAc,QAE1E,gBAAoB,IAAS,MAC7B,gBAAoB,IAAa,CAAE,UAAW,IAC5C,gBAAoB,GAAc,CAAE,OAAQ,S,8JCxItD,KAAM,GAAY,QAAY,GAC5B,QAAa,CACX,KAAM,IACD,EAAM,WAAW,OASb,EAAoB,CAAC,CAChC,gBAAgB,eACZ,C,MACJ,KAAM,GAAU,IACV,CAAE,MAAO,EAAW,IAAO,uBAC3B,CAAE,gBAAe,mBAAoB,8BAErC,CAAC,EAAc,GAAmB,eACrC,KAAC,EAAgB,MAAM,OAAO,KAA9B,OAAoC,GAAe,kBAClD,UAIJ,gBAAU,IAAM,CACd,EAAc,CACZ,KAAM,EAAe,GAAI,oBAAiB,GAAgB,UAE3D,CAAC,EAAc,IAOlB,KAAM,GAAU,CAAC,QAAW,IACzB,OAAO,GACP,OACA,OAAO,CAAC,EAAK,IACZ,GAAI,EAAK,kBAAkB,UAAY,EAChC,GACN,IAEL,MACE,iBAAoB,IAAQ,CAC1B,MAAO,gBAAoB,IAAW,CAAE,MAAO,IAC/C,MAAO,EACP,SAAU,GAAK,EAAgB,EAAE,OAAO,OACxC,QAAS,GAEP,OAAO,KAAK,GAAS,IAAI,GACzB,gBAAoB,IAAU,CAAE,MAAO,EAAM,IAAK,GAC9C,GAAG,EAAQ,W,gOC7BhB,KAAM,GAAqB,CAAC,CACjC,UACA,UACA,0BAA0B,WACtB,C,MACJ,KAAM,GACJ,G,GAAA,UAAO,gBAAc,kBAAkB,uBAAvC,OAA+D,YAC3D,EAAsB,kBAAY,KAExC,MACE,iBAAoB,iBAAgB,CAAE,MAAO,GAAG,YAAmB,QAAS,QACxE,gBAAoB,qBAAoB,KACtC,gBAAoB,UAAS,KAC3B,gBAAoB,gBAAe,CAAE,eAAgB,gBAAoB,IAAmB,OAC1F,gBAAoB,eAAc,CAClC,MAAO,mBACP,GAAI,GAAuB,MAE3B,gBAAoB,gBAAe,KAAM,uCAE3C,gBAAoB,KAAsB,KACxC,gBAAoB,KAAiB,KACnC,gBAAoB,mBAAkB,MACtC,gBAAoB,iBAAgB,CAAE,cAAe,IACrD,gBAAoB,oBAAmB,MACvC,gBAAoB,wBAAuB,MAC3C,gBAAoB,kBAAiB,OAEvC,gBAAoB,KAAqB,KACvC,gBAAoB,IAAc,CAAE,QAAS,EAAS,QAAS,UC9DlE,EAAe,GAGnB,GAFQ,SAEE,gBAAoB,EAAoB,IAAK,K,yYCIzD,WACL,EACA,CACA,WAAuB,EAAQ,C,MAC7B,MACE,MAAO,WAAP,cAAiB,QACjB,2BAAqB,EAAQ,CAC3B,YAAa,iBAAO,cAK1B,MAAO,CACL,MAAO,OACP,MAAO,gBACP,UAAW,GACX,WAAW,CAAE,OAAQ,GAAW,CAAE,OAAQ,GAAW,CAGnD,MAAO,GAAc,GAAS,cAAc,EAAc,KAE5D,OAAQ,CAAC,CAAE,YAAU,C,MACnB,uBAAoB,gBAAe,CACjC,UAAW,EACX,YAAa,kBAAO,cAAe,YACnC,MAAO,KAAO,WAAP,cAAiB,UAMzB,YAA8B,CACnC,MAAO,CACL,MAAO,SACP,MAAO,qCACP,OAAQ,CAAC,CAAE,cACT,gBAAoB,iBAAgB,CAClC,WAAY,EAAS,sBACrB,YAAa,YAMd,YAA6B,CAClC,MAAO,CACL,MAAO,QACP,MAAO,iCACP,OAAQ,CAAC,CAAE,cACT,gBAAoB,iBAAgB,CAClC,WAAY,EAAS,iBACrB,YAAa,WAMd,YAAgC,CACrC,MAAO,CACL,MAAO,OACP,MAAO,mBACP,OAAQ,IAIL,YAAqC,CAC1C,MAAO,CACL,MAAO,YACP,MAAO,yBAIJ,YAA2C,CAChD,MAAO,CACL,MAAO,cACP,MAAO,8BACP,OAAQ,CAAC,CAAE,YACT,gBAAoB,kBAAiB,CACnC,KAAM,EAAO,SAAS,YACtB,UAAW,iBAGf,MAAO,QAIJ,YAA4B,CACjC,MAAO,CACL,MAAO,OACP,MAAO,uBACP,UAAW,CACT,QAAS,qBAEX,OAAQ,CAAC,CAAE,YACT,gBAAoB,WAAgB,KAChC,EAAO,SAAS,MAChB,EAAO,SAAS,KAAK,IAAI,GACvB,gBAAoB,IAAM,CACxB,IAAK,EACL,MAAO,EACP,KAAM,QACN,QAAS,WACT,MAAO,CAAE,aAAc,c,4JCvF9B,KAAM,GAAe,CAAC,CAAE,UAAS,aAAc,C,aACpD,KAAM,CAAE,kBAAiB,uBAAwB,2BAC3C,CAAE,UAAS,QAAO,WAAU,WAAY,8BAExC,EAAiB,cACrB,IAAG,C,OAAG,OACJ,mBAAiC,CAAE,YAAa,MAAQ,OAAR,eAAc,QAC9D,uBACA,sBACA,yBACA,8BACA,oCACA,uBAEF,CAAC,MAAQ,OAAR,eAAc,QAGX,EAAiB,EAAQ,OAAS,OAElC,EAAgB,iBAAW,UAAQ,OAAR,eAAc,QAAd,QAAuB,OAExD,GAAI,EACF,MACE,iBAAoB,MAAO,KACvB,gBAAoB,eAAc,CAClC,SAAU,QACV,MAAO,qCAEL,gBAAoB,cAAa,CAAE,SAAU,OAAQ,KAAM,EAAM,eAM3E,KAAM,GAAiB,CACrB,CAAC,CAAE,aAAa,CACd,KAAM,IAAM,+BAAyB,IACrC,MAAO,CACL,KAAM,IAAM,gBAAoB,IAAW,CAAE,aAAc,OAAQ,SAAU,UAC7E,QAAS,OACT,SAAU,CAAC,GACX,QAAS,IAAM,CACT,CAAC,IACL,OAAO,KAAK,GAAK,aAIvB,CAAC,CAAE,aAAa,CACd,KAAM,IAAM,+BAAyB,IACrC,MAAO,CACL,KAAM,IAAM,gBAAoB,IAAM,CAAE,aAAc,OAAQ,SAAU,UACxE,QAAS,OACT,SAAU,CAAC,GACX,QAAS,IAAM,CACT,CAAC,IACL,OAAO,KAAK,GAAK,aAIvB,CAAC,CAAE,aAAa,CACd,KAAM,IAAY,EAAgB,IAClC,MAAO,CACL,UAAW,CAAE,YAAa,OAC1B,KAAM,IAAM,yBAAmB,IAC/B,QAAS,4BAAsB,IAC/B,QAAS,IAAM,EAAoB,OAKnC,EAAO,EAAS,IAAI,IAAU,CAClC,KAAM,IAAwB,yBAAmB,GAAQ,KAAkB,CACzE,KAAM,WAEF,GAAmB,yBAAmB,GAAQ,MAEpD,MAAO,CACL,UACA,SAAU,CACR,KAAM,2BAAqB,GAAQ,CACjC,YAAa,cAEf,sBAAuB,GACpB,IAAI,IAAK,2BAAqB,GAAG,CAAE,YAAa,WAChD,KAAK,MACR,oBACA,0BAA2B,GACxB,IAAI,IACH,2BAAqB,GAAG,CACtB,YAAa,YAGhB,KAAK,MACR,6BAKA,GAAc,IAAW,GAAgB,KAAK,IAAK,GAAE,QAAU,QACjE,IACF,IAAW,OAAS,CAAC,GAEvB,KAAM,IAAiB,EAAK,OAAS,GAErC,MACE,iBAAoB,QAAO,CACzB,UAAW,EACX,QAAS,GAAW,EACpB,QAAS,CACP,OAAQ,GACR,SAAU,GACV,mBAAoB,GACpB,YAAa,SACb,2BAA4B,CAAC,EAC7B,QAAS,QACT,gBAAiB,CAAC,GAAI,GAAI,MAE5B,MAAO,GAAG,MAAkB,EAAS,UACrC,KAAM,EACN,QAAS,GAAW,KAK1B,EAAa,QAAU,G,6ICtJhB,KAAM,GAAuB,CAAC,CAAE,cACrC,gBAAoB,IAAM,CAAE,UAAW,GAAM,MAAO,CAAE,SAAU,aAC5D,G,gFCQC,KAAM,GAAkB,CAAC,CAAE,cAAe,CAC/C,KAAM,GAAkB,QAAc,GACpC,EAAM,YAAY,KAAK,OAEnB,EAAQ,UACR,CAAC,EAAkB,GAAuB,eAAS,IAEzD,MAAO,GACL,gBAAoB,WAAgB,KAChC,gBAAoB,IAAQ,CAC5B,MAAO,CAAE,UAAW,EAAM,QAAQ,GAAI,WAAY,EAAM,QAAQ,IAChE,QAAS,IAAM,EAAoB,IACnC,UAAW,gBAAoB,IAAgB,OAC/C,WAGA,gBAAoB,KAAQ,CAC5B,KAAM,EACN,QAAS,IAAM,EAAoB,IACnC,OAAQ,OACR,iBAAkB,GAClB,YAAa,GACb,QAAS,aAEP,gBAAoB,IAAK,CAAE,EAAG,GAC5B,gBAAoB,IAAY,CAChC,QAAS,KACT,UAAW,KACX,MAAO,CAAE,aAAc,EAAM,QAAQ,KACrC,WAGA,KAKR,gBAAoB,IAAM,CAAE,KAAM,GAAM,GAAI,GACxC,IChDK,EAAsB,CAAC,CAAE,cACpC,gBAAoB,IAAM,CAAE,KAAM,GAAM,GAAI,GAAI,GAAI,IAChD,I,yGCHC,KAAM,GAA0B,6BAAuB,CAC5D,GAAI,mBACJ,SAAU,KAGC,EAAsB,6BAAuB,CACxD,GAAI,eACJ,SAAU,GACV,OAAQ,CAAC,YAAa,OAAQ,W,6ICWzB,KAAM,GAAmB,mBAAa,CAC3C,GAAI,0BCTC,GAAI,GAAkB,UAAU,EAAiB,CAItD,KAAM,GAAO,OAAQ,EAAgB,KAAU,EAI/C,KAAM,GAAQ,QAAS,EAAgB,MAAW,EAIlD,KAAM,GAAc,cAAe,EAAgB,YAAiB,IACnE,GAAoB,GAAkB,K,wDCLzC,KAAM,GAEH,SAAO,IACR,WACU,CACN,KAAM,aACN,OAAQ,UAAQ,iBAEjB,GAAG,WAAS,CAAE,MAAO,UAAQ,MAC7B,GAAG,WAAS,CAAE,MAAO,UAAQ,MAC7B,GAAG,WAAS,CAAE,IAAK,MAGlB,EAAiB,WAAS,CAC9B,MAAO,UACL,WACU,CACN,GAAI,aACJ,OAAQ,YACG,EAAgB,OACxB,GAAG,YAAU,EAAgB,SAEjC,GACC,WAAS,CACP,GAAI,aACJ,OAAQ,YAAU,EAAgB,aAClC,WAAY,QAUf,OAAwB,CAI7B,YAAY,EAAS,CAHnB,kBACA,oB,MAGA,KAAK,UAAY,EAAQ,UACzB,KAAK,QACH,KAAQ,OAAO,mBAAmB,wBAAlC,OAA2D,QAmBzD,WACJ,EACA,EACA,CAMA,GAAI,CAAC,KAAK,QACR,MAAO,GAAQ,IAAI,IAAM,EAAE,OAAQ,EAAgB,SAGrD,KAAM,GAAU,CACd,MAAO,EAAQ,IAAI,IAAU,EAC3B,GAAI,SACD,OAID,EAAgB,KAAM,MAAK,UAAU,WAAW,cAChD,EAAW,KAAM,KAAM,GAAG,cAA2B,CACzD,OAAQ,OACR,KAAM,KAAK,UAAU,GACrB,QAAS,IACJ,KAAK,uBAAuB,iBAAS,OACxC,eAAgB,sBAGpB,GAAI,CAAC,EAAS,GACZ,KAAM,MAAM,mBAA2B,GAGzC,KAAM,IAAe,KAAM,GAAS,OACpC,KAAK,oBAAoB,EAAS,IAElC,KAAM,IAAgB,GAAa,MAAM,OAAO,CAAC,GAAK,KACpD,IAAI,GAAE,IAAM,GACL,IACN,IAEH,MAAO,GAAQ,MAAM,IAAI,IAAS,GAAc,GAAM,KAGvD,uBAAuB,EAAO,CAC7B,MAAO,GAAQ,CAAE,cAAe,UAAU,KAAY,GAGvD,oBACC,EACA,EACA,CAEA,KAAM,GAAc,EADuB,MAAM,GACT,MAAM,IAAI,IAAK,GAAE,IAIzD,GAAI,CAHqB,EAAQ,MAAM,MAAM,IAC3C,EAAY,SAAS,GAAE,KAGvB,KAAM,IAAI,OACR,8DChID,OAA6B,CACjC,YACG,EACA,EACF,CAAE,KAAK,iBAAmB,EAAiB,KAAK,YAAc,QAEzD,QAAO,EAId,CACE,KAAM,CAAE,SAAQ,YAAW,YAAa,EAClC,EAAmB,GAAI,GAAiB,CAAE,YAAW,WAC3D,MAAO,IAAI,GAAsB,EAAkB,QAG/C,WAAU,EAAS,CAKvB,MAAO,MAJgB,MAAK,iBAAiB,UAC3C,CAAC,GACD,KAAM,MAAK,YAAY,mBAET,I,eCPb,KAAM,GAAgB,CAC3B,EACA,IACG,CACH,KAAM,GAAgB,aAAO,GACvB,CAAE,OAAM,SAAU,SAAO,CAAE,aAAY,eAAe,KAAM,IAAQ,CACxE,KAAM,CAAE,WAAW,KAAM,GAAc,UAAU,GACjD,MAAO,MAGT,MAAI,GACK,CAAE,QAAO,QAAS,GAAO,QAAS,IAEvC,IAAS,OACJ,CAAE,QAAS,GAAM,QAAS,IAE5B,CAAE,QAAS,GAAO,QAAS,IAAS,EAAgB,QChChD,EACX,GAKG,CACH,KAAM,CAAE,aAAY,cAAa,oBAAmB,GAAe,EAC7D,EAAmB,cAAc,EAAY,GAC7C,GAAM,SACN,CAAE,sBAAsB,GAAI,gBAElC,GAAI,IACF,IAAmB,OAAY,MAAM,cAAc,GAAmB,MAAS,EAEjF,MAAI,GAAiB,QACnB,GAAe,KACN,EAAiB,SAC1B,IAAe,EAAM,SAGhB,MAAM,cAAc,MAAO,IAAK,EAAY,QAAS,O,wICxBvD,KAAM,GAAe,mBAAa,CACvC,GAAI,+BAOC,OAAoB,CAIzB,YAAY,EAGZ,CANE,uBACA,sBAMA,KAAK,aAAe,EAAQ,aAC5B,KAAK,YAAc,EAAQ,iBAGvB,OAAM,EAAO,CACjB,KAAM,CAAE,SAAU,KAAM,MAAK,YAAY,iBACnC,EAAc,cAAa,GAC3B,EAAM,GAAG,KAAM,MAAK,aAAa,WACrC,mBACG,IACC,EAAW,KAAM,OAAM,EAAK,CAChC,QAAS,EAAQ,CAAE,cAAe,UAAU,KAAY,KAG1D,GAAI,CAAC,EAAS,GACZ,KAAM,MAAM,mBAA2B,GAGzC,MAAO,GAAS,U,iMCxBb,KAAM,GAAwB,CAAC,CACpC,SACA,OACA,kBACA,YAAY,KAGV,gBAAoB,OAAM,CAAE,GAAI,EAAO,UACnC,gBAAoB,IAAU,CAAE,WAAY,UAC1C,GAAQ,gBAAoB,IAAc,KAAM,GAChD,gBAAoB,IAAc,CAClC,uBAAwB,CAAE,QAAS,MACnC,QAAS,EAAO,MAChB,UACE,gBAAoB,IAAc,CAChC,KAAM,EACN,aAAc,SACd,KAAM,EAAO,KACb,QAAS,WAIb,GAAmB,gBAAoB,IAAK,CAAE,WAAY,YAAc,IAE1E,gBAAoB,IAAS,Q,0NCpC9B,KAAM,GAAc,CAAC,CAAE,cAAe,CAC3C,KAAM,GAAY,qBACZ,CAAE,QAAS,WAEjB,sBAAU,IAAM,CACV,GAEF,EAAU,aAAa,SAAU,IAElC,CAAC,EAAW,IAER,gBAAoB,WAAgB,KAAM,ICqB7C,EAAwB,IAErB,GADS,cAAW,QACR,OAUR,EAAgB,CAAC,CAC5B,WACA,YACA,WACA,eAAe,IACf,cAAc,GACd,YAAY,GACZ,MAAO,EACP,WAAY,EAAoB,GAChC,aAAc,KACX,MACC,CACJ,KAAM,IAAY,aAAO,gBACnB,CAAC,GAAO,IAAY,eAAS,GAC7B,GAAmB,IAEzB,gBAAU,IAAM,CACd,GAAS,IACP,KAAc,EAAgB,EAAiB,KAEhD,CAAC,IAEJ,QAAY,IAAM,EAAS,IAAQ,EAAc,CAAC,KAElD,KAAM,IAAe,kBAClB,IAAM,CACL,GAAS,GAAE,OAAO,QAEpB,CAAC,KAGG,GAAgB,kBACnB,IAAM,CACD,GAAW,EAAU,IACrB,GAAY,GAAE,MAAQ,SACxB,KAGJ,CAAC,EAAW,IAGR,GAAc,kBAAY,IAAM,CACpC,EAAS,KACR,CAAC,IAEE,GAAc,aAClB,GAAU,kBAAkB,cAAgB,cAGxC,GACJ,gBAAoB,IAAgB,CAAE,SAAU,SAC5C,gBAAoB,IAAY,CAAE,aAAc,QAAS,SAAU,IACjE,gBAAoB,IAAY,QAKlC,GACJ,gBAAoB,IAAgB,CAAE,SAAU,OAC5C,gBAAoB,IAAY,CAAE,aAAc,QAAS,QAAS,IAChE,gBAAoB,IAAa,QAKnC,GACJ,gBAAoB,EAAa,KAC7B,gBAAoB,IAAW,CAC/B,cAAe,kBACf,MAAO,GACP,YAAa,GACb,eAAgB,GAChB,aAAc,EAAc,GAAe,EAC3C,WAAY,CAAE,aAAc,YAAa,GACzC,UAAW,EACX,SAAU,GACV,UAAW,MACR,MAKT,MAAO,IACL,GAEA,gBAAoB,KAAuB,KAAM,KAgBxC,EAAY,CAAC,CAAE,cAAa,KAAY,CACnD,KAAM,CAAE,OAAM,WAAY,WAEpB,EAAgB,GAAa,CAC7B,EACF,EAAS,GAET,EAAQ,IAIZ,MAAO,iBAAoB,EAAe,CAAE,MAAO,EAAM,SAAU,KAAiB,M,6KCxH/E,KAAM,GAAgB,oBAC3B,QAGW,EAAwB,CAAC,CACpC,eAAe,CACb,KAAM,GACN,WAAY,OACZ,QAAS,GACT,MAAO,IAET,cACI,C,gBACJ,KAAM,GAAY,aAAO,KACnB,CAAC,EAAY,GAAiB,eAClC,EAAa,YAET,CAAC,EAAS,GAAc,eAAS,EAAa,SAC9C,CAAC,EAAM,GAAW,eAAS,EAAa,MACxC,CAAC,EAAO,GAAY,eAAS,EAAa,OAC1C,CAAC,EAAM,GAAW,eAAS,IAC3B,EAAc,kBAClB,IAAM,EAAQ,IAAa,CAAC,IAC5B,IAGI,GAAW,QAAY,GAEvB,GAAS,cACb,IACE,EAAU,MAAM,CACd,OACA,UACA,WAAY,EACZ,UAEJ,CAAC,EAAM,EAAS,EAAO,IAGnB,GACJ,CAAC,GAAO,SAAW,CAAC,GAAO,OAAS,QAAO,QAAP,eAAc,gBAC9C,GACJ,CAAC,GAAO,SAAW,CAAC,GAAO,OAAS,QAAO,QAAP,eAAc,oBAC9C,GAAgB,kBAAY,IAAM,C,OACtC,EAAc,OAAO,QAAP,eAAc,iBAC3B,CAAC,OAAO,QAAP,eAAc,iBACZ,GAAoB,kBAAY,IAAM,C,OAC1C,EAAc,OAAO,QAAP,eAAc,qBAC3B,CAAC,OAAO,QAAP,eAAc,qBAElB,gBAAU,IAAM,CAEV,GAAQ,IAAY,IAAS,IAC/B,EAAc,SAEf,CAAC,EAAM,GAAU,EAAa,aAEjC,KAAM,IAAQ,CACZ,UACA,UACA,aACA,OACA,cACA,OACA,UACA,QACA,WACA,aACA,gBACA,cAAe,GAAc,GAAgB,OAC7C,kBAAmB,GAAkB,GAAoB,QAG3D,MACE,iBAAoB,mBAAkB,CAAE,WAAY,CAAE,YAAa,EAAM,OAAO,KAAK,OACjF,gBAAoB,EAAc,SAAU,CAAE,MAAO,GAAO,SAAU,MAKjE,EAAY,IAAM,CAC7B,KAAM,GAAU,iBAAW,GAC3B,GAAI,IAAY,OACd,KAAM,IAAI,OAAM,yDAElB,MAAO,K,+RCpGT,KAAM,GAAY,QAAW,IAAU,EACrC,UAAW,CACT,aAAc,GACd,QAAS,OACT,OAAQ,SAEV,MAAO,CACL,KAAM,GAGR,eAAgB,CAAE,OAAQ,sBAC1B,uBAAwB,CAAE,QAAS,GAAM,QAAQ,EAAG,IACpD,gBAAiB,CAAE,cAAe,YAGvB,EAAQ,CAAC,CAAE,QAAO,GAAM,kBAAkB,CACrD,KAAM,IAAgB,kBAAY,MAC5B,GAAU,IAEV,CAAE,SAAS,WACX,CAAE,iBAAiB,mBACnB,CAAE,gBAAgB,UAElB,GAAoB,IAAM,CAC9B,KACA,WAAW,GAAc,GAAY,SAAS,gBAG1C,GAAiB,IAAM,CAC3B,MAGF,MACE,iBAAoB,IAAQ,CAC1B,QAAS,CACP,eAAgB,GAAQ,gBAE1B,QAAS,GACT,kBAAmB,qBACnB,KAAM,GACN,UAAW,GACX,SAAU,MAER,gBAAoB,IAAa,KAC/B,gBAAoB,IAAO,CAAE,UAAW,GAAQ,WAC9C,gBAAoB,YAAW,CAAE,UAAW,GAAQ,UAGxD,gBAAoB,IAAe,KACjC,gBAAoB,IAAM,CAC1B,UAAW,GACX,UAAW,cACX,eAAgB,aAChB,WAAY,UAEV,gBAAoB,IAAM,CAAE,KAAM,IAChC,gBAAoB,OAAM,CAC1B,QAAS,IAAM,CACb,KACA,WAAW,GAAc,GAAY,SAAS,gBAEhD,GAAI,GAAG,cAAyB,MAE9B,gBAAoB,OAAQ,CAAE,UAAW,GAAQ,iBAAmB,qBACpE,gBAAoB,IAAY,CAAE,MAAO,eAI/C,gBAAoB,IAAS,MAC7B,gBAAoB,eAAc,KAChC,CAAC,CAAE,cACH,gBAAoB,IAAM,KACtB,GAAQ,IAAI,CAAC,CAAE,eACf,gBAAoB,MAAO,CACzB,KAAM,SACN,SAAU,EACV,IAAK,GAAG,GAAS,eACjB,QAAS,GACT,WAAY,IAEV,gBAAoB,wBAAuB,CAC3C,IAAK,GAAS,SACd,OAAQ,UAQpB,gBAAoB,IAAe,CAAE,UAAW,GAAQ,wBACtD,gBAAoB,IAAM,CAAE,UAAW,GAAM,UAAW,OACtD,gBAAoB,IAAM,CAAE,KAAM,GAAM,GAAI,IAC1C,gBAAoB,IAAmB,WAQxC,GAAc,CAAC,CAAE,QAAO,GAAM,kBAEvC,gBAAoB,KAAuB,KACvC,gBAAoB,EAAO,CAAE,KAAM,GAAM,YAAa,O,6OC5H9D,KAAM,GAAY,QAAW,IAAO,EAClC,KAAM,CACJ,QAAS,OACT,WAAY,UAEd,MAAO,CACL,KAAM,MAUG,EAAY,CAAC,CACxB,eACA,gBACA,2BACI,CACJ,KAAM,IAAU,IAEhB,MACE,iBAAoB,IAAO,CACzB,UAAW,OACX,SAAU,IAAK,GAAa,IAC5B,UAAW,GAAQ,MAEjB,gBAAoB,IAAY,CAAE,SAAU,GAAM,KAAM,SAAU,aAAc,UAC9E,gBAAoB,IAAY,OAElC,gBAAoB,IAAW,CAC/B,UAAW,GAAQ,MACnB,YAAa,sBACb,MAAO,GACP,SAAU,IAAK,GAAa,IAC5B,WAAY,CAAE,aAAc,sBAE5B,gBAAoB,IAAY,CAAE,aAAc,SAAU,QAAS,IAAM,MACvE,gBAAoB,IAAa,S,sEC5C3C,KAAM,IAAY,QAAW,IAAU,EACrC,QAAS,CACP,MAAO,QACP,QAAS,QAEX,KAAM,CACJ,OAAQ,GAAM,QAAQ,GAAI,EAAG,EAAG,OASvB,GAAgB,CAAC,CAC5B,2BACA,0BACI,CACJ,KAAM,IAAU,KAEhB,MACE,iBAAoB,MAAO,CAAE,UAAW,GAAQ,SAC5C,gBAAoB,IAAY,CAChC,UAAW,GAAQ,KACnB,aAAc,WACd,QAAS,IAEP,gBAAoB,IAAgB,OAEtC,gBAAoB,IAAY,CAAE,QAAS,MAAQ,YAChD,IAAoD,EAAG,O,4HClBlE,KAAM,IAAY,QAAW,IAAU,EACrC,QAAS,CACP,WAAY,cACZ,UAAW,mBAEb,SAAU,CACR,QAAS,GAAM,QAAQ,EAAG,EAAG,EAAG,IAElC,SAAU,CACR,MAAO,WAsBE,GAAU,CAAC,CACtB,WACA,iBACA,gBACA,kBACA,oBACI,CACJ,KAAM,IAAU,KAEhB,MACE,iBAAoB,KAAM,CAAE,UAAW,GAAQ,SAC3C,gBAAoB,KAAY,CAChC,MAAO,gBAAoB,IAAY,CAAE,QAAS,MAAQ,WAC1D,OACE,gBAAoB,KAAQ,CAAE,MAAO,UAAW,QAAS,IAAM,MAAkB,eAKnF,gBAAoB,IAAS,MAC7B,GAAc,KAAK,SAAW,GAAK,GAAc,UAAU,SAAW,GACtE,gBAAoB,KAAa,KAC7B,gBAAoB,IAAY,CAAE,QAAS,aAAe,mDAK9D,GAAc,KAAK,OAAS,GAC5B,gBAAoB,KAAa,KAC7B,gBAAoB,IAAY,CAAE,QAAS,aAAe,QAC1D,gBAAoB,KAAQ,CAC5B,GAAI,kBACJ,SAAW,GAAG,C,MACZ,UAAe,oBAAG,SAAH,cAAW,QAE5B,QAAS,WACT,UAAW,GAAQ,SACnB,MAAO,GAAQ,UAEb,GAAc,KAAK,IAAI,GACvB,gBAAoB,KAAU,CAC5B,SAAU,IAAW,GACrB,MAAO,GACP,IAAK,EACL,MAAO,GAEL,MAMV,GAAc,UAAU,OAAS,GACjC,gBAAoB,KAAa,KAC7B,gBAAoB,IAAY,CAAE,QAAS,aAAe,aAC1D,gBAAoB,KAAM,CAAE,eAAgB,GAAM,MAAO,IACvD,GAAc,UAAU,IAAI,GAC5B,gBAAoB,KAAU,CAC5B,IAAK,EACL,MAAO,GACP,OAAQ,GACR,QAAS,IAAM,GAAc,IAE3B,gBAAoB,KAAU,CAC9B,KAAM,QACN,cAAe,GACf,UAAW,GAAQ,SACnB,MAAO,UACP,QAAS,GAAQ,QAAQ,SAAS,GAClC,SAAU,GACV,MAAO,EACP,KAAM,IAEN,gBAAoB,KAAc,CAAE,GAAI,EAAQ,QAAS,U,uCC9F3E,KAAM,IAAY,QAAW,IAAU,EACrC,YAAa,CACX,MAAO,GAAM,QAAQ,KAAK,QAC1B,WAAY,GAAM,QAAQ,WAAW,QACrC,aAAc,OAEhB,YAAa,CACX,OAAQ,GAAM,QAAQ,EAAG,EAAG,EAAG,GAC/B,QAAS,QAEX,QAAS,CACP,MAAO,MACP,OAAQ,GAAM,QAAQ,EAAG,GACzB,QAAS,GAAM,QAAQ,EAAG,OAgBxB,GAAU,CACd,CACE,MAAO,OACP,MAAO,OACP,UAAW,GACX,OAAS,IACP,gBAAoB,QAAM,CAAE,GAAI,GAAO,KAAO,IAAM,GAAO,OAG/D,CACE,MAAO,cACP,MAAO,eAET,CACE,MAAO,QACP,MAAO,SAET,CACE,MAAO,OACP,MAAO,QAET,CACE,MAAO,YACP,MAAO,cAIL,GAAc,CAAC,CACnB,eACA,2BACA,mBACA,0BACI,CACJ,KAAM,IAAU,KAEhB,MACE,iBAAoB,MAAO,CAAE,UAAW,GAAQ,aAC5C,gBAAoB,GAAe,CACnC,wBAAyB,GACzB,oBAAqB,KAErB,gBAAoB,IAAS,CAAE,UAAW,GAAQ,QAAS,YAAa,aACxE,gBAAoB,IAAM,CAAE,KAAM,GAAM,GAAI,IAC1C,GACA,gBAAoB,IAAY,CAAE,QAAS,MACvC,GAAG,MACH,GAAkB,EAAI,eAAiB,cACvC,gBAAoB,OAAQ,CAAE,UAAW,GAAQ,aAAe,IAAM,GAAa,KAAO,KAG9F,gBAAoB,IAAY,CAAE,QAAS,MAAQ,GAAG,iBAOnD,GAAe,CAAC,CAAE,kBAAkB,CAC/C,KAAM,IAAa,cAAO,MAEpB,CAAC,GAAa,IAAiB,eAAS,IACxC,CAAC,GAAiB,IAAsB,eAAS,CACrD,SAAU,GACV,QAAS,KAGL,CAAC,EAAiB,GAAsB,eAAS,IAEjD,CACJ,UACA,QACA,MAAO,GACL,cAAS,SAEJ,MADgB,IAAW,eAClB,MAAM,IAAK,IAAQ,C,mBAAI,OACrC,KAAM,GAAO,SAAS,KACtB,YAAa,GAAO,SAAS,YAC7B,MACE,MAAO,QAAO,OAAP,eAAa,QAAU,SAAW,OAAO,OAAP,eAAa,MAAQ,OAChE,KAAM,GAAO,KACb,UACE,MAAO,QAAO,OAAP,eAAa,YAAc,SAC9B,OAAO,OAAP,eAAa,UACb,OACN,IAAK,YACH,QAAO,SAAS,YAAhB,eAA2B,kBAAkB,WAC7C,SACE,GAAO,KAAK,kBAAkB,YAAY,GAAO,SAAS,UAE/D,IAyCH,GAvCA,gBAAU,IAAM,CACd,GAAI,EAAS,CACX,GAAI,IAAc,EAKd,GAAgB,WAAa,IAC/B,IAAc,EAAQ,OAAQ,IAC5B,GAAgB,SAAS,SAAS,GAAO,QAKzC,GAAgB,QAAQ,OAAS,GACnC,IAAc,GAAY,OACvB,IACC,GAAO,WACP,GAAgB,QAAQ,SAAS,GAAO,aAK1C,IACF,IAAc,GAAY,OACvB,IAAQ,C,aACP,cAAO,OAAP,eAAa,kBAAkB,SAAS,SAAS,MACjD,QAAO,OAAP,eACI,kBAAkB,SACnB,SAAS,GAAY,MAAM,KAAK,KAAK,QACxC,QAAO,cAAP,eACI,kBAAkB,SACnB,SAAS,QAIlB,EAAmB,MAEpB,CAAC,GAAiB,GAAa,IAC9B,EACF,MAAO,iBAAoB,YAAU,MAEvC,GAAI,EACF,MACE,iBAAoB,IAAO,CAAE,SAAU,SAAW,oDACxC,EAAM,YAIpB,GAAI,CAAC,GAAW,EAAQ,SAAW,EACjC,MAAO,iBAAoB,cAAY,CAAE,QAAS,OAAQ,MAAO,iCAGnE,KAAM,IAAe,IAAM,CACzB,GAAmB,CACjB,SAAU,GACV,QAAS,MAIP,GAAkB,IAAW,CACjC,GAAmB,IAAc,KAC5B,GACH,SAAU,OAIR,GAAiB,IAAW,CAChC,GAAI,GAAgB,QAAQ,SAAS,IAAS,CAC5C,GAAmB,IAAc,KAC5B,GACH,QAAS,GAAU,QAAQ,OAAO,IAAQ,KAAS,OAErD,OAGF,GAAmB,IAAc,KAC5B,GACH,QAAS,CAAC,GAAG,GAAU,QAAS,QAI9B,GAAgB,EAAQ,OAC5B,CAAC,GAAK,KACA,IAAK,MAAQ,GAAI,KAAK,QAAQ,GAAK,MAAQ,GAC7C,GAAI,KAAK,KAAK,GAAK,MAEjB,GAAK,WAAa,GAAI,UAAU,QAAQ,GAAK,WAAa,GAC5D,GAAI,UAAU,KAAK,GAAK,WAEnB,IAET,CACE,KAAM,GACN,UAAW,KAIf,MACE,iBAAoB,WAAgB,KAChC,gBAAoB,IAAM,CAAE,UAAW,IACrC,IACA,gBAAoB,IAAM,CAAE,KAAM,GAAM,GAAI,GACxC,gBAAoB,GAAS,CAC7B,QAAS,GACT,cAAe,GACf,aAAc,GACd,eAAgB,GAChB,cAAe,MAInB,gBAAoB,IAAM,CAAE,KAAM,GAAM,GAAI,GAAc,EAAI,IAC5D,gBAAoB,SAAO,CAC3B,QAAS,CAAE,OAAQ,GAAM,SAAU,GAAI,OAAQ,IAC/C,KAAM,EACN,QAAS,GACT,MACE,gBAAoB,GAAa,CAC/B,YAAa,GACb,gBAAiB,EAAgB,OACjC,wBACG,IAAgB,WAAa,GAAK,EAAI,GACvC,GAAgB,QAAQ,OAE1B,oBAAqB,IAAM,GAAc,CAAC,YChQ7C,GAAmB,IAAM,CACpC,KAAM,CAAC,GAAa,IAAkB,0BAAmB,SACnD,CAAC,GAAa,IAAkB,eAAS,YAAe,IAExD,GAAgB,GAAU,CAC9B,EAAM,iBACN,GAAe,EAAM,OAAO,QAG9B,gBAAU,IAAM,GAAe,YAAe,IAAK,CAAC,KAEpD,QACE,IAAM,CACJ,GAAe,KAEjB,IACA,CAAC,KAGH,KAAM,IAAuB,IAAM,CACjC,GAAe,KAGjB,MACE,iBAAoB,QAAM,CAAE,QAAS,QACjC,gBAAoB,UAAQ,CAAE,MAAO,WACrC,gBAAoB,WAAS,KAC3B,gBAAoB,IAAM,CAAE,UAAW,GAAM,UAAW,OACtD,gBAAoB,IAAM,CAAE,KAAM,GAAM,GAAI,IAC1C,gBAAoB,EAAW,CAC/B,aAAc,GACd,qBAAsB,GACtB,YAAa,MAGf,gBAAoB,IAAM,CAAE,KAAM,GAAM,GAAI,IAC1C,gBAAoB,GAAc,CAClC,YAAc,aAAe,IAAI,kBAAkB,gBC7CpD,GAAa,IAAM,CAC9B,KAAM,IAAW,WACX,CACJ,QACA,WACA,SACA,YACA,cACA,gBACA,UACA,cACE,WAEE,EAAkB,QAAY,GAAS,QAC7C,sBAAU,IAAM,CAEd,GAAI,GAAS,SAAW,EACtB,OAGF,KAAM,GACJ,UAAS,GAAS,OAAO,UAAU,GAAI,CAAE,WAAY,KAAQ,GAE3D,EAAM,SACR,EAAW,EAAM,SAGf,EAAM,OACR,GAAQ,EAAM,OAGZ,EAAM,YACR,EAAc,EAAM,YAGlB,EAAM,OACR,GAAS,EAAM,QAEhB,CAAC,EAAiB,GAAU,GAAS,GAAU,EAAe,IAEjE,gBAAU,IAAM,CACd,KAAM,GAAY,cAChB,CACE,MAAO,GACP,SACA,cACA,WAEF,CAAE,YAAa,aAEX,GAAS,GAAG,OAAO,SAAS,YAAY,IAM9C,OAAO,QAAQ,aAAa,KAAM,SAAS,MAAO,KACjD,CAAC,GAAM,GAAO,GAAY,IAEtB,MAGI,GAAa,IAAM,CAC9B,KAAM,IAAS,WAEf,MACE,iBAAoB,KAAuB,KACvC,gBAAoB,GAAY,MAChC,IAAU,gBAAoB,GAAkB,S,wHC/DjD,KAAM,GAAwB,CAAC,CAAE,cAAe,CACrD,KAAM,CACJ,OAAQ,CAAE,UAAS,QAAO,UACxB,WAEJ,MAAI,GACK,gBAAoB,WAAU,MAEnC,EAEA,gBAAoB,qBAAoB,CACtC,MAAO,kDACP,MAAO,IAKR,kBAAO,QAAQ,QAIb,gBAAoB,WAAgB,KAAM,EAAS,CAAE,QAAS,EAAM,WAHlE,gBAAoB,aAAY,CAAE,QAAS,OAAQ,MAAO,mC,uICzBrE,KAAM,GAAY,QAAW,GAAU,EACrC,KAAM,CACJ,QAAS,OACT,eAAgB,gBAChB,IAAK,EAAM,QAAQ,GACnB,OAAQ,EAAM,QAAQ,EAAG,OAIhB,EAAoB,IAAM,CACrC,KAAM,CAAE,gBAAe,qBAAsB,WACvC,EAAU,IAEhB,MAAI,CAAC,GAAiB,CAAC,EACd,gBAAoB,WAAgB,MAI3C,gBAAoB,MAAO,CAAE,cAAe,wBAA0B,UAAW,EAAQ,MACrF,gBAAoB,IAAQ,CAC5B,aAAc,gBACd,SAAU,CAAC,EACX,QAAS,EACT,UAAW,gBAAoB,IAAkB,OACjD,YAIA,gBAAoB,IAAQ,CAC5B,aAAc,YACd,SAAU,CAAC,EACX,QAAS,EACT,QAAS,gBAAoB,IAAqB,OAClD,W,8FC5BD,KAAM,GAAe,qBAAe,CACzC,GAAI,WAGO,EAAmB,qBAAe,CAC7C,GAAI,gBAGO,EAAe,mBAAa,CACvC,GAAI,SACJ,KAAM,CACJ,uBAAiB,CACf,IAAK,IACL,KAAM,CAAE,aAAc,kBAAiB,YAAa,kBACpD,QAAS,CAAC,CAAE,eAAc,iBACjB,GAAI,KAAa,CAAE,eAAc,mBAI9C,OAAQ,CACN,KAAM,EACN,SAAU,KAID,EAAa,EAAa,QACrC,8BAAwB,CACtB,KAAM,aACN,UAAW,IAAM,uCAAkC,KAAK,GAAK,EAAE,YAC/D,WAAY,KAUH,EAAiB,EAAa,QACzC,8BAAwB,CACtB,KAAM,iBACN,UAAW,IAAM,uCAAkC,KAAK,GAAK,EAAE,YAC/D,WAAY,KAIH,EAAY,EAAa,QACpC,+BAAyB,CACvB,KAAM,YACN,UAAW,CACT,KAAM,IAAM,uCAAiC,KAAK,GAAK,EAAE,eAWlD,EAAgB,EAAa,QACxC,+BAAyB,CACvB,KAAM,gBACN,UAAW,CACT,KAAM,IAAM,uCAAiC,KAAK,GAAK,EAAE,eAKlD,EAAe,EAAa,QACvC,+BAAyB,CACvB,KAAM,eACN,UAAW,CACT,KAAM,IAAM,wCAAoC,KAAK,GAAK,EAAE,kBAWrD,EAAmB,EAAa,QAC3C,+BAAyB,CACvB,KAAM,mBACN,UAAW,CACT,KAAM,IAAM,wCAAoC,KAAK,GAAK,EAAE,kBAKrD,EAAqB,EAAa,QAC7C,+BAAyB,CACvB,KAAM,qBACN,UAAW,CACT,KAAM,IACJ,gCAA0C,KACxC,GAAK,EAAE,wBAMJ,EAAwB,EAAa,QAChD,+BAAyB,CACvB,KAAM,wBACN,UAAW,CACT,KAAM,IACJ,wCAA6C,KAC3C,GAAK,EAAE,2BAMJ,EAAoB,EAAa,QAC5C,+BAAyB,CACvB,KAAM,oBACN,UAAW,CACT,KAAM,IACJ,gCAAyC,KAAK,GAAK,EAAE,wB,2PCjItD,KAAM,GAAiB,CAAC,CAAE,YAAa,C,MAC5C,KAAM,GAAS,aAAO,gBACtB,MACE,iBAAoB,KAAQ,CAC1B,WAAY,GACZ,UAAW,CACT,UAAW,QAAa,KAAO,SAAS,YAAhB,OAA6B,UAAW,GAChE,KAAM,QAAa,EAAO,KAAM,GAChC,KAAM,QAAa,EAAO,SAAS,KAAM,O,cCLjD,KAAM,GAAsB,4BAEf,EAAuB,GAAQ,C,QAC1C,eAAQ,uBAAQ,WAAR,cAAkB,cAAlB,cAAgC,KAE7B,EAAS,IAElB,gBAAoB,KAAQ,KACxB,gBAAoB,KAAO,CAAE,KAAM,IAAK,QAAS,gBAAoB,oBAAmB,QACxF,gBAAoB,KAAO,CAC3B,KAAM,4BACN,QAAS,gBAAoB,eAAoB,SAW5C,EAAsB,GAAW,C,MAC5C,KAAM,CAAE,UAAW,kBAInB,MAFkB,MAAO,SAAS,cAAhB,cAA8B,IAO9C,gBAAoB,KAAQ,KACxB,gBAAoB,KAAO,CAAE,KAAM,KAAM,QAAS,gBAAoB,EAAgB,CAAE,OAAQ,OAL7F,gBAAoB,8BAA6B,CAAE,WAAY,M,wGC5BnE,KAAM,GAAwB,mBAAa,CAChD,GAAI,mCAQO,EAAiB,mBAAa,CACzC,GAAI,6B,2JCdN,KAAM,GAAY,QAAW,CAC3B,cAAe,CACb,SAAU,QAEZ,SAAU,CACR,MAAO,OACP,aAAc,UAIL,EAAqB,CAAC,CACjC,SACA,YAAY,EACZ,aAAa,GACb,SAAS,GACT,WAOG,CACH,KAAM,GAAU,IACV,EAAW,IAAG,C,MAClB,uBAAoB,IAAc,CAChC,UAAW,EAAQ,SACnB,uBAAwB,CAAE,QAAS,MACnC,QACE,GAEI,GAAG,EAAO,WAAW,KAAO,cAAP,OAAsB,EAAO,YAExD,UACE,gBAAoB,IAAc,CAChC,KAAM,EACN,aAAc,SACd,KAAM,EAAO,KACb,QAAS,YAMX,EAAc,CAAC,CAAE,cACrB,EAAS,gBAAoB,OAAM,CAAE,GAAI,EAAO,UAAY,GAAY,gBAAoB,WAAgB,KAAM,GAE9G,EAAkB,CAAC,CAAE,cACzB,EACE,gBAAoB,WAAgB,KAChC,gBAAoB,IAAU,CAAE,WAAY,aAAc,UAAW,EAAQ,eAC3E,GAEF,gBAAoB,IAAS,CAAE,UAAW,QAG9C,gBAAoB,WAAgB,KAAM,GAG9C,MACE,iBAAoB,EAAa,KAC7B,gBAAoB,EAAiB,KACnC,gBAAoB,EAAU,U,mEChEjC,WAAsB,EAAK,EAAQ,CACxC,MAAO,GAAO,mBACZ,+CAEE,EACA,EAAI,kBAAkB,W,0LCMrB,KAAM,GAAe,CAAC,CAC3B,cAGG,CACH,KAAM,GAA0B,kBAAY,MACtC,EAAS,aAAO,gBACtB,MAAK,GAEH,gBAAoB,eAAc,CAAE,cAAe,gBAC9C,kBAAU,QAET,EAAS,IAAI,CAAC,EAAQ,IAAO,C,QAC3B,uBAAoB,IAAM,CAAE,IAAK,GAC7B,gBAAoB,IAAW,KAC7B,gBAAoB,iBAAgB,CACpC,MAAO,KAAO,SAAS,QAAhB,OAAyB,EAAO,SAAS,QAGlD,gBAAoB,IAAa,KAAM,EAAO,SAAS,aACvD,gBAAoB,IAAa,KAC/B,gBAAoB,SAAQ,CAC5B,GAAI,EAAwB,CAC1B,UAAW,QACT,KAAO,SAAS,YAAhB,OAA6B,UAC7B,GAEF,KAAM,QAAa,EAAO,KAAM,GAChC,KAAM,QAAa,EAAO,SAAS,KAAM,KAE3C,MAAO,UACP,cAAe,aACf,iBArBR,MAJc,O,kMCCjB,KAAM,GAAY,CAAC,CACxB,WACA,QACA,UACA,UACA,aAOG,CACH,KAAM,CAAC,CAAE,GAAmB,UACtB,EAA0B,kBAAY,MACtC,EAAS,aAAO,gBACtB,GAAI,CAAC,EAAU,MAAO,MAEtB,KAAM,GAAY,EAAS,IAAI,IAAU,C,OACvC,KAAM,IAAmB,yBAAmB,GAAQ,MACpD,MAAO,CACL,UACA,SAAU,CACR,QAAS,EAAwB,CAC/B,UAAW,QACT,OAAO,SAAS,YAAhB,QAA6B,UAC7B,GAEF,KAAM,QAAa,GAAO,KAAM,GAChC,KAAM,QAAa,GAAO,SAAS,KAAM,KAE3C,oBACA,sBAAuB,GACpB,IAAI,IAAK,2BAAqB,GAAG,CAAE,YAAa,WAChD,KAAK,UAKR,EAAiB,CACrB,qBACA,sBACA,sBAGI,EAAiB,CACrB,0BAAwC,IAG1C,MACE,iBAAoB,WAAgB,KAChC,GAAY,GAAa,EAAU,OAAS,EAC5C,gBAAoB,QAAO,CACzB,UAAW,EACX,QAAS,CACP,OAAQ,GACR,SAAU,GACV,OAAQ,GACR,mBAAoB,IAEtB,KAAM,EACN,QAAS,GAAW,EACpB,QAAS,GAAW,EACpB,MACE,EACI,GAAG,MAAU,EAAU,UACvB,QAAQ,EAAU,YAI1B,gBAAoB,aAAY,CAC9B,QAAS,OACT,MAAO,uBACP,YAAa,sEACb,OACE,gBAAoB,SAAQ,CAC1B,MAAO,UACP,GAAI,8DACJ,QAAS,aACT,a,+LCzEd,KAAM,GAAS,CACb,UAAW,YACX,aAAc,gBAoBV,EAAc,CAAC,CACnB,SACA,WACA,WAKG,CAOH,KAAM,GAAU,GANE,KAAW,CAC3B,eAAgB,CACd,aAAc,UACV,EAAO,SAAW,EAAO,SAAW,QAItC,CAAE,MAAO,GAAS,mBAElB,EAAQ,EAAO,EAAO,WAEtB,EAAgB,EAAS,OAAO,GAChC,EAAO,kBAAoB,cACxB,EAGE,gBAAU,EAAM,GAFd,GAMT,MAAO,GAAO,iBAAoB,YAClC,EAAO,gBAAgB,IAI3B,MACE,iBAAoB,WAAgB,KAChC,gBAAoB,gBAAe,CAAE,MAAO,EAAO,MAAO,YAAa,EAAO,aAC5E,IAAU,EACV,gBAAoB,gBAAe,KAAM,6CAGvC,MAEJ,gBAAoB,MAAO,CAAE,UAAW,EAAQ,gBAC9C,gBAAoB,EAAO,CAAE,cAAe,wBAAyB,SAAU,OAM5E,EAAqB,CAAC,CACjC,gBAGG,CACH,KAAM,CAAC,EAAa,GAAkB,eAAS,GACzC,EAAa,aAAO,MAEpB,CACJ,MAAO,EACP,UACA,SACE,cAAS,SAcJ,MAbgB,GAAW,YAAY,CAC5C,OAAQ,CACN,iDAAkD,MAEpD,OAAQ,CACN,aACA,OACA,WACA,YACA,aACA,gBAGY,MAAM,OAAQ,GAAW,C,OACvC,MAAO,CAAC,CAAC,OAAO,SAAS,cAAhB,eAA8B,iCAIrC,EAAmB,EAAW,GAEpC,MAAI,GAEA,gBAAoB,IAAqB,KACrC,gBAAoB,UAAS,KAC3B,gBAAoB,WAAU,QAMpC,EAEA,gBAAoB,IAAqB,KACrC,gBAAoB,UAAS,KAC3B,gBAAoB,eAAc,CAClC,SAAU,QACV,MAAO,2CAEL,gBAAoB,cAAa,CAAE,SAAU,OAAQ,KAAM,EAAM,gBAQ3E,gBAAoB,IAAqB,KACrC,gBAAoB,aAAY,CAChC,cAAe,EACf,SAAU,GAAS,EAAe,GAClC,KAAM,EAAW,IAAI,CAAC,CAAE,SAAS,IAAW,EAC1C,GAAI,EAAM,WACV,aAGF,gBAAoB,UAAS,CAAE,cAAe,oBAC5C,EAAiB,OAAO,IAAI,CAAC,EAAQ,IACrC,gBAAoB,EAAa,CAC/B,IAAK,EACL,OAAQ,EACR,SAAY,GAAsB,GAClC,MAAO,S,8HC3KZ,KAAM,GAAqB,IAAM,CACtC,KAAM,GAAa,CACjB,CACE,MAAO,WACP,OAAQ,CACN,CACE,MAAO,WACP,YACE,mEACF,UAAW,eACX,gBAAiB,IAAM,MAW7B,CACE,MAAO,kBACP,OAAQ,CACN,CACE,MAAO,kBACP,YAAa,6BACb,UAAW,YAEX,gBAAiB,kBAKzB,MAAO,iBAAoB,qBAAoB,CAAE,WAAY,KCjClD,EAAoB,IAGxB,GAFQ,SAEE,gBAAoB,EAAoB,O,qGCEpD,KAAM,GAAsB,CAAC,CAAE,cAAe,C,MAEnD,KAAM,GAAoB,8BACxB,GAFgB,aAAO,gBAEb,kBAAkB,uBAA5B,OAAoD,cAGtD,MACE,iBAAoB,iBAAgB,CAClC,MAAO,gBACP,SAAU,EACV,QAAS,iBAEP,K,gLCbD,WAAiC,EAAiB,CACvD,MAAQ,IACC,EACL,KAAM,IAAM,gBAAoB,IAAW,CAAE,SAAU,UACvD,QAAS,gDACT,QAAS,IACP,EAAgB,GAAG,OAAO,SAAS,SAAS,EAAI,SAAS,aAK1D,WACL,EACA,EACA,CACA,MAAO,CAAC,CAAE,YAAa,CACrB,KAAM,GAAY,EAAgB,GAClC,MAAO,CACL,UAAW,CAAE,YAAa,OAC1B,KAAM,IAAM,yBAAmB,GAC/B,QAAS,4BAAsB,GAC/B,QAAS,IAAM,EAAoB,O,yMCvBzC,WAAqB,EAAQ,CAC3B,MAAO,GAAO,SAAS,OAAS,EAAO,SAAS,KAG3C,YAA4B,CACjC,MAAO,CACL,MAAO,WACP,MAAO,uBACP,UAAW,GACX,OAAS,GACP,gBAAoB,eAAc,CAChC,MAAO,gBAAoB,OAAM,CAAE,GAAI,EAAI,SAAS,SAAW,EAAY,EAAI,SAC/E,SAAU,EAAI,OAAO,SAAS,eAM/B,YAA6B,CAClC,MAAO,CACL,MAAO,QACP,MAAO,iCACP,OAAQ,CAAC,CAAE,cACT,gBAAoB,iBAAgB,CAClC,WAAY,EAAS,iBACrB,YAAa,WAMd,YAA4B,CACjC,MAAO,CACL,MAAO,OACP,MAAO,sB,kMC1BX,KAAM,GAAuB,CAC3B,GACA,GACA,IACG,CACH,KAAM,GAAa,KAAa,OAAS,GAAQ,SAAS,QACpD,EAAgB,CAAC,GAAQ,MAAM,oBAC/B,EAAqB,GAAQ,WAAW,GAC9C,MAAO,IAAe,IAAiB,IAG5B,EAAa,CAAC,CACzB,sBACA,YACA,UAEO,KAAM,IAAO,CAClB,KAAM,GAAY,KAAM,IAAmB,eAErC,EAAY,MAChB,EACA,KACG,CACH,SAAW,MAAQ,GACjB,GAAI,GAAK,aAAa,IAAgB,CACpC,KAAM,IAAgB,GAAK,aAAa,IACxC,GAAI,CAAC,GAAe,OAGpB,KAAM,IAAW,KAAM,IAAmB,WACxC,GACA,GACA,GAGF,GAAI,EAAqB,GAAe,GAAe,GACrD,GAAI,CAEF,KAAM,IAAa,KAAM,MADP,OAAM,GAAU,CAAE,YAAa,aACpB,OAC7B,GAAK,aACH,GACA,6BAA6B,KAAK,YAEpC,CACA,GAAK,aAAa,MAAO,UAAU,UAGrC,IAAK,aAAa,GAAe,MAMzC,YAAM,SAAQ,IAAI,CAChB,EAAU,EAAI,iBAAiB,OAAQ,OACvC,EAAU,EAAI,iBAAiB,UAAW,OAC1C,EAAU,EAAI,iBAAiB,UAAW,OAC1C,EAAU,EAAI,iBAAiB,QAAS,QACxC,EAAU,EAAI,iBAAiB,eAAgB,UAG1C,G,yDChEJ,KAAM,GACX,IAEO,IAAO,CAEZ,KAAM,GAAe,GAAI,cACvB,4BAIF,GAAI,CAAC,GAAgB,CAAC,EAAa,KACjC,MAAO,IAGT,KAAM,GAAY,GAAI,KAAI,EAAa,MACjC,EAAc,GAAmB,MAAM,GAG7C,GAAI,kBAAa,QAAS,UAAY,kBAAa,QAAS,SAC1D,MAAO,IAIT,KAAM,GAAS,GAAI,cAAc,cAAgB,WAAW,GACzD,YACG,EAAa,mBAAmB,2BAA2B,KAC3D,GAAY,mBAChB;AAAA,EAAiB,EAAa;AAAA;AAAA,YAI1B,GACJ,kBAAa,QAAS,SAClB,SAAqB,EAAU,KAAM,QACrC,EAAU,KACV,GAAU,IAAY,IACtB,GAAW,IAAI,GAAQ,gBAAgB,GAAQ,OAE/C,GAAe,EAAa,YAClC,OAAQ,iBAAa,UACd,SACH,GAAa,KAAO,GAAG,EAAU,SAAS,8BAAoC,wBAAiC,KAC/G,UACG,SACH,GAAa,KAAO,GAAG,EAAU,SAAS,uBAA6B,UAAmB,KAC1F,cAEA,MAAO,IAEX,gBAAgB,gBAAoB,KAAuB,IAC3D,GAAa,MAAM,YAAc,MACjC,GAAa,MAAQ,+BACrB,GAAa,GAAK,oBAClB,WAAc,sBAAsB,cAAe,IAC5C,IC/DE,EAAkB,IACtB,IA+BL,CA9BkB,EAChB,EACA,IACG,CACH,MAAM,KAAK,GACR,OAAO,GAAQ,EAAK,aAAa,IACjC,QAAS,GAAS,CACjB,KAAM,GAAgB,EAAK,aAAa,GACxC,GAAI,EAAe,CAEb,EAAc,MAAM,kBACtB,EAAK,aAAa,SAAU,UAG9B,GAAI,CACF,KAAM,GAA2B,EAC/B,OAAO,SAAS,MAElB,EAAK,aACH,EACA,GAAI,KAAI,EAAe,GAA0B,iBAEnD,CAEA,EAAK,YAAY,EAAK,aAAe,SAMrC,MAAM,KAAK,GAAI,qBAAqB,MAAO,QAE9C,IAKJ,WAAsB,GAAO,CAClC,KAAM,IAAM,GAAI,KAAI,IAEpB,MAAI,CAAC,GAAI,SAAS,SAAS,MAAQ,CAAC,GAAI,SAAS,SAAS,UACxD,IAAI,UAAY,KAGX,GAAI,WCzCN,KAAM,GAAuB,CAAC,CACnC,WACA,cAEO,GACL,OAAM,KAAK,EAAI,qBAAqB,MAAM,QAAQ,GAAQ,CACxD,EAAK,iBAAiB,QAAU,GAAM,CAEpC,KAAM,GAAO,EAAO,aAAa,QAE7B,CAAC,GACD,EAAK,WAAW,KAAY,CAAC,EAAK,aAAa,aACjD,GAAE,iBACF,GAAQ,EAAG,QAKV,GCnBE,EAAkB,IACtB,IACL,OAAM,KAAK,GAAI,iBAAiB,eAAe,QAAQ,IAAY,C,MACjE,KAAM,GAAS,SAAS,cAAc,UAChC,EAAa,GAAS,aAAe,GAC3C,EAAO,UAAY,uBACnB,EAAO,MAAQ,oBACf,EAAO,UACL,8KACF,EAAO,iBAAiB,QAAS,IAC/B,UAAU,UAAU,UAAU,IAEhC,sBAAU,gBAAV,QAAyB,QAAQ,KAE5B,IClBE,EAAqB,IACzB,IAAO,C,OAEZ,aAAI,cAAc,gBAAlB,SAAiC,SAE1B,ICLE,GAAuB,IAC3B,IAAO,C,OAEZ,aAAI,cAAc,0BAAlB,SAA2C,SAEpC,ICCE,GAAa,CAAC,CACzB,iBACA,aACA,cAEO,GAAO,CACZ,KAAM,GAAW,MAAM,KACrB,EAAI,iBAAiB,kCACrB,OAAO,GAAK,C,OAAG,YAAK,aAAa,UAAlB,eAA2B,WAAW,MAEvD,GAAI,GAAQ,EAAS,OAErB,MAAI,GAAQ,GACV,GAAU,GAGZ,EAAS,QAAQ,GACf,EAAQ,iBAAiB,OAAQ,IAAM,CACrC,GAAS,EAEL,IAAU,GACZ,EAAS,MAKR,G,2BClCX,KAAM,IAAe,kCACf,GAAe,oCACf,GAAgB,iCAET,GAAiB,IAAS,CACrC,GAAI,GAAK,UAAY,GAAK,WAAa,OAAQ,CAC7C,KAAM,IAAO,GAAK,aAAa,SAAW,GACtC,GAAK,MAAM,KACb,GAAK,aAAa,MAAO,cAEvB,GAAK,MAAM,KACb,GAAK,aAAa,MAAO,cAEvB,GAAK,MAAM,KACb,GAAK,aAAa,MAAO,cAG7B,MAAO,KAGH,GAAoB,IAAwB,IAAS,CACzD,GAAI,GAAK,WAAa,SAAU,CAC9B,KAAM,GAAM,GAAK,aAAa,OAC9B,GAAI,CAAC,EACH,UAAK,SACE,GAGT,GAAI,CACF,KAAM,GAAS,GAAI,KAAI,GAElB,GAD8B,KAAK,GAAQ,EAAO,OAAS,IAE9D,GAAK,eAEA,EAAP,CAEA,QAAQ,KAAK,uBAAuB,KACpC,GAAK,UAGT,MAAO,KAOI,GAAe,IAAW,CACrC,KAAM,IACJ,oBAAQ,uBAAuB,wBAAyB,GAE1D,MAAO,IAAO,CACZ,aAAkB,0BAA2B,IAC7C,KAAM,GAAU,CAAC,QAEjB,MAAI,IAAmB,OAAS,GAC9B,cACE,yBACA,GAAiB,KAEnB,EAAQ,KAAK,WAGR,cAAmB,EAAI,UAAW,CACvC,SAAU,EACV,YAAa,CAAC,SACd,eAAgB,GAChB,WAAY,OC7DL,GAAY,CAAC,CAAE,UACnB,IACL,IACG,qBAAqB,QAAQ,GAC7B,mBAAmB,YAAa,UAAU,cAEtC,ICVE,GAAmB,IACvB,IACL,YAAW,IAAM,C,OAEf,GAAI,OAAO,SAAS,KAAM,CACxB,KAAM,GAAO,OAAO,SAAS,KAAK,MAAM,GACxC,uBAAK,cAAc,IAAI,OAAvB,SAAgC,mBAEjC,KACI,ICTE,GAAY,MACvB,GACA,KACG,CACH,GAAI,GAEJ,GAAI,MAAO,KAAS,SAClB,EAAM,GAAI,aAAY,gBAAgB,GAAM,aAAa,wBAChD,aAAgB,SACzB,EAAM,OAEN,MAAM,IAAI,OAAM,gCAGlB,SAAW,KAAe,IACxB,EAAM,KAAM,GAAY,GAG1B,MAAO,I,oDCcF,YAA+B,CACpC,kBACA,WACA,mBAIA,CAYA,MAVI,KAKA,IAAoB,sBAKpB,CAAC,IAAW,IAAoB,WAC3B,WAIL,CAAC,IAAW,IAAoB,WAC3B,gBAIJ,GAKD,IAAoB,WACf,2BAIL,IAAoB,cACf,sBAIL,IAAoB,QACf,sBAIF,gBAnBE,oBA4FJ,YACL,GACA,GACA,CACA,KAAM,GAAW,IAAK,IAEtB,OAAQ,GAAO,UACR,OAEC,GAAO,QAAU,YACnB,GAAS,SAAW,IAGtB,EAAS,gBAAkB,GAAO,MAClC,EAAS,UAAY,GAAO,UAC5B,UAEG,iBACH,EAAS,eAAiB,GAG1B,EAAS,aAAe,OACxB,UAEG,UAEC,MAAO,IAAO,MAAS,UACzB,GAAS,KAAO,GAAO,MAGzB,EAAS,eAAiB,GAC1B,EAAS,QAAU,GAAO,QAC1B,EAAS,aAAe,GAAO,aAC/B,UAEG,WACH,EAAS,SAAW,EAAS,SAAS,OAAO,GAAO,KACpD,cAGA,KAAM,IAAI,OAId,MACE,CAAC,cAAe,sBAAsB,SAAS,EAAS,kBACxD,CAAC,iBAAkB,WAAW,SAAS,GAAO,OAE9C,GAAS,gBAAkB,aAC3B,EAAS,SAAW,IAGf,EAGF,YACL,GACA,GACA,EACA,EASD,C,UACC,KAAM,CAAC,EAAO,GAAY,iBAAW,GAAS,CAC5C,gBAAiB,WACjB,OACA,eAAgB,GAChB,SAAU,KAGN,EAAqB,aAAO,KAG5B,CAAE,MAAO,IAAkB,SAAc,SAAY,CACzD,EAAS,CAAE,KAAM,mBAEjB,GAAI,CACF,KAAM,IAAa,KAAM,GAAmB,cAC1C,CAAE,QAAM,aAAW,QACnB,GAIF,SAAS,CAAE,KAAM,UAAW,QAAS,GAAY,SAE1C,SACA,GAAP,CACA,EAAS,CAAE,KAAM,UAAW,aAAc,GAAG,WAI9C,CAAC,EAAoB,GAAM,GAAW,EAAM,IAIzC,GAAa,aAAO,CACxB,QAAS,OACT,OAAQ,IAAM,KAEhB,UAAW,QAAU,CAAE,QAAS,EAAM,QAAS,OAAQ,IAGvD,eAAS,SAAY,CACnB,EAAS,CAAE,KAAM,OAAQ,MAAO,aAGhC,KAAM,IAAkB,WAAW,IAAM,CACvC,EAAS,CAAE,KAAM,OAAQ,MAAO,cAC/B,KAEH,GAAI,CAYF,OAXe,KAAM,GAAmB,eACtC,CACE,QACA,aACA,QAEF,IAAO,CACL,EAAS,CAAE,KAAM,WAAY,gBAK1B,UAEE,GAAW,QAAQ,QAItB,EAAS,CAAE,KAAM,OAAQ,MAAO,gBAHhC,IAAW,QAAQ,SACnB,EAAS,CAAE,KAAM,OAAQ,MAAO,wBAIlC,UACG,SACH,EAAS,CAAE,KAAM,OAAQ,MAAO,eAChC,cAGA,EAAS,CACP,KAAM,OACN,MAAO,QACP,UAAW,GAAI,OAAM,6BAEvB,aAEG,GAAP,CACA,EAAS,CAAE,KAAM,OAAQ,MAAO,QAAS,UAAW,YACpD,CAEA,aAAa,MAEd,CAAC,GAAM,EAAM,GAAW,EAAoB,EAAU,KAYlD,CACL,MAXmB,cACnB,IACE,GAAsB,CACpB,gBAAiB,EAAM,gBACvB,eAAgB,EAAM,eACtB,QAAS,EAAM,UAEnB,CAAC,EAAM,gBAAiB,EAAM,QAAS,EAAM,iBAK7C,iBACA,KAAM,EAAM,KACZ,QAAS,EAAM,QACf,oBAAqB,MAAM,eAAN,eAAoB,WACzC,iBAAkB,MAAM,YAAN,eAAiB,WACnC,SAAU,EAAM,UC7RpB,KAAM,IAAY,QAAW,IAAU,EACrC,UAAW,CACT,WAAY,QACZ,SAAU,gCACV,UAAW,GAAM,QAAQ,GACzB,2CAA4C,CAC1C,WAAY,QACZ,SAAU,0BAOV,GAAwB,oBAC5B,IAGI,GAAyB,CAAC,CAC9B,YACA,gBACI,CACJ,KAAM,CAAE,IAAK,GAAS,WAChB,CAAE,OAAM,YAAW,QAAS,GAC5B,EAAQ,GAAe,EAAM,EAAW,EAAM,GACpD,MACE,iBAAoB,GAAsB,SAAU,CAAE,MAAO,GACzD,KAcK,GACX,CAAC,GAAW,KACX,GAEG,MAAM,cAAc,GAAwB,CAAE,UAAW,IACrD,MAAM,cAAc,GAAW,IAAK,KAajC,GAAoB,IAAM,iBAAW,IAerC,GAAwB,IAAc,CACjD,KAAM,IAAW,WACX,EAAQ,UACR,EAAqB,aAAO,KAC5B,EAAqB,aAAO,MAC5B,EAAoB,aAAO,gBAC3B,CAAE,YAAY,GAAI,QAAO,GAAI,QAAO,IAAO,GAC3C,CAAE,SAAO,QAAM,QAAS,IAAY,KAEpC,CAAC,GAAU,IAAe,iBAC1B,CAAC,GAAK,IAAU,eAAS,MAGzB,CAAE,aAAa,iBAAW,0BAE1B,GAAwB,kBAAY,IAAM,CAC9C,GAAI,CAAC,IAAO,CAAC,GAAU,OAEvB,KAAM,IAAS,GAAI,cAAc,4BACjC,GAAS,QAAQ,IAAW,CAC1B,KAAM,IAAS,KAAK,IAAI,GAAI,wBAAwB,IAAK,GACzD,GAAQ,MAAM,IAAM,GAChB,GAAG,GAAS,GAAO,wBAAwB,WAC3C,GAAG,UAER,CAAC,GAAK,KAET,gBAAU,IACR,MACA,OAAO,iBAAiB,SAAU,GAAuB,IACzD,OAAO,iBAAiB,SAAU,IAC3B,IAAM,CACX,OAAO,oBAAoB,SAAU,GAAuB,IAC5D,OAAO,oBAAoB,SAAU,MAGtC,CAAC,GAAuB,KAG3B,KAAM,IAAoB,kBAAY,IAAM,CAC1C,GAAI,CAAC,GAAK,OACV,KAAM,IAAS,GAAI,cAAc,cAC7B,IACF,IAAO,MAAM,MAAQ,GAAG,GAAI,wBAAwB,YAErD,CAAC,KAEJ,gBAAU,IACR,MACA,OAAO,iBAAiB,SAAU,IAC3B,IAAM,CACX,OAAO,oBAAoB,SAAU,OAKzC,KAAM,IAAY,kBAChB,CAAC,GAAY,KACX,GAAY,GAAY,CACtB,GAAY,EAAkB,kBAAkB,uBAChD,EAAW,CACT,qBACA,SAAU,CACR,QACA,QACA,aAEF,KAAM,KAER,IACA,IACA,KACA,EAAmB,GACnB,GAAU,CACR,IAAK;AAAA;AAAA,2BAEY,EAAM,WAAW;AAAA,+BACb,EAAM,QAAQ,KAAK;AAAA,oCACd,EAAM,QAAQ,QAAQ;AAAA;AAAA,kCAExB,EAAM,QAAQ,KAAK;AAAA,kCACnB,EAAM,QAAQ,WAAW;AAAA,oCACvB,EAAM,QAAQ,QAAQ;AAAA,+CACX,EAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAcxC,EAAM,QAAQ;AAAA,wCACK,EAAM,QAAQ;AAAA;AAAA;AAAA,4CAGV,EAAM,QAAQ;AAAA;AAAA;AAAA;AAAA,gCAI1B,EAAM,QAAQ,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,uCAKZ,EAAM,QAAQ,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gCAS1B,EAAM,QAAQ,OAAO;AAAA;AAAA;AAAA,gCAGrB,EAAM,QAAQ,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCAMpB,EAAM,QAAQ,WAAW;AAAA;AAAA;AAAA;AAAA,2CAK7C,GAAW,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAwB3B,GAAU,CAKR,IAAK;AAAA;AAAA;AAAA;AAAA,cAMP,GAAU,CAER,IAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YASP,GAAU,CASR,IAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cA4BX,CACE,GACA,GACA,EACA,EACA,EACA,EACA,EAAM,QAAQ,OAAO,mBACrB,EAAM,QAAQ,WAAW,QACzB,EAAM,QAAQ,WAAW,MACzB,EAAM,QAAQ,QAAQ,KACtB,EAAM,QAAQ,QAAQ,KACtB,EAAM,QAAQ,KAAK,QACnB,EAAM,QAAQ,WACd,EAAM,QAAQ,eACd,EAAM,WAAW,WACjB,KAKE,GAAa,kBACjB,KAAO,KACL,GAAY,GAAoB,CAC9B,KACA,IACA,EAAqB,CACnB,QAAS,OAAO,SAAS,OACzB,QAAS,CAAC,GAAO,KAAQ,C,QAEvB,KAAM,GAAiB,GAAM,SAAW,GAAM,QACxC,EAAY,GAAI,KAAI,IAGtB,EAAU,KACR,EACF,OAAO,KAAK,GAAG,EAAU,WAAW,EAAU,OAAQ,UAEtD,IAAS,GAAG,EAAU,WAAW,EAAU,QAE3C,sBACI,cAAc,IAAI,EAAU,KAAK,MAAM,QAD3C,QAEI,kBAGF,EACF,OAAO,KAAK,EAAU,SAAU,UAEhC,IAAS,EAAU,UAEnB,sBACI,cAAc,wBADlB,QAEI,qBAKZ,GAAW,CACT,cAAe,KAAM,GAAmB,eACxC,UAAY,IAAoB,CAC7B,GAAkB,MAAM,YAAY,UAAW,MAElD,SAAW,IAAoB,C,OAC5B,GAAkB,MAAM,eAAe,WAExC,OACG,cAAc,oBADjB,SAEI,gBAAgB,OACpB,GACE,MAAM,KAAK,GAAgB,iBAAiB,sBAKtD,CAAC,GAAU,IAGb,sBAAU,IAAM,CACd,GAAI,CAAC,GAAS,MAAO,IAAM,GAG3B,GAAI,IAAuB,GAG3B,UAAU,GAAS,IAAM,KAAK,KAAM,KAA4B,CAM9D,GALI,CAAC,oBAA0B,YAK3B,CAAC,GACH,OAIF,OAAO,OAAO,CAAE,IAAK,IAGrB,KAAM,IAA4B,KAAM,IACtC,IAEF,GAAO,MAIF,IAAM,CACX,GAAuB,KAExB,CAAC,GAAS,GAAM,GAAW,KAEvB,IAGH,GAAY,CAAC,CACjB,aACA,WAAU,IAAM,GAChB,aAAa,MACT,C,UACJ,KAAM,GAAU,KACV,EAAM,GAAqB,IAC3B,EAAe,aAAO,MAEtB,EAAa,aAAO,IAC1B,sBAAU,IAAM,CACd,EAAW,QAAU,IACpB,CAAC,KAEJ,gBAAU,IAAM,CACd,GAAI,CAAC,GAAO,CAAC,EAAa,QAAS,OACnC,KAAM,IAAY,EAAa,QACzB,GACJ,GAAU,YAAc,GAAU,aAAa,CAAE,KAAM,SACzD,MAAM,KAAK,GAAW,UAAU,QAAQ,IACtC,GAAW,YAAY,KAEzB,GAAW,YAAY,GACvB,EAAW,WAGV,CAAC,IAGF,gBAAoB,WAAgB,KAChC,gBAAoB,KAAwB,MAC5C,GAAc,0BAAc,UAAd,eAAuB,aAAvB,eAAmC,YACjD,gBAAoB,IAAM,CAAE,UAAW,GAAM,UAAW,EAAQ,WAC5D,gBAAoB,KAAgB,CAAE,SAAU,MAGpD,gBAAoB,MAAO,CAAE,cAAe,8BAA+B,IAAK,MAK3E,GAAS,CAAC,CACrB,aACA,WAAU,IAAM,GAChB,aAAa,MAEb,gBAAoB,GAAwB,CAAE,UAAW,IACrD,gBAAoB,GAAW,CAC/B,UAAW,GACX,QAAS,GACT,WAAY,M,sGC3eX,KAAM,GAAmB,CAAC,CAAE,kBAAmB,CACpD,KAAM,GACJ,aAAO,gBAAc,kBAAkB,oBAEzC,GAAI,GAAiB,GACrB,MAAI,KAAoB,SACtB,GACE,+UAOF,gBAAoB,YAAW,CAC7B,OAAQ,MACR,cAAe,GAAgB,0BAC/B,eAAgB,M,yLCff,KAAM,GAAqB,IAAM,CACtC,KAAM,CAAC,EAAe,GAAoB,eAAS,IAC7C,CAAE,YAAW,OAAM,QAAS,WAE5B,EAAc,aAAO,KAErB,CAAE,MAAO,GAA0B,cAAS,IAC5C,EACK,EAAY,oBAAoB,CAAE,OAAM,YAAW,SAGrD,QAAQ,QAAQ,QACtB,CAAC,EAAM,EAAW,EAAM,EAAa,IAElC,CAAE,MAAO,EAAqB,MAAO,GACzC,cAAS,IACA,EAAY,kBAAkB,CAAE,OAAM,YAAW,SACvD,CAAC,EAAM,EAAW,EAAM,IAEvB,EAAU,kBAAY,IAAM,CAChC,EAAiB,KAChB,CAAC,IAEJ,MAAI,GACK,gBAAoB,IAAkB,CAAE,aAAc,EAAoB,UAIjF,gBAAoB,OAAM,CAAE,QAAS,iBACjC,gBAAoB,IAAoB,CACxC,iBAAkB,EAClB,eAAgB,EAChB,UAAW,CACT,OACA,YACA,UAGF,gBAAoB,UAAS,CAAE,cAAe,oBAC5C,gBAAoB,KAAQ,CAC5B,QAAS,EACT,UAAW,CACT,OACA,YACA,aC3BC,EAAe,CAAC,CAAE,cAAe,CAC5C,KAAM,GAAS,WAET,CAAC,EAAe,GAAoB,eAAS,IAC7C,CAAE,YAAW,OAAM,QAAS,WAE5B,EAAc,aAAO,KAErB,CAAE,MAAO,GAA0B,cAAS,IAC5C,EACK,EAAY,oBAAoB,CAAE,OAAM,YAAW,SAGrD,QAAQ,QAAQ,QACtB,CAAC,EAAM,EAAW,EAAM,EAAa,IAElC,CAAE,MAAO,EAAqB,MAAO,GACzC,cAAS,IACA,EAAY,kBAAkB,CAAE,OAAM,YAAW,SACvD,CAAC,EAAM,EAAW,EAAM,IAEvB,GAAU,kBAAY,IAAM,CAChC,EAAiB,KAChB,CAAC,IAEJ,MAAI,GACK,gBAAoB,IAAkB,CAAE,aAAc,EAAoB,UAG9E,EAGH,gBAAoB,OAAM,CAAE,QAAS,iBACjC,YAAoB,UAClB,EAAS,CACP,wBACA,sBACA,UAAW,CAAE,OAAM,YAAW,QAC9B,aAEF,GAXc,GAAU,gBAAoB,EAAoB,Q,kJCrCnE,KAAM,GAAqB,CAAC,CACjC,YACA,iBACA,sBACI,CACJ,KAAM,CAAE,QAAS,EAEX,CAAE,UAAW,EAAU,iBAAkB,GAC7C,GAAoB,GAEhB,CAAE,mBAAkB,QAAS,GAAkB,GAC/C,EAAY,iBAAM,UAElB,EAAmB,EACrB,yBAAmB,EAAgB,MACnC,GAEE,EAAe,kBAAY,QAE3B,EACJ,gBAAoB,WAAgB,KAChC,gBAAoB,cAAa,CACjC,MAAO,YACP,MACE,gBAAoB,gBAAe,CACjC,MAAO,UACP,UAAW,EACX,YAAa,gBAIjB,EAAiB,OAAS,GAC1B,gBAAoB,cAAa,CAC/B,MAAO,QACP,MACE,gBAAoB,iBAAgB,CAClC,MAAO,UACP,WAAY,EACZ,YAAa,YAKnB,EAAY,gBAAoB,cAAa,CAAE,MAAO,YAAa,MAAO,IAAgB,KAC1F,GACF,EAAiB,OAAS,OAC1B,EAAiB,OAAS,OACxB,gBAAoB,cAAa,CAC/B,MAAO,GACP,MACE,gBAAoB,IAAK,CACvB,KAAM,EAAiB,OACvB,OAAQ,SACR,IAAK,uBAEH,gBAAoB,IAAU,CAAE,MAAO,CAAE,UAAW,QAAS,KAAM,aAIzE,MAIR,MACE,iBAAoB,SAAQ,CAC1B,MAAO,GAAsB,IAC7B,kBAAmB,GAAY,EAC/B,SACE,GAAmB,IAAoB,OAAS,EAAkB,GAEpE,KAAM,OACN,SAAU,GAER,K,wGCxFR,KAAM,GAAY,QAAW,IAAU,EACrC,QAAS,CACP,MAAO,QACP,QAAS,QAEX,KAAM,CACJ,OAAQ,GAAM,QAAQ,GAAI,EAAG,EAAG,OASvB,EAAgB,CAAC,CAC5B,2BACA,0BACI,CACJ,KAAM,IAAU,IAEhB,MACE,OAAM,cAAc,MAAO,CAAE,UAAW,GAAQ,SAC5C,MAAM,cAAc,WAAY,CAChC,UAAW,GAAQ,KACnB,aAAc,WACd,QAAS,IAEP,MAAM,cAAc,eAAgB,OAEtC,MAAM,cAAc,WAAY,CAAE,QAAS,MAAQ,YAChD,IAAoD,EAAG,OClB5D,EAAY,QAAW,IAAU,EACrC,QAAS,CACP,WAAY,cACZ,UAAW,mBAEb,SAAU,CACR,QAAS,GAAM,QAAQ,EAAG,EAAG,EAAG,IAElC,SAAU,CACR,MAAO,WAsBE,EAAU,CAAC,CACtB,WACA,iBACA,gBACA,kBACA,oBACI,CACJ,KAAM,IAAU,IAEhB,MACE,OAAM,cAAc,KAAM,CAAE,UAAW,GAAQ,SAC3C,MAAM,cAAc,WAAY,CAChC,MAAO,MAAM,cAAc,WAAY,CAAE,QAAS,MAAQ,WAC1D,OACE,MAAM,cAAc,OAAQ,CAAE,MAAO,UAAW,QAAS,IAAM,MAAkB,eAKnF,MAAM,cAAc,QAAS,MAC7B,GAAc,KAAK,SAAW,GAAK,GAAc,UAAU,SAAW,GACtE,MAAM,cAAc,YAAa,KAC7B,MAAM,cAAc,WAAY,CAAE,QAAS,aAAe,mDAK9D,GAAc,KAAK,OAAS,GAC5B,MAAM,cAAc,YAAa,KAC7B,MAAM,cAAc,WAAY,CAAE,QAAS,aAAe,QAC1D,MAAM,cAAc,OAAQ,CAC5B,GAAI,kBACJ,SAAW,GAAG,C,MACZ,UAAe,oBAAG,SAAH,cAAW,QAE5B,QAAS,WACT,UAAW,GAAQ,SACnB,MAAO,GAAQ,UAEb,GAAc,KAAK,IAAI,GACvB,MAAM,cAAc,SAAU,CAC5B,SAAU,IAAW,GACrB,MAAO,GACP,IAAK,EACL,MAAO,GAEL,MAMV,GAAc,UAAU,OAAS,GACjC,MAAM,cAAc,YAAa,KAC7B,MAAM,cAAc,WAAY,CAAE,QAAS,aAAe,aAC1D,MAAM,cAAc,KAAM,CAAE,eAAgB,GAAM,MAAO,IACvD,GAAc,UAAU,IAAI,GAC5B,MAAM,cAAc,SAAU,CAC5B,IAAK,EACL,MAAO,GACP,OAAQ,GACR,QAAS,IAAM,GAAc,IAE3B,MAAM,cAAc,SAAU,CAC9B,KAAM,QACN,cAAe,GACf,UAAW,GAAQ,SACnB,MAAO,UACP,QAAS,GAAQ,QAAQ,SAAS,GAClC,SAAU,GACV,MAAO,EACP,KAAM,IAEN,MAAM,cAAc,aAAc,CAAE,GAAI,EAAQ,QAAS,U,2JChHpE,KAAM,GAAuB,CAClC,GACA,GACA,GAAgB,GAChB,GAAW,MACR,CACH,KAAM,IAAa,aAAO,IACpB,GAAa,IAAO,KAAM,QAAQ,QAAQ,KAE1C,CAAC,EAAO,GAAY,cAAW,GAAY,CAAC,IAAa,CAC7D,QAAS,KAqBX,GAjBA,QACE,IAAM,CAGA,GAAW,QAAQ,MAAgB,QACrC,IAAW,QAAQ,IAAc,EAAS,IAAY,KAAK,GAEzD,IAAW,QAAQ,IAAc,EAC1B,MAIb,GACA,CAAC,EAAU,KAIT,GAAc,OAChB,MAAO,CACL,QAAS,GACT,MAAO,IAKX,KAAM,GAAgB,GAAW,QAAQ,IACzC,MAAI,OAAM,QAAQ,GACT,CACL,QAAS,GACT,MAAO,GAIJ,GAMI,GAAwB,CACnC,GACA,KACG,CACH,KAAM,CAAE,eAAe,WAEvB,gBAAU,IAAM,CACV,IAAgB,CAAC,IAAc,OAAO,OAAS,GACjD,GAAW,IAAgB,KACtB,IACF,IAAO,OAIX,KCxDQ,GAAsB,IAAU,CAC3C,KAAM,CACJ,aACA,gBACA,QACA,OAAQ,GACR,oBACA,QACA,wBACA,YACA,YACE,GACE,CAAC,GAAY,IAAiB,eAAS,IAC7C,GAAsB,GAAM,IAC5B,KAAM,IACJ,MAAO,KAAgB,WAAa,GAAc,OAC9C,GACJ,MAAO,KAAgB,WAAa,OAAY,GAC5C,CAAE,MAAO,GAAQ,YAAY,EACjC,GACA,GACA,GACA,IAEI,CAAE,WAAS,eAAe,WAC1B,EACH,GAAQ,KAAY,GAAW,GAAK,MAGjC,EAAe,CACnB,GACA,KACG,CACH,GAAW,IAAa,CACtB,KAAM,EAAG,IAAO,MAAW,IAAW,GAEtC,MAAI,IACK,IAAK,IAAS,IAAO,IAEvB,IAAK,OAKV,GAAe,IACnB,gBAAoB,IAAW,IAC1B,GACH,KAAM,SACN,QAAS,WACT,MAAO,EACP,UAAW,KAKT,GAAa,CACjB,GACA,KAEA,GAAS,IAAI,CAAC,GAAQ,KACpB,gBAAoB,IAAM,CAAE,MAAO,GAAQ,MAAO,aAAc,GAAY,CAAE,cAGlF,MACE,iBAAoB,KAAc,CAChC,sBAAuB,EACvB,UAAW,EACX,SAAU,EACV,UAAW,GACX,GAAI,GAAG,EAAW,SAAW,mBAAmB,aAChD,QAAS,IAAU,GACnB,QAAS,GACT,MAAO,EACP,SAAU,EACV,cAAe,CAAC,GAAG,KAAa,GAAc,IAC9C,YAAa,GACb,WAAY,MC7EZ,GAAY,QAAW,CAC3B,MAAO,CACL,cAAe,gBAkCb,GAAkB,IAAU,CAChC,KAAM,CACJ,aACA,gBACA,SACA,QACA,OAAQ,GAAc,GACtB,oBACE,GACE,EAAU,KACV,CAAE,UAAS,cAAe,WAChC,GAAsB,GAAM,IAC5B,KAAM,IACJ,MAAO,KAAgB,WAAa,GAAc,OAC9C,GACJ,MAAO,KAAgB,WAAa,OAAY,GAC5C,CAAE,MAAO,GAAS,GAAI,YAAY,EACtC,GACA,GACA,GACA,GAGI,GAAgB,IAAM,CAC1B,KAAM,CACJ,OAAQ,CAAE,SAAO,aACf,GAEJ,EAAW,GAAe,CACxB,KAAM,EAAG,IAAO,KAAW,IAAW,EAChC,GAAS,IAAY,IAAI,OAAO,IAAK,KAAM,IAC3C,GAAQ,GAAU,CAAC,GAAG,GAAM,IAAS,GAC3C,MAAO,IAAM,OAAS,IAAK,IAAS,IAAO,IAAU,MAIzD,MACE,iBAAoB,IAAa,CAC/B,UAAW,GACX,SAAU,GACV,UAAW,GACX,cAAe,8BAEb,GAAQ,gBAAoB,IAAW,CAAE,UAAW,EAAQ,OAAS,IAAS,KAC9E,GAAO,IAAK,IAAO,C,OACnB,uBAAoB,IAAkB,CACpC,IAAK,GACL,QACE,gBAAoB,IAAU,CAC5B,MAAO,UACP,SAAU,GACV,WAAY,CAAE,kBAAmB,IACjC,MAAO,GACP,KAAM,GACN,SAAU,GACV,QAAW,OAAQ,MAAR,QAAmB,IAAI,SAAS,MAG/C,MAAO,SAOX,GAAgB,IAAU,CAC9B,KAAM,CACJ,aACA,gBACA,SACA,QACA,OAAQ,GACR,oBACE,GACE,EAAU,KAChB,GAAsB,GAAM,IAC5B,KAAM,GACJ,MAAO,KAAgB,WAAa,GAAc,OAC9C,EACJ,MAAO,KAAgB,WAAa,OAAY,GAC5C,CAAE,MAAO,GAAS,GAAI,YAAY,EACtC,EACA,GACA,EACA,GAEI,CAAE,WAAS,eAAe,WAE1B,GAAgB,IAAM,CAC1B,KAAM,CACJ,OAAQ,CAAE,WACR,GAEJ,GAAW,IAAe,CACxB,KAAM,EAAG,IAAO,KAAW,GAAW,GACtC,MAAO,IAAQ,IAAK,GAAS,IAAO,IAAW,KAInD,MACE,iBAAoB,IAAa,CAC/B,SAAU,GACV,UAAW,GACX,QAAS,SACT,UAAW,GACX,cAAe,4BAEb,GACA,gBAAoB,IAAY,CAAE,UAAW,EAAQ,MAAO,OAAQ,SAChE,IAEF,KACF,gBAAoB,IAAQ,CAC5B,QAAS,WACT,MAAO,GAAQ,KAAS,GACxB,SAAU,IAER,gBAAoB,IAAU,CAAE,MAAO,IACrC,gBAAoB,KAAM,KAAM,QAElC,GAAO,IAAK,IACZ,gBAAoB,IAAU,CAAE,IAAK,GAAO,MAAO,IAC/C,QAQR,GAAe,CAAC,CACpB,UAAW,MACR,MACC,gBAAoB,GAAS,IAAK,KAExC,GAAa,SACX,IAEG,gBAAoB,GAAc,IAAK,GAAO,UAAW,KAE9D,GAAa,OACX,IAEG,gBAAoB,GAAc,IAAK,GAAO,UAAW,KAQ9D,GAAa,aAAgB,IAC3B,gBAAoB,GAAc,IAAK,GAAO,UAAW,KAS3D,KAAM,IAAmB,K,6MCrMzB,KAAM,IAAY,QAAW,IAAU,EACrC,KAAM,CACJ,gBAAiB,sBAEnB,YAAa,CACX,WAAY,GAAM,QAAQ,IAE5B,KAAM,CACJ,MAAO,GAAM,QAAQ,OAAO,OAE9B,KAAM,CACJ,MAAO,QAET,aAAc,CACZ,MAAO,OACP,OAAQ,QAEV,UAAW,CACT,gBAAiB,GAAM,QAAQ,WAAW,OAE5C,iBAAkB,CAChB,UAAW,OACX,iBAAkB,CAChB,UAAW,SAGf,wBAAyB,CACvB,OAAQ,GAAM,QAAQ,EAAG,GACzB,iBAAkB,CAChB,OAAQ,GAAM,QAAQ,EAAG,KAG7B,iBAAkB,CAChB,QAAS,GAAM,QAAQ,EAAG,EAAG,OAiBpB,GAAuB,IAAU,CAC5C,KAAM,IAAU,KACV,CAAE,iBAAe,YAAU,UAAU,WACrC,CAAC,GAAU,GAAe,eAAS,IACnC,CAAE,eAAc,OAAM,MAAO,GAAe,GAE5C,GAAiB,IAAM,EAAY,IAAa,CAAC,IACjD,GAAe,IACZ,IAAM,CACX,GAAS,KAAS,GAAK,CAAC,IAAQ,IAChC,GAAc,QACd,EAAY,KAKhB,gBAAU,IAAM,CACV,GACF,GAAS,CAAC,KAGX,IAEH,KAAM,IAAe,CACnB,CACE,MAAO,GACP,KAAM,MACN,KAAM,gBAAoB,KAAS,OAErC,GAAG,GAEC,GAAW,GAAM,IAAM,GAE7B,MACE,iBAAoB,KAAM,CAAE,UAAW,GAAQ,MAC3C,gBAAoB,KAAY,CAAE,MAAO,EAAM,qBAAsB,CAAE,QAAS,cAChF,gBAAoB,KAAa,CAAE,UAAW,GAAQ,aACpD,gBAAoB,KAAW,CAC/B,UAAW,GAAQ,UACnB,SAAU,GACV,SAAU,IAER,gBAAoB,KAAkB,CACtC,QAAS,CACP,KAAM,GAAQ,iBACd,QAAS,GAAQ,yBAEnB,WAAY,gBAAoB,KAAgB,CAAE,UAAW,GAAQ,OACrE,gBAAiB,CAAE,KAAM,UAEvB,GACE,WACA,GAAa,OAAO,IAAK,GAAE,QAAU,IAAU,GAAG,MAEtD,gBAAoB,KAAkB,CAAE,QAAS,CAAE,KAAM,GAAQ,mBAC/D,gBAAoB,KAAM,CAC1B,UAAW,GAAQ,KACnB,UAAW,MACX,aAAc,iBACd,eAAgB,GAChB,MAAO,IAEL,GAAa,IAAI,IACjB,gBAAoB,WAAU,CAAE,IAAK,GAAK,OACtC,gBAAoB,KAAS,MAC7B,gBAAoB,KAAU,CAC9B,SACE,GAAM,KAAO,GAAK,OACjB,GAAM,SAAW,GAAK,GAAK,QAAU,GAExC,QAAS,GAAY,GAAK,OAC1B,OAAQ,IAEN,gBAAoB,KAAc,KAChC,mBAAa,GAAK,KAAM,CACxB,UAAW,GAAQ,gBAGrB,gBAAoB,KAAc,CAAE,QAAS,GAAK,gB,2BC9IxE,KAAM,IAAY,QAAY,IAAW,EACvC,KAAM,CACJ,aAAc,aAAa,GAAM,QAAQ,iBACzC,QAAS,GAAM,QAAQ,EAAG,IAE5B,IAAK,CACH,OAAQ,OACR,WAAY,GAAM,WAAW,eAC7B,SAAU,GAAM,WAAW,QAAQ,IACnC,MAAO,GAAM,QAAQ,WACrB,SAAU,YAeD,GAAkB,IAAU,CACvC,KAAM,IAAU,KACV,CAAE,iBAAe,YAAU,UAAU,WACrC,CAAE,gBAAc,MAAO,GAAe,GAEtC,EAAY,CAAC,EAAG,KAAY,CAChC,GAAS,KAAY,GAAK,CAAC,IAAW,IACtC,GAAc,SAIhB,gBAAU,IAAM,CACV,IACF,GAAS,CAAC,MAGX,IAEH,KAAM,GAAe,CACnB,CACE,MAAO,GACP,KAAM,OAER,GAAG,GAGL,MACE,iBAAoB,KAAM,CACxB,UAAW,GAAQ,KACnB,eAAgB,UAChB,MAAO,GAAM,SAAW,EAAI,GAAK,GAAM,GACvC,SAAU,GAER,EAAa,IAAI,GACjB,gBAAoB,KAAK,CACvB,UAAW,GAAQ,IACnB,cAAe,GACf,MAAO,EAAK,KACZ,MAAO,EAAK,WClDhB,EAAY,QAAW,IAAU,EACrC,MAAO,CACL,cAAe,cAEjB,MAAO,CACL,QAAS,OACT,SAAU,OACV,UAAW,GAAM,QAAQ,IAE3B,KAAM,CACJ,OAAQ,MAcN,EAAc,IAAU,CAC5B,KAAM,CAAE,aAAW,gBAAc,QAAM,UAAS,IAAO,GACjD,GAAU,IACV,CAAE,QAAO,YAAa,WAE5B,SAAc,IAAM,CACb,EAAM,QACT,CAAI,IAAgB,MAAM,QAAQ,IAChC,EAAS,IACA,IACT,EAAS,CAAC,QAKhB,KAAM,GAAgB,GAAM,CAC1B,KAAM,IAAQ,EAAE,OAAO,MACvB,EAAS,KAGX,MACE,iBAAoB,IAAa,CAC/B,UAAW,GACX,QAAS,SACT,UAAW,GACX,cAAe,0BAEb,gBAAoB,IAAY,CAAE,UAAW,GAAQ,MAAO,OAAQ,SAClE,IAEF,gBAAoB,IAAQ,CAC5B,SAAU,GACV,QAAS,WACT,MAAO,EACP,SAAU,EACV,YAAa,cACb,YAAa,GACX,gBAAoB,MAAO,CAAE,UAAW,GAAQ,OAC3C,EAAW,IAAI,IAChB,gBAAoB,IAAM,CACxB,IAAK,GACL,MAAO,GACP,UAAW,GAAQ,KACnB,KAAM,aAMZ,GAAO,IAAK,GACZ,gBAAoB,IAAU,CAAE,IAAK,EAAO,MAAO,GAC/C,gBAAoB,IAAU,CAAE,QAAS,EAAM,QAAQ,GAAS,KAChE,gBAAoB,KAAc,CAAE,QAAS,SAa3D,EAAW,UAAa,IACf,gBAAoB,GAAqB,IAAK,KAQvD,EAAW,KAAQ,IACV,gBAAoB,GAAgB,IAAK,K,gDC1G3C,KAAM,IAAiB,IAAU,CACtC,KAAM,IAAc,YAAY,cAC1B,CAAE,iBAAiB,aACnB,GAAW,cACX,GAAe,YAClB,IAAU,CACT,KAAM,GAAc,GAAG,UAAU,CAAE,UAAS,CAAE,eAAgB,KAC9D,KACA,GAAS,GAAG,OAAgB,MAE9B,CAAC,GAAc,GAAU,KAG3B,MACE,OAAM,cAAc,mBAAoB,CACtC,KAAM,GAAM,KACZ,SAAU,GACV,GAAI,a,uFCOV,KAAM,IAAoB,CAAC,CACzB,YACA,gBAAe,OACX,CACJ,KAAM,CAAC,GAAM,IAAW,eAAS,IAC3B,GAAW,YACX,CACJ,QACA,UACA,OAAQ,CAAE,UAAS,MAAO,IACxB,WACE,CAAC,EAAS,IAAc,eAAS,IACvC,gBAAU,IAAM,CACd,GAAI,IAAU,GAEd,GAAI,IAAW,EAAW,CAIxB,KAAM,IAAgB,EAAU,QAAQ,MAAM,EAAG,IACjD,GAAW,IAEb,MAAO,IAAM,CACX,GAAU,KAEX,CAAC,EAAS,IAEb,KAAM,CAAC,GAAO,IAAY,eAAS,IAEnC,QAAY,IAAM,EAAQ,IAAQ,GAAc,CAAC,KAEjD,KAAM,IAAe,IAAM,CACpB,IACH,GAAQ,IAEV,GAAS,GAAE,OAAO,QAGd,GAAkB,CAAC,GAAG,KAAc,CACxC,GAAI,mBAAW,SAAU,CACvB,KAAM,CAAE,aAAa,GAAU,SAC/B,GAAS,MAIb,MACE,iBAAoB,KAAM,CAAE,KAAM,GAAM,GAAI,IACxC,gBAAoB,KAAc,CAClC,cAAe,sBACf,KAAM,QACN,KAAM,GACN,eAAgB,IAAM,GACtB,cAAe,IACN,GAET,QAAS,IAAM,CACb,GAAQ,KAEV,QAAS,IAAM,CACb,GAAQ,KAEV,SAAU,GACV,aAAc,GACd,cAAe,mBACf,MAAO,KACP,QAAS,EACT,aAAc,CAAC,CAAE,eACf,gBAAoB,KAAoB,CACtC,OAAQ,GACR,UAAW,EACX,WAAY,GACZ,OAAQ,GACR,MAAO,GAAS,QAGpB,QAAS,EACT,YAAa,IACX,gBAAoB,IAAW,IAC1B,GACH,cAAe,4BACf,QAAS,WACT,UAAW,GACX,YAAa,UAAU,GAAS,YAChC,MAAO,GACP,SAAU,GACV,WAAY,IACP,GAAO,WACV,eACE,gBAAoB,KAAgB,CAAE,SAAU,SAC5C,gBAAoB,KAAY,CAAE,aAAc,QAAS,SAAU,IACjE,gBAAoB,KAAY,QAIxC,aACE,gBAAoB,WAAgB,KAChC,EACA,gBAAoB,KAAkB,CAAE,MAAO,UAAW,KAAM,KAC9D,KACF,GAAO,WAAW,qBAWzB,GAAkB,IAAU,CACvC,KAAM,IAAe,CACnB,KAAM,GACN,MAAO,CAAC,YACR,WAAY,GACZ,QAAS,GAAM,UAEjB,MACE,iBAAoB,KAAuB,CAAE,aAAc,IACvD,gBAAoB,GAAmB,IAAK,Q,uMC5IpD,KAAM,GAAkB,QAAY,GAClC,QAAa,CACX,MAAO,CACL,MAAO,QACN,EAAM,YAAY,GAAG,OAAQ,CAC5B,MAAO,QAER,EAAM,YAAY,GAAG,OAAQ,CAC5B,MAAO,OAET,QAAS,EAAM,QAAQ,MAEzB,KAAM,CACJ,OAAQ,OACR,SAAU,UAEZ,KAAM,CACJ,WAAY,EAAM,QAAQ,WAAW,YAK9B,EAAiC,CAAC,CAC7C,WACA,aAIG,CACH,KAAM,GAAU,IACV,GACJ,EAAS,SAAW,EAAI,sBAAwB,EAAS,KAAK;AAAA,GAChE,MACE,iBAAoB,IAAM,CACxB,UAAW,GACX,UAAW,SACX,UAAW,EAAQ,KACnB,QAAS,EACT,KAAM,UAEJ,gBAAoB,IAAM,CAC1B,KAAM,GACN,UAAW,GACX,eAAgB,gBAChB,WAAY,SACZ,QAAS,EACT,KAAM,UAEJ,gBAAoB,IAAY,CAAE,QAAS,MAAQ,iBACnD,gBAAoB,IAAY,CAChC,IAAK,UACL,MAAO,mBACP,QAAS,EACT,MAAO,WAEL,gBAAoB,IAAO,QAG/B,gBAAoB,YAAW,CAAE,KAAM,GAAS,QAAS,CAAE,KAAM,EAAQ,UAKpE,EAAoB,CAAC,CAAE,cAAe,CACjD,KAAM,GAAU,IACV,CAAC,EAAM,IAAW,eAAS,IAEjC,MACE,iBAAoB,WAAgB,KAChC,gBAAoB,IAAQ,CAAE,MAAO,UAAW,QAAS,IAAM,GAAQ,KAAS,mBAGhF,gBAAoB,KAAQ,CAC5B,QAAS,CAAE,MAAO,EAAQ,OAC1B,OAAQ,QACR,KAAM,EACN,QAAS,IAAM,GAAQ,KAErB,gBAAoB,EAAgC,CACpD,SAAU,EACV,QAAS,IAAM,GAAQ,S,0BCrFjC,KAAM,GAAY,QAAW,IAAO,EAClC,QAAS,CAGP,UAAW,aACX,aAAc,eAaL,EAAyB,IAAM,CAC1C,GAAI,GAAa,KACjB,KAAM,GAAU,IAEV,CACJ,QACA,iBACA,uBACA,oBACA,aACE,WAEE,GAAiB,IAAU,WAAa,gBAAoB,WAAU,MAAS,KAErF,MAAI,KAAU,iBACZ,GACE,gBAAoB,IAAO,CACzB,QAAS,WACT,SAAU,OACV,KAAM,gBAAoB,IAAkB,CAAE,KAAM,SACpD,OAAQ,gBAAoB,EAAmB,CAAE,SAAU,MAC3D,8GAOF,IAAU,4BACZ,GACE,gBAAoB,IAAO,CACzB,QAAS,WACT,SAAU,OACV,KAAM,gBAAoB,IAAkB,CAAE,KAAM,SACpD,OAAQ,gBAAoB,EAAmB,CAAE,SAAU,MAC3D,2FAOF,IAAU,uBACZ,GACE,gBAAoB,IAAO,CACzB,QAAS,WACT,SAAU,UACV,OACE,gBAAoB,IAAQ,CAAE,MAAO,UAAW,QAAS,IAAM,MAAmB,YAIpF,oFAOF,IAAU,uBACZ,GACE,gBAAoB,IAAO,CACzB,QAAS,WACT,SAAU,QACV,OAAQ,gBAAoB,EAAmB,CAAE,SAAU,KAC3D,QAAS,CAAE,QAAS,EAAQ,UAC5B,yDACS,IACP,KAKJ,IAAU,qBACZ,GACE,gBAAoB,WAAgB,KAChC,IACA,gBAAoB,IAAO,CACzB,QAAS,WACT,SAAU,QACV,OAAQ,gBAAoB,EAAmB,CAAE,SAAU,KAC3D,QAAS,CAAE,QAAS,EAAQ,UAC5B,yDACS,IACP,IAGJ,gBAAoB,IAAkB,CAAE,aAAc,OAM5D,gBAAoB,WAAgB,KAChC,GACA,K,qUCxHD,KAAM,GAAe,qBAAe,CACzC,GAAI,wBAGO,EAAmB,qBAAe,CAC7C,GAAI,uBACJ,OAAQ,CAAC,YAAa,OAAQ,UAGnB,EAA0B,qBAAe,CACpD,GAAI,kC","file":"static/main.367d4ef1.js","sourcesContent":["\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * A Symbol to define if a catalog filter exists or not.\n *\n * @public\n */\nexport const CATALOG_FILTER_EXISTS = Symbol('CATALOG_FILTER_EXISTS');\n\n/**\n * A request type for retrieving catalog Entities.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n\n\n LOCATION_ANNOTATION,\n ORIGIN_LOCATION_ANNOTATION,\n parseEntityRef,\n stringifyEntityRef,\n stringifyLocationReference,\n} from '@backstage/catalog-model';\nimport { ResponseError } from '@backstage/errors';\nimport crossFetch from 'cross-fetch';\nimport {\n CATALOG_FILTER_EXISTS,\n\n\n\n\n\n\n\n\n} from './types/api';\n\n\n\n/**\n * A frontend and backend compatible client for communicating with the Backstage Catalog.\n *\n * @public\n * */\nexport class CatalogClient {\n discoveryApi;\n fetchApi;\n\n constructor(options) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi || { fetch: crossFetch };\n }\n\n /**\n * Gets the Ancestors of an Entity.\n *\n * @param request - A request type for retrieving Entity ancestors.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogEntityAncestorsResponse.\n *\n * @public\n */\n async getEntityAncestors(\n request,\n options,\n ) {\n const { kind, namespace, name } = parseEntityRef(request.entityRef);\n return await this.requestRequired(\n 'GET',\n `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(\n namespace,\n )}/${encodeURIComponent(name)}/ancestry`,\n options,\n );\n }\n\n /**\n * Gets a Location by Id.\n *\n * @param id - A string containing the Id.\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getLocationById(\n id,\n options,\n ) {\n return await this.requestOptional(\n 'GET',\n `/locations/${encodeURIComponent(id)}`,\n options,\n );\n }\n\n /**\n * Gets a set of Entities.\n *\n * @param request - A request type for retrieving an Entity.\n * @param options - An object with your preferred options.\n *\n * @returns A CatalogListResponse.\n *\n * @public\n */\n async getEntities(\n request,\n options,\n ) {\n const { filter = [], fields = [], offset, limit, after } = request ?? {};\n const filterItems = [filter].flat();\n const params = [];\n\n // filter param can occur multiple times, for example\n // /api/catalog/entities?filter=metadata.name=wayback-search,kind=component&filter=metadata.name=www-artist,kind=component'\n // the \"outer array\" defined by `filter` occurrences corresponds to \"anyOf\" filters\n // the \"inner array\" defined within a `filter` param corresponds to \"allOf\" filters\n for (const filterItem of filterItems) {\n const filterParts = [];\n for (const [key, value] of Object.entries(filterItem)) {\n for (const v of [value].flat()) {\n if (v === CATALOG_FILTER_EXISTS) {\n filterParts.push(encodeURIComponent(key));\n } else if (typeof v === 'string') {\n filterParts.push(\n `${encodeURIComponent(key)}=${encodeURIComponent(v)}`,\n );\n }\n }\n }\n\n if (filterParts.length) {\n params.push(`filter=${filterParts.join(',')}`);\n }\n }\n\n if (fields.length) {\n params.push(`fields=${fields.map(encodeURIComponent).join(',')}`);\n }\n\n if (offset !== undefined) {\n params.push(`offset=${offset}`);\n }\n if (limit !== undefined) {\n params.push(`limit=${limit}`);\n }\n if (after !== undefined) {\n params.push(`after=${encodeURIComponent(after)}`);\n }\n\n const query = params.length ? `?${params.join('&')}` : '';\n const entities = await this.requestRequired(\n 'GET',\n `/entities${query}`,\n options,\n );\n\n const refCompare = (a, b) => {\n // in case field filtering is used, these fields might not be part of the response\n if (\n a.metadata?.name === undefined ||\n a.kind === undefined ||\n b.metadata?.name === undefined ||\n b.kind === undefined\n ) {\n return 0;\n }\n\n const aRef = stringifyEntityRef(a);\n const bRef = stringifyEntityRef(b);\n if (aRef < bRef) {\n return -1;\n }\n if (aRef > bRef) {\n return 1;\n }\n return 0;\n };\n\n return { items: entities.sort(refCompare) };\n }\n\n /**\n * Gets a given Entity based on a provided name.\n *\n * @param compoundName - A string containing the name.\n * @param options - An object with your preferred options.\n *\n * @returns An {@link catalog-model#Entity}.\n *\n * @public\n */\n async getEntityByName(\n compoundName,\n options,\n ) {\n const { kind, namespace = 'default', name } = compoundName;\n return this.requestOptional(\n 'GET',\n `/entities/by-name/${encodeURIComponent(kind)}/${encodeURIComponent(\n namespace,\n )}/${encodeURIComponent(name)}`,\n options,\n );\n }\n\n /**\n * Refreshes an Entity.\n *\n * @param entityRef - A string containing the entityREf\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async refreshEntity(entityRef, options) {\n const response = await this.fetchApi.fetch(\n `${await this.discoveryApi.getBaseUrl('catalog')}/refresh`,\n {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'POST',\n body: JSON.stringify({ entityRef }),\n },\n );\n\n if (response.status !== 200) {\n throw new Error(await response.text());\n }\n }\n\n /**\n * Adds a location.\n *\n * @param options - An object with your preferred options.\n * @param AddLocationRequest - A request object for adding locations.\n *\n * @returns An AddLocationResponse\n *\n * @public\n */\n async addLocation(\n { type = 'url', target, dryRun, presence },\n options,\n ) {\n const response = await this.fetchApi.fetch(\n `${await this.discoveryApi.getBaseUrl('catalog')}/locations${\n dryRun ? '?dryRun=true' : ''\n }`,\n {\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.token && { Authorization: `Bearer ${options?.token}` }),\n },\n method: 'POST',\n body: JSON.stringify({ type, target, presence }),\n },\n );\n\n if (response.status !== 201) {\n throw new Error(await response.text());\n }\n\n const { location, entities, exists } = await response.json();\n\n if (!location) {\n throw new Error(`Location wasn't added: ${target}`);\n }\n\n return {\n location,\n entities,\n exists,\n };\n }\n\n /**\n * Gets an origin Location By Entity.\n *\n * @param entity - An Entity\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getOriginLocationByEntity(\n entity,\n options,\n ) {\n const locationCompound =\n entity.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION];\n if (!locationCompound) {\n return undefined;\n }\n const all = await this.requestRequired(\n 'GET',\n '/locations',\n options,\n );\n return all\n .map(r => r.data)\n .find(l => locationCompound === stringifyLocationReference(l));\n }\n\n /**\n * Gets a Location by Entity.\n *\n * @param entity - An Entity\n * @param options - An object with your preferred options.\n *\n * @returns A {@link catalog-model#Location_2}.\n *\n * @public\n */\n async getLocationByEntity(\n entity,\n options,\n ) {\n const locationCompound = entity.metadata.annotations?.[LOCATION_ANNOTATION];\n if (!locationCompound) {\n return undefined;\n }\n const all = await this.requestRequired(\n 'GET',\n '/locations',\n options,\n );\n return all\n .map(r => r.data)\n .find(l => locationCompound === stringifyLocationReference(l));\n }\n\n /**\n * Removes a location as identified by Id.\n *\n * @param id - A string containing the Id\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async removeLocationById(\n id,\n options,\n ) {\n await this.requestIgnored(\n 'DELETE',\n `/locations/${encodeURIComponent(id)}`,\n options,\n );\n }\n\n /**\n * Removes an Entity as identified by Uid.\n *\n * @param uid - A string containing the Uid\n * @param options - An object with your preferred options.\n *\n * @public\n */\n async removeEntityByUid(\n uid,\n options,\n ) {\n await this.requestIgnored(\n 'DELETE',\n `/entities/by-uid/${encodeURIComponent(uid)}`,\n options,\n );\n }\n\n //\n // Private methods\n //\n\n async requestIgnored(\n method,\n path,\n options,\n ) {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await this.fetchApi.fetch(url, { method, headers });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n }\n\n async requestRequired(\n method,\n path,\n options,\n ) {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await this.fetchApi.fetch(url, { method, headers });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n\n async requestOptional(\n method,\n path,\n options,\n ) {\n const url = `${await this.discoveryApi.getBaseUrl('catalog')}${path}`;\n const headers = options?.token\n ? { Authorization: `Bearer ${options.token}` }\n : {};\n const response = await this.fetchApi.fetch(url, { method, headers });\n\n if (!response.ok) {\n if (response.status === 404) {\n return undefined;\n }\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The namespace that entities without an explicit namespace fall into.\n *\n * @public\n */\nexport const ENTITY_DEFAULT_NAMESPACE = 'default';\n\n/**\n * The keys of EntityMeta that are auto-generated.\n *\n * @public\n */\nexport const ENTITY_META_GENERATED_FIELDS = [\n 'uid',\n 'etag',\n 'generation',\n] ;\n\n/**\n * Annotation for linking to entity page from catalog pages.\n *\n * @public\n */\nexport const VIEW_URL_ANNOTATION = 'backstage.io/view-url';\n\n/**\n * Annotation for linking to entity edit page from catalog pages.\n *\n * @public\n */\nexport const EDIT_URL_ANNOTATION = 'backstage.io/edit-url';\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport lodash from 'lodash';\n\nimport { ENTITY_DEFAULT_NAMESPACE } from '../constants';\n\n\n/**\n * Sets a default namespace if none was set.\n *\n * @public\n */\nexport class DefaultNamespaceEntityPolicy {\n namespace;\n\n constructor(namespace = ENTITY_DEFAULT_NAMESPACE) {\n this.namespace = namespace;\n }\n\n async enforce(entity) {\n if (entity.metadata.namespace) {\n return entity;\n }\n\n return lodash.merge({ metadata: { namespace: this.namespace } }, entity);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport lodash from 'lodash';\n\n/**\n * Contains various helper validation and normalization functions that can be\n * composed to form a Validator.\n *\n * @public\n */\nexport class CommonValidatorFunctions {\n /**\n * Checks that the value is on the form <suffix> or <prefix><separator><suffix>, and validates\n * those parts separately.\n *\n * @param value - The value to check\n * @param separator - The separator between parts\n * @param isValidPrefix - Checks that the part before the separator is valid, if present\n * @param isValidSuffix - Checks that the part after the separator (or the entire value if there is no separator) is valid\n */\n static isValidPrefixAndOrSuffix(\n value,\n separator,\n isValidPrefix,\n isValidSuffix,\n ) {\n if (typeof value !== 'string') {\n return false;\n }\n\n const parts = value.split(separator);\n if (parts.length === 1) {\n return isValidSuffix(parts[0]);\n } else if (parts.length === 2) {\n return isValidPrefix(parts[0]) && isValidSuffix(parts[1]);\n }\n\n return false;\n }\n\n /**\n * Checks that the value can be safely transferred as JSON.\n *\n * @param value - The value to check\n */\n static isJsonSafe(value) {\n try {\n return lodash.isEqual(value, JSON.parse(JSON.stringify(value)));\n } catch {\n return false;\n }\n }\n\n /**\n * Checks that the value is a valid DNS subdomain name.\n *\n * @param value - The value to check\n * @see https://tools.ietf.org/html/rfc1123\n */\n static isValidDnsSubdomain(value) {\n return (\n typeof value === 'string' &&\n value.length >= 1 &&\n value.length <= 253 &&\n value.split('.').every(CommonValidatorFunctions.isValidDnsLabel)\n );\n }\n\n /**\n * Checks that the value is a valid DNS label.\n *\n * @param value - The value to check\n * @see https://tools.ietf.org/html/rfc1123\n */\n static isValidDnsLabel(value) {\n return (\n typeof value === 'string' &&\n value.length >= 1 &&\n value.length <= 63 &&\n /^[a-z0-9]+(\\-[a-z0-9]+)*$/.test(value)\n );\n }\n\n /**\n * Checks that the value is a valid tag.\n *\n * @param value - The value to check\n */\n static isValidTag(value) {\n return (\n typeof value === 'string' &&\n value.length >= 1 &&\n value.length <= 63 &&\n /^[a-z0-9+#]+(\\-[a-z0-9+#]+)*$/.test(value)\n );\n }\n\n /**\n * Checks that the value is a valid URL.\n *\n * @param value - The value to check\n */\n static isValidUrl(value) {\n if (typeof value !== 'string') {\n return false;\n }\n\n try {\n // eslint-disable-next-line no-new\n new URL(value);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Checks that the value is a non empty string value.\n *\n * @param value - The value to check\n */\n static isValidString(value) {\n return typeof value === 'string' && value?.trim()?.length >= 1;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Ajv, { } from 'ajv';\nimport entitySchema from '../schema/Entity.schema.json';\nimport entityEnvelopeSchema from '../schema/EntityEnvelope.schema.json';\nimport entityMetaSchema from '../schema/EntityMeta.schema.json';\nimport commonSchema from '../schema/shared/common.schema.json';\n\n// A local cache of compiled schemas, to avoid duplicate work.\n// The keys are JSON stringified versions of the schema\nconst compiledSchemaCache = new Map();\n\n// The core schemas that others can depend on\nconst refDependencyCandidates = [\n entityEnvelopeSchema,\n entitySchema,\n entityMetaSchema,\n commonSchema,\n];\n\nexport function throwAjvError(\n errors,\n) {\n if (!errors?.length) {\n throw new TypeError('Unknown error');\n }\n\n const error = errors[0];\n throw new TypeError(\n `${error.dataPath || '<root>'} ${error.message}${\n error.params\n ? ` - ${Object.entries(error.params)\n .map(([key, val]) => `${key}: ${val}`)\n .join(', ')}`\n : ''\n }`,\n );\n}\n\n// Compiles the given schema, and makes sure to also grab any core dependencies\n// that it depends on\nexport function compileAjvSchema(\n schema,\n options = {},\n) {\n const disableCache = options?.disableCache ?? false;\n const cacheKey = disableCache ? '' : JSON.stringify(schema);\n\n if (!disableCache) {\n const cached = compiledSchemaCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n }\n\n const extraSchemas = getExtraSchemas(schema);\n const ajv = new Ajv({\n allowUnionTypes: true,\n allErrors: true,\n validateSchema: true,\n });\n if (extraSchemas.length) {\n ajv.addSchema(extraSchemas, undefined, undefined, true);\n }\n const compiled = ajv.compile(schema);\n\n if (!disableCache) {\n compiledSchemaCache.set(cacheKey, compiled);\n }\n\n return compiled;\n}\n\n// Find refs in the given schema and recursively in all known schemas it\n// targets, collecting that list of schemas as we go\nfunction getExtraSchemas(schema) {\n if (typeof schema !== 'object') {\n return [];\n }\n\n const seen = new Set();\n if (schema.$id) {\n seen.add(schema.$id);\n }\n\n const selected = new Array();\n\n const todo = [schema];\n while (todo.length) {\n const current = todo.pop();\n\n for (const ref of getAllRefs(current)) {\n if (!seen.has(ref)) {\n seen.add(ref);\n\n const match = refDependencyCandidates.find(c => c.$id === ref);\n if (match) {\n selected.push(match);\n todo.push(match);\n }\n }\n }\n }\n\n return selected;\n}\n\n// Naively step through the entire schema looking for \"$ref\": \"x\" pairs. The\n// resulting iterator may contain duplicates. Ignores fragments, i.e. for a ref\n// of \"a#b\", it will just yield \"a\".\nfunction* getAllRefs(schema) {\n const todo = [schema];\n while (todo.length) {\n const current = todo.pop();\n if (typeof current === 'object' && current) {\n for (const [key, value] of Object.entries(current)) {\n if (key === '$ref' && typeof value === 'string') {\n yield value.split('#')[0];\n } else {\n todo.push(value);\n }\n }\n }\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport entityEnvelopeSchema from '../schema/EntityEnvelope.schema.json';\nimport { compileAjvSchema, throwAjvError } from './ajv';\n\n/**\n * Creates a validation function that takes some arbitrary data, and either\n * returns that data cast to an {@link EntityEnvelope} (or the given subtype)\n * if it matches that schema, or throws a {@link globals#TypeError} describing the\n * errors.\n *\n * @remarks\n *\n * Note that this validator is only meant for applying the base schema checks;\n * it does not take custom policies or additional processor based validation\n * into account.\n *\n * By default, the plain `EntityEnvelope` schema is used. If you pass in your\n * own, it may contain `$ref` references to the following, which are resolved\n * automatically for you:\n *\n * - {@link EntityEnvelope}\n * - {@link Entity}\n * - {@link EntityMeta}\n * - `common#<id>`\n *\n * See also {@link https://github.com/backstage/backstage/tree/master/packages/catalog-model/src/schema}\n *\n * @public\n *\n */\nexport function entityEnvelopeSchemaValidator\n\n(schema) {\n const validate = compileAjvSchema(\n schema ? (schema ) : entityEnvelopeSchema,\n );\n\n return data => {\n const result = validate(data);\n if (result === true) {\n return data ;\n }\n\n throw throwAjvError(validate.errors);\n };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { compileAjvSchema, throwAjvError } from './ajv';\n\n/**\n * Creates a validation function that takes some arbitrary data, and either\n * returns that data cast to a `T` if it matches that schema, or `false` if the\n * schema apiVersion/kind didn't apply to that data, or throws a\n * {@link globals#TypeError} describing actual errors.\n *\n * @remarks\n *\n * This validator is highly specialized, in that it has special treatment of\n * the `kind` and `apiVersion` root keys. This only works if your schema has\n * their rule set to `\"enum\"`:\n *\n * ```\n * \"apiVersion\": {\n * \"enum\": [\"backstage.io/v1alpha1\", \"backstage.io/v1beta1\"]\n * },\n * \"kind\": {\n * \"enum\": [\"Group\"]\n * },\n * ```\n *\n * In the above example, the created validator will return `false` if and only\n * if the kind and/or apiVersion mismatch.\n *\n * Note that this validator is only meant for applying the base schema checks;\n * it does not take custom policies or additional processor based validation\n * into account.\n *\n * The given schema may contain `$ref` references to the following, which are\n * resolved automatically for you:\n *\n * - {@link Entity}\n *\n * - {@link EntityEnvelope}\n *\n * - {@link EntityMeta}\n *\n * - `common#<id>`\n * @see {@link https://github.com/backstage/backstage/tree/master/packages/catalog-model/src/schema}\n *\n * @public\n */\nexport function entityKindSchemaValidator(\n schema,\n) {\n const validate = compileAjvSchema(schema );\n\n return data => {\n const result = validate(data);\n if (result === true) {\n return data ;\n }\n\n // Only in the case where kind and/or apiVersion have enum mismatches AND\n // have NO other errors, we call it a soft error.\n const softCandidates = validate.errors?.filter(e =>\n ['/kind', '/apiVersion'].includes(e.dataPath),\n );\n if (\n softCandidates?.length &&\n softCandidates.every(e => e.keyword === 'enum')\n ) {\n return false;\n }\n\n throw throwAjvError(validate.errors);\n };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport entitySchema from '../schema/Entity.schema.json';\nimport { compileAjvSchema, throwAjvError } from './ajv';\n\n/**\n * Creates a validation function that takes some arbitrary data, and either\n * returns that data cast to an {@link Entity} (or the given subtype) if it\n * matches that schema, or throws a {@link globals#TypeError} describing the errors.\n *\n * @remarks\n *\n * Note that this validator is only meant for applying the base schema checks;\n * it does not take custom policies or additional processor based validation\n * into account.\n *\n * By default, the plain {@link Entity} schema is used. If you pass in your own, it\n * may contain `$ref` references to the following, which are resolved\n * automatically for you:\n *\n * - {@link Entity}\n * - {@link EntityEnvelope}\n * - {@link EntityMeta}\n * - `common#<id>`\n *\n * @public\n * @see {@link https://github.com/backstage/backstage/tree/master/packages/catalog-model/src/schema}\n */\nexport function entitySchemaValidator(\n schema,\n) {\n const validate = compileAjvSchema(schema ? (schema ) : entitySchema);\n\n return data => {\n const result = validate(data);\n if (result === true) {\n return data ;\n }\n\n throw throwAjvError(validate.errors);\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CommonValidatorFunctions } from './CommonValidatorFunctions';\n\n/**\n * Contains validation functions that match the Kubernetes spec, usable to\n * build a catalog that is compatible with those rule sets.\n *\n * @public\n * @see https://kubernetes.io/docs/concepts/overview/working-with-objects/names/\n * @see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set\n * @see https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/#syntax-and-character-set\n */\nexport class KubernetesValidatorFunctions {\n static isValidApiVersion(value) {\n return CommonValidatorFunctions.isValidPrefixAndOrSuffix(\n value,\n '/',\n CommonValidatorFunctions.isValidDnsSubdomain,\n n => n.length >= 1 && n.length <= 63 && /^[a-z0-9A-Z]+$/.test(n),\n );\n }\n\n static isValidKind(value) {\n return (\n typeof value === 'string' &&\n value.length >= 1 &&\n value.length <= 63 &&\n /^[a-zA-Z][a-z0-9A-Z]*$/.test(value)\n );\n }\n\n static isValidObjectName(value) {\n return (\n typeof value === 'string' &&\n value.length >= 1 &&\n value.length <= 63 &&\n /^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$/.test(value)\n );\n }\n\n static isValidNamespace(value) {\n return CommonValidatorFunctions.isValidDnsLabel(value);\n }\n\n static isValidLabelKey(value) {\n return CommonValidatorFunctions.isValidPrefixAndOrSuffix(\n value,\n '/',\n CommonValidatorFunctions.isValidDnsSubdomain,\n KubernetesValidatorFunctions.isValidObjectName,\n );\n }\n\n static isValidLabelValue(value) {\n return (\n value === '' || KubernetesValidatorFunctions.isValidObjectName(value)\n );\n }\n\n static isValidAnnotationKey(value) {\n return CommonValidatorFunctions.isValidPrefixAndOrSuffix(\n value,\n '/',\n CommonValidatorFunctions.isValidDnsSubdomain,\n KubernetesValidatorFunctions.isValidObjectName,\n );\n }\n\n static isValidAnnotationValue(value) {\n return typeof value === 'string';\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CommonValidatorFunctions } from './CommonValidatorFunctions';\nimport { KubernetesValidatorFunctions } from './KubernetesValidatorFunctions';\n\n\nconst defaultValidators = {\n isValidApiVersion: KubernetesValidatorFunctions.isValidApiVersion,\n isValidKind: KubernetesValidatorFunctions.isValidKind,\n isValidEntityName: KubernetesValidatorFunctions.isValidObjectName,\n isValidNamespace: KubernetesValidatorFunctions.isValidNamespace,\n isValidLabelKey: KubernetesValidatorFunctions.isValidLabelKey,\n isValidLabelValue: KubernetesValidatorFunctions.isValidLabelValue,\n isValidAnnotationKey: KubernetesValidatorFunctions.isValidAnnotationKey,\n isValidAnnotationValue: KubernetesValidatorFunctions.isValidAnnotationValue,\n isValidTag: CommonValidatorFunctions.isValidTag,\n};\n\n/**\n * Creates a {@link Validators} object from `overrides`, with default values taken from {@link KubernetesValidatorFunctions}\n *\n * @public\n */\nexport function makeValidator(overrides = {}) {\n return {\n ...defaultValidators,\n ...overrides,\n };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport {\n CommonValidatorFunctions,\n KubernetesValidatorFunctions,\n makeValidator,\n\n} from '../../validation';\n\n\n/**\n * Ensures that the format of individual fields of the entity envelope\n * is valid.\n *\n * @remarks\n *\n * This does not take into account machine generated fields such as uid, etag\n * and generation.\n *\n * @public\n */\nexport class FieldFormatEntityPolicy {\n validators;\n\n constructor(validators = makeValidator()) {\n this.validators = validators;\n }\n\n async enforce(entity) {\n function require(\n field,\n value,\n validator,\n ) {\n if (value === undefined || value === null) {\n throw new Error(`${field} must have a value`);\n }\n\n let isValid;\n try {\n isValid = validator(value);\n } catch (e) {\n throw new Error(`${field} could not be validated, ${e}`);\n }\n\n if (!isValid) {\n let expectation;\n switch (\n validator.name \n\n\n ) {\n case 'isValidLabelValue':\n case 'isValidObjectName':\n expectation =\n 'a string that is sequences of [a-zA-Z0-9] separated by any of [-_.], at most 63 characters in total';\n break;\n case 'isValidLabelKey':\n case 'isValidApiVersion':\n case 'isValidAnnotationKey':\n expectation = 'a valid prefix and/or suffix';\n break;\n case 'isValidNamespace':\n case 'isValidDnsLabel':\n expectation =\n 'a string that is sequences of [a-z0-9] separated by [-], at most 63 characters in total';\n break;\n case 'isValidTag':\n expectation =\n 'a string that is sequences of [a-z0-9+#] separated by [-], at most 63 characters in total';\n break;\n case 'isValidAnnotationValue':\n expectation = 'a string';\n break;\n case 'isValidKind':\n expectation =\n 'a string that is a sequence of [a-zA-Z][a-z0-9A-Z], at most 63 characters in total';\n break;\n case 'isValidUrl':\n expectation = 'a string that is a valid url';\n break;\n case 'isValidString':\n expectation = 'a non empty string';\n break;\n default:\n expectation = undefined;\n break;\n }\n\n // ensure that if there are other/future validators, the error message defaults to a general \"is not valid, visit link\"\n const message = expectation\n ? ` expected ${expectation} but found \"${value}\".`\n : '';\n\n throw new Error(\n `\"${field}\" is not valid;${message} To learn more about catalog file format, visit: https://github.com/backstage/backstage/blob/master/docs/architecture-decisions/adr002-default-catalog-file-format.md`,\n );\n }\n }\n\n function optional(\n field,\n value,\n validator,\n ) {\n return value === undefined || require(field, value, validator);\n }\n\n require('apiVersion', entity.apiVersion, this.validators.isValidApiVersion);\n require('kind', entity.kind, this.validators.isValidKind);\n\n require('metadata.name', entity.metadata.name, this.validators\n .isValidEntityName);\n optional(\n 'metadata.namespace',\n entity.metadata.namespace,\n this.validators.isValidNamespace,\n );\n\n for (const [k, v] of Object.entries(entity.metadata.labels ?? [])) {\n require(`labels.${k}`, k, this.validators.isValidLabelKey);\n require(`labels.${k}`, v, this.validators.isValidLabelValue);\n }\n\n for (const [k, v] of Object.entries(entity.metadata.annotations ?? [])) {\n require(`annotations.${k}`, k, this.validators.isValidAnnotationKey);\n require(`annotations.${k}`, v, this.validators.isValidAnnotationValue);\n }\n\n const tags = entity.metadata.tags ?? [];\n\n for (let i = 0; i < tags.length; ++i) {\n require(`tags.${i}`, tags[i], this.validators.isValidTag);\n }\n\n const links = entity.metadata.links ?? [];\n\n for (let i = 0; i < links.length; ++i) {\n require(`links.${i}.url`, links[i]\n ?.url, CommonValidatorFunctions.isValidUrl);\n optional(\n `links.${i}.title`,\n links[i]?.title,\n CommonValidatorFunctions.isValidString,\n );\n optional(\n `links.${i}.icon`,\n links[i]?.icon,\n KubernetesValidatorFunctions.isValidObjectName,\n );\n }\n\n return entity;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Ajv, { } from 'ajv';\nimport entitySchema from '../../schema/Entity.schema.json';\nimport entityMetaSchema from '../../schema/EntityMeta.schema.json';\nimport commonSchema from '../../schema/shared/common.schema.json';\n\n\n\n/**\n * Ensures that the entity spec is valid according to a schema.\n *\n * @remarks\n *\n * This should be the first policy in the list, to ensure that other downstream\n * policies can work with a structure that is at least valid in therms of the\n * typescript type.\n *\n * @public\n */\nexport class SchemaValidEntityPolicy {\n validate;\n\n async enforce(entity) {\n if (!this.validate) {\n const ajv = new Ajv({ allowUnionTypes: true });\n this.validate = ajv\n .addSchema([commonSchema, entityMetaSchema], undefined, undefined, true)\n .compile(entitySchema);\n }\n\n const result = this.validate(entity);\n if (result === true) {\n return entity;\n }\n\n const [error] = this.validate.errors || [];\n if (!error) {\n throw new Error(`Malformed envelope, Unknown error`);\n }\n\n throw new Error(\n `Malformed envelope, ${error.dataPath || '<root>'} ${error.message}`,\n );\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { ENTITY_DEFAULT_NAMESPACE } from './constants';\n\n\nfunction parseRefString(ref)\n\n\n\n {\n const match = /^([^:/]+:)?([^:/]+\\/)?([^:/]+)$/.exec(ref.trim());\n if (!match) {\n throw new TypeError(\n `Entity reference \"${ref}\" was not on the form [<kind>:][<namespace>/]<name>`,\n );\n }\n\n return {\n kind: match[1]?.slice(0, -1),\n namespace: match[2]?.slice(0, -1),\n name: match[3],\n };\n}\n\n/**\n * Extracts the kind, namespace and name that form the name triplet of the\n * given entity.\n *\n * @public\n * @param entity - An entity\n * @returns The complete entity name\n */\nexport function getEntityName(entity) {\n return {\n kind: entity.kind,\n namespace: entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE,\n name: entity.metadata.name,\n };\n}\n\n/**\n * The context of defaults that entity reference parsing happens within.\n *\n * @public\n */\n\n\n\n\n\n\n\n/**\n * Parses an entity reference, either on string or compound form, and always\n * returns a complete entity name including kind, namespace and name.\n *\n * @remarks\n *\n * This function automatically assumes the default namespace \"default\" unless\n * otherwise specified as part of the options, and will throw an error if no\n * kind was specified in the input reference and no default kind was given.\n *\n * @public\n * @param ref - The reference to parse\n * @param context - The context of defaults that the parsing happens within\n * @returns A complete entity name\n */\nexport function parseEntityName(\n ref,\n context = {},\n) {\n const { kind, namespace, name } = parseEntityRef(ref, {\n defaultNamespace: ENTITY_DEFAULT_NAMESPACE,\n ...context,\n });\n\n if (!kind) {\n throw new Error(\n `Entity reference ${namespace}/${name} did not contain a kind`,\n );\n }\n\n return { kind, namespace, name };\n}\n\n/**\n * Parses an entity reference, either on string or compound form, and returns\n * a structure with a name, and optional kind and namespace.\n *\n * @remarks\n *\n * The context object can contain default values for the kind and namespace,\n * that will be used if the input reference did not specify any.\n *\n * @public\n * @param ref - The reference to parse\n * @param context - The context of defaults that the parsing happens within\n * @returns The compound form of the reference\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * parseEntityRef with optional Kind and Namespace.\n *\n * @public\n */\nexport function parseEntityRef(\n ref,\n context = {},\n)\n\n\n\n {\n if (!ref) {\n throw new Error(`Entity reference must not be empty`);\n }\n\n if (typeof ref === 'string') {\n const parsed = parseRefString(ref);\n return {\n kind: parsed.kind ?? context.defaultKind,\n namespace: parsed.namespace ?? context.defaultNamespace,\n name: parsed.name,\n };\n }\n\n const { kind, namespace, name } = ref;\n if (kind === '') {\n throw new Error('Entity reference kinds must not be empty');\n } else if (namespace === '') {\n throw new Error('Entity reference namespaces must not be empty');\n } else if (!name) {\n throw new Error('Entity references must contain a name');\n }\n\n return {\n kind: kind ?? context.defaultKind,\n namespace: namespace ?? context.defaultNamespace,\n name,\n };\n}\n\n/**\n * Takes an entity reference or name, and outputs an entity reference on the\n * most compact form possible. I.e. if the parts do not contain any\n * special/reserved characters, it outputs the string form, otherwise it\n * outputs the compound form.\n *\n * @public\n * @deprecated Use `stringifyEntityRef` instead\n * @param ref - The reference to serialize\n * @returns The same reference on either string or compound form\n */\nexport function serializeEntityRef(\n ref\n\n\n\n\n\n,\n) {\n let kind;\n let namespace;\n let name;\n\n if ('metadata' in ref) {\n kind = ref.kind;\n namespace = ref.metadata.namespace;\n name = ref.metadata.name;\n } else {\n kind = ref.kind;\n namespace = ref.namespace;\n name = ref.name;\n }\n\n if (\n kind?.includes(':') ||\n kind?.includes('/') ||\n namespace?.includes(':') ||\n namespace?.includes('/') ||\n name.includes(':') ||\n name.includes('/')\n ) {\n return { kind, namespace, name };\n }\n\n return `${kind ? `${kind}:` : ''}${namespace ? `${namespace}/` : ''}${name}`;\n}\n\n/**\n * Takes an entity or entity name/reference, and returns the string form of an\n * entity ref.\n *\n * @remarks\n *\n * This function creates a canonical and unique reference to the entity, converting\n * all parts of the name to lowercase and inserts the default namespace if needed.\n * It is typically not the best way to represent the entity reference to the user.\n *\n * @public\n * @param ref - The reference to serialize\n * @returns The same reference on either string or compound form\n */\nexport function stringifyEntityRef(\n ref,\n) {\n let kind;\n let namespace;\n let name;\n\n if ('metadata' in ref) {\n kind = ref.kind;\n namespace = ref.metadata.namespace ?? ENTITY_DEFAULT_NAMESPACE;\n name = ref.metadata.name;\n } else {\n kind = ref.kind;\n namespace = ref.namespace ?? ENTITY_DEFAULT_NAMESPACE;\n name = ref.name;\n }\n\n return `${kind.toLocaleLowerCase('en-US')}:${namespace.toLocaleLowerCase(\n 'en-US',\n )}/${name.toLocaleLowerCase('en-US')}`;\n}\n\n/**\n * Compares an entity to either a string reference or a compound reference.\n *\n * @remarks\n *\n * The comparison is case insensitive, and all of kind, namespace, and name\n * must match (after applying the optional context to the ref).\n *\n * @public\n * @param entity - The entity to match\n * @param ref - A string or compound entity ref\n * @param context - An optional context of default kind and namespace, that apply\n * to the ref if given\n * @returns True if matching, false otherwise\n */\nexport function compareEntityToRef(\n entity,\n ref,\n context,\n) {\n const entityKind = entity.kind;\n const entityNamespace = entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE;\n const entityName = entity.metadata.name;\n\n let refKind;\n let refNamespace;\n let refName;\n if (typeof ref === 'string') {\n const parsed = parseRefString(ref);\n refKind = parsed.kind || context?.defaultKind;\n refNamespace =\n parsed.namespace || context?.defaultNamespace || ENTITY_DEFAULT_NAMESPACE;\n refName = parsed.name;\n } else {\n refKind = ref.kind || context?.defaultKind;\n refNamespace =\n ref.namespace || context?.defaultNamespace || ENTITY_DEFAULT_NAMESPACE;\n refName = ref.name;\n }\n\n if (!refKind || !refNamespace) {\n throw new Error(\n `Entity reference or context did not contain kind and namespace`,\n );\n }\n\n return (\n entityKind.toLocaleLowerCase('en-US') ===\n refKind.toLocaleLowerCase('en-US') &&\n entityNamespace.toLocaleLowerCase('en-US') ===\n refNamespace.toLocaleLowerCase('en-US') &&\n entityName.toLocaleLowerCase('en-US') === refName.toLocaleLowerCase('en-US')\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport lodash from 'lodash';\nimport { v4 as uuidv4 } from 'uuid';\n\n\n/**\n * Generates a new random UID for an entity.\n *\n * @public\n * @returns A string with enough randomness to uniquely identify an entity\n */\nexport function generateEntityUid() {\n return uuidv4();\n}\n\n/**\n * Generates a new random Etag for an entity.\n *\n * @public\n * @returns A string with enough randomness to uniquely identify an entity\n * revision\n */\nexport function generateEntityEtag() {\n return Buffer.from(uuidv4(), 'utf8').toString('base64').replace(/[^\\w]/g, '');\n}\n\n/**\n * Checks whether there are any significant changes going from the previous to\n * the next version of this entity.\n *\n * @remarks\n *\n * Significance, in this case, means that we do not compare generated fields\n * such as uid, etag and generation.\n *\n * Note that this comparison does NOT take status, relations or similar into\n * account. It only compares the actual input entity data, i.e. metadata and\n * spec.\n *\n * @public\n * @param previous - The old state of the entity\n * @param next - The new state of the entity\n */\nexport function entityHasChanges(previous, next) {\n const e1 = lodash.cloneDeep(previous);\n const e2 = lodash.cloneDeep(next);\n\n if (!e1.metadata.labels) {\n e1.metadata.labels = {};\n }\n if (!e2.metadata.labels) {\n e2.metadata.labels = {};\n }\n if (!e1.metadata.annotations) {\n e1.metadata.annotations = {};\n }\n if (!e2.metadata.annotations) {\n e2.metadata.annotations = {};\n }\n if (!e1.metadata.tags) {\n e1.metadata.tags = [];\n }\n if (!e2.metadata.tags) {\n e2.metadata.tags = [];\n }\n\n // Remove generated fields\n delete e1.metadata.uid;\n delete e1.metadata.etag;\n delete e1.metadata.generation;\n delete e2.metadata.uid;\n delete e2.metadata.etag;\n delete e2.metadata.generation;\n\n // Remove things that we explicitly do not compare\n delete e1.relations;\n delete (e1 ).status;\n delete e2.relations;\n delete (e2 ).status;\n\n return !lodash.isEqual(e1, e2);\n}\n\n/**\n * Takes an old revision of an entity and a new desired state, and merges\n * them into a complete new state.\n *\n * @remarks\n *\n * The previous revision is expected to be a complete model loaded from the\n * catalog, including the uid, etag and generation fields.\n *\n * @public\n * @param previous - The old state of the entity\n * @param next - The new state of the entity\n * @returns An entity with the merged state of both\n */\nexport function generateUpdatedEntity(previous, next) {\n const { uid, etag, generation } = previous.metadata;\n if (!uid || !etag || !generation) {\n throw new Error('Previous entity must have uid, etag and generation');\n }\n\n const result = lodash.cloneDeep(next);\n\n // Generated fields are copied and updated\n const bumpEtag = entityHasChanges(previous, result);\n const bumpGeneration = !lodash.isEqual(previous.spec, result.spec);\n result.metadata.uid = uid;\n result.metadata.etag = bumpEtag ? generateEntityEtag() : etag;\n result.metadata.generation = bumpGeneration ? generation + 1 : generation;\n\n return result;\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n// Helper that requires that all of a set of policies can be successfully\n// applied\nclass AllEntityPolicies {\n constructor( policies) {;this.policies = policies;}\n\n async enforce(entity) {\n let result = entity;\n for (const policy of this.policies) {\n const output = await policy.enforce(result);\n if (!output) {\n throw new Error(\n `Policy ${policy.constructor.name} did not return a result`,\n );\n }\n result = output;\n }\n return result;\n }\n}\n\n// Helper that requires that at least one of a set of policies can be\n// successfully applied\nclass AnyEntityPolicy {\n constructor( policies) {;this.policies = policies;}\n\n async enforce(entity) {\n for (const policy of this.policies) {\n const output = await policy.enforce(entity);\n if (output) {\n return output;\n }\n }\n throw new Error(`The entity did not match any known policy`);\n }\n}\n\n/**\n * Provides helpers for enforcing a set of {@link EntityPolicy} in an `and`/`or` expression.\n *\n * @public\n */\nexport const EntityPolicies = {\n allOf(policies) {\n return new AllEntityPolicies(policies);\n },\n oneOf(policies) {\n return new AnyEntityPolicy(policies);\n },\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { entityKindSchemaValidator } from '../validation';\n\n\n// TODO(freben): Left here as a compatibility helper. It would be nicer to\n// just export the inner validator directly. However, all of the already\n// exported kind validators have the `KindValidator` signature which is\n// different. So let's postpone that change until a later time.\nexport function ajvCompiledJsonSchemaValidator(schema) {\n const validator = entityKindSchemaValidator(schema);\n return {\n async check(data) {\n return validator(data) === data;\n },\n };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport schema from '../schema/kinds/API.v1alpha1.schema.json';\nimport { ajvCompiledJsonSchemaValidator } from './util';\n\n/**\n * Backstage API kind Entity. APIs describe the interfaces for Components to communicate.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/features/software-catalog/system-model}\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * {@link KindValidator} for {@link ApiEntityV1alpha1}.\n *\n * @public\n */\nexport const apiEntityV1alpha1Validator =\n ajvCompiledJsonSchemaValidator(schema);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport schema from '../schema/kinds/Component.v1alpha1.schema.json';\nimport { ajvCompiledJsonSchemaValidator } from './util';\n\n/**\n * Backstage catalog Component kind Entity. Represents a single, individual piece of software.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/features/software-catalog/system-model}\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * {@link KindValidator} for {@link ComponentEntityV1alpha1}.\n *\n * @public\n */\nexport const componentEntityV1alpha1Validator =\n ajvCompiledJsonSchemaValidator(schema);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport schema from '../schema/kinds/Domain.v1alpha1.schema.json';\nimport { ajvCompiledJsonSchemaValidator } from './util';\n\n/**\n * Backstage Domain kind Entity. Domains group Systems together.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/features/software-catalog/system-model}\n *\n * @public\n */\n\n\n\n\n\n\n\n\n/**\n * {@link KindValidator} for {@link DomainEntityV1alpha1}.\n *\n * @public\n */\nexport const domainEntityV1alpha1Validator =\n ajvCompiledJsonSchemaValidator(schema);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport schema from '../schema/kinds/Group.v1alpha1.schema.json';\nimport { ajvCompiledJsonSchemaValidator } from './util';\n\n/**\n * Backstage catalog Group kind Entity.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * {@link KindValidator} for {@link GroupEntityV1alpha1}.\n * @public\n */\nexport const groupEntityV1alpha1Validator =\n ajvCompiledJsonSchemaValidator(schema);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport schema from '../schema/kinds/Location.v1alpha1.schema.json';\nimport { ajvCompiledJsonSchemaValidator } from './util';\n\n/**\n * Backstage catalog Location kind Entity.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n/**\n * {@link KindValidator} for {@link LocationEntityV1alpha1}.\n *\n * @public\n */\nexport const locationEntityV1alpha1Validator =\n ajvCompiledJsonSchemaValidator(schema);\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\nNaming rules for relations in priority order:\n\n1. Use at most two words. One main verb and a specifier, e.g. \"ownerOf\"\n2. Reading out \"<source-kind> <type> <target-kind>\" should make sense in English.\n3. Maintain symmetry between pairs, e.g. \"ownedBy\" and \"ownerOf\" rather than \"owns\".\n*/\n\n/**\n * An ownership relation where the owner is usually an organizational\n * entity (user or group), and the other entity can be anything. Reversed\n * direction of {@link RELATION_OWNER_OF}.\n *\n * @public\n */\nexport const RELATION_OWNED_BY = 'ownedBy';\n\n/**\n * A relationship from an owner to the owned entity. Reversed direction of\n * {@link RELATION_OWNED_BY}.\n *\n * @public\n */\nexport const RELATION_OWNER_OF = 'ownerOf';\n\n/**\n * A relation with an API entity, typically from a component. Reversed direction of\n * {@link RELATION_API_CONSUMED_BY}.\n *\n * @public\n */\nexport const RELATION_CONSUMES_API = 'consumesApi';\n\n/**\n * A relation of an API being consumed, typically by a component. Reversed direction of\n * {@link RELATION_CONSUMES_API}.\n *\n * @public\n */\nexport const RELATION_API_CONSUMED_BY = 'apiConsumedBy';\n\n/**\n * A relation from an API provider entity (typically a component) to the API. Reversed direction of\n * {@link RELATION_API_PROVIDED_BY}.\n *\n * @public\n */\nexport const RELATION_PROVIDES_API = 'providesApi';\n\n/**\n * A relation from an API to its provider entity (typically a component). Reversed direction of\n * {@link RELATION_PROVIDES_API}.\n *\n * @public\n */\nexport const RELATION_API_PROVIDED_BY = 'apiProvidedBy';\n\n/**\n * A relation denoting a dependency on another entity. Reversed direction of\n * {@link RELATION_DEPENDENCY_OF}.\n *\n * @public\n */\nexport const RELATION_DEPENDS_ON = 'dependsOn';\n\n/**\n * A relation denoting a reverse dependency by another entity. Reversed direction of\n * {@link RELATION_DEPENDS_ON}.\n *\n * @public\n */\nexport const RELATION_DEPENDENCY_OF = 'dependencyOf';\n\n/**\n * A parent/child relation to build up a tree, used for example to describe\n * the organizational structure between groups. Reversed direction of\n * {@link RELATION_CHILD_OF}.\n *\n * @public\n */\nexport const RELATION_PARENT_OF = 'parentOf';\n\n/**\n * A relation from a child to a parent entity, used for example to describe\n * the organizational structure between groups. Reversed direction of\n * {@link RELATION_PARENT_OF}.\n *\n * @public\n */\nexport const RELATION_CHILD_OF = 'childOf';\n\n/**\n * A membership relation, typically for users in a group. Reversed direction of\n * {@link RELATION_HAS_MEMBER}.\n *\n * @public\n */\nexport const RELATION_MEMBER_OF = 'memberOf';\n\n/**\n * A relation from a group to its member, typcally a user in a group. Reversed direction of\n * {@link RELATION_MEMBER_OF}.\n *\n * @public\n */\nexport const RELATION_HAS_MEMBER = 'hasMember';\n\n/**\n * A part/whole relation, typically for components in a system and systems\n * in a domain. Reversed direction of {@link RELATION_HAS_PART}.\n *\n * @public\n */\nexport const RELATION_PART_OF = 'partOf';\n\n/**\n * A relation from a containing entity to a contained entity. Reversed direction of\n * {@link RELATION_PART_OF}.\n *\n * @public\n */\nexport const RELATION_HAS_PART = 'hasPart';\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport schema from '../schema/kinds/Resource.v1alpha1.schema.json';\nimport { ajvCompiledJsonSchemaValidator } from './util';\n\n/**\n * Backstage catalog Resource kind Entity. Represents infrastructure required to operate Components.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/features/software-catalog/system-model}\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n/**\n * {@link KindValidator} for {@link ResourceEntityV1alpha1}.\n *\n * @public\n */\nexport const resourceEntityV1alpha1Validator =\n ajvCompiledJsonSchemaValidator(schema);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport schema from '../schema/kinds/System.v1alpha1.schema.json';\nimport { ajvCompiledJsonSchemaValidator } from './util';\n\n/**\n * Backstage catalog System kind Entity. Systems group Comopnents, Resources and APIs together.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/features/software-catalog/system-model}\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n/**\n * {@link KindValidator} for {@link SystemEntityV1alpha1}.\n *\n * @public\n */\nexport const systemEntityV1alpha1Validator =\n ajvCompiledJsonSchemaValidator(schema);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport schema from '../schema/kinds/Template.v1beta2.schema.json';\nimport { ajvCompiledJsonSchemaValidator } from './util';\n\n/**\n * Backstage catalog Template kind Entity. Templates are used by the Scaffolder plugin to create new Components.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * {@link KindValidator} for {@link TemplateEntityV1beta2}.\n *\n * @public\n */\nexport const templateEntityV1beta2Validator =\n ajvCompiledJsonSchemaValidator(schema);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport schema from '../schema/kinds/User.v1alpha1.schema.json';\nimport { ajvCompiledJsonSchemaValidator } from './util';\n\n/**\n * Backstage catalog User kind Entity.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * {@link KindValidator} for {@link UserEntityV1alpha1}.\n *\n * @public\n */\nexport const userEntityV1alpha1Validator =\n ajvCompiledJsonSchemaValidator(schema);\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Constant storing location annotation.\n *\n * @public */\nexport const LOCATION_ANNOTATION = 'backstage.io/managed-by-location';\n/**\n * Constant storing origin location annotation\n *\n * @public */\nexport const ORIGIN_LOCATION_ANNOTATION =\n 'backstage.io/managed-by-origin-location';\n\n/**\n * Contant storing source location annotation\n *\n * @public */\nexport const SOURCE_LOCATION_ANNOTATION = 'backstage.io/source-location';\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { stringifyEntityRef } from '../entity';\nimport { LOCATION_ANNOTATION, SOURCE_LOCATION_ANNOTATION } from './annotation';\n\n/**\n * Parses a string form location reference.\n *\n * Note that the return type is not `LocationSpec`, because we do not want to\n * conflate the string form with the additional properties of that type.\n *\n * @public\n * @param ref - A string-form location reference, e.g. `'url:https://host'`\n * @returns A location reference, e.g. `{ type: 'url', target: 'https://host' }`\n */\nexport function parseLocationReference(ref)\n\n\n {\n if (typeof ref !== 'string') {\n throw new TypeError(\n `Unable to parse location reference '${ref}', unexpected argument ${typeof ref}`,\n );\n }\n\n const splitIndex = ref.indexOf(':');\n if (splitIndex < 0) {\n throw new TypeError(\n `Unable to parse location reference '${ref}', expected '<type>:<target>', e.g. 'url:https://host/path'`,\n );\n }\n\n const type = ref.substr(0, splitIndex).trim();\n const target = ref.substr(splitIndex + 1).trim();\n\n if (!type || !target) {\n throw new TypeError(\n `Unable to parse location reference '${ref}', expected '<type>:<target>', e.g. 'url:https://host/path'`,\n );\n }\n\n if (type === 'http' || type === 'https') {\n throw new TypeError(\n `Invalid location reference '${ref}', please prefix it with 'url:', e.g. 'url:${ref}'`,\n );\n }\n\n return { type, target };\n}\n\n/**\n * Turns a location reference into its string form.\n *\n * @remarks\n *\n * Note that the input type is not `LocationSpec`, because we do not want to\n * conflate the string form with the additional properties of that type.\n *\n * @public\n * @param ref - A location reference, e.g. `{ type: 'url', target: 'https://host' }`\n * @returns A string-form location reference, e.g. `'url:https://host'`\n */\nexport function stringifyLocationReference(ref\n\n\n) {\n const { type, target } = ref;\n\n if (!type) {\n throw new TypeError(`Unable to stringify location reference, empty type`);\n } else if (!target) {\n throw new TypeError(`Unable to stringify location reference, empty target`);\n }\n\n return `${type}:${target}`;\n}\n\n/**\n * Returns the source code location of the Entity, to the extent that one exists.\n *\n * @remarks\n *\n * If the returned location type is of type 'url', the target should be readable at least\n * using the UrlReader from `@backstage/backend-common`. If it is not of type 'url', the caller\n * needs to have explicit handling of each location type or signal that it is not supported.\n *\n * @public\n */\nexport function getEntitySourceLocation(entity)\n\n\n {\n const locationRef =\n entity.metadata?.annotations?.[SOURCE_LOCATION_ANNOTATION] ??\n entity.metadata?.annotations?.[LOCATION_ANNOTATION];\n\n if (!locationRef) {\n throw new Error(\n `Entity '${stringifyEntityRef(entity)}' is missing location`,\n );\n }\n\n return parseLocationReference(locationRef);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as yup from 'yup';\n\n\n/**\n * Deprecated.\n *\n * @public\n * @deprecated Use {@link JSONSchema} or validators instead.\n */\nexport const locationSpecSchema = yup\n .object({\n type: yup.string().required(),\n target: yup.string().required(),\n presence: yup.mixed().oneOf(['required', 'optional']),\n })\n .noUnknown()\n .required();\n\n/**\n * Deprecated.\n *\n * @public\n * @deprecated Use {@link JSONSchema} or validators instead.\n */\nexport const locationSchema = yup\n .object({\n id: yup.string().required(),\n type: yup.string().required(),\n target: yup.string().required(),\n presence: yup.mixed().oneOf(['required', 'optional']),\n })\n .noUnknown()\n .required();\n\n/**\n * Deprecated.\n *\n * @public\n * @deprecated Use {@link JSONSchema} or validators instead.\n */\nexport const analyzeLocationSchema =\n yup\n .object({\n location: locationSpecSchema,\n })\n .noUnknown()\n .required();\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { PublishSubject } from '../../../lib/subjects';\n\n/**\n * Base implementation for the AlertApi that simply forwards alerts to consumers.\n *\n * @public\n */\nexport class AlertApiForwarder {\n subject = new PublishSubject();\n\n post(alert) {\n this.subject.next(alert);\n }\n\n alert$() {\n return this.subject;\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Base implementation for the AnalyticsApi that does nothing.\n *\n * @public\n */\nexport class NoOpAnalyticsApi {\n captureEvent(_event) {}\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { BehaviorSubject } from '../../../lib/subjects';\n\nconst STORAGE_KEY = 'theme';\n\n/**\n * Exposes the themes installed in the app, and permits switching the currently\n * active theme.\n *\n * @public\n */\nexport class AppThemeSelector {\n static createWithStorage(themes) {\n const selector = new AppThemeSelector(themes);\n\n if (!window.localStorage) {\n return selector;\n }\n\n const initialThemeId =\n window.localStorage.getItem(STORAGE_KEY) ?? undefined;\n\n selector.setActiveThemeId(initialThemeId);\n\n selector.activeThemeId$().subscribe(themeId => {\n if (themeId) {\n window.localStorage.setItem(STORAGE_KEY, themeId);\n } else {\n window.localStorage.removeItem(STORAGE_KEY);\n }\n });\n\n window.addEventListener('storage', event => {\n if (event.key === STORAGE_KEY) {\n const themeId = localStorage.getItem(STORAGE_KEY) ?? undefined;\n selector.setActiveThemeId(themeId);\n }\n });\n\n return selector;\n }\n\n activeThemeId;\n subject = new BehaviorSubject(undefined);\n\n constructor( themes) {;this.themes = themes;}\n\n getInstalledThemes() {\n return this.themes.slice();\n }\n\n activeThemeId$() {\n return this.subject;\n }\n\n getActiveThemeId() {\n return this.activeThemeId;\n }\n\n setActiveThemeId(themeId) {\n this.activeThemeId = themeId;\n this.subject.next(themeId);\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport cloneDeep from 'lodash/cloneDeep';\nimport mergeWith from 'lodash/mergeWith';\n\n// Update the same pattern in config-loader package if this is changed\nconst CONFIG_KEY_PART_PATTERN = /^[a-z][a-z0-9]*(?:[-_][a-z][a-z0-9]*)*$/i;\n\nfunction isObject(value) {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction typeOf(value) {\n if (value === null) {\n return 'null';\n } else if (Array.isArray(value)) {\n return 'array';\n }\n const type = typeof value;\n if (type === 'number' && isNaN(value )) {\n return 'nan';\n }\n if (type === 'string' && value === '') {\n return 'empty-string';\n }\n return type;\n}\n\n// Separate out a couple of common error messages to reduce bundle size.\nconst errors = {\n type(key, context, typeName, expected) {\n return `Invalid type in config for key '${key}' in '${context}', got ${typeName}, wanted ${expected}`;\n },\n missing(key) {\n return `Missing required config value at '${key}'`;\n },\n convert(key, context, expected) {\n return `Unable to convert config value for key '${key}' in '${context}' to a ${expected}`;\n },\n};\n\n/**\n * An implementation of the `Config` interface that uses a plain JavaScript object\n * for the backing data, with the ability of linking multiple readers together.\n *\n * @public\n */\nexport class ConfigReader {\n /**\n * A set of key paths that where removed from the config due to not being visible.\n *\n * This was added as a mutable private member to avoid changes to the public API.\n * Its only purpose of this is to warn users of missing visibility when running\n * the frontend in development mode.\n */\n filteredKeys;\n notifiedFilteredKeys = new Set();\n\n /**\n * Instantiates the config reader from a list of application config objects.\n */\n static fromConfigs(configs) {\n if (configs.length === 0) {\n return new ConfigReader(undefined);\n }\n\n // Merge together all configs into a single config with recursive fallback\n // readers, giving the first config object in the array the lowest priority.\n return configs.reduce(\n (previousReader, { data, context, filteredKeys, deprecatedKeys }) => {\n const reader = new ConfigReader(data, context, previousReader);\n reader.filteredKeys = filteredKeys;\n\n if (deprecatedKeys) {\n for (const { key, description } of deprecatedKeys) {\n // eslint-disable-next-line no-console\n console.warn(\n `The configuration key '${key}' of ${context} is deprecated and may be removed soon. ${\n description || ''\n }`,\n );\n }\n }\n\n return reader;\n },\n undefined,\n );\n }\n\n constructor(\n data,\n context = 'mock-config',\n fallback,\n prefix = '',\n ) {;this.data = data;this.context = context;this.fallback = fallback;this.prefix = prefix;}\n\n /** {@inheritdoc Config.has} */\n has(key) {\n const value = this.readValue(key);\n if (value !== undefined) {\n return true;\n }\n return this.fallback?.has(key) ?? false;\n }\n\n /** {@inheritdoc Config.keys} */\n keys() {\n const localKeys = this.data ? Object.keys(this.data) : [];\n const fallbackKeys = this.fallback?.keys() ?? [];\n return [...new Set([...localKeys, ...fallbackKeys])];\n }\n\n /** {@inheritdoc Config.get} */\n get(key) {\n const value = this.getOptional(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key ?? '')));\n }\n return value ;\n }\n\n /** {@inheritdoc Config.getOptional} */\n getOptional(key) {\n const value = cloneDeep(this.readValue(key));\n const fallbackValue = this.fallback?.getOptional(key);\n\n if (value === undefined) {\n if (process.env.NODE_ENV === 'development') {\n if (fallbackValue === undefined && key) {\n const fullKey = this.fullKey(key);\n if (\n this.filteredKeys?.includes(fullKey) &&\n !this.notifiedFilteredKeys.has(fullKey)\n ) {\n this.notifiedFilteredKeys.add(fullKey);\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration value at '${fullKey}' as it is not visible. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n }\n return fallbackValue;\n } else if (fallbackValue === undefined) {\n return value ;\n }\n\n // Avoid merging arrays and primitive values, since that's how merging works for other\n // methods for reading config.\n return mergeWith({}, { value: fallbackValue }, { value }, (into, from) =>\n !isObject(from) || !isObject(into) ? from : undefined,\n ).value ;\n }\n\n /** {@inheritdoc Config.getConfig} */\n getConfig(key) {\n const value = this.getOptionalConfig(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n /** {@inheritdoc Config.getOptionalConfig} */\n getOptionalConfig(key) {\n const value = this.readValue(key);\n const fallbackConfig = this.fallback?.getOptionalConfig(key);\n\n if (isObject(value)) {\n return this.copy(value, key, fallbackConfig);\n }\n if (value !== undefined) {\n throw new TypeError(\n errors.type(this.fullKey(key), this.context, typeOf(value), 'object'),\n );\n }\n return fallbackConfig;\n }\n\n /** {@inheritdoc Config.getConfigArray} */\n getConfigArray(key) {\n const value = this.getOptionalConfigArray(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n /** {@inheritdoc Config.getOptionalConfigArray} */\n getOptionalConfigArray(key) {\n const configs = this.readConfigValue(key, values => {\n if (!Array.isArray(values)) {\n return { expected: 'object-array' };\n }\n\n for (const [index, value] of values.entries()) {\n if (!isObject(value)) {\n return { expected: 'object-array', value, key: `${key}[${index}]` };\n }\n }\n return true;\n });\n\n if (!configs) {\n if (process.env.NODE_ENV === 'development') {\n const fullKey = this.fullKey(key);\n if (\n this.filteredKeys?.some(k => k.startsWith(fullKey)) &&\n !this.notifiedFilteredKeys.has(key)\n ) {\n this.notifiedFilteredKeys.add(key);\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration array at '${key}' as it does not have any visible elements. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n return undefined;\n }\n\n return configs.map((obj, index) => this.copy(obj, `${key}[${index}]`));\n }\n\n /** {@inheritdoc Config.getNumber} */\n getNumber(key) {\n const value = this.getOptionalNumber(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n /** {@inheritdoc Config.getOptionalNumber} */\n getOptionalNumber(key) {\n const value = this.readConfigValue(\n key,\n val =>\n typeof val === 'number' ||\n typeof val === 'string' || { expected: 'number' },\n );\n if (typeof value === 'number' || value === undefined) {\n return value;\n }\n const number = Number(value);\n if (!Number.isFinite(number)) {\n throw new Error(\n errors.convert(this.fullKey(key), this.context, 'number'),\n );\n }\n return number;\n }\n\n /** {@inheritdoc Config.getBoolean} */\n getBoolean(key) {\n const value = this.getOptionalBoolean(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n /** {@inheritdoc Config.getOptionalBoolean} */\n getOptionalBoolean(key) {\n return this.readConfigValue(\n key,\n value => typeof value === 'boolean' || { expected: 'boolean' },\n );\n }\n\n /** {@inheritdoc Config.getString} */\n getString(key) {\n const value = this.getOptionalString(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n /** {@inheritdoc Config.getOptionalString} */\n getOptionalString(key) {\n return this.readConfigValue(\n key,\n value =>\n (typeof value === 'string' && value !== '') || { expected: 'string' },\n );\n }\n\n /** {@inheritdoc Config.getStringArray} */\n getStringArray(key) {\n const value = this.getOptionalStringArray(key);\n if (value === undefined) {\n throw new Error(errors.missing(this.fullKey(key)));\n }\n return value;\n }\n\n /** {@inheritdoc Config.getOptionalStringArray} */\n getOptionalStringArray(key) {\n return this.readConfigValue(key, values => {\n if (!Array.isArray(values)) {\n return { expected: 'string-array' };\n }\n for (const [index, value] of values.entries()) {\n if (typeof value !== 'string' || value === '') {\n return { expected: 'string-array', value, key: `${key}[${index}]` };\n }\n }\n return true;\n });\n }\n\n fullKey(key) {\n return `${this.prefix}${this.prefix ? '.' : ''}${key}`;\n }\n\n copy(data, key, fallback) {\n const reader = new ConfigReader(\n data,\n this.context,\n fallback,\n this.fullKey(key),\n );\n reader.filteredKeys = this.filteredKeys;\n return reader;\n }\n\n readConfigValue(\n key,\n validate\n\n,\n ) {\n const value = this.readValue(key);\n\n if (value === undefined) {\n if (process.env.NODE_ENV === 'development') {\n const fullKey = this.fullKey(key);\n if (\n this.filteredKeys?.includes(fullKey) &&\n !this.notifiedFilteredKeys.has(fullKey)\n ) {\n this.notifiedFilteredKeys.add(fullKey);\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to read configuration value at '${fullKey}' as it is not visible. ` +\n 'See https://backstage.io/docs/conf/defining#visibility for instructions on how to make it visible.',\n );\n }\n }\n\n return this.fallback?.readConfigValue(key, validate);\n }\n const result = validate(value);\n if (result !== true) {\n const { key: keyName = key, value: theValue = value, expected } = result;\n throw new TypeError(\n errors.type(\n this.fullKey(keyName),\n this.context,\n typeOf(theValue),\n expected,\n ),\n );\n }\n\n return value ;\n }\n\n readValue(key) {\n const parts = key ? key.split('.') : [];\n for (const part of parts) {\n if (!CONFIG_KEY_PART_PATTERN.test(part)) {\n throw new TypeError(`Invalid config key '${key}'`);\n }\n }\n\n if (this.data === undefined) {\n return undefined;\n }\n\n let value = this.data;\n for (const [index, part] of parts.entries()) {\n if (isObject(value)) {\n value = value[part];\n } else if (value !== undefined) {\n const badKey = this.fullKey(parts.slice(0, index).join('.'));\n throw new TypeError(\n errors.type(badKey, this.context, typeOf(value), 'object'),\n );\n }\n }\n\n return value;\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst ERROR_PREFIX = 'Invalid discovery URL pattern,';\n\n/**\n * UrlPatternDiscovery is a lightweight DiscoveryApi implementation.\n * It uses a single template string to construct URLs for each plugin.\n *\n * @public\n */\nexport class UrlPatternDiscovery {\n /**\n * Creates a new UrlPatternDiscovery given a template. The the only\n * interpolation done for the template is to replace instances of `{{pluginId}}`\n * with the ID of the plugin being requested.\n *\n * Example pattern: `http://localhost:7007/api/{{ pluginId }}`\n */\n static compile(pattern) {\n const parts = pattern.split(/\\{\\{\\s*pluginId\\s*\\}\\}/);\n const urlStr = parts.join('pluginId');\n\n let url;\n try {\n url = new URL(urlStr);\n } catch {\n throw new Error(`${ERROR_PREFIX} URL '${urlStr}' is invalid`);\n }\n if (url.hash) {\n throw new Error(`${ERROR_PREFIX} URL must not have a hash`);\n }\n if (url.search) {\n throw new Error(`${ERROR_PREFIX} URL must not have a query`);\n }\n if (urlStr.endsWith('/')) {\n throw new Error(`${ERROR_PREFIX} URL must not end with a slash`);\n }\n\n return new UrlPatternDiscovery(parts);\n }\n\n constructor( parts) {;this.parts = parts;}\n\n async getBaseUrl(pluginId) {\n return this.parts.join(pluginId);\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Decorates an ErrorApi by also forwarding error messages\n * to the alertApi with an 'error' severity.\n *\n * @public\n */\nexport class ErrorAlerter {\n constructor(\n alertApi,\n errorApi,\n ) {;this.alertApi = alertApi;this.errorApi = errorApi;}\n\n post(error, context) {\n if (!context?.hidden) {\n this.alertApi.post({ message: error.message, severity: 'error' });\n }\n\n return this.errorApi.post(error, context);\n }\n\n error$() {\n return this.errorApi.error$();\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { PublishSubject } from '../../../lib/subjects';\n\n/**\n * Base implementation for the ErrorApi that simply forwards errors to consumers.\n *\n * @public\n */\nexport class ErrorApiForwarder {\n subject = new PublishSubject\n\n\n();\n\n post(error, context) {\n this.subject.next({ error, context });\n }\n\n error$() {\n return this.subject;\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Utility class that helps with error forwarding.\n *\n * @public\n */\nexport class UnhandledErrorForwarder {\n /**\n * Add event listener, such that unhandled errors can be forwarded using an given `ErrorApi` instance\n */\n static forward(errorApi, errorContext) {\n window.addEventListener(\n 'unhandledrejection',\n (e) => {\n errorApi.post(e.reason , errorContext);\n },\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FeatureFlagState,\n\n\n\n} from '@backstage/core-plugin-api';\n\nexport function validateFlagName(name) {\n if (name.length < 3) {\n throw new Error(\n `The '${name}' feature flag must have a minimum length of three characters.`,\n );\n }\n\n if (name.length > 150) {\n throw new Error(\n `The '${name}' feature flag must not exceed 150 characters.`,\n );\n }\n\n if (!name.match(/^[a-z]+[a-z0-9-]+$/)) {\n throw new Error(\n `The '${name}' feature flag must start with a lowercase letter and only contain lowercase letters, numbers and hyphens. ` +\n 'Examples: feature-flag-one, alpha, release-2020',\n );\n }\n}\n\n/**\n * A feature flags implementation that stores the flags in the browser's local\n * storage.\n *\n * @public\n */\nexport class LocalStorageFeatureFlags {\n registeredFeatureFlags = [];\n flags;\n\n registerFlag(flag) {\n validateFlagName(flag.name);\n this.registeredFeatureFlags.push(flag);\n }\n\n getRegisteredFlags() {\n return this.registeredFeatureFlags.slice();\n }\n\n isActive(name) {\n if (!this.flags) {\n this.flags = this.load();\n }\n return this.flags.get(name) === FeatureFlagState.Active;\n }\n\n save(options) {\n if (!this.flags) {\n this.flags = this.load();\n }\n if (!options.merge) {\n this.flags.clear();\n }\n for (const [name, state] of Object.entries(options.states)) {\n this.flags.set(name, state);\n }\n\n const enabled = Array.from(this.flags.entries()).filter(\n ([, state]) => state === FeatureFlagState.Active,\n );\n window.localStorage.setItem(\n 'featureFlags',\n JSON.stringify(Object.fromEntries(enabled)),\n );\n }\n\n load() {\n try {\n const jsonStr = window.localStorage.getItem('featureFlags');\n if (!jsonStr) {\n return new Map();\n }\n const json = JSON.parse(jsonStr) ;\n if (typeof json !== 'object' || json === null || Array.isArray(json)) {\n return new Map();\n }\n\n const entries = Object.entries(json).filter(([name, value]) => {\n validateFlagName(name);\n return value === FeatureFlagState.Active;\n });\n\n return new Map(entries);\n } catch {\n return new Map();\n }\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Builds a fetch API, based on the builtin fetch wrapped by a set of optional\n * middleware implementations that add behaviors.\n *\n * @remarks\n *\n * The middleware are applied in reverse order, i.e. the last one will be\n * \"closest\" to the base implementation. Passing in `[M1, M2, M3]` effectively\n * leads to `M1(M2(M3(baseImplementation)))`.\n *\n * @public\n */\nexport function createFetchApi(options\n\n\n) {\n let result = options.baseImplementation || global.fetch;\n\n const middleware = [options.middleware ?? []].flat().reverse();\n for (const m of middleware) {\n result = m.apply(result);\n }\n\n return {\n fetch: result,\n };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * A fetch middleware, which injects a Backstage token header when the user is\n * signed in.\n */\nexport class IdentityAuthInjectorFetchMiddleware {\n static create(options\n\n\n\n\n\n\n\n\n) {\n const matcher = buildMatcher(options);\n const headerName = options.header?.name || 'authorization';\n const headerValue = options.header?.value || (token => `Bearer ${token}`);\n\n return new IdentityAuthInjectorFetchMiddleware(\n options.identityApi,\n matcher,\n headerName,\n headerValue,\n );\n }\n\n constructor(\n identityApi,\n allowUrl,\n headerName,\n headerValue,\n ) {;this.identityApi = identityApi;this.allowUrl = allowUrl;this.headerName = headerName;this.headerValue = headerValue;}\n\n apply(next) {\n return async (input, init) => {\n // Skip this middleware if the header already exists, or if the URL\n // doesn't match any of the allowlist items, or if there was no token\n const request = new Request(input, init);\n const { token } = await this.identityApi.getCredentials();\n if (\n request.headers.get(this.headerName) ||\n typeof token !== 'string' ||\n !token ||\n !this.allowUrl(request.url)\n ) {\n return next(input, init);\n }\n\n request.headers.set(this.headerName, this.headerValue(token));\n return next(request);\n };\n }\n}\n\nfunction buildMatcher(options\n\n\n\n) {\n if (options.allowUrl) {\n return options.allowUrl;\n } else if (options.urlPrefixAllowlist) {\n return buildPrefixMatcher(options.urlPrefixAllowlist);\n } else if (options.config) {\n return buildPrefixMatcher([options.config.getString('backend.baseUrl')]);\n }\n return () => false;\n}\n\nfunction buildPrefixMatcher(prefixes) {\n const trimmedPrefixes = prefixes.map(prefix => prefix.replace(/\\/$/, ''));\n return url =>\n trimmedPrefixes.some(\n prefix => url === prefix || url.startsWith(`${prefix}/`),\n );\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nfunction join(left, right) {\n if (!right || right === '/') {\n return left;\n }\n\n return `${left.replace(/\\/$/, '')}/${right.replace(/^\\//, '')}`;\n}\n\n/**\n * Handles translation from plugin://some-plugin-id/<path> to concrete http(s)\n * URLs.\n */\nexport class PluginProtocolResolverFetchMiddleware {\n constructor( discoveryApi) {;this.discoveryApi = discoveryApi;}\n\n apply(next) {\n return async (input, init) => {\n const request = new Request(input, init);\n const prefix = 'plugin://';\n\n if (!request.url.startsWith(prefix)) {\n return next(input, init);\n }\n\n // Switch to a known protocol, since browser URL parsing misbehaves wildly\n // on foreign protocols\n const { hostname, pathname, search, hash, username, password } = new URL(\n `http://${request.url.substring(prefix.length)}`,\n );\n\n let base = await this.discoveryApi.getBaseUrl(hostname);\n if (username || password) {\n const baseUrl = new URL(base);\n const authority = `${username}${password ? `:${password}` : ''}@`;\n base = `${baseUrl.protocol}//${authority}${baseUrl.host}${baseUrl.pathname}`;\n }\n\n const target = `${join(base, pathname)}${search}${hash}`;\n return next(target, request);\n };\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { IdentityAuthInjectorFetchMiddleware } from './IdentityAuthInjectorFetchMiddleware';\nimport { PluginProtocolResolverFetchMiddleware } from './PluginProtocolResolverFetchMiddleware';\n\n\n/**\n * A collection of common middlewares for the FetchApi.\n *\n * @public\n */\nexport class FetchMiddlewares {\n /**\n * Handles translation from `plugin://` URLs to concrete http(s) URLs based on\n * the discovery API.\n *\n * @remarks\n *\n * If the request is for `plugin://catalog/entities?filter=x=y`, the discovery\n * API will be queried for `'catalog'`. If it returned\n * `https://backstage.example.net/api/catalog`, the resulting query would be\n * `https://backstage.example.net/api/catalog/entities?filter=x=y`.\n *\n * If the incoming URL protocol was not `plugin`, the request is just passed\n * through verbatim to the underlying implementation.\n */\n static resolvePluginProtocol(options\n\n) {\n return new PluginProtocolResolverFetchMiddleware(options.discoveryApi);\n }\n\n /**\n * Injects a Backstage token header when the user is signed in.\n *\n * @remarks\n *\n * Per default, an `Authorization: Bearer <token>` is generated. This can be\n * customized using the `header` option.\n *\n * The header injection only happens on allowlisted URLs. Per default, if the\n * `config` option is passed in, the `backend.baseUrl` is allowlisted, unless\n * the `urlPrefixAllowlist` or `allowUrl` options are passed in, in which case\n * they take precedence. If you pass in neither config nor an\n * allowlist/callback, the middleware will have no effect since effectively no\n * request will match the (nonexistent) rules.\n */\n static injectIdentityAuth(options\n\n\n\n\n\n\n\n\n) {\n return IdentityAuthInjectorFetchMiddleware.create(options);\n }\n\n constructor() {}\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { BehaviorSubject } from '../../../lib/subjects';\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport function hasScopes(\n searched,\n searchFor,\n) {\n for (const scope of searchFor) {\n if (!searched.has(scope)) {\n return false;\n }\n }\n return true;\n}\n\nexport function joinScopes(\n scopes,\n ...moreScopess\n) {\n const result = new Set(scopes);\n\n for (const moreScopes of moreScopess) {\n for (const scope of moreScopes) {\n result.add(scope);\n }\n }\n\n return result;\n}\n\n/**\n * The OAuthPendingRequests class is a utility for managing and observing\n * a stream of requests for oauth scopes for a single provider, and resolving\n * them correctly once requests are fulfilled.\n */\nexport class OAuthPendingRequests {\n requests = [];\n subject = new BehaviorSubject(\n this.getCurrentPending(),\n );\n\n request(scopes) {\n return new Promise((resolve, reject) => {\n this.requests.push({ scopes, resolve, reject });\n\n this.subject.next(this.getCurrentPending());\n });\n }\n\n resolve(scopes, result) {\n this.requests = this.requests.filter(request => {\n if (hasScopes(scopes, request.scopes)) {\n request.resolve(result);\n return false;\n }\n return true;\n });\n\n this.subject.next(this.getCurrentPending());\n }\n\n reject(error) {\n this.requests.forEach(request => request.reject(error));\n this.requests = [];\n\n this.subject.next(this.getCurrentPending());\n }\n\n pending() {\n return this.subject;\n }\n\n getCurrentPending() {\n const currentScopes =\n this.requests.length === 0\n ? undefined\n : this.requests\n .slice(1)\n .reduce(\n (acc, current) => joinScopes(acc, current.scopes),\n this.requests[0].scopes,\n );\n\n return {\n scopes: currentScopes,\n resolve: (value) => {\n if (currentScopes) {\n this.resolve(currentScopes, value);\n }\n },\n reject: (reason) => {\n if (currentScopes) {\n this.reject(reason);\n }\n },\n };\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { OAuthPendingRequests, } from './OAuthPendingRequests';\nimport { BehaviorSubject } from '../../../lib/subjects';\n\n/**\n * The OAuthRequestManager is an implementation of the OAuthRequestApi.\n *\n * The purpose of this class and the API is to read a stream of incoming requests\n * of OAuth access tokens from different providers with varying scope, and funnel\n * them all together into a single request for each OAuth provider.\n *\n * @public\n */\nexport class OAuthRequestManager {\n subject = new BehaviorSubject([]);\n currentRequests = [];\n handlerCount = 0;\n\n createAuthRequester(options) {\n if (!options.provider.id) {\n // eslint-disable-next-line no-console\n console.warn(\n 'DEPRECATION WARNING: Not passing a provider id to createAuthRequester is deprecated, it will be required in the future',\n );\n }\n const handler = new OAuthPendingRequests();\n\n const index = this.handlerCount;\n this.handlerCount++;\n\n handler.pending().subscribe({\n next: scopeRequest => {\n const newRequests = this.currentRequests.slice();\n const request = this.makeAuthRequest(scopeRequest, options);\n if (!request) {\n delete newRequests[index];\n } else {\n newRequests[index] = request;\n }\n this.currentRequests = newRequests;\n // Convert from sparse array to array of present items only\n this.subject.next(newRequests.filter(Boolean));\n },\n });\n\n return scopes => {\n return handler.request(scopes);\n };\n }\n\n // Converts the pending request and popup options into a popup request that we can forward to subscribers.\n makeAuthRequest(\n request,\n options,\n ) {\n const { scopes } = request;\n if (!scopes) {\n return undefined;\n }\n\n return {\n provider: options.provider,\n trigger: async () => {\n const result = await options.onAuthRequest(scopes);\n request.resolve(result);\n },\n reject: () => {\n const error = new Error('Login failed, rejected by user');\n error.name = 'RejectedError';\n request.reject(error);\n },\n };\n }\n\n authRequest$() {\n return this.subject;\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport ObservableImpl from 'zen-observable';\n\nconst buckets = new Map();\n\n/**\n * An implementation of the storage API, that uses the browser's local storage.\n *\n * @public\n */\nexport class WebStorage {\n constructor(\n namespace,\n errorApi,\n ) {;this.namespace = namespace;this.errorApi = errorApi;}\n\n static create(options\n\n\n) {\n return new WebStorage(options.namespace ?? '', options.errorApi);\n }\n\n get(key) {\n return this.snapshot(key).value ;\n }\n\n snapshot(key) {\n let value = undefined;\n let presence = 'absent';\n try {\n const item = localStorage.getItem(this.getKeyName(key));\n if (item) {\n value = JSON.parse(item, (_key, val) => {\n if (typeof val === 'object' && val !== null) {\n Object.freeze(val);\n }\n return val;\n });\n presence = 'present';\n }\n } catch (e) {\n this.errorApi.post(\n new Error(`Error when parsing JSON config from storage for: ${key}`),\n );\n }\n return { key, value, newValue: value, presence };\n }\n\n forBucket(name) {\n const bucketPath = `${this.namespace}/${name}`;\n if (!buckets.has(bucketPath)) {\n buckets.set(bucketPath, new WebStorage(bucketPath, this.errorApi));\n }\n return buckets.get(bucketPath);\n }\n\n async set(key, data) {\n localStorage.setItem(this.getKeyName(key), JSON.stringify(data));\n this.notifyChanges(key);\n }\n\n async remove(key) {\n localStorage.removeItem(this.getKeyName(key));\n this.notifyChanges(key);\n }\n\n observe$(key) {\n return this.observable.filter(({ key: messageKey }) => messageKey === key);\n }\n\n getKeyName(key) {\n return `${this.namespace}/${encodeURIComponent(key)}`;\n }\n\n notifyChanges(key) {\n const snapshot = this.snapshot(key);\n for (const subscription of this.subscribers) {\n subscription.next(snapshot);\n }\n }\n\n subscribers = new Set\n\n();\n\n observable = new ObservableImpl\n\n(subscriber => {\n this.subscribers.add(subscriber);\n return () => {\n this.subscribers.delete(subscriber);\n };\n });\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { OAuth2 } from '../oauth2';\n\n\nconst DEFAULT_PROVIDER = {\n id: 'atlassian',\n title: 'Atlassian',\n icon: () => null,\n};\n\n/**\n * Implements the OAuth flow to Atlassian products.\n *\n * @public\n */\nexport default class AtlassianAuth {\n static create(options) {\n const {\n discoveryApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n oauthRequestApi,\n } = options;\n\n return OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n provider,\n environment,\n });\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { OAuth2 } from '../oauth2';\n\n\nconst DEFAULT_PROVIDER = {\n id: 'auth0',\n title: 'Auth0',\n icon: () => null,\n};\n\n/**\n * Implements the OAuth flow to Auth0 products.\n *\n * @public\n * @deprecated Use {@link OAuth2} instead\n *\n * @example\n *\n * ```ts\n * OAuth2.create({\n * discoveryApi,\n * oauthRequestApi,\n * provider: {\n * id: 'auth0',\n * title: 'Auth0',\n * icon: () => null,\n * },\n * defaultScopes: ['openid', 'email', 'profile'],\n * environment: configApi.getOptionalString('auth.environment'),\n * })\n * ```\n */\nexport default class Auth0Auth {\n static create(options) {\n const {\n discoveryApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n oauthRequestApi,\n defaultScopes = ['openid', `email`, `profile`],\n } = options;\n\n return OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n provider,\n environment,\n defaultScopes,\n });\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { OAuth2 } from '../oauth2';\n\n\n\n\n\n\n\n\n\n\n\nconst DEFAULT_PROVIDER = {\n id: 'bitbucket',\n title: 'Bitbucket',\n icon: () => null,\n};\n\n/**\n * Implements the OAuth flow to Bitbucket products.\n *\n * @public\n */\nexport default class BitbucketAuth {\n static create(options) {\n const {\n discoveryApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n oauthRequestApi,\n defaultScopes = ['team'],\n } = options;\n\n return OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n provider,\n environment,\n defaultScopes,\n });\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { OAuth2 } from '../oauth2';\n\n\nconst DEFAULT_PROVIDER = {\n id: 'github',\n title: 'GitHub',\n icon: () => null,\n};\n\n/**\n * Implements the OAuth flow to GitHub products.\n *\n * @public\n */\nexport default class GithubAuth {\n static create(options) {\n const {\n discoveryApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n oauthRequestApi,\n defaultScopes = ['read:user'],\n } = options;\n\n return OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n provider,\n environment,\n defaultScopes,\n });\n }\n\n /**\n * @deprecated This method is deprecated and will be removed in a future release.\n */\n static normalizeScope(scope) {\n if (!scope) {\n return new Set();\n }\n\n const scopeList = Array.isArray(scope)\n ? scope\n : scope.split(/[\\s|,]/).filter(Boolean);\n\n return new Set(scopeList);\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { OAuth2 } from '../oauth2';\n\n\nconst DEFAULT_PROVIDER = {\n id: 'gitlab',\n title: 'GitLab',\n icon: () => null,\n};\n\n/**\n * Implements the OAuth flow to GitLab products.\n *\n * @public\n */\nexport default class GitlabAuth {\n static create(options) {\n const {\n discoveryApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n oauthRequestApi,\n defaultScopes = ['read_user'],\n } = options;\n\n return OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n provider,\n environment,\n defaultScopes,\n });\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { OAuth2 } from '../oauth2';\n\n\nconst DEFAULT_PROVIDER = {\n id: 'google',\n title: 'Google',\n icon: () => null,\n};\n\nconst SCOPE_PREFIX = 'https://www.googleapis.com/auth/';\n\n/**\n * Implements the OAuth flow to Google products.\n *\n * @public\n */\nexport default class GoogleAuth {\n static create(options) {\n const {\n discoveryApi,\n oauthRequestApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n defaultScopes = [\n 'openid',\n `${SCOPE_PREFIX}userinfo.email`,\n `${SCOPE_PREFIX}userinfo.profile`,\n ],\n } = options;\n\n return OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n provider,\n environment,\n defaultScopes,\n scopeTransform(scopes) {\n return scopes.map(scope => {\n if (scope === 'openid') {\n return scope;\n }\n\n if (scope === 'profile' || scope === 'email') {\n return `${SCOPE_PREFIX}userinfo.${scope}`;\n }\n\n if (scope.startsWith(SCOPE_PREFIX)) {\n return scope;\n }\n\n return `${SCOPE_PREFIX}${scope}`;\n });\n },\n });\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { OAuth2 } from '../oauth2';\n\n\nconst DEFAULT_PROVIDER = {\n id: 'microsoft',\n title: 'Microsoft',\n icon: () => null,\n};\n\n/**\n * Implements the OAuth flow to Microsoft products.\n *\n * @public\n */\nexport default class MicrosoftAuth {\n static create(options) {\n const {\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n oauthRequestApi,\n discoveryApi,\n defaultScopes = [\n 'openid',\n 'offline_access',\n 'profile',\n 'email',\n 'User.Read',\n ],\n } = options;\n\n return OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n provider,\n environment,\n defaultScopes,\n });\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { showLoginPopup } from '../loginPopup';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nfunction defaultJoinScopes(scopes) {\n return [...scopes].join(' ');\n}\n\n/**\n * DefaultAuthConnector is the default auth connector in Backstage. It talks to the\n * backend auth plugin through the standardized API, and requests user permission\n * via the OAuthRequestApi.\n */\nexport class DefaultAuthConnector\n\n{\n discoveryApi;\n environment;\n provider;\n joinScopesFunc;\n authRequester;\n sessionTransform;\n\n constructor(options) {\n const {\n discoveryApi,\n environment,\n provider,\n joinScopes = defaultJoinScopes,\n oauthRequestApi,\n sessionTransform = id => id,\n } = options;\n\n this.authRequester = oauthRequestApi.createAuthRequester({\n provider,\n onAuthRequest: scopes => this.showPopup(scopes),\n });\n\n this.discoveryApi = discoveryApi;\n this.environment = environment;\n this.provider = provider;\n this.joinScopesFunc = joinScopes;\n this.sessionTransform = sessionTransform;\n }\n\n async createSession(options) {\n if (options.instantPopup) {\n return this.showPopup(options.scopes);\n }\n return this.authRequester(options.scopes);\n }\n\n async refreshSession() {\n const res = await fetch(\n await this.buildUrl('/refresh', { optional: true }),\n {\n headers: {\n 'x-requested-with': 'XMLHttpRequest',\n },\n credentials: 'include',\n },\n ).catch(error => {\n throw new Error(`Auth refresh request failed, ${error}`);\n });\n\n if (!res.ok) {\n const error = new Error(\n `Auth refresh request failed, ${res.statusText}`,\n );\n error.status = res.status;\n throw error;\n }\n\n const authInfo = await res.json();\n\n if (authInfo.error) {\n const error = new Error(authInfo.error.message);\n if (authInfo.error.name) {\n error.name = authInfo.error.name;\n }\n throw error;\n }\n return await this.sessionTransform(authInfo);\n }\n\n async removeSession() {\n const res = await fetch(await this.buildUrl('/logout'), {\n method: 'POST',\n headers: {\n 'x-requested-with': 'XMLHttpRequest',\n },\n credentials: 'include',\n }).catch(error => {\n throw new Error(`Logout request failed, ${error}`);\n });\n\n if (!res.ok) {\n const error = new Error(`Logout request failed, ${res.statusText}`);\n error.status = res.status;\n throw error;\n }\n }\n\n async showPopup(scopes) {\n const scope = this.joinScopesFunc(scopes);\n const popupUrl = await this.buildUrl('/start', {\n scope,\n origin: location.origin,\n });\n\n const payload = await showLoginPopup({\n url: popupUrl,\n name: `${this.provider.title} Login`,\n origin: new URL(popupUrl).origin,\n width: 450,\n height: 730,\n });\n\n return await this.sessionTransform(payload);\n }\n\n async buildUrl(\n path,\n query,\n ) {\n const baseUrl = await this.discoveryApi.getBaseUrl('auth');\n const queryString = this.buildQueryString({\n ...query,\n env: this.environment,\n });\n\n return `${baseUrl}/${this.provider.id}${path}${queryString}`;\n }\n\n buildQueryString(query\n\n) {\n if (!query) {\n return '';\n }\n\n const queryString = Object.entries(query)\n .map(([key, value]) => {\n if (typeof value === 'string') {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n } else if (value) {\n return encodeURIComponent(key);\n }\n return undefined;\n })\n .filter(Boolean)\n .join('&');\n\n if (!queryString) {\n return '';\n }\n return `?${queryString}`;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DefaultAuthConnector } from '../../../../lib/AuthConnector';\nimport { RefreshingAuthSessionManager } from '../../../../lib/AuthSessionManager';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * OAuth2 create options.\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst DEFAULT_PROVIDER = {\n id: 'oauth2',\n title: 'Your Identity Provider',\n icon: () => null,\n};\n\n/**\n * Implements a generic OAuth2 flow for auth.\n *\n * @public\n */\nexport default class OAuth2\n \n\n\n\n\n\n{\n static create(options) {\n const {\n discoveryApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n oauthRequestApi,\n defaultScopes = [],\n scopeTransform = x => x,\n } = options;\n\n const connector = new DefaultAuthConnector({\n discoveryApi,\n environment,\n provider,\n oauthRequestApi: oauthRequestApi,\n sessionTransform(res) {\n return {\n ...res,\n providerInfo: {\n idToken: res.providerInfo.idToken,\n accessToken: res.providerInfo.accessToken,\n scopes: OAuth2.normalizeScopes(\n scopeTransform,\n res.providerInfo.scope,\n ),\n expiresAt: new Date(\n Date.now() + res.providerInfo.expiresInSeconds * 1000,\n ),\n },\n };\n },\n });\n\n const sessionManager = new RefreshingAuthSessionManager({\n connector,\n defaultScopes: new Set(defaultScopes),\n sessionScopes: (session) => session.providerInfo.scopes,\n sessionShouldRefresh: (session) => {\n const expiresInSec =\n (session.providerInfo.expiresAt.getTime() - Date.now()) / 1000;\n return expiresInSec < 60 * 5;\n },\n });\n\n return new OAuth2({ sessionManager, scopeTransform });\n }\n\n sessionManager;\n scopeTransform;\n\n constructor(options\n\n\n) {\n this.sessionManager = options.sessionManager;\n this.scopeTransform = options.scopeTransform;\n }\n\n async signIn() {\n await this.getAccessToken();\n }\n\n async signOut() {\n await this.sessionManager.removeSession();\n }\n\n sessionState$() {\n return this.sessionManager.sessionState$();\n }\n\n async getAccessToken(\n scope,\n options,\n ) {\n const normalizedScopes = OAuth2.normalizeScopes(this.scopeTransform, scope);\n const session = await this.sessionManager.getSession({\n ...options,\n scopes: normalizedScopes,\n });\n return session?.providerInfo.accessToken ?? '';\n }\n\n async getIdToken(options = {}) {\n const session = await this.sessionManager.getSession(options);\n return session?.providerInfo.idToken ?? '';\n }\n\n async getBackstageIdentity(\n options = {},\n ) {\n const session = await this.sessionManager.getSession(options);\n return session?.backstageIdentity;\n }\n\n async getProfile(options = {}) {\n const session = await this.sessionManager.getSession(options);\n return session?.profile;\n }\n\n static normalizeScopes(\n scopeTransform,\n scopes,\n ) {\n if (!scopes) {\n return new Set();\n }\n\n const scopeList = Array.isArray(scopes)\n ? scopes\n : scopes.split(/[\\s|,]/).filter(Boolean);\n\n return new Set(scopeTransform(scopeList));\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { OAuth2 } from '../oauth2';\n\n\nconst DEFAULT_PROVIDER = {\n id: 'okta',\n title: 'Okta',\n icon: () => null,\n};\n\nconst OKTA_OIDC_SCOPES = new Set([\n 'openid',\n 'profile',\n 'email',\n 'phone',\n 'address',\n 'groups',\n 'offline_access',\n]);\n\nconst OKTA_SCOPE_PREFIX = 'okta.';\n\n/**\n * Implements the OAuth flow to Okta products.\n *\n * @public\n */\nexport default class OktaAuth {\n static create(options) {\n const {\n discoveryApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n oauthRequestApi,\n defaultScopes = ['openid', 'email', 'profile', 'offline_access'],\n } = options;\n\n return OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n provider,\n environment,\n defaultScopes,\n scopeTransform(scopes) {\n return scopes.map(scope => {\n if (OKTA_OIDC_SCOPES.has(scope)) {\n return scope;\n }\n\n if (scope.startsWith(OKTA_SCOPE_PREFIX)) {\n return scope;\n }\n\n return `${OKTA_SCOPE_PREFIX}${scope}`;\n });\n },\n });\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { OAuth2 } from '../oauth2';\n\n/**\n * OneLogin auth provider create options.\n * @public\n */\n\n\n\n\n\n\n\nconst DEFAULT_PROVIDER = {\n id: 'onelogin',\n title: 'onelogin',\n icon: () => null,\n};\n\nconst OIDC_SCOPES = new Set([\n 'openid',\n 'profile',\n 'email',\n 'phone',\n 'address',\n 'groups',\n 'offline_access',\n]);\n\nconst SCOPE_PREFIX = 'onelogin.';\n\n/**\n * Implements a OneLogin OAuth flow.\n *\n * @public\n */\nexport default class OneLoginAuth {\n static create(\n options,\n ) {\n const {\n discoveryApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n oauthRequestApi,\n } = options;\n\n return OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n provider,\n environment,\n defaultScopes: ['openid', 'email', 'profile', 'offline_access'],\n scopeTransform(scopes) {\n return scopes.map(scope => {\n if (OIDC_SCOPES.has(scope)) {\n return scope;\n }\n\n if (scope.startsWith(SCOPE_PREFIX)) {\n return scope;\n }\n\n return `${SCOPE_PREFIX}${scope}`;\n });\n },\n });\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { showLoginPopup } from '../loginPopup';\n\n\n\n\n\n\nexport class DirectAuthConnector {\n discoveryApi;\n environment;\n provider;\n\n constructor(options) {\n const { discoveryApi, environment, provider } = options;\n\n this.discoveryApi = discoveryApi;\n this.environment = environment;\n this.provider = provider;\n }\n\n async createSession() {\n const popupUrl = await this.buildUrl('/start');\n const payload = await showLoginPopup({\n url: popupUrl,\n name: `${this.provider.title} Login`,\n origin: new URL(popupUrl).origin,\n width: 450,\n height: 730,\n });\n\n return {\n ...payload,\n id: payload.profile.email,\n };\n }\n\n async refreshSession() {}\n\n async removeSession() {\n const res = await fetch(await this.buildUrl('/logout'), {\n method: 'POST',\n headers: {\n 'x-requested-with': 'XMLHttpRequest',\n },\n credentials: 'include',\n }).catch(error => {\n throw new Error(`Logout request failed, ${error}`);\n });\n\n if (!res.ok) {\n const error = new Error(`Logout request failed, ${res.statusText}`);\n error.status = res.status;\n throw error;\n }\n }\n\n async buildUrl(path) {\n const baseUrl = await this.discoveryApi.getBaseUrl('auth');\n return `${baseUrl}/${this.provider.id}${path}?env=${this.environment}`;\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { z } from 'zod';\n\n/**\n * Session information for SAML auth.\n *\n * @public\n * @deprecated This type is internal and will be removed\n */\n\n\n\n\n\n\n\n\n\n\n\n\n/** @internal */\nexport const samlSessionSchema = z.object({\n profile: z.object({\n email: z.string().optional(),\n displayName: z.string().optional(),\n picture: z.string().optional(),\n }),\n backstageIdentity: z.object({\n id: z.string(),\n token: z.string(),\n identity: z.object({\n type: z.literal('user'),\n userEntityRef: z.string(),\n ownershipEntityRefs: z.array(z.string()),\n }),\n }),\n});\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { DirectAuthConnector } from '../../../../lib/AuthConnector';\nimport {\n AuthSessionStore,\n StaticAuthSessionManager,\n} from '../../../../lib/AuthSessionManager';\n\n\nimport { samlSessionSchema } from './types';\n\n\n\n\n\n\nconst DEFAULT_PROVIDER = {\n id: 'saml',\n title: 'SAML',\n icon: () => null,\n};\n\n/**\n * Implements a general SAML based auth flow.\n *\n * @public\n */\nexport default class SamlAuth\n \n{\n static create(options) {\n const {\n discoveryApi,\n environment = 'development',\n provider = DEFAULT_PROVIDER,\n } = options;\n\n const connector = new DirectAuthConnector({\n discoveryApi,\n environment,\n provider,\n });\n\n const sessionManager = new StaticAuthSessionManager({\n connector,\n });\n\n const authSessionStore = new AuthSessionStore({\n manager: sessionManager,\n storageKey: `${provider.id}Session`,\n schema: samlSessionSchema,\n });\n\n return new SamlAuth(authSessionStore);\n }\n\n sessionState$() {\n return this.sessionManager.sessionState$();\n }\n\n constructor(\n sessionManager,\n ) {;this.sessionManager = sessionManager;}\n\n async signIn() {\n await this.getBackstageIdentity({});\n }\n async signOut() {\n await this.sessionManager.removeSession();\n }\n\n async getBackstageIdentity(\n options = {},\n ) {\n const session = await this.sessionManager.getSession(options);\n return session?.backstageIdentity;\n }\n\n async getProfile(options = {}) {\n const session = await this.sessionManager.getSession(options);\n return session?.profile;\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Scope type when registering API factories.\n * @public\n */\n\n\n\n // APIs that can't be overridden, e.g. config\n\nvar ScopePriority; (function (ScopePriority) {\n ScopePriority[ScopePriority[\"default\"] = 10] = \"default\";\n const app = 50; ScopePriority[ScopePriority[\"app\"] = app] = \"app\";\n ScopePriority[ScopePriority[\"static\"] = 100] = \"static\";\n})(ScopePriority || (ScopePriority = {}));\n\n\n\n\n\n\n/**\n * ApiFactoryRegistry is an ApiFactoryHolder implementation that enables\n * registration of API Factories with different scope.\n *\n * Each scope has an assigned priority, where factories registered with\n * higher priority scopes override ones with lower priority.\n *\n * @public\n */\nexport class ApiFactoryRegistry {\n factories = new Map();\n\n /**\n * Register a new API factory. Returns true if the factory was added\n * to the registry.\n *\n * A factory will not be added to the registry if there is already\n * an existing factory with the same or higher priority.\n */\n register(\n scope,\n factory,\n ) {\n const priority = ScopePriority[scope];\n const existing = this.factories.get(factory.api.id);\n if (existing && existing.priority >= priority) {\n return false;\n }\n\n this.factories.set(factory.api.id, { priority, factory });\n return true;\n }\n\n get(\n api,\n ) {\n const tuple = this.factories.get(api.id);\n if (!tuple) {\n return undefined;\n }\n return tuple.factory ;\n }\n\n getAllApis() {\n const refs = new Set();\n for (const { factory } of this.factories.values()) {\n refs.add(factory.api);\n }\n return refs;\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * An ApiHolder that queries multiple other holders from for\n * an Api implementation, returning the first one encountered..\n */\nexport class ApiAggregator {\n holders;\n\n constructor(...holders) {\n this.holders = holders;\n }\n\n get(apiRef) {\n for (const holder of this.holders) {\n const api = holder.get(apiRef);\n if (api) {\n return api;\n }\n }\n return undefined;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useContext, } from 'react';\nimport PropTypes from 'prop-types';\n\nimport { ApiAggregator } from './ApiAggregator';\nimport {\n createVersionedValueMap,\n createVersionedContext,\n} from '@backstage/version-bridge';\n\n/**\n * Prop types for the ApiProvider component.\n * @public\n */\n\n\n\n\n\nconst ApiContext = createVersionedContext('api-context');\n\n/**\n * Provides an {@link @backstage/core-plugin-api#ApiHolder} for consumption in\n * the React tree.\n *\n * @public\n */\nexport const ApiProvider = (props) => {\n const { apis, children } = props;\n const parentHolder = useContext(ApiContext)?.atVersion(1);\n const holder = parentHolder ? new ApiAggregator(apis, parentHolder) : apis;\n\n return (\n React.createElement(ApiContext.Provider, {\n value: createVersionedValueMap({ 1: holder }),\n children: children,}\n )\n );\n};\n\nApiProvider.propTypes = {\n apis: PropTypes.shape({ get: PropTypes.func.isRequired }).isRequired,\n children: PropTypes.node,\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Handles the actual on-demand instantiation and memoization of APIs out of\n * an {@link ApiFactoryHolder}.\n *\n * @public\n */\nexport class ApiResolver {\n /**\n * Validate factories by making sure that each of the apis can be created\n * without hitting any circular dependencies.\n */\n static validateFactories(\n factories,\n apis,\n ) {\n for (const api of apis) {\n const heap = [api];\n const allDeps = new Set();\n\n while (heap.length) {\n const apiRef = heap.shift();\n const factory = factories.get(apiRef);\n if (!factory) {\n continue;\n }\n\n for (const dep of Object.values(factory.deps)) {\n if (dep.id === api.id) {\n throw new Error(`Circular dependency of api factory for ${api}`);\n }\n if (!allDeps.has(dep)) {\n allDeps.add(dep);\n heap.push(dep);\n }\n }\n }\n }\n }\n\n apis = new Map();\n\n constructor( factories) {;this.factories = factories;}\n\n get(ref) {\n return this.load(ref);\n }\n\n load(ref, loading = []) {\n const impl = this.apis.get(ref.id);\n if (impl) {\n return impl ;\n }\n\n const factory = this.factories.get(ref);\n if (!factory) {\n return undefined;\n }\n\n if (loading.includes(factory.api)) {\n throw new Error(`Circular dependency of api factory for ${factory.api}`);\n }\n\n const deps = this.loadDeps(ref, factory.deps, [...loading, factory.api]);\n const api = factory.factory(deps);\n this.apis.set(ref.id, api);\n return api ;\n }\n\n loadDeps(\n dependent,\n apis,\n loading,\n ) {\n const impls = {} ;\n\n for (const key in apis) {\n if (apis.hasOwnProperty(key)) {\n const ref = apis[key];\n\n const api = this.load(ref, loading);\n if (!api) {\n throw new Error(\n `No API factory available for dependency ${ref} of dependent ${dependent}`,\n );\n }\n impls[key] = api;\n }\n }\n\n return impls;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isValidElement, Children } from 'react';\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * A function that allows you to traverse a tree of React elements using\n * varying methods to discover child nodes and collect data along the way.\n */\nexport function traverseElementTree(options\n\n\n\n) {\n const collectors\n\n = {};\n\n // Bootstrap all collectors, initializing the accumulators and providing the visitor function\n for (const name in options.collectors) {\n if (options.collectors.hasOwnProperty(name)) {\n collectors[name] = options.collectors[name]();\n }\n }\n\n // Internal representation of an element in the tree that we're iterating over\n \n\n\n\n\n\n const queue = [\n {\n node: Children.toArray(options.root),\n parent: undefined,\n contexts: {},\n } ,\n ];\n\n while (queue.length !== 0) {\n const { node, parent, contexts } = queue.shift();\n\n // While the parent and the element we pass on to collectors and discoverers\n // have been validated and are known to be React elements, the child nodes\n // emitted by the discoverers are not.\n Children.forEach(node, element => {\n if (!isValidElement(element)) {\n return;\n }\n\n const nextContexts = {};\n\n // Collectors populate their result data using the current node, and compute\n // context for the next iteration\n for (const name in collectors) {\n if (collectors.hasOwnProperty(name)) {\n const collector = collectors[name];\n\n nextContexts[name] = collector.visit(\n collector.accumulator,\n element,\n parent,\n contexts[name],\n );\n }\n }\n\n // Discoverers provide ways to continue the traversal from the current element\n for (const discoverer of options.discoverers) {\n const children = discoverer(element);\n if (children) {\n queue.push({\n node: children,\n parent: element,\n contexts: nextContexts,\n });\n }\n }\n });\n }\n\n return Object.fromEntries(\n Object.entries(collectors).map(([name, c]) => [name, c.accumulator]),\n ) ;\n}\n\nexport function createCollector(\n accumulatorFactory,\n visit,\n) {\n return () => ({ accumulator: accumulatorFactory(), visit });\n}\n\nexport function childDiscoverer(element) {\n return element.props?.children;\n}\n\nexport function routeElementDiscoverer(element) {\n if (element.props?.path && element.props?.element) {\n return element.props?.element;\n }\n return undefined;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getComponentData } from '@backstage/core-plugin-api';\nimport { createCollector } from '../extensions/traversal';\n\nexport const pluginCollector = createCollector(\n () => new Set(),\n (acc, node) => {\n const plugin = getComponentData(\n node,\n 'core.plugin',\n );\n if (plugin) {\n acc.add(plugin);\n }\n },\n);\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isValidElement, } from 'react';\nimport {\n\n getComponentData,\n\n} from '@backstage/core-plugin-api';\n\nimport { createCollector } from '../extensions/traversal';\nimport { FeatureFlagged, } from './FeatureFlagged';\n\nfunction getMountPoint(node) {\n const element = node.props?.element;\n\n let routeRef = getComponentData(node, 'core.mountPoint');\n if (!routeRef && isValidElement(element)) {\n routeRef = getComponentData(element, 'core.mountPoint');\n }\n\n return routeRef;\n}\n\nexport const routePathCollector = createCollector(\n () => new Map(),\n (acc, node, parent, ctxPath) => {\n // The context path is used during mount point gathering to assign the same path\n // to all discovered mount points\n let currentCtxPath = ctxPath;\n\n if (parent?.props.element === node) {\n return currentCtxPath;\n }\n\n // Start gathering mount points when we encounter a mount point gathering flag\n if (getComponentData(node, 'core.gatherMountPoints')) {\n const path = node.props?.path;\n if (!path) {\n throw new Error('Mount point gatherer must have a path');\n }\n currentCtxPath = path;\n }\n\n const routeRef = getMountPoint(node);\n if (routeRef) {\n let path = node.props?.path;\n // If we're gathering mount points we use the context path as out path, unless\n // the element has its own path, in which case we use that instead and stop gathering\n if (currentCtxPath) {\n if (path) {\n currentCtxPath = undefined;\n } else {\n path = currentCtxPath;\n }\n }\n if (!path) {\n throw new Error('Mounted routable extension must have a path');\n }\n acc.set(routeRef, path);\n }\n return currentCtxPath;\n },\n);\n\nexport const routeParentCollector = createCollector(\n () => new Map(),\n (acc, node, parent, parentRouteRef) => {\n if (parent?.props.element === node) {\n return parentRouteRef;\n }\n\n let nextParent = parentRouteRef;\n\n const routeRef = getMountPoint(node);\n if (routeRef) {\n // \"sticky\" route ref is when we've encountered a mount point gatherer, and we want a\n // mount points beneath it to have the same parent, regardless of internal structure\n if (parentRouteRef && 'sticky' in parentRouteRef) {\n acc.set(routeRef, parentRouteRef.sticky);\n\n // When we encounter a mount point with an explicit path, we stop gathering\n // mount points withing the children and remove the sticky state\n if (node.props?.path) {\n nextParent = routeRef;\n } else {\n nextParent = parentRouteRef;\n }\n } else {\n acc.set(routeRef, parentRouteRef);\n nextParent = routeRef;\n }\n }\n\n // Mount point gatherers are marked as \"sticky\"\n if (getComponentData(node, 'core.gatherMountPoints')) {\n return { sticky: nextParent };\n }\n\n return nextParent;\n },\n);\n\n// We always add a child that matches all subroutes but without any route refs. This makes\n// sure that we're always able to match each route no matter how deep the navigation goes.\n// The route resolver then takes care of selecting the most specific match in order to find\n// mount points that are as deep in the routing tree as possible.\nexport const MATCH_ALL_ROUTE = {\n caseSensitive: false,\n path: '/*',\n element: 'match-all', // These elements aren't used, so we add in a bit of debug information\n routeRefs: new Set(),\n};\n\nexport const routeObjectCollector = createCollector(\n () => Array(),\n (acc, node, parent, parentObj) => {\n const parentChildren = parentObj?.children ?? acc;\n if (parent?.props.element === node) {\n return parentObj;\n }\n\n const path = node.props?.path;\n const caseSensitive = Boolean(node.props?.caseSensitive);\n\n const routeRef = getMountPoint(node);\n if (routeRef) {\n if (path) {\n const newObject = {\n caseSensitive,\n path,\n element: 'mounted',\n routeRefs: new Set([routeRef]),\n children: [MATCH_ALL_ROUTE],\n plugin: getComponentData(\n node.props.element,\n 'core.plugin',\n ),\n };\n parentChildren.push(newObject);\n return newObject;\n }\n\n parentObj?.routeRefs.add(routeRef);\n }\n\n const isGatherer = getComponentData(\n node,\n 'core.gatherMountPoints',\n );\n if (isGatherer) {\n if (!path) {\n throw new Error('Mount point gatherer must have a path');\n }\n const newObject = {\n caseSensitive,\n path,\n element: 'gathered',\n routeRefs: new Set(),\n children: [MATCH_ALL_ROUTE],\n plugin: parentObj?.plugin,\n };\n parentChildren.push(newObject);\n return newObject;\n }\n\n return parentObj;\n },\n);\n\nexport const featureFlagCollector = createCollector(\n () => new Set(),\n (acc, node) => {\n if (node.type === FeatureFlagged) {\n const props = node.props ;\n acc.add('with' in props ? props.with : props.without);\n }\n },\n);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\n\n\n\n\n\nexport const routeRefType = getOrCreateGlobalSingleton(\n 'route-ref-type',\n () => Symbol('route-ref-type'),\n);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport function isRouteRef(\n routeRef\n\n\n,\n) {\n return routeRef[routeRefType] === 'absolute';\n}\n\nexport function isSubRouteRef(\n routeRef\n\n\n,\n) {\n return routeRef[routeRefType] === 'sub';\n}\n\nexport function isExternalRouteRef\n\n\n(\n routeRef\n\n\n,\n) {\n return routeRef[routeRefType] === 'external';\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { generatePath, matchRoutes } from 'react-router-dom';\nimport {\n\n\n\n\n routeRefType,\n isRouteRef,\n isSubRouteRef,\n isExternalRouteRef,\n} from './types';\n\n\n\n\n\n\n// Joins a list of paths together, avoiding trailing and duplicate slashes\nfunction joinPaths(...paths) {\n const normalized = paths.join('/').replace(/\\/\\/+/g, '/');\n if (normalized !== '/' && normalized.endsWith('/')) {\n return normalized.slice(0, -1);\n }\n return normalized;\n}\n\n/**\n * Resolves the absolute route ref that our target route ref is pointing pointing to, as well\n * as the relative target path.\n *\n * Returns an undefined target ref if one could not be fully resolved.\n */\nfunction resolveTargetRef(\n anyRouteRef,\n routePaths,\n routeBindings,\n) {\n // First we figure out which absolute route ref we're dealing with, an if there was an sub route path to append.\n // For sub routes it will be the parent path, while for external routes it will be the bound route.\n let targetRef;\n let subRoutePath = '';\n if (isRouteRef(anyRouteRef)) {\n targetRef = anyRouteRef;\n } else if (isSubRouteRef(anyRouteRef)) {\n targetRef = anyRouteRef.parent;\n subRoutePath = anyRouteRef.path;\n } else if (isExternalRouteRef(anyRouteRef)) {\n const resolvedRoute = routeBindings.get(anyRouteRef);\n if (!resolvedRoute) {\n return [undefined, ''];\n }\n if (isRouteRef(resolvedRoute)) {\n targetRef = resolvedRoute;\n } else if (isSubRouteRef(resolvedRoute)) {\n targetRef = resolvedRoute.parent;\n subRoutePath = resolvedRoute.path;\n } else {\n throw new Error(\n `ExternalRouteRef was bound to invalid target, ${resolvedRoute}`,\n );\n }\n } else if (anyRouteRef[routeRefType]) {\n throw new Error(\n `Unknown or invalid route ref type, ${anyRouteRef[routeRefType]}`,\n );\n } else {\n throw new Error(`Unknown object passed to useRouteRef, got ${anyRouteRef}`);\n }\n\n // Bail if no absolute path could be resolved\n if (!targetRef) {\n return [undefined, ''];\n }\n\n // Find the path that our target route is bound to\n const resolvedPath = routePaths.get(targetRef);\n if (!resolvedPath) {\n return [undefined, ''];\n }\n\n // SubRouteRefs join the path from the parent route with its own path\n const targetPath = joinPaths(resolvedPath, subRoutePath);\n return [targetRef, targetPath];\n}\n\n/**\n * Resolves the complete base path for navigating to the target RouteRef.\n */\nfunction resolveBasePath(\n targetRef,\n sourceLocation,\n routePaths,\n routeParents,\n routeObjects,\n) {\n // While traversing the app element tree we build up the routeObjects structure\n // used here. It is the same kind of structure that react-router creates, with the\n // addition that associated route refs are stored throughout the tree. This lets\n // us look up all route refs that can be reached from our source location.\n // Because of the similar route object structure, we can use `matchRoutes` from\n // react-router to do the lookup of our current location.\n const match = matchRoutes(routeObjects, sourceLocation) ?? [];\n\n // While we search for a common routing root between our current location and\n // the target route, we build a list of all route refs we find that we need\n // to traverse to reach the target.\n const refDiffList = Array();\n\n let matchIndex = -1;\n for (\n let targetSearchRef = targetRef;\n targetSearchRef;\n targetSearchRef = routeParents.get(targetSearchRef)\n ) {\n // The match contains a list of all ancestral route refs present at our current location\n // Starting at the desired target ref and traversing back through its parents, we search\n // for a target ref that is present in the match for our current location. When a match\n // is found it means we have found a common base to resolve the route from.\n matchIndex = match.findIndex(m =>\n (m.route ).routeRefs.has(targetSearchRef),\n );\n if (matchIndex !== -1) {\n break;\n }\n\n // Every time we move a step up in the ancestry of the target ref, we add the current ref\n // to the diff list, which ends up being the list of route refs to traverse form the common base\n // in order to reach our target.\n refDiffList.unshift(targetSearchRef);\n }\n\n // If our target route is present in the initial match we need to construct the final path\n // from the parent of the matched route segment. That's to allow the caller of the route\n // function to supply their own params.\n if (refDiffList.length === 0) {\n matchIndex -= 1;\n }\n\n // This is the part of the route tree that the target and source locations have in common.\n // We re-use the existing pathname directly along with all params.\n const parentPath = matchIndex === -1 ? '' : match[matchIndex].pathname;\n\n // This constructs the mid section of the path using paths resolved from all route refs\n // we need to traverse to reach our target except for the very last one. None of these\n // paths are allowed to require any parameters, as the caller would have no way of knowing\n // what parameters those are.\n const diffPath = joinPaths(\n ...refDiffList.slice(0, -1).map(ref => {\n const path = routePaths.get(ref);\n if (!path) {\n throw new Error(`No path for ${ref}`);\n }\n if (path.includes(':')) {\n throw new Error(\n `Cannot route to ${targetRef} with parent ${ref} as it has parameters`,\n );\n }\n return path;\n }),\n );\n\n return parentPath + diffPath;\n}\n\nexport class RouteResolver {\n constructor(\n routePaths,\n routeParents,\n routeObjects,\n routeBindings\n\n\n,\n appBasePath, // base path without a trailing slash\n ) {;this.routePaths = routePaths;this.routeParents = routeParents;this.routeObjects = routeObjects;this.routeBindings = routeBindings;this.appBasePath = appBasePath;}\n\n resolve(\n anyRouteRef\n\n\n,\n sourceLocation,\n ) {\n // First figure out what our target absolute ref is, as well as our target path.\n const [targetRef, targetPath] = resolveTargetRef(\n anyRouteRef,\n this.routePaths,\n this.routeBindings,\n );\n if (!targetRef) {\n return undefined;\n }\n\n // The location that we get passed in uses the full path, so start by trimming off\n // the app base path prefix in case we're running the app on a sub-path.\n let relativeSourceLocation;\n if (typeof sourceLocation === 'string') {\n relativeSourceLocation = this.trimPath(sourceLocation);\n } else if (sourceLocation.pathname) {\n relativeSourceLocation = {\n ...sourceLocation,\n pathname: this.trimPath(sourceLocation.pathname),\n };\n } else {\n relativeSourceLocation = sourceLocation;\n }\n\n // Next we figure out the base path, which is the combination of the common parent path\n // between our current location and our target location, as well as the additional path\n // that is the difference between the parent path and the base of our target location.\n const basePath =\n this.appBasePath +\n resolveBasePath(\n targetRef,\n relativeSourceLocation,\n this.routePaths,\n this.routeParents,\n this.routeObjects,\n );\n\n const routeFunc = (...[params]) => {\n return basePath + generatePath(targetPath, params);\n };\n return routeFunc;\n }\n\n trimPath(targetPath) {\n if (!targetPath) {\n return targetPath;\n }\n\n if (targetPath.startsWith(this.appBasePath)) {\n return targetPath.slice(this.appBasePath.length);\n }\n return targetPath;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\n\n\n\n\n\nimport {\n createVersionedValueMap,\n createVersionedContext,\n} from '@backstage/version-bridge';\nimport { RouteResolver } from './RouteResolver';\n\n\nconst RoutingContext =\n createVersionedContext('routing-context');\n\n\n\n\n\n\n\n\n\n\nexport const RoutingProvider = ({\n routePaths,\n routeParents,\n routeObjects,\n routeBindings,\n basePath = '',\n children,\n}) => {\n const resolver = new RouteResolver(\n routePaths,\n routeParents,\n routeObjects,\n routeBindings,\n basePath,\n );\n\n const versionedValue = createVersionedValueMap({ 1: resolver });\n return (\n React.createElement(RoutingContext.Provider, { value: versionedValue,}\n , children\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect, useMemo } from 'react';\nimport { matchRoutes, useLocation } from 'react-router-dom';\nimport {\n useAnalytics,\n AnalyticsContext,\n\n\n} from '@backstage/core-plugin-api';\nimport { routeObjectCollector } from './collectors';\nimport {\n childDiscoverer,\n routeElementDiscoverer,\n traverseElementTree,\n} from '../extensions/traversal';\n\n\n/**\n * Returns an extension context given the current pathname and a list of\n * Backstage route objects.\n */\nconst getExtensionContext = (\n pathname,\n routes,\n) => {\n try {\n // Find matching routes for the given path name.\n const matches = matchRoutes(routes, { pathname }) \n\n;\n\n // Of the matching routes, get the last (e.g. most specific) instance of\n // the BackstageRouteObject.\n const routeObject = matches\n ?.filter(match => match?.route.routeRefs?.size > 0)\n .pop()?.route;\n\n // If there is no route object, then allow inheritance of default context.\n if (!routeObject) {\n return {};\n }\n\n // If there is a single route ref, return it.\n // todo: get routeRef of rendered gathered mount point(?)\n let routeRef;\n if (routeObject.routeRefs.size === 1) {\n routeRef = routeObject.routeRefs.values().next().value;\n }\n\n return {\n extension: 'App',\n pluginId: routeObject.plugin?.getId() || 'root',\n ...(routeRef ? { routeRef: (routeRef ).id } : {}),\n };\n } catch {\n return {};\n }\n};\n\n/**\n * Performs the actual event capture on render.\n */\nconst TrackNavigation = ({\n pathname,\n search,\n hash,\n}\n\n\n\n) => {\n const analytics = useAnalytics();\n\n useEffect(() => {\n analytics.captureEvent('navigate', `${pathname}${search}${hash}`);\n }, [analytics, pathname, search, hash]);\n\n return null;\n};\n\n/**\n * Logs a \"navigate\" event with appropriate plugin-level analytics context\n * attributes each time the user navigates to a page.\n */\nexport const RouteTracker = ({ tree }) => {\n const { pathname, search, hash } = useLocation();\n // todo(iamEAP): Work this into the existing traversal and make the data\n // available on the provider. Then grab from app instance on the router.\n const { routeObjects } = useMemo(() => {\n return traverseElementTree({\n root: tree,\n discoverers: [childDiscoverer, routeElementDiscoverer],\n collectors: {\n routeObjects: routeObjectCollector,\n },\n });\n }, [tree]);\n\n return (\n React.createElement(AnalyticsContext, { attributes: getExtensionContext(pathname, routeObjects),}\n , React.createElement(TrackNavigation, { pathname: pathname, search: search, hash: hash,} )\n )\n );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n// Validates that there is no duplication of route parameter names\nexport function validateRouteParameters(\n routePaths,\n routeParents,\n) {\n const notLeafRoutes = new Set(routeParents.values());\n notLeafRoutes.delete(undefined);\n\n for (const route of routeParents.keys()) {\n if (notLeafRoutes.has(route)) {\n continue;\n }\n\n let currentRouteRef = route;\n\n let fullPath = '';\n while (currentRouteRef) {\n const path = routePaths.get(currentRouteRef);\n if (!path) {\n throw new Error(`No path for ${currentRouteRef}`);\n }\n fullPath = `${path}${fullPath}`;\n currentRouteRef = routeParents.get(currentRouteRef);\n }\n\n const params = fullPath.match(/:(\\w+)/g);\n if (params) {\n for (let j = 0; j < params.length; j++) {\n for (let i = j + 1; i < params.length; i++) {\n if (params[i] === params[j]) {\n throw new Error(\n `Parameter ${params[i]} is duplicated in path ${fullPath}`,\n );\n }\n }\n }\n }\n }\n}\n\n// Validates that all non-optional external routes have been bound\nexport function validateRouteBindings(\n routeBindings,\n plugins,\n) {\n for (const plugin of plugins) {\n if (!plugin.externalRoutes) {\n continue;\n }\n\n for (const [name, externalRouteRef] of Object.entries(\n plugin.externalRoutes,\n )) {\n if (externalRouteRef.optional) {\n continue;\n }\n\n if (!routeBindings.has(externalRouteRef)) {\n throw new Error(\n `External route '${name}' of the '${plugin.getId()}' plugin must be bound to a target route. ` +\n 'See https://backstage.io/link?bind-routes for details.',\n );\n }\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\nimport {\n createVersionedValueMap,\n createVersionedContext,\n} from '@backstage/version-bridge';\n\n\nconst AppContext = createVersionedContext('app-context');\n\n\n\n\n\nexport const AppContextProvider = ({\n appContext,\n children,\n}) => {\n const versionedValue = createVersionedValueMap({ 1: appContext });\n\n return React.createElement(AppContext.Provider, { value: versionedValue, children: children,} );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nfunction mkError(thing) {\n return new Error(\n `Tried to access IdentityApi ${thing} before app was loaded`,\n );\n}\n\nfunction logDeprecation(thing) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: Call to ${thing} is deprecated and will break in the future`,\n );\n}\n\n// We use this for a period of backwards compatibility. It is a hidden\n// compatibility that will allow old plugins to continue working for a limited time.\n\n\n\n\n\n\n/**\n * Implementation of the connection between the App-wide IdentityApi\n * and sign-in page.\n */\nexport class AppIdentityProxy {\n target;\n waitForTarget;\n resolveTarget = () => {};\n\n constructor() {\n this.waitForTarget = new Promise(resolve => {\n this.resolveTarget = resolve;\n });\n }\n\n // This is called by the app manager once the sign-in page provides us with an implementation\n setTarget(identityApi) {\n this.target = identityApi;\n this.resolveTarget(identityApi);\n }\n\n getUserId() {\n if (!this.target) {\n throw mkError('getUserId');\n }\n if (!this.target.getUserId) {\n throw new Error('IdentityApi does not implement getUserId');\n }\n logDeprecation('getUserId');\n return this.target.getUserId();\n }\n\n getProfile() {\n if (!this.target) {\n throw mkError('getProfile');\n }\n if (!this.target.getProfile) {\n throw new Error('IdentityApi does not implement getProfile');\n }\n logDeprecation('getProfile');\n return this.target.getProfile();\n }\n\n async getProfileInfo() {\n return this.waitForTarget.then(target => target.getProfileInfo());\n }\n\n async getBackstageIdentity() {\n const identity = await this.waitForTarget.then(target =>\n target.getBackstageIdentity(),\n );\n if (!identity.userEntityRef.match(/^.*:.*\\/.*$/)) {\n // eslint-disable-next-line no-console\n console.warn(\n `WARNING: The App IdentityApi provided an invalid userEntityRef, '${identity.userEntityRef}'. ` +\n `It must be a full Entity Reference of the form '<kind>:<namespace>/<name>'.`,\n );\n }\n\n return identity;\n }\n\n async getCredentials() {\n return this.waitForTarget.then(target => target.getCredentials());\n }\n\n async getIdToken() {\n return this.waitForTarget.then(target => {\n if (!target.getIdToken) {\n throw new Error('IdentityApi does not implement getIdToken');\n }\n logDeprecation('getIdToken');\n return target.getIdToken();\n });\n }\n\n async signOut() {\n await this.waitForTarget.then(target => target.signOut());\n location.reload();\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useMemo, useEffect, useState, } from 'react';\nimport { useApi, appThemeApiRef, } from '@backstage/core-plugin-api';\nimport useObservable from 'react-use/lib/useObservable';\n\n// This tries to find the most accurate match, but also falls back to less\n// accurate results in order to avoid errors.\nfunction resolveTheme(\n themeId,\n shouldPreferDark,\n themes,\n) {\n if (themeId !== undefined) {\n const selectedTheme = themes.find(theme => theme.id === themeId);\n if (selectedTheme) {\n return selectedTheme;\n }\n }\n\n if (shouldPreferDark) {\n const darkTheme = themes.find(theme => theme.variant === 'dark');\n if (darkTheme) {\n return darkTheme;\n }\n }\n\n const lightTheme = themes.find(theme => theme.variant === 'light');\n if (lightTheme) {\n return lightTheme;\n }\n\n return themes[0];\n}\n\nconst useShouldPreferDarkTheme = () => {\n const mediaQuery = useMemo(\n () => window.matchMedia('(prefers-color-scheme: dark)'),\n [],\n );\n const [shouldPreferDark, setPrefersDark] = useState(mediaQuery.matches);\n\n useEffect(() => {\n const listener = (event) => {\n setPrefersDark(event.matches);\n };\n mediaQuery.addListener(listener);\n return () => {\n mediaQuery.removeListener(listener);\n };\n }, [mediaQuery]);\n\n return shouldPreferDark;\n};\n\nexport function AppThemeProvider({ children }) {\n const appThemeApi = useApi(appThemeApiRef);\n const themeId = useObservable(\n appThemeApi.activeThemeId$(),\n appThemeApi.getActiveThemeId(),\n );\n\n // Browser feature detection won't change over time, so ignore lint rule\n const shouldPreferDark = Boolean(window.matchMedia)\n ? useShouldPreferDarkTheme() // eslint-disable-line react-hooks/rules-of-hooks\n : false;\n\n const appTheme = resolveTheme(\n themeId,\n shouldPreferDark,\n appThemeApi.getInstalledThemes(),\n );\n if (!appTheme) {\n throw new Error('App has no themes');\n }\n\n return React.createElement(appTheme.Provider, { children: children,} );\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/** @internal */\nclass ApiRegistryBuilder {\n apis = [];\n\n add(api, impl) {\n this.apis.push([api.id, impl]);\n return impl;\n }\n\n build() {\n // eslint-disable-next-line @typescript-eslint/no-use-before-define\n return new ApiRegistry(new Map(this.apis));\n }\n}\n\n/**\n * A registry for utility APIs.\n *\n * @internal\n */\nexport class ApiRegistry {\n static builder() {\n return new ApiRegistryBuilder();\n }\n\n /**\n * Creates a new ApiRegistry with a list of API implementations.\n *\n * @param apis - A list of pairs mapping an ApiRef to its respective implementation\n */\n static from(apis) {\n return new ApiRegistry(new Map(apis.map(([api, impl]) => [api.id, impl])));\n }\n\n /**\n * Creates a new ApiRegistry with a single API implementation.\n *\n * @param api - ApiRef for the API to add\n * @param impl - Implementation of the API to add\n */\n static with(api, impl) {\n return new ApiRegistry(new Map([[api.id, impl]]));\n }\n\n constructor( apis) {;this.apis = apis;}\n\n /**\n * Returns a new ApiRegistry with the provided API added to the existing ones.\n *\n * @param api - ApiRef for the API to add\n * @param impl - Implementation of the API to add\n */\n with(api, impl) {\n return new ApiRegistry(new Map([...this.apis, [api.id, impl]]));\n }\n\n get(api) {\n return this.apis.get(api.id) ;\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport function resolveRouteBindings(bindRoutes) {\n const result = new Map();\n\n if (bindRoutes) {\n const bind = (\n externalRoutes,\n targetRoutes,\n ) => {\n for (const [key, value] of Object.entries(targetRoutes)) {\n const externalRoute = externalRoutes[key];\n if (!externalRoute) {\n throw new Error(`Key ${key} is not an existing external route`);\n }\n if (!value && !externalRoute.optional) {\n throw new Error(\n `External route ${key} is required but was undefined`,\n );\n }\n if (value) {\n result.set(externalRoute, value);\n }\n }\n };\n bindRoutes({ bind });\n }\n\n return result;\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport React, {\n\n\n\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport { Route, Routes } from 'react-router-dom';\nimport useAsync from 'react-use/lib/useAsync';\nimport {\n ApiProvider,\n AppThemeSelector,\n ConfigReader,\n LocalStorageFeatureFlags,\n} from '../apis';\nimport {\n useApi,\n\n\n\n\n appThemeApiRef,\n configApiRef,\n\n\n featureFlagsApiRef,\n\n identityApiRef,\n\n} from '@backstage/core-plugin-api';\nimport { ApiFactoryRegistry, ApiResolver } from '../apis/system';\nimport {\n childDiscoverer,\n routeElementDiscoverer,\n traverseElementTree,\n} from '../extensions/traversal';\nimport { pluginCollector } from '../plugins/collectors';\nimport {\n featureFlagCollector,\n routeObjectCollector,\n routeParentCollector,\n routePathCollector,\n} from '../routing/collectors';\nimport { RoutingProvider } from '../routing/RoutingProvider';\nimport { RouteTracker } from '../routing/RouteTracker';\nimport {\n validateRouteParameters,\n validateRouteBindings,\n} from '../routing/validation';\nimport { AppContextProvider } from './AppContext';\nimport { AppIdentityProxy } from '../apis/implementations/IdentityApi/AppIdentityProxy';\n\n\n\n\n\n\n\n\nimport { AppThemeProvider } from './AppThemeProvider';\nimport { defaultConfigLoader } from './defaultConfigLoader';\nimport { ApiRegistry } from '../apis/system/ApiRegistry';\nimport { resolveRouteBindings } from './resolveRouteBindings';\n\n\n\n\n\n\n\n/**\n * Get the app base path from the configured app baseUrl.\n *\n * The returned path does not have a trailing slash.\n */\nfunction getBasePath(configApi) {\n let { pathname } = new URL(\n configApi.getOptionalString('app.baseUrl') ?? '/',\n 'http://dummy.dev', // baseUrl can be specified as just a path\n );\n pathname = pathname.replace(/\\/*$/, '');\n return pathname;\n}\n\nfunction useConfigLoader(\n configLoader,\n components,\n appThemeApi,\n) {\n // Keeping this synchronous when a config loader isn't set simplifies tests a lot\n const hasConfig = Boolean(configLoader);\n const config = useAsync(configLoader || (() => Promise.resolve([])));\n\n let noConfigNode = undefined;\n\n if (hasConfig && config.loading) {\n const { Progress } = components;\n noConfigNode = React.createElement(Progress, null );\n } else if (config.error) {\n const { BootErrorPage } = components;\n noConfigNode = React.createElement(BootErrorPage, { step: \"load-config\", error: config.error,} );\n }\n\n const { ThemeProvider = AppThemeProvider } = components;\n\n // Before the config is loaded we can't use a router, so exit early\n if (noConfigNode) {\n return {\n node: (\n React.createElement(ApiProvider, { apis: ApiRegistry.with(appThemeApiRef, appThemeApi),}\n , React.createElement(ThemeProvider, null, noConfigNode)\n )\n ),\n };\n }\n\n const configReader = ConfigReader.fromConfigs(config.value ?? []);\n\n return { api: configReader };\n}\n\nclass AppContextImpl {\n constructor( app) {;this.app = app;}\n\n getPlugins() {\n return this.app.getPlugins();\n }\n\n getSystemIcon(key) {\n return this.app.getSystemIcon(key);\n }\n\n getComponents() {\n return this.app.getComponents();\n }\n}\n\nexport class AppManager {\n apiHolder;\n configApi;\n\n apis;\n icons;\n plugins;\n components;\n themes;\n configLoader;\n defaultApis;\n bindRoutes;\n\n appIdentityProxy = new AppIdentityProxy();\n apiFactoryRegistry;\n\n constructor(options) {\n this.apis = options.apis ?? [];\n this.icons = options.icons;\n this.plugins = new Set((options.plugins ) ?? []);\n this.components = options.components;\n this.themes = options.themes ;\n this.configLoader = options.configLoader ?? defaultConfigLoader;\n this.defaultApis = options.defaultApis ?? [];\n this.bindRoutes = options.bindRoutes;\n this.apiFactoryRegistry = new ApiFactoryRegistry();\n }\n\n getPlugins() {\n return Array.from(this.plugins) ;\n }\n\n getSystemIcon(key) {\n return this.icons[key];\n }\n\n getComponents() {\n return this.components;\n }\n\n getProvider() {\n const appContext = new AppContextImpl(this);\n\n // We only validate routes once\n let routesHaveBeenValidated = false;\n\n const Provider = ({ children }) => {\n const appThemeApi = useMemo(\n () => AppThemeSelector.createWithStorage(this.themes),\n [],\n );\n\n const {\n routePaths,\n routeParents,\n routeObjects,\n featureFlags,\n routeBindings,\n } = useMemo(() => {\n const result = traverseElementTree({\n root: children,\n discoverers: [childDiscoverer, routeElementDiscoverer],\n collectors: {\n routePaths: routePathCollector,\n routeParents: routeParentCollector,\n routeObjects: routeObjectCollector,\n collectedPlugins: pluginCollector,\n featureFlags: featureFlagCollector,\n },\n });\n\n // TODO(Rugvip): Restructure the public API so that we can get an immediate view of\n // the app, rather than having to wait for the provider to render.\n // For now we need to push the additional plugins we find during\n // collection and then make sure we initialize things afterwards.\n result.collectedPlugins.forEach(plugin => this.plugins.add(plugin));\n this.verifyPlugins(this.plugins);\n\n // Initialize APIs once all plugins are available\n this.getApiHolder();\n return {\n ...result,\n routeBindings: resolveRouteBindings(this.bindRoutes),\n };\n }, [children]);\n\n if (!routesHaveBeenValidated) {\n routesHaveBeenValidated = true;\n validateRouteParameters(routePaths, routeParents);\n validateRouteBindings(\n routeBindings,\n this.plugins ,\n );\n }\n\n const loadedConfig = useConfigLoader(\n this.configLoader,\n this.components,\n appThemeApi,\n );\n\n const hasConfigApi = 'api' in loadedConfig;\n if (hasConfigApi) {\n const { api } = loadedConfig ;\n this.configApi = api;\n }\n\n useEffect(() => {\n if (hasConfigApi) {\n const featureFlagsApi = this.getApiHolder().get(featureFlagsApiRef);\n\n for (const plugin of this.plugins.values()) {\n if ('getFeatureFlags' in plugin) {\n for (const flag of plugin.getFeatureFlags()) {\n featureFlagsApi.registerFlag({\n name: flag.name,\n pluginId: plugin.getId(),\n });\n }\n } else {\n for (const output of plugin.output()) {\n if (output.type === 'feature-flag') {\n featureFlagsApi.registerFlag({\n name: output.name,\n pluginId: plugin.getId(),\n });\n }\n }\n }\n }\n\n // Go through the featureFlags returned from the traversal and\n // register those now the configApi has been loaded\n for (const name of featureFlags) {\n featureFlagsApi.registerFlag({ name, pluginId: '' });\n }\n }\n }, [hasConfigApi, loadedConfig, featureFlags]);\n\n if ('node' in loadedConfig) {\n // Loading or error\n return loadedConfig.node;\n }\n\n const { ThemeProvider = AppThemeProvider } = this.components;\n\n return (\n React.createElement(ApiProvider, { apis: this.getApiHolder(),}\n , React.createElement(AppContextProvider, { appContext: appContext,}\n , React.createElement(ThemeProvider, null\n , React.createElement(RoutingProvider, {\n routePaths: routePaths,\n routeParents: routeParents,\n routeObjects: routeObjects,\n routeBindings: routeBindings,\n basePath: getBasePath(loadedConfig.api),}\n \n , children\n )\n )\n )\n )\n );\n };\n return Provider;\n }\n\n getRouter() {\n const { Router: RouterComponent, SignInPage: SignInPageComponent } =\n this.components;\n\n // This wraps the sign-in page and waits for sign-in to be completed before rendering the app\n const SignInPageWrapper = ({\n component: Component,\n children,\n }\n\n\n) => {\n const [identityApi, setIdentityApi] = useState();\n\n if (!identityApi) {\n return React.createElement(Component, { onSignInSuccess: setIdentityApi,} );\n }\n\n this.appIdentityProxy.setTarget(identityApi);\n return children;\n };\n\n const AppRouter = ({ children }) => {\n const configApi = useApi(configApiRef);\n const mountPath = `${getBasePath(configApi)}/*`;\n\n // If the app hasn't configured a sign-in page, we just continue as guest.\n if (!SignInPageComponent) {\n this.appIdentityProxy.setTarget({\n getUserId: () => 'guest',\n getIdToken: async () => undefined,\n getProfile: () => ({\n email: 'guest@example.com',\n displayName: 'Guest',\n }),\n getProfileInfo: async () => ({\n email: 'guest@example.com',\n displayName: 'Guest',\n }),\n getBackstageIdentity: async () => ({\n type: 'user',\n userEntityRef: 'user:default/guest',\n ownershipEntityRefs: ['user:default/guest'],\n }),\n getCredentials: async () => ({}),\n signOut: async () => {},\n });\n\n return (\n React.createElement(RouterComponent, null\n , React.createElement(RouteTracker, { tree: children,} )\n , React.createElement(Routes, null\n , React.createElement(Route, { path: mountPath, element: React.createElement(React.Fragment, null, children),} )\n )\n )\n );\n }\n\n return (\n React.createElement(RouterComponent, null\n , React.createElement(RouteTracker, { tree: children,} )\n , React.createElement(SignInPageWrapper, { component: SignInPageComponent,}\n , React.createElement(Routes, null\n , React.createElement(Route, { path: mountPath, element: React.createElement(React.Fragment, null, children),} )\n )\n )\n )\n );\n };\n\n return AppRouter;\n }\n\n getApiHolder() {\n if (this.apiHolder) {\n // Register additional plugins if they have been added.\n // Routes paths, objects and others are already updated in the provider when children of it change\n for (const plugin of this.plugins) {\n for (const factory of plugin.getApis()) {\n if (!this.apiFactoryRegistry.get(factory.api)) {\n this.apiFactoryRegistry.register('default', factory);\n }\n }\n }\n ApiResolver.validateFactories(\n this.apiFactoryRegistry,\n this.apiFactoryRegistry.getAllApis(),\n );\n return this.apiHolder;\n }\n this.apiFactoryRegistry.register('static', {\n api: appThemeApiRef,\n deps: {},\n factory: () => AppThemeSelector.createWithStorage(this.themes),\n });\n this.apiFactoryRegistry.register('static', {\n api: configApiRef,\n deps: {},\n factory: () => {\n if (!this.configApi) {\n throw new Error(\n 'Tried to access config API before config was loaded',\n );\n }\n return this.configApi;\n },\n });\n this.apiFactoryRegistry.register('static', {\n api: identityApiRef,\n deps: {},\n factory: () => this.appIdentityProxy,\n });\n\n // It's possible to replace the feature flag API, but since we must have at least\n // one implementation we add it here directly instead of through the defaultApis.\n this.apiFactoryRegistry.register('default', {\n api: featureFlagsApiRef,\n deps: {},\n factory: () => new LocalStorageFeatureFlags(),\n });\n for (const factory of this.defaultApis) {\n this.apiFactoryRegistry.register('default', factory);\n }\n\n for (const plugin of this.plugins) {\n for (const factory of plugin.getApis()) {\n if (!this.apiFactoryRegistry.register('default', factory)) {\n throw new Error(\n `Plugin ${plugin.getId()} tried to register duplicate or forbidden API factory for ${\n factory.api\n }`,\n );\n }\n }\n }\n\n for (const factory of this.apis) {\n if (!this.apiFactoryRegistry.register('app', factory)) {\n throw new Error(\n `Duplicate or forbidden API factory for ${factory.api} in app`,\n );\n }\n }\n\n ApiResolver.validateFactories(\n this.apiFactoryRegistry,\n this.apiFactoryRegistry.getAllApis(),\n );\n\n this.apiHolder = new ApiResolver(this.apiFactoryRegistry);\n return this.apiHolder;\n }\n\n verifyPlugins(plugins) {\n const pluginIds = new Set();\n\n for (const plugin of plugins) {\n const id = plugin.getId();\n if (pluginIds.has(id)) {\n throw new Error(`Duplicate plugin found '${id}'`);\n }\n pluginIds.add(id);\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AppManager } from './AppManager';\n\n\n/**\n * Creates a new Backstage App where the full set of options are required.\n *\n * @public\n * @param options - A set of options for creating the app\n * @returns\n * @remarks\n *\n * You will most likely want to use {@link @backstage/app-defaults#createApp},\n * however, this low-level API allows you to provide a full set of options,\n * including your own `components`, `icons`, `defaultApis`, and `themes`. This\n * is particularly useful if you are not using `@backstage/core-components` or\n * MUI, as it allows you to avoid those dependencies completely.\n */\nexport function createSpecializedApp(options) {\n return new AppManager(options);\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * The default config loader, which expects that config is available at compile-time\n * in `process.env.APP_CONFIG`. APP_CONFIG should be an array of config objects as\n * returned by the config loader.\n *\n * It will also load runtime config from the __APP_INJECTED_RUNTIME_CONFIG__ string,\n * which can be rewritten at runtime to contain an additional JSON config object.\n * If runtime config is present, it will be placed first in the config array, overriding\n * other config values.\n *\n * @public\n */\nexport const defaultConfigLoader = async (\n // This string may be replaced at runtime to provide additional config.\n // It should be replaced by a JSON-serialized config object.\n // It's a param so we can test it, but at runtime this will always fall back to default.\n runtimeConfigJson = '__APP_INJECTED_RUNTIME_CONFIG__',\n) => {\n const appConfig = process.env.APP_CONFIG;\n if (!appConfig) {\n throw new Error('No static configuration provided');\n }\n if (!Array.isArray(appConfig)) {\n throw new Error('Static configuration has invalid format');\n }\n const configs = appConfig.slice() ;\n\n // Avoiding this string also being replaced at runtime\n if (\n runtimeConfigJson !==\n '__app_injected_runtime_config__'.toLocaleUpperCase('en-US')\n ) {\n try {\n const data = JSON.parse(runtimeConfigJson) ;\n if (Array.isArray(data)) {\n configs.push(...data);\n } else {\n configs.push({ data, context: 'env' });\n }\n } catch (error) {\n throw new Error(`Failed to load runtime configuration, ${error}`);\n }\n }\n\n const windowAppConfig = (window ).__APP_CONFIG__;\n if (windowAppConfig) {\n configs.push({\n context: 'window',\n data: windowAppConfig,\n });\n }\n return configs;\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport function hasScopes(\n searched,\n searchFor,\n) {\n for (const scope of searchFor) {\n if (!searched.has(scope)) {\n return false;\n }\n }\n return true;\n}\n\n\n\n\n\n\nexport class SessionScopeHelper {\n constructor( options) {;this.options = options;}\n\n sessionExistsAndHasScope(\n session,\n scopes,\n ) {\n if (!session) {\n return false;\n }\n if (!scopes) {\n return true;\n }\n if (this.options.sessionScopes === undefined) {\n return true;\n }\n const sessionScopes = this.options.sessionScopes(session);\n return hasScopes(sessionScopes, scopes);\n }\n\n getExtendedScope(session, scopes) {\n const newScope = new Set(this.options.defaultScopes);\n if (session && this.options.sessionScopes !== undefined) {\n const sessionScopes = this.options.sessionScopes(session);\n for (const scope of sessionScopes) {\n newScope.add(scope);\n }\n }\n if (scopes) {\n for (const scope of scopes) {\n newScope.add(scope);\n }\n }\n return newScope;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BehaviorSubject } from '../subjects';\nimport { SessionState } from '@backstage/core-plugin-api';\n\n\nexport class SessionStateTracker {\n subject = new BehaviorSubject(\n SessionState.SignedOut,\n );\n\n signedIn = false;\n\n setIsSignedIn(isSignedIn) {\n if (this.signedIn !== isSignedIn) {\n this.signedIn = isSignedIn;\n this.subject.next(\n this.signedIn ? SessionState.SignedIn : SessionState.SignedOut,\n );\n }\n }\n\n sessionState$() {\n return this.subject;\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { SessionScopeHelper, hasScopes } from './common';\nimport { SessionStateTracker } from './SessionStateTracker';\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * RefreshingAuthSessionManager manages an underlying session that has\n * and expiration time and needs to be refreshed periodically.\n */\nexport class RefreshingAuthSessionManager {\n connector;\n helper;\n sessionScopesFunc;\n sessionShouldRefreshFunc;\n stateTracker = new SessionStateTracker();\n\n refreshPromise;\n currentSession;\n\n constructor(options) {\n const {\n connector,\n defaultScopes = new Set(),\n sessionScopes,\n sessionShouldRefresh,\n } = options;\n\n this.connector = connector;\n this.sessionScopesFunc = sessionScopes;\n this.sessionShouldRefreshFunc = sessionShouldRefresh;\n this.helper = new SessionScopeHelper({ sessionScopes, defaultScopes });\n }\n\n async getSession(options) {\n if (\n this.helper.sessionExistsAndHasScope(this.currentSession, options.scopes)\n ) {\n const shouldRefresh = this.sessionShouldRefreshFunc(this.currentSession);\n if (!shouldRefresh) {\n return this.currentSession;\n }\n\n try {\n const refreshedSession = await this.collapsedSessionRefresh();\n const currentScopes = this.sessionScopesFunc(this.currentSession);\n const refreshedScopes = this.sessionScopesFunc(refreshedSession);\n if (hasScopes(refreshedScopes, currentScopes)) {\n this.currentSession = refreshedSession;\n }\n return refreshedSession;\n } catch (error) {\n if (options.optional) {\n return undefined;\n }\n throw error;\n }\n }\n\n // The user may still have a valid refresh token in their cookies. Attempt to\n // initiate a fresh session through the backend using that refresh token.\n //\n // We skip this check if an instant login popup is requested, as we need to\n // stay in a synchronous call stack from the user interaction. The downside\n // is that that the user will sometimes be requested to log in even if they\n // already had an existing session.\n if (!this.currentSession && !options.instantPopup) {\n try {\n const newSession = await this.collapsedSessionRefresh();\n this.currentSession = newSession;\n // The session might not have the scopes requested so go back and check again\n return this.getSession(options);\n } catch {\n // If the refresh attempt fails we assume we don't have a session, so continue to create one.\n }\n }\n\n // If we continue here we will show a popup, so exit if this is an optional session request.\n if (options.optional) {\n return undefined;\n }\n\n // We can call authRequester multiple times, the returned session will contain all requested scopes.\n this.currentSession = await this.connector.createSession({\n ...options,\n scopes: this.helper.getExtendedScope(this.currentSession, options.scopes),\n });\n this.stateTracker.setIsSignedIn(true);\n return this.currentSession;\n }\n\n async removeSession() {\n this.currentSession = undefined;\n await this.connector.removeSession();\n this.stateTracker.setIsSignedIn(false);\n }\n\n sessionState$() {\n return this.stateTracker.sessionState$();\n }\n\n async collapsedSessionRefresh() {\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.refreshPromise = this.connector.refreshSession();\n\n try {\n const session = await this.refreshPromise;\n this.stateTracker.setIsSignedIn(true);\n return session;\n } finally {\n delete this.refreshPromise;\n }\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { SessionScopeHelper } from './common';\nimport { SessionStateTracker } from './SessionStateTracker';\n\n\n\n\n\n\n\n\n\n\n/**\n * StaticAuthSessionManager manages an underlying session that does not expire.\n */\nexport class StaticAuthSessionManager {\n connector;\n helper;\n stateTracker = new SessionStateTracker();\n\n currentSession;\n\n constructor(options) {\n const { connector, defaultScopes = new Set(), sessionScopes } = options;\n\n this.connector = connector;\n this.helper = new SessionScopeHelper({ sessionScopes, defaultScopes });\n }\n\n setSession(session) {\n this.currentSession = session;\n this.stateTracker.setIsSignedIn(Boolean(session));\n }\n\n async getSession(options) {\n if (\n this.helper.sessionExistsAndHasScope(this.currentSession, options.scopes)\n ) {\n return this.currentSession;\n }\n\n // If we continue here we will show a popup, so exit if this is an optional session request.\n if (options.optional) {\n return undefined;\n }\n\n // We can call authRequester multiple times, the returned session will contain all requested scopes.\n this.currentSession = await this.connector.createSession({\n ...options,\n scopes: this.helper.getExtendedScope(this.currentSession, options.scopes),\n });\n this.stateTracker.setIsSignedIn(true);\n return this.currentSession;\n }\n\n /**\n * We don't call this.connector.removeSession here, since this session manager\n * is intended to be static. As such there's no need to hit the remote logout\n * endpoint - simply discarding the local session state when signing out is\n * enough.\n */\n async removeSession() {\n this.currentSession = undefined;\n this.stateTracker.setIsSignedIn(false);\n }\n\n sessionState$() {\n return this.stateTracker.sessionState$();\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { SessionScopeHelper } from './common';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * AuthSessionStore decorates another SessionManager with a functionality\n * to store the session in local storage.\n *\n * Session is serialized to JSON with special support for following types: Set.\n */\nexport class AuthSessionStore {\n manager;\n storageKey;\n schema;\n sessionShouldRefreshFunc;\n helper;\n\n constructor(options) {\n const {\n manager,\n storageKey,\n schema,\n sessionScopes,\n sessionShouldRefresh = () => false,\n } = options;\n\n this.manager = manager;\n this.storageKey = storageKey;\n this.schema = schema;\n this.sessionShouldRefreshFunc = sessionShouldRefresh;\n this.helper = new SessionScopeHelper({\n sessionScopes,\n defaultScopes: new Set(),\n });\n }\n\n setSession(session) {\n this.manager.setSession(session);\n this.saveSession(session);\n }\n\n async getSession(options) {\n const { scopes } = options;\n const session = this.loadSession();\n\n if (this.helper.sessionExistsAndHasScope(session, scopes)) {\n const shouldRefresh = this.sessionShouldRefreshFunc(session);\n\n if (!shouldRefresh) {\n this.manager.setSession(session);\n return session;\n }\n }\n\n const newSession = await this.manager.getSession(options);\n this.saveSession(newSession);\n return newSession;\n }\n\n async removeSession() {\n localStorage.removeItem(this.storageKey);\n await this.manager.removeSession();\n }\n\n sessionState$() {\n return this.manager.sessionState$();\n }\n\n loadSession() {\n try {\n const sessionJson = localStorage.getItem(this.storageKey);\n if (sessionJson) {\n const session = JSON.parse(sessionJson, (_key, value) => {\n if (value?.__type === 'Set') {\n return new Set(value.__value);\n }\n return value;\n });\n\n try {\n return this.schema.parse(session);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.log(\n `Failed to load session from local storage because it did not conform to the expected schema, ${e}`,\n );\n throw e;\n }\n }\n\n return undefined;\n } catch (error) {\n localStorage.removeItem(this.storageKey);\n return undefined;\n }\n }\n\n saveSession(session) {\n if (session === undefined) {\n localStorage.removeItem(this.storageKey);\n return;\n }\n\n try {\n this.schema.parse(session);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to save session to local storage because it did not conform to the expected schema, ${e}`,\n );\n return;\n }\n\n localStorage.setItem(\n this.storageKey,\n JSON.stringify(session, (_key, value) => {\n if (value instanceof Set) {\n return {\n __type: 'Set',\n __value: Array.from(value),\n };\n }\n return value;\n }),\n );\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Options used to open a login popup.\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Show a popup pointing to a URL that starts an auth flow. Implementing the receiving\n * end of the postMessage mechanism outlined in https://tools.ietf.org/html/draft-sakimura-oauth-wmrm-00\n *\n * The redirect handler of the flow should use postMessage to communicate back\n * to the app window. The message posted to the app must match the AuthResult type.\n *\n * The returned promise resolves to the response of the message that was posted from the auth popup.\n */\nexport function showLoginPopup(options) {\n return new Promise((resolve, reject) => {\n const width = options.width || 500;\n const height = options.height || 700;\n const left = window.screen.width / 2 - width / 2;\n const top = window.screen.height / 2 - height / 2;\n\n const popup = window.open(\n options.url,\n options.name,\n `menubar=no,location=no,resizable=no,scrollbars=no,status=no,width=${width},height=${height},top=${top},left=${left}`,\n );\n\n let targetOrigin = '';\n\n if (!popup || typeof popup.closed === 'undefined' || popup.closed) {\n const error = new Error('Failed to open auth popup.');\n error.name = 'PopupRejectedError';\n reject(error);\n return;\n }\n\n const messageListener = (event) => {\n if (event.source !== popup) {\n return;\n }\n if (event.origin !== options.origin) {\n return;\n }\n const { data } = event;\n\n if (data.type === 'config_info') {\n targetOrigin = data.targetOrigin;\n return;\n }\n\n if (data.type !== 'authorization_response') {\n return;\n }\n const authResult = data ;\n\n if ('error' in authResult) {\n const error = new Error(authResult.error.message);\n error.name = authResult.error.name;\n // TODO: proper error type\n // error.extra = authResult.error.extra;\n reject(error);\n } else {\n resolve(authResult.response);\n }\n done();\n };\n\n const intervalId = setInterval(() => {\n if (popup.closed) {\n const errMessage = `Login failed, ${\n targetOrigin && targetOrigin !== window.location.origin\n ? `Incorrect app origin, expected ${targetOrigin}`\n : 'popup was closed'\n }`;\n const error = new Error(errMessage);\n error.name = 'PopupClosedError';\n reject(error);\n done();\n }\n }, 100);\n\n function done() {\n window.removeEventListener('message', messageListener);\n clearInterval(intervalId);\n }\n\n window.addEventListener('message', messageListener);\n });\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport ObservableImpl from 'zen-observable';\n\n// TODO(Rugvip): These are stopgap and probably incomplete implementations of subjects.\n// If we add a more complete Observables library they should be replaced.\n\n/**\n * A basic implementation of ReactiveX publish subjects.\n *\n * A subject is a convenient way to create an observable when you want\n * to fan out a single value to all subscribers.\n *\n * See http://reactivex.io/documentation/subject.html\n */\nexport class PublishSubject\n\n{\n isClosed = false;\n terminatingError;\n\n observable = new ObservableImpl(subscriber => {\n if (this.isClosed) {\n if (this.terminatingError) {\n subscriber.error(this.terminatingError);\n } else {\n subscriber.complete();\n }\n return () => {};\n }\n\n this.subscribers.add(subscriber);\n return () => {\n this.subscribers.delete(subscriber);\n };\n });\n\n subscribers = new Set\n\n();\n\n [Symbol.observable]() {\n return this;\n }\n\n get closed() {\n return this.isClosed;\n }\n\n next(value) {\n if (this.isClosed) {\n throw new Error('PublishSubject is closed');\n }\n this.subscribers.forEach(subscriber => subscriber.next(value));\n }\n\n error(error) {\n if (this.isClosed) {\n throw new Error('PublishSubject is closed');\n }\n this.isClosed = true;\n this.terminatingError = error;\n this.subscribers.forEach(subscriber => subscriber.error(error));\n }\n\n complete() {\n if (this.isClosed) {\n throw new Error('PublishSubject is closed');\n }\n this.isClosed = true;\n this.subscribers.forEach(subscriber => subscriber.complete());\n }\n\n \n\n\n\n\n\n subscribe(\n onNext,\n onError,\n onComplete,\n ) {\n const observer =\n typeof onNext === 'function'\n ? {\n next: onNext,\n error: onError,\n complete: onComplete,\n }\n : onNext;\n\n return this.observable.subscribe(observer);\n }\n}\n\n/**\n * A basic implementation of ReactiveX behavior subjects.\n *\n * A subject is a convenient way to create an observable when you want\n * to fan out a single value to all subscribers.\n *\n * The BehaviorSubject will emit the most recently emitted value or error\n * whenever a new observer subscribes to the subject.\n *\n * See http://reactivex.io/documentation/subject.html\n */\n\nexport class BehaviorSubject\n\n{\n isClosed;\n currentValue;\n terminatingError;\n observable;\n\n constructor(value) {\n this.isClosed = false;\n this.currentValue = value;\n this.terminatingError = undefined;\n this.observable = new ObservableImpl(subscriber => {\n if (this.isClosed) {\n if (this.terminatingError) {\n subscriber.error(this.terminatingError);\n } else {\n subscriber.complete();\n }\n return () => {};\n }\n\n subscriber.next(this.currentValue);\n\n this.subscribers.add(subscriber);\n return () => {\n this.subscribers.delete(subscriber);\n };\n });\n }\n\n subscribers = new Set\n\n();\n\n [Symbol.observable]() {\n return this;\n }\n\n get closed() {\n return this.isClosed;\n }\n\n next(value) {\n if (this.isClosed) {\n throw new Error('BehaviorSubject is closed');\n }\n this.currentValue = value;\n this.subscribers.forEach(subscriber => subscriber.next(value));\n }\n\n error(error) {\n if (this.isClosed) {\n throw new Error('BehaviorSubject is closed');\n }\n this.isClosed = true;\n this.terminatingError = error;\n this.subscribers.forEach(subscriber => subscriber.error(error));\n }\n\n complete() {\n if (this.isClosed) {\n throw new Error('BehaviorSubject is closed');\n }\n this.isClosed = true;\n this.subscribers.forEach(subscriber => subscriber.complete());\n }\n\n \n\n\n\n\n\n subscribe(\n onNext,\n onError,\n onComplete,\n ) {\n const observer =\n typeof onNext === 'function'\n ? {\n next: onNext,\n error: onError,\n complete: onComplete,\n }\n : onNext;\n\n return this.observable.subscribe(observer);\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n featureFlagsApiRef,\n useApi,\n attachComponentData,\n} from '@backstage/core-plugin-api';\nimport React, { } from 'react';\n\n/**\n * Props for the {@link FeatureFlagged} component.\n *\n * @public\n */\n\n\n\n\n\n/**\n * Enables or disables rendering of its children based on the state of a given\n * feature flag.\n *\n * @public\n */\nexport const FeatureFlagged = (props) => {\n const { children } = props;\n const featureFlagApi = useApi(featureFlagsApiRef);\n const isEnabled =\n 'with' in props\n ? featureFlagApi.isActive(props.with)\n : !featureFlagApi.isActive(props.without);\n return React.createElement(React.Fragment, null, isEnabled ? children : null);\n};\n\nattachComponentData(FeatureFlagged, 'core.featureFlagged', true);\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\nimport { useRoutes } from 'react-router-dom';\nimport { useApp, useElementFilter } from '@backstage/core-plugin-api';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * A wrapper around a set of routes.\n *\n * @remarks\n *\n * The root of the routing hierarchy in your app should use this component,\n * instead of the one from `react-router-dom`. This ensures that all of the\n * plugin route and utility API wiring happens under the hood.\n *\n * @public\n */\nexport const FlatRoutes = (props) => {\n const app = useApp();\n const { NotFoundErrorPage } = app.getComponents();\n const routes = useElementFilter(props.children, elements =>\n elements\n .getElements()\n .flatMap(child => {\n let path = child.props.path;\n\n // TODO(Rugvip): Work around plugins registering empty paths, remove once deprecated routes are gone\n if (path === '') {\n return [];\n }\n path = path?.replace(/\\/\\*$/, '') ?? '/';\n\n return [\n {\n path,\n element: child,\n children: child.props.children\n ? [\n // These are the children of each route, which we all add in under a catch-all\n // subroute in order to make them available to `useOutlet`\n {\n path: path === '/' ? '/' : '/*', // The root path must require an exact match\n element: child.props.children,\n },\n ]\n : undefined,\n },\n ];\n })\n // Routes are sorted to work around a bug where prefixes are unexpectedly matched\n .sort((a, b) => b.path.localeCompare(a.path))\n // We make sure all routes have '/*' appended, except '/'\n .map(obj => {\n obj.path = obj.path === '/' ? '/' : `${obj.path}/*`;\n return obj;\n }),\n );\n\n // TODO(Rugvip): Possibly add a way to skip this, like a noNotFoundPage prop\n routes.push({\n element: React.createElement(NotFoundErrorPage, null ),\n path: '/*',\n });\n\n return useRoutes(routes);\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect, useState } from 'react';\nimport Snackbar from '@material-ui/core/Snackbar';\nimport IconButton from '@material-ui/core/IconButton';\nimport CloseIcon from '@material-ui/icons/Close';\nimport { Alert } from '@material-ui/lab';\nimport { useApi, alertApiRef } from '@backstage/core-plugin-api';\nimport pluralize from 'pluralize';\n\n/**\n * Displays alerts from {@link @backstage/core-plugin-api#AlertApi}\n *\n * @public\n * @remarks\n *\n * Shown as SnackBar at the top of the page\n */\n// TODO: improve on this and promote to a shared component for use by all apps.\nexport function AlertDisplay(_props) {\n const [messages, setMessages] = useState([]);\n const alertApi = useApi(alertApiRef);\n\n useEffect(() => {\n const subscription = alertApi\n .alert$()\n .subscribe(message => setMessages(msgs => msgs.concat(message)));\n\n return () => {\n subscription.unsubscribe();\n };\n }, [alertApi]);\n\n if (messages.length === 0) {\n return null;\n }\n\n const [firstMessage] = messages;\n\n const handleClose = () => {\n setMessages(msgs => msgs.filter(msg => msg !== firstMessage));\n };\n\n return (\n React.createElement(Snackbar, { open: true, anchorOrigin: { vertical: 'top', horizontal: 'center' },}\n , React.createElement(Alert, {\n action: \n React.createElement(IconButton, {\n color: \"inherit\",\n size: \"small\",\n onClick: handleClose,\n 'data-testid': \"error-button-close\",}\n \n , React.createElement(CloseIcon, null )\n )\n ,\n severity: firstMessage.severity,}\n \n , React.createElement('span', null\n , firstMessage.message.toString()\n , messages.length > 1 && (\n React.createElement('em', null, ` (${messages.length - 1} older ${pluralize(\n 'message',\n messages.length - 1,\n )})`)\n )\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { } from 'react';\nimport { createStyles, makeStyles, } from '@material-ui/core/styles';\nimport MaterialAvatar from '@material-ui/core/Avatar';\nimport { extractInitials, stringToColor } from './utils';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n (theme) =>\n createStyles({\n avatar: {\n width: '4rem',\n height: '4rem',\n color: '#fff',\n fontWeight: theme.typography.fontWeightBold,\n letterSpacing: '1px',\n textTransform: 'uppercase',\n },\n }),\n { name: 'BackstageAvatar' },\n);\n\n/**\n * Properties for {@link Avatar}.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Component rendering an Avatar\n *\n * @public\n * @remarks\n *\n * Based on https://v4.mui.com/components/avatars/#avatar with some styling adjustment and two-letter initials\n */\nexport function Avatar(props) {\n const { displayName, picture, customStyles } = props;\n const classes = useStyles();\n return (\n React.createElement(MaterialAvatar, {\n alt: displayName,\n src: picture,\n className: classes.avatar,\n style: {\n backgroundColor: stringToColor(displayName || picture || ''),\n ...customStyles,\n },}\n \n , displayName && extractInitials(displayName)\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useAnalytics } from '@backstage/core-plugin-api';\nimport MaterialLink, {\n\n} from '@material-ui/core/Link';\nimport React, { } from 'react';\nimport {\n Link as RouterLink,\n\n} from 'react-router-dom';\n\nexport const isExternalUri = (uri) => /^([a-z+.-]+):/.test(uri);\n\n\n\n\n\n\n\n\n\n/**\n * Given a react node, try to retrieve its text content.\n */\nconst getNodeText = (node) => {\n // If the node is an array of children, recurse and join.\n if (node instanceof Array) {\n return node.map(getNodeText).join(' ').trim();\n }\n\n // If the node is a react element, recurse on its children.\n if (typeof node === 'object' && node) {\n return getNodeText((node )?.props?.children);\n }\n\n // Base case: the node is just text. Return it.\n if (['string', 'number'].includes(typeof node)) {\n return String(node);\n }\n\n // Base case: just return an empty string.\n return '';\n};\n\n/**\n * Thin wrapper on top of material-ui's Link component, which...\n * - Makes the Link use react-router\n * - Captures Link clicks as analytics events.\n */\nconst ActualLink = React.forwardRef(\n ({ onClick, noTrack, ...props }, ref) => {\n const analytics = useAnalytics();\n const to = String(props.to);\n const linkText = getNodeText(props.children) || to;\n const external = isExternalUri(to);\n const newWindow = external && !!/^https?:/.exec(to);\n\n const handleClick = (event) => {\n onClick?.(event);\n if (!noTrack) {\n analytics.captureEvent('click', linkText, { attributes: { to } });\n }\n };\n\n return external ? (\n // External links\n React.createElement(MaterialLink, {\n ref: ref,\n href: to,\n onClick: handleClick,\n ...(newWindow ? { target: '_blank', rel: 'noopener' } : {}),\n ...props,}\n )\n ) : (\n // Interact with React Router for internal links\n React.createElement(MaterialLink, {\n ref: ref,\n component: RouterLink,\n onClick: handleClick,\n ...props,}\n )\n );\n },\n);\n\n// TODO(Rugvip): We use this as a workaround to make the exported type be a\n// function, which makes our API reference docs much nicer.\n// The first type to be exported gets priority, but it will\n// be thrown away when compiling to JS.\n// @ts-ignore\nexport { ActualLink as Link };\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport MaterialButton, {\n\n} from '@material-ui/core/Button';\nimport React from 'react';\nimport { Link, } from '../Link';\n\n/**\n * Properties for {@link Button}\n *\n * @public\n * @remarks\n *\n * See {@link https://v4.mui.com/api/button/#props | Material-UI Button Props} for all properties\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * This wrapper is here to reset the color of the Link and make typescript happy.\n */\nconst LinkWrapper = React.forwardRef((props, ref) => (\n React.createElement(Link, { ref: ref, ...props, color: \"initial\",} )\n));\n\n/** @public */\nconst ActualButton = React.forwardRef((props, ref) => (\n React.createElement(MaterialButton, { ref: ref, component: LinkWrapper, ...props,} )\n)) ;\n\n// TODO(Rugvip): We use this as a workaround to make the exported type be a\n// function, which makes our API reference docs much nicer.\n// The first type to be exported gets priority, but it will\n// be thrown away when compiling to JS.\n// @ts-ignore\nexport { ActualButton as Button };\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorApiRef, useApi } from '@backstage/core-plugin-api';\nimport IconButton from '@material-ui/core/IconButton';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport CopyIcon from '@material-ui/icons/FileCopy';\nimport React, { useEffect, useState } from 'react';\nimport useCopyToClipboard from 'react-use/lib/useCopyToClipboard';\n\n/**\n * Properties for {@link CopyTextButton}\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Copy text button with visual feedback\n *\n * @public\n * @remarks\n *\n * Visual feedback takes form of:\n * - a hover color\n * - click ripple\n * - Tooltip shown when user has clicked\n *\n * @example\n *\n * `<CopyTextButton text=\"My text that I want to be copied to the clipboard\" />`\n */\nexport function CopyTextButton(props) {\n const {\n text,\n tooltipDelay = 1000,\n tooltipText = 'Text copied to clipboard',\n } = props;\n const errorApi = useApi(errorApiRef);\n const [open, setOpen] = useState(false);\n const [{ error }, copyToClipboard] = useCopyToClipboard();\n\n useEffect(() => {\n if (error) {\n errorApi.post(error);\n }\n }, [error, errorApi]);\n\n const handleCopyClick = e => {\n e.stopPropagation();\n setOpen(true);\n copyToClipboard(text);\n };\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(Tooltip, {\n id: \"copy-test-tooltip\",\n title: tooltipText,\n placement: \"top\",\n leaveDelay: tooltipDelay,\n onClose: () => setOpen(false),\n open: open,}\n \n , React.createElement(IconButton, { onClick: handleCopyClick,}\n , React.createElement(CopyIcon, null )\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { useTheme } from '@material-ui/core/styles';\n\nimport { CopyTextButton } from '../CopyTextButton';\nimport { LightAsync } from 'react-syntax-highlighter';\nimport dark from 'react-syntax-highlighter/dist/esm/styles/hljs/dark';\nimport docco from 'react-syntax-highlighter/dist/esm/styles/hljs/docco';\n\n/**\n * Properties for {@link CodeSnippet}\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Thin wrapper on top of {@link https://react-syntax-highlighter.github.io/react-syntax-highlighter/ | react-syntax-highlighter}\n * providing consistent theming and copy code button\n *\n * @public\n */\nexport function CodeSnippet(props) {\n const {\n text,\n language,\n showLineNumbers = false,\n highlightedNumbers,\n customStyle,\n showCopyCodeButton = false,\n } = props;\n const theme = useTheme();\n const mode = theme.palette.type === 'dark' ? dark : docco;\n const highlightColor = theme.palette.type === 'dark' ? '#256bf3' : '#e6ffed';\n\n return (\n React.createElement('div', { style: { position: 'relative' },}\n , React.createElement(LightAsync, {\n customStyle: customStyle,\n language: language,\n style: mode,\n showLineNumbers: showLineNumbers,\n wrapLines: true,\n lineNumberStyle: { color: theme.palette.textVerySubtle },\n lineProps: (lineNumber) =>\n highlightedNumbers?.includes(lineNumber)\n ? {\n style: {\n backgroundColor: highlightColor,\n },\n }\n : {}\n ,}\n \n , text\n )\n , showCopyCodeButton && (\n React.createElement('div', { style: { position: 'absolute', top: 0, right: 0 },}\n , React.createElement(CopyTextButton, { text: text,} )\n )\n )\n )\n );\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport Button from '@material-ui/core/Button';\nimport IconButton from '@material-ui/core/IconButton';\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport React from 'react';\nimport { Link as RouterLink, } from 'react-router-dom';\nimport AddCircleOutline from '@material-ui/icons/AddCircleOutline';\n\n/**\n * Properties for {@link CreateButton}\n *\n * @public\n */\n\n\n\n\n/**\n * Responsive Button giving consistent UX for creation of different things\n *\n * @public\n */\nexport function CreateButton(props) {\n const { title, to } = props;\n const isXSScreen = useMediaQuery(theme =>\n theme.breakpoints.down('xs'),\n );\n\n if (!to) {\n return null;\n }\n\n return isXSScreen ? (\n React.createElement(IconButton, {\n component: RouterLink,\n color: \"primary\",\n title: title,\n size: \"small\",\n to: to,}\n \n , React.createElement(AddCircleOutline, null )\n )\n ) : (\n React.createElement(Button, { component: RouterLink, variant: \"contained\", color: \"primary\", to: to,}\n , title\n )\n );\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Edge of {@link DependencyGraph}\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Graph direction\n *\n * @public\n */\nexport var Direction; (function (Direction) {\n /**\n * Top to Bottom\n */\n const TOP_BOTTOM = 'TB'; Direction[\"TOP_BOTTOM\"] = TOP_BOTTOM;\n /**\n * Bottom to Top\n */\n const BOTTOM_TOP = 'BT'; Direction[\"BOTTOM_TOP\"] = BOTTOM_TOP;\n /**\n * Left to Right\n */\n const LEFT_RIGHT = 'LR'; Direction[\"LEFT_RIGHT\"] = LEFT_RIGHT;\n /**\n * Right to Left\n */\n const RIGHT_LEFT = 'RL'; Direction[\"RIGHT_LEFT\"] = RIGHT_LEFT;\n})(Direction || (Direction = {}));\n\n/**\n * Node alignment\n *\n * @public\n */\nexport var Alignment; (function (Alignment) {\n /**\n * Up Left\n */\n const UP_LEFT = 'UL'; Alignment[\"UP_LEFT\"] = UP_LEFT;\n /**\n * Up Right\n */\n const UP_RIGHT = 'UR'; Alignment[\"UP_RIGHT\"] = UP_RIGHT;\n /**\n * Down Left\n */\n const DOWN_LEFT = 'DL'; Alignment[\"DOWN_LEFT\"] = DOWN_LEFT;\n /**\n * Down Right\n */\n const DOWN_RIGHT = 'DR'; Alignment[\"DOWN_RIGHT\"] = DOWN_RIGHT;\n})(Alignment || (Alignment = {}));\n\n/**\n * Algorithm used to rand nodes in graph\n */\nexport var Ranker; (function (Ranker) {\n /**\n * {@link https://en.wikipedia.org/wiki/Network_simplex_algorithm | Network Simplex} algorithm\n */\n const NETWORK_SIMPLEX = 'network-simplex'; Ranker[\"NETWORK_SIMPLEX\"] = NETWORK_SIMPLEX;\n /**\n * Tight Tree algorithm\n */\n const TIGHT_TREE = 'tight-tree'; Ranker[\"TIGHT_TREE\"] = TIGHT_TREE;\n /**\n * Longest path algorithm\n *\n * @remarks\n *\n * Simplest and fastest\n */\n const LONGEST_PATH = 'longest-path'; Ranker[\"LONGEST_PATH\"] = LONGEST_PATH;\n})(Ranker || (Ranker = {}));\n\n/**\n * Position of label in relation to the edge\n *\n * @public\n */\nexport var LabelPosition; (function (LabelPosition) {\n const LEFT = 'l'; LabelPosition[\"LEFT\"] = LEFT;\n const RIGHT = 'r'; LabelPosition[\"RIGHT\"] = RIGHT;\n const CENTER = 'c'; LabelPosition[\"CENTER\"] = CENTER;\n})(LabelPosition || (LabelPosition = {}));\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\n\n\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n (theme) => ({\n node: {\n fill: theme.palette.primary.light,\n stroke: theme.palette.primary.light,\n },\n text: {\n fill: theme.palette.primary.contrastText,\n },\n }),\n { name: 'BackstageDependencyGraphDefaultNode' },\n);\n\n/** @public */\nexport function DefaultNode({ node: { id } }) {\n const classes = useStyles();\n const [width, setWidth] = React.useState(0);\n const [height, setHeight] = React.useState(0);\n const idRef = React.useRef(null);\n\n React.useLayoutEffect(() => {\n // set the width to the length of the ID\n if (idRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n idRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n\n if (renderedHeight !== height || renderedWidth !== width) {\n setWidth(renderedWidth);\n setHeight(renderedHeight);\n }\n }\n }, [width, height]);\n\n const padding = 10;\n const paddedWidth = width + padding * 2;\n const paddedHeight = height + padding * 2;\n\n return (\n React.createElement('g', null\n , React.createElement('rect', {\n className: classes.node,\n width: paddedWidth,\n height: paddedHeight,\n rx: 10,}\n )\n , React.createElement('text', {\n ref: idRef,\n className: classes.text,\n y: paddedHeight / 2,\n x: paddedWidth / 2,\n textAnchor: \"middle\",\n alignmentBaseline: \"middle\",}\n \n , id\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport const ARROW_MARKER_ID = 'arrow-marker';\n\nexport const NODE_TEST_ID = 'node';\nexport const EDGE_TEST_ID = 'edge';\nexport const LABEL_TEST_ID = 'label';\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport makeStyles from '@material-ui/core/styles/makeStyles';\nimport { DefaultNode } from './DefaultNode';\n\nimport { NODE_TEST_ID } from './constants';\n\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n theme => ({\n node: {\n transition: `${theme.transitions.duration.shortest}ms`,\n },\n }),\n { name: 'BackstageDependencyGraphNode' },\n);\n\n\n\n\n\n\n\n\n\nconst renderDefault = (props) => React.createElement(DefaultNode, { ...props,} );\n\nexport function Node({\n render = renderDefault,\n setNode,\n node,\n}) {\n const { width, height, x = 0, y = 0 } = node;\n const nodeProps = node;\n const classes = useStyles();\n const nodeRef = React.useRef(null);\n\n React.useLayoutEffect(() => {\n // set the node width to the actual rendered width to properly layout graph\n if (nodeRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n nodeRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n\n if (renderedHeight !== height || renderedWidth !== width) {\n setNode(node.id, {\n ...node,\n height: renderedHeight,\n width: renderedWidth,\n });\n }\n }\n }, [node, width, height, setNode]);\n\n return (\n React.createElement('g', {\n ref: nodeRef,\n 'data-testid': NODE_TEST_ID,\n className: classes.node,\n transform: `translate(${x - width / 2},${y - height / 2})`,}\n \n , render({ node: nodeProps })\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport makeStyles from '@material-ui/core/styles/makeStyles';\n\n\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n (theme) => ({\n text: {\n fill: theme.palette.textContrast,\n },\n }),\n { name: 'BackstageDependencyGraphDefaultLabel' },\n);\n\n/** @public */\nexport function DefaultLabel({ edge: { label } }) {\n const classes = useStyles();\n return (\n React.createElement('text', { className: classes.text, textAnchor: \"middle\",}\n , label\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport * as d3Shape from 'd3-shape';\nimport isFinite from 'lodash/isFinite';\nimport makeStyles from '@material-ui/core/styles/makeStyles';\n\n\n\n\n\n\n\nimport { ARROW_MARKER_ID, EDGE_TEST_ID, LABEL_TEST_ID } from './constants';\nimport { DefaultLabel } from './DefaultLabel';\n\n\n/* Based on: https://github.com/dagrejs/dagre/wiki#configuring-the-layout */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n (theme) => ({\n path: {\n strokeWidth: 2,\n stroke: theme.palette.textSubtle,\n fill: 'none',\n transition: `${theme.transitions.duration.shortest}ms`,\n },\n label: {\n transition: `${theme.transitions.duration.shortest}ms`,\n },\n }),\n { name: 'BackstageDependencyGraphEdge' },\n);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst renderDefault = (props) => (\n React.createElement(DefaultLabel, { ...props,} )\n);\n\nconst createPath = d3Shape\n .line()\n .x(d => d.x)\n .y(d => d.y)\n .curve(d3Shape.curveMonotoneX);\n\nexport function Edge({\n render = renderDefault,\n setEdge,\n id,\n edge,\n}) {\n const { x = 0, y = 0, width, height, points } = edge;\n const labelProps = edge;\n const classes = useStyles();\n\n const labelRef = React.useRef(null);\n\n React.useLayoutEffect(() => {\n // set the label width to the actual rendered width to properly layout graph\n if (labelRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n labelRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n\n if (renderedHeight !== height || renderedWidth !== width) {\n setEdge(id, {\n ...edge,\n height: renderedHeight,\n width: renderedWidth,\n });\n }\n }\n }, [edge, height, width, setEdge, id]);\n\n let path = '';\n\n if (points) {\n const finitePoints = points.filter(\n (point) => isFinite(point.x) && isFinite(point.y),\n );\n path = createPath(finitePoints) || '';\n }\n\n return (\n React.createElement(React.Fragment, null\n , path && (\n React.createElement('path', {\n 'data-testid': EDGE_TEST_ID,\n className: classes.path,\n markerEnd: `url(#${ARROW_MARKER_ID})`,\n d: path,}\n )\n )\n , labelProps.label ? (\n React.createElement('g', {\n ref: labelRef,\n 'data-testid': LABEL_TEST_ID,\n className: classes.label,\n transform: `translate(${x},${y})`,}\n \n , render({ edge: labelProps })\n )\n ) : null\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport * as d3Zoom from 'd3-zoom';\nimport * as d3Selection from 'd3-selection';\nimport useTheme from '@material-ui/core/styles/useTheme';\nimport dagre from 'dagre';\nimport debounce from 'lodash/debounce';\n\nimport {\n\n\n Direction,\n\n Ranker,\n\n\n LabelPosition,\n} from './types';\nimport { Node } from './Node';\nimport { Edge, } from './Edge';\nimport { ARROW_MARKER_ID } from './constants';\n\n/**\n * Properties of {@link DependencyGraph}\n *\n * @public\n * @remarks\n * <NodeData> and <EdgeData> are useful when rendering custom or edge labels\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst WORKSPACE_ID = 'workspace';\n\n/**\n * Graph component used to visualize relations between entities\n *\n * @public\n */\nexport function DependencyGraph(\n props,\n) {\n const {\n edges,\n nodes,\n renderNode,\n direction = Direction.TOP_BOTTOM,\n align,\n nodeMargin = 50,\n edgeMargin = 10,\n rankMargin = 50,\n paddingX = 0,\n paddingY = 0,\n acyclicer,\n ranker = Ranker.NETWORK_SIMPLEX,\n labelPosition = LabelPosition.RIGHT,\n labelOffset = 10,\n edgeRanks = 1,\n edgeWeight = 1,\n renderLabel,\n defs,\n zoom = 'enabled',\n ...svgProps\n } = props;\n const theme = useTheme();\n const [containerWidth, setContainerWidth] = React.useState(100);\n const [containerHeight, setContainerHeight] = React.useState(100);\n\n const graph = React.useRef(\n new dagre.graphlib.Graph(),\n );\n const [graphWidth, setGraphWidth] = React.useState(\n graph.current.graph()?.width || 0,\n );\n const [graphHeight, setGraphHeight] = React.useState(\n graph.current.graph()?.height || 0,\n );\n const [graphNodes, setGraphNodes] = React.useState([]);\n const [graphEdges, setGraphEdges] = React.useState([]);\n\n const maxWidth = Math.max(graphWidth, containerWidth);\n const maxHeight = Math.max(graphHeight, containerHeight);\n\n const containerRef = React.useMemo(\n () =>\n debounce((node) => {\n if (!node) {\n return;\n }\n // Set up zooming + panning\n const container = d3Selection.select(node);\n const workspace = d3Selection.select(node.getElementById(WORKSPACE_ID));\n\n function enableZoom() {\n container.call(\n d3Zoom\n .zoom()\n .scaleExtent([1, 10])\n .on('zoom', event => {\n event.transform.x = Math.min(\n 0,\n Math.max(\n event.transform.x,\n maxWidth - maxWidth * event.transform.k,\n ),\n );\n event.transform.y = Math.min(\n 0,\n Math.max(\n event.transform.y,\n maxHeight - maxHeight * event.transform.k,\n ),\n );\n workspace.attr('transform', event.transform);\n }),\n );\n }\n\n if (zoom === 'enabled') {\n enableZoom();\n } else if (zoom === 'enable-on-click') {\n container.on('click', () => enableZoom());\n }\n\n const { width: newContainerWidth, height: newContainerHeight } =\n node.getBoundingClientRect();\n if (containerWidth !== newContainerWidth) {\n setContainerWidth(newContainerWidth);\n }\n if (containerHeight !== newContainerHeight) {\n setContainerHeight(newContainerHeight);\n }\n }, 100),\n [containerHeight, containerWidth, maxWidth, maxHeight, zoom],\n );\n\n const setNodesAndEdges = React.useCallback(() => {\n // Cleaning up lingering nodes and edges\n const currentGraphNodes = graph.current.nodes();\n const currentGraphEdges = graph.current.edges();\n\n currentGraphNodes.forEach(nodeId => {\n const remainingNode = nodes.some(node => node.id === nodeId);\n if (!remainingNode) {\n graph.current.removeNode(nodeId);\n }\n });\n\n currentGraphEdges.forEach(e => {\n const remainingEdge = edges.some(\n edge => edge.from === e.v && edge.to === e.w,\n );\n if (!remainingEdge) {\n graph.current.removeEdge(e.v, e.w);\n }\n });\n\n // Adding/updating nodes and edges\n nodes.forEach(node => {\n const existingNode = graph.current\n .nodes()\n .find(nodeId => node.id === nodeId);\n\n if (existingNode && graph.current.node(existingNode)) {\n const { width, height, x, y } = graph.current.node(existingNode);\n graph.current.setNode(existingNode, { ...node, width, height, x, y });\n } else {\n graph.current.setNode(node.id, { ...node, width: 0, height: 0 });\n }\n });\n\n edges.forEach(e => {\n graph.current.setEdge(e.from, e.to, {\n ...e,\n label: e.label,\n width: 0,\n height: 0,\n labelpos: labelPosition,\n labeloffset: labelOffset,\n weight: edgeWeight,\n minlen: edgeRanks,\n });\n });\n }, [edges, nodes, labelPosition, labelOffset, edgeWeight, edgeRanks]);\n\n const updateGraph = React.useMemo(\n () =>\n debounce(\n () => {\n dagre.layout(graph.current);\n const { height, width } = graph.current.graph();\n const newHeight = Math.max(0, height || 0);\n const newWidth = Math.max(0, width || 0);\n setGraphWidth(newWidth);\n setGraphHeight(newHeight);\n\n setGraphNodes(graph.current.nodes());\n setGraphEdges(graph.current.edges());\n },\n 250,\n { leading: true },\n ),\n [],\n );\n\n React.useEffect(() => {\n graph.current.setGraph({\n rankdir: direction,\n align,\n nodesep: nodeMargin,\n edgesep: edgeMargin,\n ranksep: rankMargin,\n marginx: paddingX,\n marginy: paddingY,\n acyclicer,\n ranker,\n });\n\n setNodesAndEdges();\n updateGraph();\n\n return updateGraph.cancel;\n }, [\n acyclicer,\n align,\n direction,\n edgeMargin,\n paddingX,\n paddingY,\n nodeMargin,\n rankMargin,\n ranker,\n setNodesAndEdges,\n updateGraph,\n ]);\n\n function setNode(id, node) {\n graph.current.setNode(id, node);\n updateGraph();\n return graph.current;\n }\n\n function setEdge(id, edge) {\n graph.current.setEdge(id, edge);\n updateGraph();\n return graph.current;\n }\n\n return (\n React.createElement('svg', {\n ref: containerRef,\n ...svgProps,\n width: \"100%\",\n height: maxHeight,\n viewBox: `0 0 ${maxWidth} ${maxHeight}`,}\n \n , React.createElement('defs', null\n , React.createElement('marker', {\n id: ARROW_MARKER_ID,\n viewBox: \"0 0 24 24\" ,\n markerWidth: \"14\",\n markerHeight: \"14\",\n refX: \"16\",\n refY: \"12\",\n orient: \"auto\",\n markerUnits: \"strokeWidth\",}\n \n , React.createElement('path', {\n fill: theme.palette.textSubtle,\n d: \"M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z\" ,}\n )\n )\n , defs\n )\n , React.createElement('g', { id: WORKSPACE_ID,}\n , React.createElement('svg', {\n width: graphWidth,\n height: graphHeight,\n y: maxHeight / 2 - graphHeight / 2,\n x: maxWidth / 2 - graphWidth / 2,\n viewBox: `0 0 ${graphWidth} ${graphHeight}`,}\n \n , graphEdges.map(e => {\n const edge = graph.current.edge(e) ;\n if (!edge) return null;\n return (\n React.createElement(Edge, {\n key: `${e.v}-${e.w}`,\n id: e,\n setEdge: setEdge,\n render: renderLabel,\n edge: edge,}\n )\n );\n })\n , graphNodes.map((id) => {\n const node = graph.current.node(id);\n if (!node) return null;\n return (\n React.createElement(Node, {\n key: id,\n setNode: setNode,\n render: renderNode,\n node: node,}\n )\n );\n })\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useState, useEffect } from 'react';\nimport { useApi, storageApiRef } from '@backstage/core-plugin-api';\nimport useObservable from 'react-use/lib/useObservable';\nimport classNames from 'classnames';\nimport { makeStyles } from '@material-ui/core/styles';\n\nimport Snackbar from '@material-ui/core/Snackbar';\nimport SnackbarContent from '@material-ui/core/SnackbarContent';\nimport IconButton from '@material-ui/core/IconButton';\nimport Close from '@material-ui/icons/Close';\n\n/** @public */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n (theme) => ({\n root: {\n padding: theme.spacing(0),\n marginBottom: theme.spacing(0),\n marginTop: theme.spacing(0),\n display: 'flex',\n flexFlow: 'row nowrap',\n },\n // showing on top\n topPosition: {\n position: 'relative',\n marginBottom: theme.spacing(6),\n marginTop: -theme.spacing(3),\n zIndex: 'unset',\n },\n icon: {\n fontSize: 20,\n },\n content: {\n width: '100%',\n maxWidth: 'inherit',\n flexWrap: 'nowrap',\n },\n message: {\n display: 'flex',\n alignItems: 'center',\n color: theme.palette.banner.text,\n '& a': {\n color: theme.palette.banner.link,\n },\n },\n info: {\n backgroundColor: theme.palette.banner.info,\n },\n error: {\n backgroundColor: theme.palette.banner.error,\n },\n warning: {\n backgroundColor:\n theme.palette.banner.warning ?? theme.palette.banner.error,\n },\n }),\n { name: 'BackstageDismissableBanner' },\n);\n\n\n\n\n\n\n\n\n/** @public */\nexport const DismissableBanner = (props) => {\n const { variant, message, id, fixed = false } = props;\n const classes = useStyles();\n const storageApi = useApi(storageApiRef);\n const notificationsStore = storageApi.forBucket('notifications');\n const rawDismissedBanners =\n notificationsStore.get('dismissedBanners') ?? [];\n\n const [dismissedBanners, setDismissedBanners] = useState(\n new Set(rawDismissedBanners),\n );\n\n const observedItems = useObservable(\n notificationsStore.observe$('dismissedBanners'),\n );\n\n useEffect(() => {\n if (observedItems?.newValue) {\n const currentValue = observedItems?.newValue ?? [];\n setDismissedBanners(new Set(currentValue));\n }\n }, [observedItems?.newValue]);\n\n const handleClick = () => {\n notificationsStore.set('dismissedBanners', [...dismissedBanners, id]);\n };\n\n return (\n React.createElement(Snackbar, {\n anchorOrigin: \n fixed\n ? { vertical: 'bottom', horizontal: 'center' }\n : { vertical: 'top', horizontal: 'center' }\n ,\n open: !dismissedBanners.has(id),\n classes: {\n root: classNames(classes.root, !fixed && classes.topPosition),\n },}\n \n , React.createElement(SnackbarContent, {\n classes: {\n root: classNames(classes.content, classes[variant]),\n message: classes.message,\n },\n message: message,\n action: [\n React.createElement(IconButton, {\n key: \"dismiss\",\n title: \"Permanently dismiss this message\" ,\n color: \"inherit\",\n onClick: handleClick,}\n \n , React.createElement(Close, { className: classes.icon,} )\n ),\n ],}\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport missingAnnotation from './assets/missingAnnotation.svg';\nimport noInformation from './assets/noInformation.svg';\nimport createComponent from './assets/createComponent.svg';\nimport noBuild from './assets/noBuild.svg';\nimport { makeStyles } from '@material-ui/core/styles';\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n {\n generalImg: {\n width: '95%',\n zIndex: 2,\n position: 'relative',\n left: '50%',\n top: '50%',\n transform: 'translate(-50%, 15%)',\n },\n },\n { name: 'BackstageEmptyStateImage' },\n);\n\n/** @public */\nexport const EmptyStateImage = ({ missing }) => {\n const classes = useStyles();\n switch (missing) {\n case 'field':\n return (\n React.createElement('img', {\n src: missingAnnotation,\n className: classes.generalImg,\n alt: \"annotation is missing\" ,}\n )\n );\n case 'info':\n return (\n React.createElement('img', {\n src: noInformation,\n alt: \"no Information\" ,\n className: classes.generalImg,}\n )\n );\n case 'content':\n return (\n React.createElement('img', {\n src: createComponent,\n alt: \"create Component\" ,\n className: classes.generalImg,}\n )\n );\n case 'data':\n return (\n React.createElement('img', { src: noBuild, alt: \"no Build\" , className: classes.generalImg,} )\n );\n default:\n return null;\n }\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Grid from '@material-ui/core/Grid';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport React from 'react';\nimport { EmptyStateImage } from './EmptyStateImage';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n backgroundColor: theme.palette.background.default,\n padding: theme.spacing(2, 0, 0, 0),\n },\n action: {\n marginTop: theme.spacing(2),\n },\n imageContainer: {\n position: 'relative',\n },\n }),\n { name: 'BackstageEmptyState' },\n);\n\n\n\n\n\n\n\n\n/**\n * Various placeholder views for empty state pages\n *\n * @public\n *\n */\nexport function EmptyState(props) {\n const { title, description, missing, action } = props;\n const classes = useStyles();\n return (\n React.createElement(Grid, {\n container: true,\n direction: \"row\",\n justifyContent: \"space-around\",\n alignItems: \"flex-start\",\n className: classes.root,\n spacing: 2,}\n \n , React.createElement(Grid, { item: true, xs: 12, md: 6,}\n , React.createElement(Grid, { container: true, direction: \"column\",}\n , React.createElement(Grid, { item: true, xs: true,}\n , React.createElement(Typography, { variant: \"h5\",}, title)\n )\n , React.createElement(Grid, { item: true, xs: true,}\n , React.createElement(Typography, { variant: \"body1\",}, description)\n )\n , React.createElement(Grid, { item: true, xs: true, className: classes.action,}\n , action\n )\n )\n )\n , React.createElement(Grid, { item: true, xs: 12, md: 6, className: classes.imageContainer,}\n , React.createElement(EmptyStateImage, { missing: missing,} )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Button from '@material-ui/core/Button';\nimport Typography from '@material-ui/core/Typography';\n\nimport { Link } from '../Link';\nimport { EmptyState } from './EmptyState';\nimport { CodeSnippet } from '../CodeSnippet';\n\nconst COMPONENT_YAML = `apiVersion: backstage.io/v1alpha1\nkind: Component\nmetadata:\n name: example\n description: example.com\n annotations:\n ANNOTATION: value\nspec:\n type: website\n lifecycle: production\n owner: user:guest`;\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n code: {\n borderRadius: 6,\n margin: `${theme.spacing(2)}px 0px`,\n background: theme.palette.type === 'dark' ? '#444' : '#fff',\n },\n }),\n { name: 'BackstageMissingAnnotationEmptyState' },\n);\n\nexport function MissingAnnotationEmptyState(props) {\n const { annotation } = props;\n const classes = useStyles();\n const description = (\n React.createElement(React.Fragment, null, \"The \"\n , React.createElement('code', null, annotation), \" annotation is missing. You need to add the annotation to your component if you want to enable this tool.\"\n\n )\n );\n return (\n React.createElement(EmptyState, {\n missing: \"field\",\n title: \"Missing Annotation\" ,\n description: description,\n action: \n React.createElement(React.Fragment, null\n , React.createElement(Typography, { variant: \"body1\",}, \"Add the annotation to your component YAML as shown in the highlighted example below:\"\n\n\n )\n , React.createElement('div', { className: classes.code,}\n , React.createElement(CodeSnippet, {\n text: COMPONENT_YAML.replace('ANNOTATION', annotation),\n language: \"yaml\",\n showLineNumbers: true,\n highlightedNumbers: [6, 7],\n customStyle: { background: 'inherit', fontSize: '115%' },}\n )\n )\n , React.createElement(Button, {\n color: \"primary\",\n component: Link,\n to: \"https://backstage.io/docs/features/software-catalog/well-known-annotations\",}\n , \"Read more\"\n\n )\n )\n ,}\n )\n );\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { makeStyles, darken, lighten } from '@material-ui/core/styles';\nimport Accordion from '@material-ui/core/Accordion';\nimport AccordionSummary from '@material-ui/core/AccordionSummary';\nimport AccordionDetails from '@material-ui/core/AccordionDetails';\nimport Grid from '@material-ui/core/Grid';\nimport Typography from '@material-ui/core/Typography';\nimport ErrorOutline from '@material-ui/icons/ErrorOutline';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport React from 'react';\n\nconst getWarningTextColor = (\n severity,\n theme,\n) => {\n const getColor = theme.palette.type === 'light' ? darken : lighten;\n return getColor(theme.palette[severity].light, 0.6);\n};\n\nconst getWarningBackgroundColor = (\n severity,\n theme,\n) => {\n const getBackgroundColor = theme.palette.type === 'light' ? lighten : darken;\n return getBackgroundColor(theme.palette[severity].light, 0.9);\n};\n\nconst useErrorOutlineStyles = makeStyles(theme => ({\n root: {\n marginRight: theme.spacing(1),\n fill: ({ severity }) =>\n getWarningTextColor(\n severity ,\n theme,\n ),\n },\n}));\n\nconst ErrorOutlineStyled = ({ severity }) => {\n const classes = useErrorOutlineStyles({ severity });\n return React.createElement(ErrorOutline, { classes: classes,} );\n};\nconst ExpandMoreIconStyled = ({ severity }) => {\n const classes = useErrorOutlineStyles({ severity });\n return React.createElement(ExpandMoreIcon, { classes: classes,} );\n};\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n panel: {\n backgroundColor: ({ severity }) =>\n getWarningBackgroundColor(\n severity ,\n theme,\n ),\n color: ({ severity }) =>\n getWarningTextColor(\n severity ,\n theme,\n ),\n verticalAlign: 'middle',\n },\n summary: {\n display: 'flex',\n flexDirection: 'row',\n },\n summaryText: {\n color: ({ severity }) =>\n getWarningTextColor(\n severity ,\n theme,\n ),\n fontWeight: 'bold',\n },\n message: {\n width: '100%',\n display: 'block',\n color: ({ severity }) =>\n getWarningTextColor(\n severity ,\n theme,\n ),\n backgroundColor: ({ severity }) =>\n getWarningBackgroundColor(\n severity ,\n theme,\n ),\n },\n details: {\n width: '100%',\n display: 'block',\n color: theme.palette.textContrast,\n backgroundColor: theme.palette.background.default,\n border: `1px solid ${theme.palette.border}`,\n padding: theme.spacing(2.0),\n fontFamily: 'sans-serif',\n },\n }),\n { name: 'BackstageWarningPanel' },\n);\n\n\n\n\n\n\n\n\n\nconst capitalize = (s) => {\n return s.charAt(0).toLocaleUpperCase('en-US') + s.slice(1);\n};\n\n/**\n * WarningPanel. Show a user friendly error message to a user similar to\n * ErrorPanel except that the warning panel only shows the warning message to\n * the user.\n *\n * @param severity - Ability to change the severity of the alert. Default value\n * \"warning\"\n * @param title - A title for the warning. If not supplied, \"Warning\" will be\n * used.\n * @param message - Optional more detailed user-friendly message elaborating on\n * the cause of the error.\n * @param children - Objects to provide context, such as a stack trace or detailed\n * error reporting. Will be available inside an unfolded accordion.\n */\nexport function WarningPanel(props) {\n const {\n severity = 'warning',\n title,\n message,\n children,\n defaultExpanded,\n } = props;\n const classes = useStyles({ severity });\n\n // If no severity or title provided, the heading will read simply \"Warning\"\n const subTitle = capitalize(severity) + (title ? `: ${title}` : '');\n\n return (\n React.createElement(Accordion, {\n defaultExpanded: defaultExpanded ?? false,\n className: classes.panel,\n role: \"alert\",}\n \n , React.createElement(AccordionSummary, {\n expandIcon: React.createElement(ExpandMoreIconStyled, { severity: severity,} ),\n className: classes.summary,}\n \n , React.createElement(ErrorOutlineStyled, { severity: severity,} )\n , React.createElement(Typography, { className: classes.summaryText, variant: \"subtitle1\",}\n , subTitle\n )\n )\n , (message || children) && (\n React.createElement(AccordionDetails, null\n , React.createElement(Grid, { container: true,}\n , message && (\n React.createElement(Grid, { item: true, xs: 12,}\n , React.createElement(Typography, { className: classes.message, variant: \"body1\",}\n , message\n )\n )\n )\n , children && (\n React.createElement(Grid, { item: true, xs: 12, className: classes.details,}\n , children\n )\n )\n )\n )\n )\n )\n );\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport List from '@material-ui/core/List';\nimport ListItem from '@material-ui/core/ListItem';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport React, { } from 'react';\nimport { CopyTextButton } from '../CopyTextButton';\nimport { WarningPanel } from '../WarningPanel';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n theme => ({\n text: {\n fontFamily: 'monospace',\n whiteSpace: 'pre',\n overflowX: 'auto',\n marginRight: theme.spacing(2),\n },\n divider: {\n margin: theme.spacing(2),\n },\n }),\n { name: 'BackstageErrorPanel' },\n);\n\n\n\n\n\n\n\n\n\nconst ErrorList = ({\n error,\n message,\n stack,\n children,\n}) => {\n const classes = useStyles();\n\n return (\n React.createElement(List, { dense: true,}\n , React.createElement(ListItem, { alignItems: \"flex-start\",}\n , React.createElement(ListItemText, {\n classes: { secondary: classes.text },\n primary: \"Error\",\n secondary: error,}\n )\n , React.createElement(CopyTextButton, { text: error,} )\n )\n\n , React.createElement(ListItem, { alignItems: \"flex-start\",}\n , React.createElement(ListItemText, {\n classes: { secondary: classes.text },\n primary: \"Message\",\n secondary: message,}\n )\n , React.createElement(CopyTextButton, { text: message,} )\n )\n\n , stack && (\n React.createElement(ListItem, { alignItems: \"flex-start\",}\n , React.createElement(ListItemText, {\n classes: { secondary: classes.text },\n primary: \"Stack Trace\" ,\n secondary: stack,}\n )\n , React.createElement(CopyTextButton, { text: stack,} )\n )\n )\n\n , children\n )\n );\n};\n\n/** @public */\n\n\n\n\n\n\n/**\n * Renders a warning panel as the effect of an error.\n *\n * @public\n */\nexport function ErrorPanel(props) {\n const { title, error, defaultExpanded, children } = props;\n return (\n React.createElement(WarningPanel, {\n severity: \"error\",\n title: title ?? error.message,\n defaultExpanded: defaultExpanded,}\n \n , React.createElement(ErrorList, {\n error: error.name,\n message: error.message,\n stack: error.stack,\n children: children,}\n )\n )\n );\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport Divider from '@material-ui/core/Divider';\nimport ListItem from '@material-ui/core/ListItem';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport React from 'react';\nimport { CodeSnippet } from '../CodeSnippet';\nimport { CopyTextButton } from '../CopyTextButton';\nimport { ErrorPanel, } from '../ErrorPanel';\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n text: {\n fontFamily: 'monospace',\n whiteSpace: 'pre',\n overflowX: 'auto',\n marginRight: theme.spacing(2),\n },\n divider: {\n margin: theme.spacing(2),\n },\n }),\n { name: 'BackstageResponseErrorPanel' },\n);\n\n/**\n * Renders a warning panel as the effect of a failed server request.\n *\n * Has special treatment for ResponseError errors, to display rich\n * server-provided information about what happened.\n */\nexport function ResponseErrorPanel(props) {\n const { title, error, defaultExpanded } = props;\n const classes = useStyles();\n\n if (error.name !== 'ResponseError') {\n return (\n React.createElement(ErrorPanel, {\n title: title ?? error.message,\n defaultExpanded: defaultExpanded,\n error: error,}\n )\n );\n }\n\n const { body, cause } = error ;\n const { request, response } = body;\n\n const errorString = `${response.statusCode}: ${cause.name}`;\n const requestString = request && `${request.method} ${request.url}`;\n const messageString = cause.message.replace(/\\\\n/g, '\\n');\n const stackString = cause.stack?.replace(/\\\\n/g, '\\n');\n const jsonString = JSON.stringify(body, undefined, 2);\n\n return (\n React.createElement(ErrorPanel, {\n title: title ?? error.message,\n defaultExpanded: defaultExpanded,\n error: { name: errorString, message: messageString, stack: stackString },}\n \n , requestString && (\n React.createElement(ListItem, { alignItems: \"flex-start\",}\n , React.createElement(ListItemText, {\n classes: { secondary: classes.text },\n primary: \"Request\",\n secondary: request ? `${requestString}` : undefined,}\n )\n , React.createElement(CopyTextButton, { text: requestString,} )\n )\n )\n , React.createElement(React.Fragment, null\n , React.createElement(Divider, { component: \"li\", className: classes.divider,} )\n , React.createElement(ListItem, { alignItems: \"flex-start\",}\n , React.createElement(ListItemText, {\n classes: { secondary: classes.text },\n primary: \"Full Error as JSON\" ,}\n )\n )\n , React.createElement(CodeSnippet, { language: \"json\", text: jsonString, showCopyCodeButton: true,} )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useRef, useEffect } from 'react';\n\n/**\n * Creates DOM element to be used as React root.\n */\nfunction createRootElement(id) {\n const rootContainer = document.createElement('div');\n rootContainer.setAttribute('id', id);\n return rootContainer;\n}\n\n/**\n * Appends element as last child of body.\n */\nfunction addRootElement(rootElem) {\n document.body.insertBefore(\n rootElem,\n document.body.lastElementChild.nextElementSibling,\n );\n}\n\n/**\n * Hook to create a React Portal.\n *\n * Automatically handles creating and tearing-down the root elements (no SRR\n * makes this trivial), so there is no need to ensure the parent target already\n * exists.\n *\n * @example\n * const target = usePortal(id, [id]);\n * return createPortal(children, target);\n *\n * @param id - The id of the target container, e.g 'modal' or 'spotlight'\n * @returns The DOM node to use as the Portal target.\n */\nexport function usePortal(id) {\n const rootElemRef = useRef(null);\n\n useEffect(\n function setupElement() {\n // Look for existing target dom element to append to\n const existingParent = document.querySelector(`#${id}`);\n // Parent is either a new root or the existing dom element\n const parentElem = existingParent || createRootElement(id);\n\n // If there is no existing DOM element, add a new one.\n if (!existingParent) {\n addRootElement(parentElem);\n }\n\n // Add the detached element to the parent\n parentElem.appendChild(rootElemRef.current);\n\n return function removeElement() {\n rootElemRef.current.remove();\n if (parentElem.childNodes.length === -1) {\n parentElem.remove();\n }\n };\n },\n [id],\n );\n\n /**\n * It's important we evaluate this lazily:\n * - We need first render to contain the DOM element, so it shouldn't happen\n * in useEffect. We would normally put this in the constructor().\n * - We can't do 'const rootElemRef = useRef(document.createElement('div))',\n * since this will run every single render (that's a lot).\n * - We want the ref to consistently point to the same DOM element and only\n * ever run once.\n * @link https://reactjs.org/docs/hooks-faq.html#how-to-create-expensive-objects-lazily\n */\n function getRootElem() {\n if (!rootElemRef.current) {\n rootElemRef.current = document.createElement('div');\n }\n return rootElemRef.current;\n }\n\n return getRootElem();\n}\n\nexport default usePortal;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useState } from 'react';\n\nconst STATES_LOCAL_STORAGE_KEY = 'core.calloutSeen';\n\nfunction useCalloutStates()\n\n\n {\n const [states, setStates] = useState(() => {\n const raw = localStorage.getItem(STATES_LOCAL_STORAGE_KEY);\n return raw ? JSON.parse(raw) : {};\n });\n\n const setState = useCallback((key, value) => {\n const raw = localStorage.getItem(STATES_LOCAL_STORAGE_KEY);\n const oldStates = raw ? JSON.parse(raw) : {};\n const newStates = { ...oldStates, [key]: value };\n setStates(newStates);\n localStorage.setItem(STATES_LOCAL_STORAGE_KEY, JSON.stringify(newStates));\n }, []);\n\n return { states, setState };\n}\n\nfunction useCalloutHasBeenSeen(featureId)\n\n\n {\n const { states, setState } = useCalloutStates();\n\n const markSeen = useCallback(() => {\n setState(featureId, true);\n }, [setState, featureId]);\n\n return { seen: states[featureId] === true, markSeen };\n}\n\nexport function useShowCallout(featureId)\n\n\n {\n const { seen, markSeen } = useCalloutHasBeenSeen(featureId);\n return { show: seen === false, hide: markSeen };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport ClickAwayListener from '@material-ui/core/ClickAwayListener';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport React, {\n\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { usePortal } from './lib/usePortal';\nimport { useShowCallout } from './lib/useShowCallout';\n\n/** @public */\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n {\n '@keyframes pulsateSlightly': {\n '0%': { transform: 'scale(1.0)' },\n '100%': { transform: 'scale(1.1)' },\n },\n '@keyframes pulsateAndFade': {\n '0%': { transform: 'scale(1.0)', opacity: 0.9 },\n '100%': { transform: 'scale(1.5)', opacity: 0 },\n },\n featureWrapper: {\n position: 'relative',\n },\n backdrop: {\n zIndex: 2000,\n position: 'fixed',\n overflow: 'hidden',\n left: 0,\n right: 0,\n top: 0,\n bottom: 0,\n },\n dot: {\n position: 'absolute',\n backgroundColor: 'transparent',\n borderRadius: '100%',\n border: '1px solid rgba(103, 146, 180, 0.98)',\n boxShadow: '0px 0px 0px 20000px rgba(0, 0, 0, 0.5)',\n zIndex: 2001,\n transformOrigin: 'center center',\n animation:\n '$pulsateSlightly 1744ms 1.2s cubic-bezier(0.4, 0, 0.2, 1) alternate infinite',\n },\n pulseCircle: {\n width: '100%',\n height: '100%',\n backgroundColor: 'transparent',\n borderRadius: '100%',\n border: '2px solid white',\n zIndex: 2001,\n transformOrigin: 'center center',\n animation:\n '$pulsateAndFade 872ms 1.2s cubic-bezier(0.4, 0, 0.2, 1) infinite',\n },\n text: {\n position: 'absolute',\n color: 'white',\n zIndex: 2003,\n },\n },\n { name: 'BackstageFeatureCalloutCircular' },\n);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * One-time, round 'telescope' animation showing new feature.\n *\n * @public\n *\n */\nexport function FeatureCalloutCircular(props) {\n const { featureId, title, description, children } = props;\n const { show, hide } = useShowCallout(featureId);\n const portalElement = usePortal('core.callout');\n const wrapperRef = useRef(null);\n const [placement, setPlacement] = useState();\n const classes = useStyles();\n\n const update = useCallback(() => {\n if (wrapperRef.current) {\n const wrapperBounds = wrapperRef.current.getBoundingClientRect();\n const longest = Math.max(wrapperBounds.width, wrapperBounds.height);\n\n const borderWidth = 800;\n const dotLeft =\n wrapperBounds.x - (longest - wrapperBounds.width) / 2 - borderWidth;\n const dotTop =\n wrapperBounds.y - (longest - wrapperBounds.height) / 2 - borderWidth;\n const dotSize = longest + 2 * borderWidth;\n\n const textWidth = 450;\n const textLeft = wrapperBounds.x + wrapperBounds.width / 2 - textWidth;\n const textTop =\n wrapperBounds.y - (longest - wrapperBounds.height) / 2 + longest + 20;\n\n setPlacement({\n dotLeft,\n dotTop,\n dotSize,\n borderWidth,\n textTop,\n textLeft,\n textWidth,\n });\n }\n }, []);\n\n useEffect(() => {\n window.addEventListener('resize', update);\n window.addEventListener('scroll', update);\n return () => {\n window.removeEventListener('resize', update);\n window.removeEventListener('scroll', update);\n };\n }, [update]);\n\n useLayoutEffect(update, [wrapperRef.current, update]);\n\n if (!show) {\n return React.createElement(React.Fragment, null, children);\n }\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement('div', { className: classes.featureWrapper, ref: wrapperRef,}\n , children\n )\n , createPortal(\n React.createElement('div', { className: classes.backdrop,}\n , React.createElement(ClickAwayListener, { onClickAway: hide,}\n , React.createElement(React.Fragment, null\n , React.createElement('div', {\n className: classes.dot,\n 'data-testid': \"dot\",\n style: {\n left: placement?.dotLeft,\n top: placement?.dotTop,\n width: placement?.dotSize,\n height: placement?.dotSize,\n borderWidth: placement?.borderWidth,\n },\n onClick: hide,\n onKeyDown: hide,\n role: \"button\",\n tabIndex: 0,}\n \n , React.createElement('div', { className: classes.pulseCircle,} )\n )\n , React.createElement('div', {\n className: classes.text,\n 'data-testid': \"text\",\n style: {\n left: placement?.textLeft,\n top: placement?.textTop,\n width: placement?.textWidth,\n },}\n \n , React.createElement(Typography, { variant: \"h2\", paragraph: true,}\n , title\n )\n , React.createElement(Typography, null, description)\n )\n )\n )\n ),\n portalElement,\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport classnames from 'classnames';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Link from '@material-ui/core/Link';\nimport LinkIcon from '@material-ui/icons/Link';\nimport { Link as RouterLink } from '../Link';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst useIconStyles = makeStyles(\n theme => ({\n link: {\n display: 'grid',\n justifyItems: 'center',\n gridGap: 4,\n textAlign: 'center',\n },\n disabled: {\n color: 'gray',\n cursor: 'default',\n },\n primary: {\n color: theme.palette.primary.main,\n },\n secondary: {\n color: theme.palette.secondary.main,\n },\n label: {\n fontSize: '0.7rem',\n textTransform: 'uppercase',\n fontWeight: 600,\n letterSpacing: 1.2,\n },\n }),\n { name: 'BackstageIconLinkVertical' },\n);\n\n/** @public */\nexport function IconLinkVertical({\n color = 'primary',\n disabled = false,\n href = '#',\n icon = React.createElement(LinkIcon, null ),\n label,\n onClick,\n title,\n}) {\n const classes = useIconStyles();\n\n if (disabled) {\n return (\n React.createElement(Link, {\n title: title,\n className: classnames(classes.link, classes.disabled),\n underline: \"none\",}\n \n , icon\n , React.createElement('span', { className: classes.label,}, label)\n )\n );\n }\n\n return (\n React.createElement(Link, {\n title: title,\n className: classnames(classes.link, classes[color]),\n to: href,\n component: RouterLink,\n onClick: onClick,}\n \n , icon\n , React.createElement('span', { className: classes.label,}, label)\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { makeStyles } from '@material-ui/core/styles';\nimport React from 'react';\nimport { IconLinkVertical, } from './IconLinkVertical';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n theme => ({\n links: {\n margin: theme.spacing(2, 0),\n display: 'grid',\n gridAutoFlow: 'column',\n gridAutoColumns: 'min-content',\n gridGap: theme.spacing(3),\n },\n }),\n { name: 'BackstageHeaderIconLinkRow' },\n);\n\n\n\n\n\n/**\n * HTML nav tag with links mapped inside\n *\n * @public\n *\n */\nexport function HeaderIconLinkRow(props) {\n const { links } = props;\n const classes = useStyles();\n return (\n React.createElement('nav', { className: classes.links,}\n , links.map((link, index) => (\n React.createElement(IconLinkVertical, { key: index + 1, ...link,} )\n ))\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Grid from '@material-ui/core/Grid';\nimport IconButton from '@material-ui/core/IconButton';\nimport { makeStyles, } from '@material-ui/core/styles';\nimport ChevronLeftIcon from '@material-ui/icons/ChevronLeft';\nimport ChevronRightIcon from '@material-ui/icons/ChevronRight';\nimport classNames from 'classnames';\nimport React, { } from 'react';\n\nconst generateGradientStops = (themeType) => {\n // 97% corresponds to the theme.palette.background.default for the light theme\n // 16% for the dark theme\n const luminance = themeType === 'dark' ? '16%' : '97%';\n // Generated with https://larsenwork.com/easing-gradients/\n return `\n hsl(0, 0%, ${luminance}) 0%,\n hsla(0, 0%, ${luminance}, 0.987) 8.1%,\n hsla(0, 0%, ${luminance}, 0.951) 15.5%,\n hsla(0, 0%, ${luminance}, 0.896) 22.5%,\n hsla(0, 0%, ${luminance}, 0.825) 29%,\n hsla(0, 0%, ${luminance}, 0.741) 35.3%,\n hsla(0, 0%, ${luminance}, 0.648) 41.2%,\n hsla(0, 0%, ${luminance}, 0.55) 47.1%,\n hsla(0, 0%, ${luminance}, 0.45) 52.9%,\n hsla(0, 0%, ${luminance}, 0.352) 58.8%,\n hsla(0, 0%, ${luminance}, 0.259) 64.7%,\n hsla(0, 0%, ${luminance}, 0.175) 71%,\n hsla(0, 0%, ${luminance}, 0.104) 77.5%,\n hsla(0, 0%, ${luminance}, 0.049) 84.5%,\n hsla(0, 0%, ${luminance}, 0.013) 91.9%,\n hsla(0, 0%, ${luminance}, 0) 100%\n `;\n};\n\nconst fadeSize = 100;\nconst fadePadding = 10;\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n position: 'relative',\n display: 'flex',\n flexFlow: 'row nowrap',\n alignItems: 'center',\n },\n container: {\n overflow: 'auto',\n scrollbarWidth: 0 , // hide in FF\n '&::-webkit-scrollbar': {\n display: 'none', // hide in Chrome\n },\n },\n fade: {\n position: 'absolute',\n width: fadeSize,\n height: `calc(100% + ${fadePadding}px)`,\n transition: 'opacity 300ms',\n pointerEvents: 'none',\n },\n fadeLeft: {\n left: -fadePadding,\n background: `linear-gradient(90deg, ${generateGradientStops(\n theme.palette.type,\n )})`,\n },\n fadeRight: {\n right: -fadePadding,\n background: `linear-gradient(270deg, ${generateGradientStops(\n theme.palette.type,\n )})`,\n },\n fadeHidden: {\n opacity: 0,\n },\n button: {\n position: 'absolute',\n },\n buttonLeft: {\n left: -theme.spacing(2),\n },\n buttonRight: {\n right: -theme.spacing(2),\n },\n }),\n { name: 'BackstageHorizontalScrollGrid' },\n);\n\n// Returns scroll distance from left and right\nfunction useScrollDistance(\n ref,\n) {\n const [[scrollLeft, scrollRight], setScroll] = React.useState\n\n([0, 0]);\n\n React.useLayoutEffect(() => {\n const el = ref.current;\n if (!el) {\n setScroll([0, 0]);\n return;\n }\n\n const handleUpdate = () => {\n const left = el.scrollLeft;\n const right = el.scrollWidth - el.offsetWidth - el.scrollLeft;\n setScroll([left, right]);\n };\n\n handleUpdate();\n\n el.addEventListener('scroll', handleUpdate);\n window.addEventListener('resize', handleUpdate);\n // TODO(freben): Remove this eslint exception later\n // It's here because @types/react-router-dom v5 pulls in @types/react that have the wrong signature\n // eslint-disable-next-line consistent-return\n return () => {\n el.removeEventListener('scroll', handleUpdate);\n window.removeEventListener('resize', handleUpdate);\n };\n }, [ref]);\n\n return [scrollLeft, scrollRight];\n}\n\n// Used to animate scrolling. Returns a single setScrollTarger function, when called with e.g. 200,\n// the element pointer to by the ref will be scrolled 200px forwards over time.\nfunction useSmoothScroll(\n ref,\n speed,\n minDistance,\n) {\n const [scrollTarget, setScrollTarget] = React.useState(0);\n\n React.useLayoutEffect(() => {\n if (scrollTarget === 0) {\n return;\n }\n\n const startTime = performance.now();\n const id = requestAnimationFrame(frameTime => {\n if (!ref.current) {\n return;\n }\n const frameDuration = frameTime - startTime;\n const scrollDistance = (Math.abs(scrollTarget) * frameDuration) / speed;\n const cappedScrollDistance = Math.max(minDistance, scrollDistance);\n const scrollAmount = cappedScrollDistance * Math.sign(scrollTarget);\n\n ref.current.scrollBy({ left: scrollAmount });\n\n const newScrollTarget = scrollTarget - scrollAmount;\n if (Math.sign(scrollTarget) !== Math.sign(newScrollTarget)) {\n setScrollTarget(0);\n } else {\n setScrollTarget(newScrollTarget);\n }\n });\n\n // TODO(freben): Remove this eslint exception later\n // It's here because @types/react-router-dom v5 pulls in @types/react that have the wrong signature\n // eslint-disable-next-line consistent-return\n return () => cancelAnimationFrame(id);\n }, [ref, scrollTarget, speed, minDistance]);\n\n return setScrollTarget;\n}\n\n/**\n * Horizontal scrollable component with arrows to navigate\n *\n * @public\n *\n */\nexport function HorizontalScrollGrid(props) {\n const {\n scrollStep = 100,\n scrollSpeed = 50,\n minScrollDistance = 5,\n children,\n ...otherProps\n } = props;\n const classes = useStyles(props);\n const ref = React.useRef();\n\n const [scrollLeft, scrollRight] = useScrollDistance(ref);\n const setScrollTarget = useSmoothScroll(ref, scrollSpeed, minScrollDistance);\n\n const handleScrollClick = (forwards) => {\n const el = ref.current;\n if (!el) {\n return;\n }\n setScrollTarget(forwards ? scrollStep : -scrollStep);\n };\n\n return (\n React.createElement('div', { ...otherProps, className: classes.root,}\n , React.createElement(Grid, {\n container: true,\n direction: \"row\",\n wrap: \"nowrap\",\n className: classes.container,\n ref: ref ,}\n \n , children\n )\n , React.createElement('div', {\n className: classNames(classes.fade, classes.fadeLeft, {\n [classes.fadeHidden]: scrollLeft === 0,\n }),}\n )\n , React.createElement('div', {\n className: classNames(classes.fade, classes.fadeRight, {\n [classes.fadeHidden]: scrollRight === 0,\n }),}\n )\n , scrollLeft > 0 && (\n React.createElement(IconButton, {\n title: \"Scroll Left\" ,\n onClick: () => handleScrollClick(false),\n className: classNames(classes.button, classes.buttonLeft, {}),}\n \n , React.createElement(ChevronLeftIcon, null )\n )\n )\n , scrollRight > 0 && (\n React.createElement(IconButton, {\n title: \"Scroll Right\" ,\n onClick: () => handleScrollClick(true),\n className: classNames(classes.button, classes.buttonRight, {}),}\n \n , React.createElement(ChevronRightIcon, null )\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport { makeStyles } from '@material-ui/core/styles';\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n {\n alpha: {\n color: '#ffffff',\n fontFamily: 'serif',\n fontWeight: 'normal',\n fontStyle: 'italic',\n },\n beta: {\n color: '#4d65cc',\n fontFamily: 'serif',\n fontWeight: 'normal',\n fontStyle: 'italic',\n },\n },\n { name: 'BackstageLifecycle' },\n);\n\nexport function Lifecycle(props) {\n const classes = useStyles(props);\n const { shorthand, alpha } = props;\n return shorthand ? (\n React.createElement('span', {\n className: classes[alpha ? 'alpha' : 'beta'],\n style: { fontSize: '120%' },}\n \n , alpha ? React.createElement(React.Fragment, null, \"α\") : React.createElement(React.Fragment, null, \"β\")\n )\n ) : (\n React.createElement('span', { className: classes[alpha ? 'alpha' : 'beta'],}\n , alpha ? 'Alpha' : 'Beta'\n )\n );\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { lazy, Suspense } from 'react';\nimport { useApp } from '@backstage/core-plugin-api';\n\nconst RealLogViewer = lazy(() =>\n import('./RealLogViewer').then(m => ({ default: m.RealLogViewer })),\n);\n\n/**\n * The properties for the LogViewer component.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * A component that displays logs in a scrollable text area.\n *\n * The LogViewer has support for search and filtering, as well as displaying\n * text content with ANSI color escape codes.\n *\n * Since the LogViewer uses windowing to avoid rendering all contents at once, the\n * log is sized automatically to fill the available vertical space. This means\n * it may often be needed to wrap the LogViewer in a container that provides it\n * with a fixed amount of space.\n *\n * @public\n */\nexport function LogViewer(props) {\n const { Progress } = useApp().getComponents();\n return (\n React.createElement(Suspense, { fallback: React.createElement(Progress, null ),}\n , React.createElement(RealLogViewer, { ...props,} )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport ReactMarkdown, { } from 'react-markdown';\nimport gfm from 'remark-gfm';\nimport React from 'react';\n\nimport { CodeSnippet } from '../CodeSnippet';\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n markdown: {\n '& table': {\n borderCollapse: 'collapse',\n border: `1px solid ${theme.palette.border}`,\n },\n '& th, & td': {\n border: `1px solid ${theme.palette.border}`,\n padding: theme.spacing(1),\n },\n '& td': {\n wordBreak: 'break-word',\n overflow: 'hidden',\n verticalAlign: 'middle',\n lineHeight: '1',\n margin: 0,\n padding: theme.spacing(3, 2, 3, 2.5),\n borderBottom: 0,\n },\n '& th': {\n backgroundColor: theme.palette.background.paper,\n },\n '& tr': {\n backgroundColor: theme.palette.background.paper,\n },\n '& tr:nth-child(odd)': {\n backgroundColor: theme.palette.background.default,\n },\n\n '& a': {\n color: theme.palette.link,\n },\n '& img': {\n maxWidth: '100%',\n },\n },\n }),\n { name: 'BackstageMarkdownContent' },\n);\n\n\n\n\n\n\n\nconst components = {\n code: ({ inline, className, children, ...props }) => {\n const text = String(children).replace(/\\n+$/, '');\n const match = /language-(\\w+)/.exec(className || '');\n return !inline && match ? (\n React.createElement(CodeSnippet, { language: match[1], text: text,} )\n ) : (\n React.createElement('code', { className: className, ...props,}\n , children\n )\n );\n },\n};\n\n/**\n * MarkdownContent\n * --\n * Renders markdown with the default dialect [gfm - GitHub flavored Markdown](https://github.github.com/gfm/) to backstage theme styled HTML.\n * If you just want to render to plain [CommonMark](https://commonmark.org/), set the dialect to `'common-mark'`\n */\nexport function MarkdownContent(props) {\n const { content, dialect = 'gfm', linkTarget } = props;\n const classes = useStyles();\n return (\n React.createElement(ReactMarkdown, {\n remarkPlugins: dialect === 'gfm' ? [gfm] : [],\n className: classes.markdown,\n children: content,\n components: components,\n linkTarget: linkTarget,}\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeStyles, } from '@material-ui/core/styles';\nimport ListItem from '@material-ui/core/ListItem';\nimport ListItemAvatar from '@material-ui/core/ListItemAvatar';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport Typography from '@material-ui/core/Typography';\nimport Button from '@material-ui/core/Button';\nimport React, { useState } from 'react';\nimport { isError } from '@backstage/errors';\n\n\n\n\nconst useItemStyles = makeStyles(\n theme => ({\n root: {\n paddingLeft: theme.spacing(3),\n },\n }),\n { name: 'BackstageLoginRequestListItem' },\n);\n\n\n\n\n\n\n\nconst LoginRequestListItem = ({ request, busy, setBusy }) => {\n const classes = useItemStyles();\n const [error, setError] = useState();\n\n const handleContinue = async () => {\n setBusy(true);\n try {\n await request.trigger();\n } catch (e) {\n setError(isError(e) ? e.message : 'An unspecified error occurred');\n } finally {\n setBusy(false);\n }\n };\n\n const IconComponent = request.provider.icon;\n\n return (\n React.createElement(ListItem, { button: true, disabled: busy, classes: { root: classes.root },}\n , React.createElement(ListItemAvatar, null\n , React.createElement(IconComponent, { fontSize: \"large\",} )\n )\n , React.createElement(ListItemText, {\n primary: request.provider.title,\n secondary: error && React.createElement(Typography, { color: \"error\",}, error),}\n )\n , React.createElement(Button, { color: \"primary\", variant: \"contained\", onClick: handleContinue,}, \"Log in\"\n\n )\n )\n );\n};\n\nexport default LoginRequestListItem;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeStyles, } from '@material-ui/core/styles';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport List from '@material-ui/core/List';\nimport Button from '@material-ui/core/Button';\nimport React, { useMemo, useState } from 'react';\nimport useObservable from 'react-use/lib/useObservable';\nimport LoginRequestListItem from './LoginRequestListItem';\nimport { useApi, oauthRequestApiRef } from '@backstage/core-plugin-api';\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n dialog: {\n paddingTop: theme.spacing(1),\n },\n title: {\n minWidth: 0,\n },\n contentList: {\n padding: 0,\n },\n actionButtons: {\n padding: theme.spacing(2, 0),\n },\n }),\n { name: 'OAuthRequestDialog' },\n);\n\nexport function OAuthRequestDialog(_props) {\n const classes = useStyles();\n const [busy, setBusy] = useState(false);\n const oauthRequestApi = useApi(oauthRequestApiRef);\n const requests = useObservable(\n useMemo(() => oauthRequestApi.authRequest$(), [oauthRequestApi]),\n [],\n );\n\n const handleRejectAll = () => {\n requests.forEach(request => request.reject());\n };\n\n return (\n React.createElement(Dialog, {\n open: Boolean(requests.length),\n fullWidth: true,\n maxWidth: \"xs\",\n classes: { paper: classes.dialog },}\n \n , React.createElement(DialogTitle, { classes: { root: classes.title },}, \"Login Required\"\n\n )\n\n , React.createElement(DialogContent, { dividers: true, classes: { root: classes.contentList },}\n , React.createElement(List, null\n , requests.map(request => (\n React.createElement(LoginRequestListItem, {\n key: request.provider.title,\n request: request,\n busy: busy,\n setBusy: setBusy,}\n )\n ))\n )\n )\n\n , React.createElement(DialogActions, { classes: { root: classes.actionButtons },}\n , React.createElement(Button, { onClick: handleRejectAll,}, \"Reject All\" )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport Tooltip, { } from '@material-ui/core/Tooltip';\nimport React, { useState } from 'react';\nimport TextTruncate, { } from 'react-text-truncate';\nimport useMountedState from 'react-use/lib/useMountedState';\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n {\n container: {\n overflow: 'visible !important',\n },\n },\n { name: 'BackstageOverflowTooltip' },\n);\n\nexport function OverflowTooltip(props) {\n const [hover, setHover] = useState(false);\n const isMounted = useMountedState();\n const classes = useStyles();\n\n const handleToggled = (truncated) => {\n if (isMounted()) {\n setHover(truncated);\n }\n };\n\n return (\n React.createElement(Tooltip, {\n title: props.title ?? (props.text || ''),\n placement: props.placement,\n disableHoverListener: !hover,}\n \n , React.createElement(TextTruncate, {\n text: props.text,\n line: props.line,\n onToggled: handleToggled,\n containerClassName: classes.container,}\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useState, useEffect, } from 'react';\nimport LinearProgress, {\n\n} from '@material-ui/core/LinearProgress';\n\nexport function Progress(props) {\n const [isVisible, setIsVisible] = useState(false);\n\n useEffect(() => {\n const handle = setTimeout(() => setIsVisible(true), 250);\n return () => clearTimeout(handle);\n }, []);\n\n return isVisible ? (\n React.createElement(LinearProgress, { ...props, 'data-testid': \"progress\",} )\n ) : (\n React.createElement('div', { style: { display: 'none' },} )\n );\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport Box from '@material-ui/core/Box';\nimport Divider from '@material-ui/core/Divider';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport ArrowIcon from '@material-ui/icons/ArrowForward';\nimport React from 'react';\nimport { Link } from '../../components/Link';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n maxWidth: 'fit-content',\n padding: theme.spacing(2, 2, 2, 2.5),\n },\n boxTitle: {\n margin: 0,\n color: theme.palette.textSubtle,\n },\n arrow: {\n color: theme.palette.textSubtle,\n },\n }),\n { name: 'BackstageBottomLink' },\n);\n\n/** @public */\n\n\n\n\n\n\n/**\n * Footer with link used in {@link InfoCard } and {@link TabbedCard}\n *\n * @public\n *\n */\nexport function BottomLink(props) {\n const { link, title, onClick } = props;\n const classes = useStyles();\n\n return (\n React.createElement('div', null\n , React.createElement(Divider, null )\n , React.createElement(Link, { to: link, onClick: onClick, underline: \"none\",}\n , React.createElement(Box, { display: \"flex\", alignItems: \"center\", className: classes.root,}\n , React.createElement(Box, { className: classes.boxTitle, fontWeight: \"fontWeightBold\", m: 1,}\n , React.createElement(Typography, null\n , React.createElement('strong', null, title)\n )\n )\n , React.createElement(ArrowIcon, { className: classes.arrow,} )\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { Component, } from 'react';\nimport { Button } from '../../components/Button';\nimport { ErrorPanel } from '../../components/ErrorPanel';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst SlackLink = (props) => {\n const { slackChannel } = props;\n\n if (!slackChannel) {\n return null;\n } else if (typeof slackChannel === 'string') {\n return React.createElement(React.Fragment, null, \"Please contact \" , slackChannel, \" for help.\" );\n } else if (!slackChannel.href) {\n return React.createElement(React.Fragment, null, \"Please contact \" , slackChannel.name, \" for help.\" );\n }\n\n return (\n React.createElement(Button, { to: slackChannel.href, variant: \"contained\",}\n , slackChannel.name\n )\n );\n};\n\n/** @public */\nexport const ErrorBoundary\n\n\n = class ErrorBoundary extends Component {\n constructor(props) {\n super(props);\n this.state = {\n error: undefined,\n errorInfo: undefined,\n };\n }\n\n componentDidCatch(error, errorInfo) {\n // eslint-disable-next-line no-console\n console.error(`ErrorBoundary, error: ${error}, info: ${errorInfo}`);\n this.setState({ error, errorInfo });\n }\n\n render() {\n const { slackChannel, children } = this.props;\n const { error } = this.state;\n\n if (!error) {\n return children;\n }\n\n return (\n React.createElement(ErrorPanel, { title: \"Something Went Wrong\" , error: error,}\n , React.createElement(SlackLink, { slackChannel: slackChannel,} )\n )\n );\n }\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Card from '@material-ui/core/Card';\nimport CardActions from '@material-ui/core/CardActions';\nimport CardContent from '@material-ui/core/CardContent';\nimport CardHeader, { } from '@material-ui/core/CardHeader';\nimport Divider from '@material-ui/core/Divider';\nimport { makeStyles, withStyles } from '@material-ui/core/styles';\nimport classNames from 'classnames';\nimport React, { } from 'react';\nimport { BottomLink, } from '../BottomLink';\nimport { ErrorBoundary, } from '../ErrorBoundary';\n\n/** @public */\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n noPadding: {\n padding: 0,\n '&:last-child': {\n paddingBottom: 0,\n },\n },\n header: {\n padding: theme.spacing(2, 2, 2, 2.5),\n },\n headerTitle: {\n fontWeight: 700,\n },\n headerSubheader: {\n paddingTop: theme.spacing(1),\n },\n headerAvatar: {},\n headerAction: {},\n headerContent: {},\n subheader: {\n display: 'flex',\n },\n }),\n { name: 'BackstageInfoCard' },\n);\n\n/** @public */\n\n\nconst CardActionsTopRight = withStyles(\n theme => ({\n root: {\n display: 'inline-block',\n padding: theme.spacing(8, 8, 0, 0),\n float: 'right',\n },\n }),\n { name: 'BackstageInfoCardCardActionsTopRight' },\n)(CardActions);\n\nconst VARIANT_STYLES = {\n card: {\n flex: {\n display: 'flex',\n flexDirection: 'column',\n },\n fullHeight: {\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n },\n gridItem: {\n display: 'flex',\n flexDirection: 'column',\n height: 'calc(100% - 10px)', // for pages without content header\n marginBottom: '10px',\n },\n },\n cardContent: {\n fullHeight: {\n flex: 1,\n },\n gridItem: {\n flex: 1,\n },\n },\n};\n\n/** @public */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Material-ui card with header , content and actions footer\n *\n * @public\n *\n */\nexport function InfoCard(props) {\n const {\n title,\n subheader,\n divider = true,\n deepLink,\n slackChannel,\n errorBoundaryProps,\n variant,\n children,\n headerStyle,\n headerProps,\n icon,\n action,\n actionsClassName,\n actions,\n cardClassName,\n actionsTopRight,\n className,\n noPadding,\n titleTypographyProps,\n } = props;\n const classes = useStyles();\n /**\n * If variant is specified, we build up styles for that particular variant for both\n * the Card and the CardContent (since these need to be synced)\n */\n let calculatedStyle = {};\n let calculatedCardStyle = {};\n if (variant) {\n const variants = variant.split(/[\\s]+/g);\n variants.forEach(name => {\n calculatedStyle = {\n ...calculatedStyle,\n ...VARIANT_STYLES.card[name ],\n };\n calculatedCardStyle = {\n ...calculatedCardStyle,\n ...VARIANT_STYLES.cardContent[\n name \n ],\n };\n });\n }\n\n const cardSubTitle = () => {\n return (\n React.createElement('div', { className: classes.headerSubheader,}\n , subheader && React.createElement('div', { className: classes.subheader,}, subheader)\n , icon\n )\n );\n };\n\n const errProps =\n errorBoundaryProps || (slackChannel ? { slackChannel } : {});\n\n return (\n React.createElement(Card, { style: calculatedStyle, className: className,}\n , React.createElement(ErrorBoundary, { ...errProps,}\n , title && (\n React.createElement(CardHeader, {\n classes: {\n root: classes.header,\n title: classes.headerTitle,\n subheader: classes.headerSubheader,\n avatar: classes.headerAvatar,\n action: classes.headerAction,\n content: classes.headerContent,\n },\n title: title,\n subheader: cardSubTitle(),\n action: action,\n style: { ...headerStyle },\n titleTypographyProps: titleTypographyProps,\n ...headerProps,}\n )\n )\n , actionsTopRight && (\n React.createElement(CardActionsTopRight, null, actionsTopRight)\n )\n , divider && React.createElement(Divider, null )\n , React.createElement(CardContent, {\n className: classNames(cardClassName, {\n [classes.noPadding]: noPadding,\n }),\n style: calculatedCardStyle,}\n \n , children\n )\n , actions && (\n React.createElement(CardActions, { className: actionsClassName,}, actions)\n )\n , deepLink && React.createElement(BottomLink, { ...deepLink,} )\n )\n )\n );\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { makeStyles, useTheme } from '@material-ui/core/styles';\nimport { Circle } from 'rc-progress';\nimport React, { useEffect, useState } from 'react';\n\n/** @public */\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n position: 'relative',\n lineHeight: 0,\n },\n overlay: {\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -60%)',\n fontSize: 45,\n fontWeight: 'bold',\n color: theme.palette.textContrast,\n },\n description: {\n fontSize: '100%',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n position: 'absolute',\n wordBreak: 'break-all',\n display: 'inline-block',\n },\n circle: {\n width: '80%',\n transform: 'translate(10%, 0)',\n },\n colorUnknown: {},\n }),\n { name: 'BackstageGauge' },\n);\n\n/** @public */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst defaultGaugeProps = {\n fractional: true,\n inverse: false,\n unit: '%',\n max: 100,\n};\n\nexport const getProgressColor = ({\n palette,\n value,\n inverse,\n max,\n}) => {\n if (isNaN(value)) {\n return '#ddd';\n }\n\n const actualMax = max ? max : defaultGaugeProps.max;\n const actualValue = inverse ? actualMax - value : value;\n\n if (actualValue < actualMax / 3) {\n return palette.status.error;\n } else if (actualValue < actualMax * (2 / 3)) {\n return palette.status.warning;\n }\n\n return palette.status.ok;\n};\n\n/**\n * Circular Progress Bar\n *\n * @public\n *\n */\n\nexport function Gauge(props) {\n const [hoverRef, setHoverRef] = useState(null);\n const { getColor = getProgressColor } = props;\n const classes = useStyles(props);\n const { palette } = useTheme();\n const { value, fractional, inverse, unit, max, description } = {\n ...defaultGaugeProps,\n ...props,\n };\n\n const asPercentage = fractional ? Math.round(value * max) : value;\n const asActual = max !== 100 ? Math.round(value) : asPercentage;\n\n const [isHovering, setIsHovering] = useState(false);\n\n useEffect(() => {\n const node = hoverRef;\n const handleMouseOver = () => setIsHovering(true);\n const handleMouseOut = () => setIsHovering(false);\n if (node && description) {\n node.addEventListener('mouseenter', handleMouseOver);\n node.addEventListener('mouseleave', handleMouseOut);\n\n return () => {\n node.removeEventListener('mouseenter', handleMouseOver);\n node.removeEventListener('mouseleave', handleMouseOut);\n };\n }\n return () => {\n setIsHovering(false);\n };\n }, [description, hoverRef]);\n\n return (\n React.createElement('div', { ref: setHoverRef, className: classes.root,}\n , React.createElement(Circle, {\n strokeLinecap: \"butt\",\n percent: asPercentage,\n strokeWidth: 12,\n trailWidth: 12,\n strokeColor: getColor({ palette, value: asActual, inverse, max }),\n className: classes.circle,}\n )\n , description && isHovering ? (\n React.createElement('div', { className: classes.description,}, description)\n ) : (\n React.createElement('div', { className: classes.overlay,}\n , isNaN(value) ? 'N/A' : `${asActual}${unit}`\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport React, { } from 'react';\n\nimport { InfoCard, } from '../../layout/InfoCard';\nimport { Gauge, } from './Gauge';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n {\n root: {\n height: '100%',\n width: 250,\n },\n },\n { name: 'BackstageGaugeCard' },\n);\n\n/**\n * {@link Gauge} with header, subheader and footer\n *\n * @public\n *\n */\nexport function GaugeCard(props) {\n const classes = useStyles(props);\n const {\n title,\n subheader,\n progress,\n inverse,\n deepLink,\n description,\n icon,\n variant,\n getColor,\n } = props;\n\n const gaugeProps = {\n inverse,\n description,\n getColor,\n value: progress,\n };\n\n return (\n React.createElement('div', { className: classes.root,}\n , React.createElement(InfoCard, {\n title: title,\n subheader: subheader,\n deepLink: deepLink,\n variant: variant,\n icon: icon,}\n \n , React.createElement(Gauge, { ...gaugeProps,} )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { useTheme } from '@material-ui/core/styles';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport { Line } from 'rc-progress';\n\nimport { getProgressColor, } from './Gauge';\n\n\n\n\n\n\n\n\n\nexport function LinearGauge(props) {\n const { value, getColor = getProgressColor } = props;\n const { palette } = useTheme();\n if (isNaN(value)) {\n return null;\n }\n let percent = Math.round(value * 100 * 100) / 100;\n if (percent > 100) {\n percent = 100;\n }\n const strokeColor = getColor({\n palette,\n value: percent,\n inverse: false,\n max: 100,\n });\n return (\n React.createElement(Tooltip, { title: `${percent}%`,}\n , React.createElement('span', null\n , React.createElement(Line, {\n percent: percent,\n strokeWidth: 4,\n trailWidth: 4,\n strokeColor: strokeColor,}\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { makeStyles, createStyles } from '@material-ui/core/styles';\nimport SvgIcon from '@material-ui/core/SvgIcon';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n () =>\n createStyles({\n icon: {\n position: 'absolute',\n right: '4px',\n pointerEvents: 'none',\n },\n }),\n { name: 'BackstageClosedDropdown' },\n);\n\nconst ClosedDropdown = () => {\n const classes = useStyles();\n return (\n React.createElement(SvgIcon, {\n className: classes.icon,\n fill: \"none\",\n xmlns: \"http://www.w3.org/2000/svg\",}\n \n , React.createElement('path', {\n d: \"M7.5 8L6 9.5L12.0703 15.5703L18.1406 9.5L16.6406 8L12.0703 12.5703L7.5 8Z\" ,\n fill: \"#616161\",}\n )\n )\n );\n};\n\nexport default ClosedDropdown;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { makeStyles, createStyles } from '@material-ui/core/styles';\nimport SvgIcon from '@material-ui/core/SvgIcon';\n\n\n\nconst useStyles = makeStyles(\n () =>\n createStyles({\n icon: {\n position: 'absolute',\n right: '4px',\n pointerEvents: 'none',\n },\n }),\n { name: 'BackstageOpenedDropdown' },\n);\n\nconst OpenedDropdown = () => {\n const classes = useStyles();\n return (\n React.createElement(SvgIcon, {\n className: classes.icon,\n fill: \"none\",\n xmlns: \"http://www.w3.org/2000/svg\",}\n \n , React.createElement('path', {\n d: \"M16.5 16L18 14.5L11.9297 8.42969L5.85938 14.5L7.35938 16L11.9297 11.4297L16.5 16Z\" ,\n fill: \"#616161\",}\n )\n )\n );\n};\n\nexport default OpenedDropdown;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Chip from '@material-ui/core/Chip';\nimport ClickAwayListener from '@material-ui/core/ClickAwayListener';\nimport FormControl from '@material-ui/core/FormControl';\nimport InputBase from '@material-ui/core/InputBase';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Select from '@material-ui/core/Select';\nimport {\n createStyles,\n makeStyles,\n\n withStyles,\n} from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport React, { useEffect, useState } from 'react';\nimport ClosedDropdown from './static/ClosedDropdown';\nimport OpenedDropdown from './static/OpenedDropdown';\n\n/** @public */\n\n\nconst BootstrapInput = withStyles(\n (theme) =>\n createStyles({\n root: {\n 'label + &': {\n marginTop: theme.spacing(3),\n },\n },\n input: {\n borderRadius: 4,\n position: 'relative',\n backgroundColor: theme.palette.background.paper,\n border: '1px solid #ced4da',\n fontSize: 16,\n padding: '10px 26px 10px 12px',\n transition: theme.transitions.create(['border-color', 'box-shadow']),\n fontFamily: 'Helvetica Neue',\n '&:focus': {\n background: theme.palette.background.paper,\n borderRadius: 4,\n },\n },\n }),\n { name: 'BackstageSelectInputBase' },\n)(InputBase);\n\n/** @public */\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n (theme) =>\n createStyles({\n formControl: {\n margin: `${theme.spacing(1)} 0px`,\n maxWidth: 300,\n },\n label: {\n transform: 'initial',\n fontWeight: 'bold',\n fontSize: 14,\n fontFamily: theme.typography.fontFamily,\n color: theme.palette.text.primary,\n '&.Mui-focused': {\n color: theme.palette.text.primary,\n },\n },\n chips: {\n display: 'flex',\n flexWrap: 'wrap',\n },\n chip: {\n margin: 2,\n },\n checkbox: {},\n\n root: {\n display: 'flex',\n flexDirection: 'column',\n },\n }),\n { name: 'BackstageSelect' },\n);\n\n/** @public */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/** @public */\nexport function SelectComponent(props) {\n const {\n multiple,\n items,\n label,\n placeholder,\n selected,\n onChange,\n triggerReset,\n native = false,\n disabled = false,\n } = props;\n const classes = useStyles();\n const [value, setValue] = useState(\n selected || (multiple ? [] : ''),\n );\n const [isOpen, setOpen] = useState(false);\n\n useEffect(() => {\n setValue(multiple ? [] : '');\n }, [triggerReset, multiple]);\n\n useEffect(() => {\n if (selected !== undefined) {\n setValue(selected);\n }\n }, [selected]);\n\n const handleChange = (event) => {\n setValue(event.target.value );\n onChange(event.target.value );\n };\n\n const handleClick = (event) => {\n if (disabled) {\n event.preventDefault();\n return;\n }\n setOpen(previous => {\n if (multiple && !(event.target instanceof HTMLElement)) {\n return true;\n }\n return !previous;\n });\n };\n\n const handleClickAway = () => {\n setOpen(false);\n };\n\n const handleDelete = (selectedValue) => () => {\n const newValue = (value ).filter(chip => chip !== selectedValue);\n setValue(newValue);\n onChange(newValue);\n };\n\n return (\n React.createElement('div', { className: classes.root,}\n , React.createElement(Typography, { variant: \"button\",}, label)\n , React.createElement(ClickAwayListener, { onClickAway: handleClickAway,}\n , React.createElement(FormControl, { className: classes.formControl,}\n , React.createElement(Select, {\n value: value,\n native: native,\n disabled: disabled,\n 'data-testid': \"select\",\n displayEmpty: true,\n multiple: multiple,\n onChange: handleChange,\n onClick: handleClick,\n open: isOpen,\n input: React.createElement(BootstrapInput, null ),\n renderValue: s =>\n multiple && (value ).length !== 0 ? (\n React.createElement('div', { className: classes.chips,}\n , (s ).map(selectedValue => (\n React.createElement(Chip, {\n key: items.find(el => el.value === selectedValue)?.value,\n label: \n items.find(el => el.value === selectedValue)?.label\n ,\n clickable: true,\n onDelete: handleDelete(selectedValue),\n className: classes.chip,}\n )\n ))\n )\n ) : (\n React.createElement(Typography, null\n , (value ).length === 0\n ? placeholder || ''\n : items.find(el => el.value === s)?.label\n )\n )\n ,\n IconComponent: () =>\n !isOpen ? React.createElement(ClosedDropdown, null ) : React.createElement(OpenedDropdown, null )\n ,\n MenuProps: {\n anchorOrigin: {\n vertical: 'bottom',\n horizontal: 'left',\n },\n transformOrigin: {\n vertical: 'top',\n horizontal: 'left',\n },\n getContentAnchorEl: null,\n },}\n \n , placeholder && !multiple && (\n React.createElement(MenuItem, { value: [],}, placeholder)\n )\n , native\n ? items &&\n items.map(item => (\n React.createElement('option', { value: item.value, key: item.value,}\n , item.label\n )\n ))\n : items &&\n items.map(item => (\n React.createElement(MenuItem, { key: item.value, value: item.value,}\n , multiple && (\n React.createElement(Checkbox, {\n color: \"primary\",\n checked: (value ).includes(item.value) || false,\n className: classes.checkbox,}\n )\n )\n , item.label\n )\n ))\n )\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, {\n Children,\n isValidElement,\n useState,\n useEffect,\n\n} from 'react';\nimport MuiStepper from '@material-ui/core/Stepper';\n\n\n\n\n\n\n\n\n\n\nconst noop = () => {};\nexport const VerticalStepperContext = React.createContext({\n stepperLength: 0,\n stepIndex: 0,\n setStepIndex: noop,\n stepHistory: [],\n setStepHistory: noop,\n onStepChange: noop,\n});\n\n\n\n\n\n\n\nexport function SimpleStepper(props) {\n const { children, elevated, onStepChange, activeStep = 0 } = props;\n const [stepIndex, setStepIndex] = useState(activeStep);\n const [stepHistory, setStepHistory] = useState([0]);\n\n useEffect(() => {\n setStepIndex(activeStep);\n }, [activeStep]);\n\n const steps = [];\n let endStep;\n Children.forEach(children, child => {\n if (isValidElement(child)) {\n if (child.props.end) {\n endStep = child;\n } else {\n steps.push(child);\n }\n }\n });\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(VerticalStepperContext.Provider, {\n value: {\n stepIndex,\n setStepIndex,\n stepHistory,\n setStepHistory,\n onStepChange,\n stepperLength: Children.count(children),\n },}\n \n , React.createElement(MuiStepper, {\n activeStep: stepIndex,\n orientation: \"vertical\",\n elevation: elevated ? 2 : 0,}\n \n , steps\n )\n )\n , stepIndex >= Children.count(children) - 1 && endStep\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { useContext, } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Button from '@material-ui/core/Button';\n\nimport { VerticalStepperContext } from './SimpleStepper';\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n marginTop: theme.spacing(3),\n '& button': {\n marginRight: theme.spacing(1),\n },\n },\n }),\n { name: 'BackstageSimpleStepperFooter' },\n);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const RestartBtn = ({ text, handleClick }) => (\n React.createElement(Button, { onClick: handleClick,}, text || 'Reset')\n);\n\nconst NextBtn = ({\n text,\n handleClick,\n disabled,\n last,\n stepIndex,\n}) => (\n React.createElement(Button, {\n variant: \"contained\",\n color: \"primary\",\n disabled: disabled,\n 'data-testid': `nextButton-${stepIndex}`,\n onClick: handleClick,}\n \n , text || (last ? 'Finish' : 'Next')\n )\n);\n\nconst BackBtn = ({ text, handleClick, disabled, stepIndex }) => (\n React.createElement(Button, {\n onClick: handleClick,\n 'data-testid': `backButton-${stepIndex}`,\n disabled: disabled,}\n \n , text || 'Back'\n )\n);\n\n\n\n\n\n\nexport const SimpleStepperFooter = ({\n actions = {},\n children,\n}) => {\n const classes = useStyles();\n const {\n stepperLength,\n stepIndex,\n setStepIndex,\n stepHistory,\n setStepHistory,\n onStepChange,\n } = useContext(VerticalStepperContext);\n\n const onChange = (newIndex, callback) => {\n if (callback) {\n callback();\n }\n if (onStepChange) {\n onStepChange(stepIndex, newIndex);\n }\n\n setStepIndex(newIndex);\n };\n\n const handleNext = () => {\n const newIndex = actions.nextStep\n ? actions.nextStep(stepIndex, stepperLength - 1)\n : stepIndex + 1;\n onChange(newIndex, actions.onNext);\n setStepHistory([...stepHistory, newIndex]);\n };\n const handleBack = () => {\n stepHistory.pop();\n onChange(stepHistory[stepHistory.length - 1], actions.onBack);\n setStepHistory([...stepHistory]);\n };\n const handleRestart = () => {\n onChange(0, actions.onRestart);\n setStepHistory([0]);\n };\n\n return (\n React.createElement('div', { className: classes.root,}\n , [undefined, true].includes(actions.showBack) && stepIndex !== 0 && (\n React.createElement(BackBtn, {\n text: actions.backText,\n handleClick: handleBack,\n disabled: stepIndex === 0,\n stepIndex: stepIndex,}\n )\n )\n , [undefined, true].includes(actions.showNext) && (\n React.createElement(NextBtn, {\n text: actions.nextText,\n handleClick: handleNext,\n disabled: \n (!!stepperLength && stepIndex >= stepperLength) ||\n (!!actions.canNext && !actions.canNext())\n ,\n stepIndex: stepIndex,}\n )\n )\n , actions.showRestart && stepIndex !== 0 && (\n React.createElement(RestartBtn, {\n text: actions.restartText,\n handleClick: handleRestart,\n stepIndex: stepIndex,}\n )\n )\n , children\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport MuiStep from '@material-ui/core/Step';\nimport StepContent from '@material-ui/core/StepContent';\nimport StepLabel from '@material-ui/core/StepLabel';\nimport Typography from '@material-ui/core/Typography';\nimport { SimpleStepperFooter } from './SimpleStepperFooter';\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n end: {\n padding: theme.spacing(3),\n },\n }),\n { name: 'SimpleStepperStep' },\n);\n\nexport function SimpleStepperStep(props) {\n const { title, children, end, actions, ...muiProps } = props;\n const classes = useStyles();\n\n // The end step is not a part of the stepper\n // It simply is the final screen with an option to have buttons such as reset or back\n return end ? (\n React.createElement('div', { className: classes.end,}\n , React.createElement(Typography, { variant: \"h6\",}, title)\n , children\n , React.createElement(SimpleStepperFooter, { actions: { ...(actions || {}), showNext: false },} )\n )\n ) : (\n React.createElement(MuiStep, { ...muiProps,}\n , React.createElement(StepLabel, null\n , React.createElement(Typography, { variant: \"h6\",}, title)\n )\n , React.createElement(StepContent, null\n , children\n , React.createElement(SimpleStepperFooter, { actions: actions,} )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeStyles } from '@material-ui/core/styles';\n\nimport classNames from 'classnames';\nimport React, { } from 'react';\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n status: {\n fontWeight: 500,\n '&::before': {\n width: '0.7em',\n height: '0.7em',\n display: 'inline-block',\n marginRight: 8,\n borderRadius: '50%',\n content: '\"\"',\n },\n },\n ok: {\n '&::before': {\n backgroundColor: theme.palette.status.ok,\n },\n },\n warning: {\n '&::before': {\n backgroundColor: theme.palette.status.warning,\n },\n },\n error: {\n '&::before': {\n backgroundColor: theme.palette.status.error,\n },\n },\n pending: {\n '&::before': {\n backgroundColor: theme.palette.status.pending,\n },\n },\n running: {\n '&::before': {\n backgroundColor: theme.palette.status.running,\n },\n },\n aborted: {\n '&::before': {\n backgroundColor: theme.palette.status.aborted,\n },\n },\n }),\n { name: 'BackstageStatus' },\n);\n\nexport function StatusOK(props) {\n const classes = useStyles(props);\n return (\n React.createElement('span', {\n className: classNames(classes.status, classes.ok),\n 'aria-label': \"Status ok\" ,\n 'aria-hidden': \"true\",\n ...props,}\n )\n );\n}\n\nexport function StatusWarning(props) {\n const classes = useStyles(props);\n return (\n React.createElement('span', {\n className: classNames(classes.status, classes.warning),\n 'aria-label': \"Status warning\" ,\n 'aria-hidden': \"true\",\n ...props,}\n )\n );\n}\n\nexport function StatusError(props) {\n const classes = useStyles(props);\n return (\n React.createElement('span', {\n className: classNames(classes.status, classes.error),\n 'aria-label': \"Status error\" ,\n 'aria-hidden': \"true\",\n ...props,}\n )\n );\n}\n\nexport function StatusPending(props) {\n const classes = useStyles(props);\n return (\n React.createElement('span', {\n className: classNames(classes.status, classes.pending),\n 'aria-label': \"Status pending\" ,\n 'aria-hidden': \"true\",\n ...props,}\n )\n );\n}\n\nexport function StatusRunning(props) {\n const classes = useStyles(props);\n return (\n React.createElement('span', {\n className: classNames(classes.status, classes.running),\n 'aria-label': \"Status running\" ,\n 'aria-hidden': \"true\",\n ...props,}\n )\n );\n}\n\nexport function StatusAborted(props) {\n const classes = useStyles(props);\n return (\n React.createElement('span', {\n className: classNames(classes.status, classes.aborted),\n 'aria-label': \"Status aborted\" ,\n 'aria-hidden': \"true\",\n ...props,}\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport {\n withStyles,\n createStyles,\n\n\n} from '@material-ui/core/styles';\nimport Table from '@material-ui/core/Table';\nimport TableBody from '@material-ui/core/TableBody';\nimport TableCell from '@material-ui/core/TableCell';\nimport TableRow from '@material-ui/core/TableRow';\n\n\n\nconst tableTitleCellStyles = (theme) =>\n createStyles({\n root: {\n fontWeight: 'bolder',\n whiteSpace: 'nowrap',\n paddingRight: theme.spacing(4),\n border: '0',\n verticalAlign: 'top',\n },\n });\n\n\n\nconst tableContentCellStyles = {\n root: {\n border: '0',\n verticalAlign: 'top',\n },\n};\n\n\n\nconst listStyles = (theme) =>\n createStyles({\n root: {\n listStyle: 'none',\n margin: theme.spacing(0, 0, -1, 0),\n padding: '0',\n },\n });\n\n\n\nconst listItemStyles = (theme) =>\n createStyles({\n root: {\n padding: theme.spacing(0, 0, 1, 0),\n },\n random: {},\n });\n\nconst TitleCell = withStyles(tableTitleCellStyles, {\n name: 'BackstageMetadataTableTitleCell',\n})(TableCell);\nconst ContentCell = withStyles(tableContentCellStyles, {\n name: 'BackstageMetadataTableCell',\n})(TableCell);\n\nexport const MetadataTable = ({\n dense,\n children,\n}\n\n\n) => (\n React.createElement(Table, { size: dense ? 'small' : 'medium',}\n , React.createElement(TableBody, null, children)\n )\n);\n\nexport const MetadataTableItem = ({\n title,\n children,\n ...rest\n}\n\n\n) => (\n React.createElement(TableRow, null\n , title && React.createElement(TitleCell, null, title)\n , React.createElement(ContentCell, { colSpan: title ? 1 : 2, ...rest,}\n , children\n )\n )\n);\n\n\n\n\n\nexport const MetadataList = withStyles(listStyles, {\n name: 'BackstageMetadataTableList',\n})(({ classes, children }) => (\n React.createElement('ul', { className: classes.root,}, children)\n));\n\nexport const MetadataListItem = withStyles(listItemStyles, {\n name: 'BackstageMetadataTableListItem',\n})(({ classes, children }) => (\n React.createElement('li', { className: classes.root,}, children)\n));\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { Fragment, } from 'react';\nimport {\n withStyles,\n createStyles,\n\n\n} from '@material-ui/core/styles';\nimport startCase from 'lodash/startCase';\n\nimport {\n MetadataTable,\n MetadataTableItem,\n MetadataList,\n MetadataListItem,\n} from './MetadataTable';\n\n\n\nconst listStyle = createStyles({\n root: {\n margin: '0 0',\n listStyleType: 'none',\n },\n});\n\n\n\nconst nestedListStyle = (theme) =>\n createStyles({\n root: {\n ...listStyle.root,\n paddingLeft: theme.spacing(1),\n },\n });\n\n\n\n\n// Sub Components\nconst StyledList = withStyles(listStyle, {\n name: 'BackstageStructuredMetadataTableList',\n})(({ classes, children }) => (\n React.createElement(MetadataList, { classes: classes,}, children)\n));\nconst StyledNestedList = withStyles(nestedListStyle, {\n name: 'BackstageStructuredMetadataTableNestedList',\n})(({ classes, children }) => (\n React.createElement(MetadataList, { classes: classes,}, children)\n));\n\nfunction renderList(list, nested) {\n const values = list.map((item, index) => (\n React.createElement(MetadataListItem, { key: index,}, toValue(item))\n ));\n return nested ? (\n React.createElement(StyledNestedList, null, values)\n ) : (\n React.createElement(StyledList, null, values)\n );\n}\n\nfunction renderMap(\n map,\n nested,\n options,\n) {\n const values = Object.keys(map).map(key => {\n const value = toValue(map[key], true);\n const fmtKey =\n options && options.titleFormat\n ? options.titleFormat(key)\n : startCase(key);\n return (\n React.createElement(MetadataListItem, { key: key,}\n , `${fmtKey}: `\n , value\n )\n );\n });\n\n return nested ? (\n React.createElement(StyledNestedList, null, values)\n ) : (\n React.createElement(StyledList, null, values)\n );\n}\n\nfunction toValue(\n value,\n options,\n nested,\n) {\n if (React.isValidElement(value)) {\n return React.createElement(Fragment, null, value);\n }\n\n if (typeof value === 'object' && !Array.isArray(value)) {\n return renderMap(value, options, nested);\n }\n\n if (Array.isArray(value)) {\n return renderList(value, nested);\n }\n\n if (typeof value === 'boolean') {\n return React.createElement(Fragment, null, value ? '✅' : '❌');\n }\n\n return React.createElement(Fragment, null, value);\n}\nconst ItemValue = ({ value, options }) => (\n React.createElement(Fragment, null, toValue(value, options))\n);\n\nconst TableItem = ({\n title,\n value,\n options,\n}\n\n\n\n) => {\n return (\n React.createElement(MetadataTableItem, {\n title: \n options && options.titleFormat\n ? options.titleFormat(title)\n : startCase(title)\n ,}\n \n , React.createElement(ItemValue, { value: value, options: options,} )\n )\n );\n};\n\nfunction mapToItems(info, options) {\n return Object.keys(info).map(key => (\n React.createElement(TableItem, { key: key, title: key, value: info[key], options: options,} )\n ));\n}\n\n\n\n\n\n\n\nexport function StructuredMetadataTable(props) {\n const { metadata, dense = true, options } = props;\n const metadataItems = mapToItems(metadata, options || {});\n return React.createElement(MetadataTable, { dense: dense,}, metadataItems);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isEqual } from 'lodash';\nimport qs from 'qs';\nimport { useEffect, useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport useDebounce from 'react-use/lib/useDebounce';\n\nfunction stringify(queryParams) {\n // Even though these setting don't look nice (e.g. escaped brackets), we should keep\n // them this way. The current syntax handles all cases, including variable types with\n // arrays or strings.\n return qs.stringify(queryParams, {\n strictNullHandling: true,\n });\n}\n\nfunction parse(queryString) {\n return qs.parse(queryString, {\n ignoreQueryPrefix: true,\n strictNullHandling: true,\n });\n}\n\nfunction extractState(queryString, stateName) {\n const queryParams = parse(queryString);\n\n return queryParams[stateName];\n}\n\nfunction joinQueryString(\n queryString,\n stateName,\n state,\n) {\n const queryParams = {\n ...parse(queryString),\n [stateName]: state,\n };\n return stringify(queryParams);\n}\n\n\n\nexport function useQueryParamState(\n stateName,\n /** @deprecated Don't configure a custom debouceTime */\n debounceTime = 250,\n) {\n const [searchParams, setSearchParams] = useSearchParams();\n const searchParamsString = searchParams.toString();\n const [queryParamState, setQueryParamState] = useState(\n extractState(searchParamsString, stateName),\n );\n\n useEffect(() => {\n const newState = extractState(searchParamsString, stateName);\n\n setQueryParamState(oldState =>\n isEqual(newState, oldState) ? oldState : newState,\n );\n }, [searchParamsString, setQueryParamState, stateName]);\n\n useDebounce(\n () => {\n const queryString = joinQueryString(\n searchParamsString,\n stateName,\n queryParamState,\n );\n\n if (searchParamsString !== queryString) {\n setSearchParams(queryString, { replace: true });\n }\n },\n debounceTime,\n [setSearchParams, queryParamState, searchParamsString, stateName],\n );\n\n return [queryParamState, setQueryParamState];\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useApiHolder, configApiRef } from '@backstage/core-plugin-api';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst DEFAULT_SUPPORT_CONFIG = {\n url: 'https://github.com/backstage/backstage/issues',\n items: [\n {\n title: 'Support Not Configured',\n icon: 'warning',\n links: [\n {\n // TODO: Update to dedicated support page on backstage.io/docs\n title: 'Add `app.support` config key',\n url: 'https://github.com/andrewthauer/backstage/blob/master/app-config.yaml',\n },\n ],\n },\n ],\n};\n\nexport function useSupportConfig() {\n const apiHolder = useApiHolder();\n const config = apiHolder.get(configApiRef);\n const supportConfig = config?.getOptionalConfig('app.support');\n\n if (!supportConfig) {\n return DEFAULT_SUPPORT_CONFIG;\n }\n\n return {\n url: supportConfig.getString('url'),\n items: supportConfig.getConfigArray('items').flatMap(itemConf => ({\n title: itemConf.getString('title'),\n icon: itemConf.getOptionalString('icon'),\n links: (itemConf.getOptionalConfigArray('links') ?? []).flatMap(\n linkConf => ({\n url: linkConf.getString('url'),\n title: linkConf.getString('title'),\n }),\n ),\n })),\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useApp } from '@backstage/core-plugin-api';\nimport MuiBrokenImageIcon from '@material-ui/icons/BrokenImage';\nimport React, { } from 'react';\n\n\n\nfunction useSystemIcon(key, props) {\n const app = useApp();\n const Icon = app.getSystemIcon(key);\n return Icon ? React.createElement(Icon, { ...props,} ) : React.createElement(MuiBrokenImageIcon, { ...props,} );\n}\n\n// Should match the list of overridable system icon keys in @backstage/core-app-api\n/**\n * Broken Image Icon\n *\n * @public\n *\n */\nexport function BrokenImageIcon(props) {\n return useSystemIcon('brokenImage', props);\n}\n/** @public */\nexport function CatalogIcon(props) {\n return useSystemIcon('catalog', props);\n}\n/** @public */\nexport function ChatIcon(props) {\n return useSystemIcon('chat', props);\n}\n/** @public */\nexport function DashboardIcon(props) {\n return useSystemIcon('dashboard', props);\n}\n/** @public */\nexport function DocsIcon(props) {\n return useSystemIcon('docs', props);\n}\n/** @public */\nexport function EmailIcon(props) {\n return useSystemIcon('email', props);\n}\n/** @public */\nexport function GitHubIcon(props) {\n return useSystemIcon('github', props);\n}\n/** @public */\nexport function GroupIcon(props) {\n return useSystemIcon('group', props);\n}\n/** @public */\nexport function HelpIcon(props) {\n return useSystemIcon('help', props);\n}\n/** @public */\nexport function UserIcon(props) {\n return useSystemIcon('user', props);\n}\n/** @public */\nexport function WarningIcon(props) {\n return useSystemIcon('warning', props);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useApp } from '@backstage/core-plugin-api';\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport Box from '@material-ui/core/Box';\nimport Button from '@material-ui/core/Button';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport IconButton from '@material-ui/core/IconButton';\nimport List from '@material-ui/core/List';\nimport ListItem from '@material-ui/core/ListItem';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport Popover from '@material-ui/core/Popover';\nimport Typography from '@material-ui/core/Typography';\nimport React, { useState } from 'react';\nimport { useSupportConfig } from '../../hooks';\nimport { HelpIcon } from '../../icons';\nimport { Link } from '../Link';\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n {\n popoverList: {\n minWidth: 260,\n maxWidth: 400,\n },\n },\n { name: 'BackstageSupportButton' },\n);\n\nconst SupportIcon = ({ icon }) => {\n const app = useApp();\n const Icon = icon ? app.getSystemIcon(icon) ?? HelpIcon : HelpIcon;\n return React.createElement(Icon, null );\n};\n\nconst SupportLink = ({ link }) => (\n React.createElement(Link, { to: link.url,}, link.title ?? link.url)\n);\n\nconst SupportListItem = ({ item }) => {\n return (\n React.createElement(ListItem, null\n , React.createElement(ListItemIcon, null\n , React.createElement(SupportIcon, { icon: item.icon,} )\n )\n , React.createElement(ListItemText, {\n primary: item.title,\n secondary: item.links?.reduce(\n (prev, link, idx) => [\n ...prev,\n idx > 0 && React.createElement('br', { key: idx,} ),\n React.createElement(SupportLink, { link: link, key: link.url,} ),\n ],\n [],\n ),}\n )\n )\n );\n};\n\nexport function SupportButton(props) {\n const { title, children } = props;\n const { items } = useSupportConfig();\n\n const [popoverOpen, setPopoverOpen] = useState(false);\n const [anchorEl, setAnchorEl] = useState(null);\n const classes = useStyles();\n const isSmallScreen = useMediaQuery(theme =>\n theme.breakpoints.down('sm'),\n );\n\n const onClickHandler = event => {\n setAnchorEl(event.currentTarget);\n setPopoverOpen(true);\n };\n\n const popoverCloseHandler = () => {\n setPopoverOpen(false);\n };\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(Box, { display: \"flex\", ml: 1,}\n , isSmallScreen ? (\n React.createElement(IconButton, {\n color: \"primary\",\n size: \"small\",\n onClick: onClickHandler,\n 'data-testid': \"support-button\",}\n \n , React.createElement(HelpIcon, null )\n )\n ) : (\n React.createElement(Button, {\n 'data-testid': \"support-button\",\n color: \"primary\",\n onClick: onClickHandler,\n startIcon: React.createElement(HelpIcon, null ),}\n , \"Support\"\n\n )\n )\n )\n , React.createElement(Popover, {\n 'data-testid': \"support-button-popover\",\n open: popoverOpen,\n anchorEl: anchorEl,\n anchorOrigin: {\n vertical: 'bottom',\n horizontal: 'right',\n },\n transformOrigin: {\n vertical: 'top',\n horizontal: 'right',\n },\n onClose: popoverCloseHandler,}\n \n , React.createElement(List, { className: classes.popoverList,}\n , title && (\n React.createElement(ListItem, { alignItems: \"flex-start\",}\n , React.createElement(Typography, { variant: \"subtitle1\",}, title)\n )\n )\n , React.Children.map(children, (child, i) => (\n React.createElement(ListItem, { alignItems: \"flex-start\", key: `child-${i}`,}\n , child\n )\n ))\n , items &&\n items.map((item, i) => (\n React.createElement(SupportListItem, { item: item, key: `item-${i}`,} )\n ))\n )\n , React.createElement(DialogActions, null\n , React.createElement(Button, { color: \"primary\", onClick: popoverCloseHandler,}, \"Close\"\n\n )\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createContext, } from 'react';\n\nconst drawerWidthClosed = 72;\nconst iconPadding = 24;\nconst userBadgePadding = 18;\n\nexport const sidebarConfig = {\n drawerWidthClosed,\n drawerWidthOpen: 224,\n // As per NN/g's guidance on timing for exposing hidden content\n // See https://www.nngroup.com/articles/timing-exposing-content/\n defaultOpenDelayMs: 100,\n defaultCloseDelayMs: 0,\n defaultFadeDuration: 200,\n logoHeight: 32,\n iconContainerWidth: drawerWidthClosed,\n iconSize: drawerWidthClosed - iconPadding * 2,\n iconPadding,\n selectedIndicatorWidth: 3,\n userBadgePadding,\n userBadgeDiameter: drawerWidthClosed - userBadgePadding * 2,\n mobileSidebarHeight: 56,\n};\n\nexport const submenuConfig = {\n drawerWidthClosed: 0,\n drawerWidthOpen: 202,\n defaultOpenDelayMs: sidebarConfig.defaultOpenDelayMs + 200,\n};\n\nexport const SIDEBAR_INTRO_LOCAL_STORAGE =\n '@backstage/core/sidebar-intro-dismissed';\n\n/**\n * Types for the `SidebarContext`\n */\n\n\n\n\n\n/**\n * Context wether the `Sidebar` is open\n */\nexport const SidebarContext = createContext({\n isOpen: false,\n setOpen: () => {},\n});\n\n\n\n\n\n\nexport const SidebarItemWithSubmenuContext =\n createContext({\n isHoveredOn: false,\n setIsHoveredOn: () => {},\n });\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nvar LocalStorageKeys; (function (LocalStorageKeys) {\n const SIDEBAR_PIN_STATE = 'sidebarPinState'; LocalStorageKeys[\"SIDEBAR_PIN_STATE\"] = SIDEBAR_PIN_STATE;\n})(LocalStorageKeys || (LocalStorageKeys = {}));\n\nexport const LocalStorage = {\n getSidebarPinState() {\n let value;\n try {\n value = JSON.parse(\n window.localStorage.getItem(LocalStorageKeys.SIDEBAR_PIN_STATE) ||\n 'true',\n );\n } catch {\n return true;\n }\n return !!value;\n },\n setSidebarPinState(state) {\n return window.localStorage.setItem(\n LocalStorageKeys.SIDEBAR_PIN_STATE,\n JSON.stringify(state),\n );\n },\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeStyles } from '@material-ui/core/styles';\n\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { sidebarConfig } from './config';\n\nimport { LocalStorage } from './localStorage';\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n width: '100%',\n transition: 'padding-left 0.1s ease-out',\n isolation: 'isolate',\n [theme.breakpoints.up('sm')]: {\n paddingLeft: ({ isPinned }) =>\n isPinned\n ? sidebarConfig.drawerWidthOpen\n : sidebarConfig.drawerWidthClosed,\n },\n [theme.breakpoints.down('xs')]: {\n paddingBottom: sidebarConfig.mobileSidebarHeight,\n },\n },\n content: {\n zIndex: 0,\n isolation: 'isolate',\n '&:focus': {\n outline: 0,\n },\n },\n }),\n { name: 'BackstageSidebarPage' },\n);\n\n/**\n * Type of `SidebarPinStateContext`\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Contains the state on how the `Sidebar` is rendered\n *\n * @public\n */\nexport const SidebarPinStateContext = createContext(\n {\n isPinned: true,\n toggleSidebarPinState: () => {},\n isMobile: false,\n },\n);\n\n\n\n\n\n\n\nconst PageContext = createContext({\n content: {\n contentRef: undefined,\n },\n});\nexport function SidebarPage(props) {\n const [isPinned, setIsPinned] = useState(() =>\n LocalStorage.getSidebarPinState(),\n );\n\n const contentRef = useRef(null);\n\n const pageContext = useMemo(\n () => ({\n content: {\n contentRef,\n },\n }),\n [contentRef],\n );\n\n useEffect(() => {\n LocalStorage.setSidebarPinState(isPinned);\n }, [isPinned]);\n\n const isMobile = useMediaQuery(\n theme => theme.breakpoints.down('xs'),\n { noSsr: true },\n );\n\n const toggleSidebarPinState = () => setIsPinned(!isPinned);\n\n const classes = useStyles({ isPinned });\n\n return (\n React.createElement(SidebarPinStateContext.Provider, {\n value: {\n isPinned,\n toggleSidebarPinState,\n isMobile,\n },}\n \n , React.createElement(PageContext.Provider, { value: pageContext,}\n , React.createElement('div', { className: classes.root,}, props.children)\n )\n )\n );\n}\n\n/**\n * This hook provides a react ref to the main content.\n * Allows to set an element as the main content and focus on that component.\n *\n * *Note: If `contentRef` is not set `focusContent` is noop. `Content` component sets this ref automaticaly*\n *\n * @public\n * @example\n * Focus current content\n * ```tsx\n * const { focusContent} = useContent();\n * ...\n * <Button onClick={focusContent}>\n * focus main content\n * </Button>\n * ```\n * @example\n * Set the reference to an Html element\n * ```\n * const { contentRef } = useContent();\n * ...\n * <article ref={contentRef} tabIndex={-1}>Main Content</article>\n * ```\n */\nexport function useContent() {\n const { content } = useContext(PageContext);\n\n const focusContent = useCallback(() => {\n content?.contentRef?.current?.focus();\n }, [content]);\n\n return { focusContent, contentRef: content?.contentRef };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport BottomNavigationAction, {\n\n} from '@material-ui/core/BottomNavigationAction';\nimport { makeStyles } from '@material-ui/core/styles';\nimport React, { useContext } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { SidebarPinStateContext } from '.';\nimport { Link } from '../../components';\nimport { sidebarConfig } from './config';\nimport { MobileSidebarContext } from './MobileSidebar';\n\n/**\n * Props for the `SidebarGroup`\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(theme => ({\n root: {\n flexGrow: 0,\n margin: theme.spacing(0, 2),\n color: theme.palette.navigation.color,\n },\n\n selected: {\n color: `${theme.palette.navigation.selectedColor}!important`,\n borderTop: `solid ${sidebarConfig.selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`,\n marginTop: '-1px',\n },\n\n label: {\n display: 'none',\n },\n}));\n\n/**\n * Returns a MUI `BottomNavigationAction`, which is aware of the current location & the selected item in the `BottomNavigation`,\n * such that it will highlight a `MobileSidebarGroup` either on location change or if the selected item changes.\n *\n * @param props `to`: pathname of link; `value`: index of the selected item\n * @internal\n */\nconst MobileSidebarGroup = (props) => {\n const { to, label, icon, value } = props;\n const classes = useStyles();\n const location = useLocation();\n const { selectedMenuItemIndex, setSelectedMenuItemIndex } =\n useContext(MobileSidebarContext);\n\n const onChange = (_, value) => {\n if (value === selectedMenuItemIndex) {\n setSelectedMenuItemIndex(-1);\n } else {\n setSelectedMenuItemIndex(value);\n }\n };\n\n const selected =\n (value === selectedMenuItemIndex && selectedMenuItemIndex >= 0) ||\n (!(value === selectedMenuItemIndex) &&\n !(selectedMenuItemIndex >= 0) &&\n to === location.pathname);\n\n return (\n // Material UI issue: https://github.com/mui-org/material-ui/issues/27820\n React.createElement(BottomNavigationAction, {\n label: label,\n icon: icon,\n component: Link ,\n to: (to ? to : location.pathname) ,\n onChange: onChange,\n value: value,\n selected: selected,\n classes: classes,}\n )\n );\n};\n\n/**\n * Groups items of the `Sidebar` together.\n *\n * On bigger screens, this won't have any effect at the moment.\n * On small screens, it will add an action to the bottom navigation - either triggering an overlay menu or acting as a link\n *\n * @public\n */\nexport const SidebarGroup = (props) => {\n const { children, to, label, icon, value } = props;\n const { isMobile } = useContext(SidebarPinStateContext);\n\n return isMobile ? (\n React.createElement(MobileSidebarGroup, { to: to, label: label, icon: icon, value: value,} )\n ) : (\n React.createElement(React.Fragment, null, children)\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useElementFilter } from '@backstage/core-plugin-api';\n\nimport BottomNavigation from '@material-ui/core/BottomNavigation';\nimport Box from '@material-ui/core/Box';\nimport IconButton from '@material-ui/core/IconButton';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Drawer from '@material-ui/core/Drawer';\nimport Typography from '@material-ui/core/Typography';\nimport CloseIcon from '@material-ui/icons/Close';\nimport MenuIcon from '@material-ui/icons/Menu';\nimport { orderBy } from 'lodash';\nimport React, { createContext, useEffect, useState } from 'react';\nimport { useLocation } from 'react-router';\nimport { SidebarContext } from '.';\nimport { sidebarConfig } from './config';\nimport { SidebarGroup } from './SidebarGroup';\n\n/**\n * Type of `MobileSidebarContext`\n *\n * @internal\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(theme => ({\n root: {\n position: 'fixed',\n backgroundColor: theme.palette.navigation.background,\n color: theme.palette.navigation.color,\n bottom: 0,\n left: 0,\n right: 0,\n zIndex: theme.zIndex.snackbar,\n // SidebarDivider color\n borderTop: '1px solid #383838',\n },\n\n overlay: {\n background: theme.palette.navigation.background,\n width: '100%',\n bottom: `${sidebarConfig.mobileSidebarHeight}px`,\n height: `calc(100% - ${sidebarConfig.mobileSidebarHeight}px)`,\n flex: '0 1 auto',\n overflow: 'auto',\n },\n\n overlayHeader: {\n display: 'flex',\n color: theme.palette.bursts.fontColor,\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: theme.spacing(2, 3),\n },\n\n overlayHeaderClose: {\n color: theme.palette.bursts.fontColor,\n },\n\n marginMobileSidebar: {\n marginBottom: `${sidebarConfig.mobileSidebarHeight}px`,\n },\n}));\n\nconst sortSidebarGroupsForPriority = (children) =>\n orderBy(\n children,\n ({ props: { priority } }) => (Number.isInteger(priority) ? priority : -1),\n 'desc',\n );\n\nconst sidebarGroupType = React.createElement(SidebarGroup).type;\n\nconst OverlayMenu = ({\n children,\n label = 'Menu',\n open,\n onClose,\n}) => {\n const classes = useStyles();\n\n return (\n React.createElement(Drawer, {\n anchor: \"bottom\",\n open: open,\n onClose: onClose,\n ModalProps: {\n BackdropProps: { classes: { root: classes.marginMobileSidebar } },\n },\n classes: {\n root: classes.marginMobileSidebar,\n paperAnchorBottom: classes.overlay,\n },}\n \n , React.createElement(Box, { className: classes.overlayHeader,}\n , React.createElement(Typography, { variant: \"h3\",}, label)\n , React.createElement(IconButton, {\n onClick: onClose,\n classes: { root: classes.overlayHeaderClose },}\n \n , React.createElement(CloseIcon, null )\n )\n )\n , React.createElement(Box, null, children)\n )\n );\n};\n\n/**\n * Context on which `SidebarGroup` is currently selected\n *\n * @internal\n */\nexport const MobileSidebarContext = createContext({\n selectedMenuItemIndex: -1,\n setSelectedMenuItemIndex: () => {},\n});\n\n/**\n * A navigation component for mobile screens, which sticks to the bottom.\n *\n * It alternates the normal sidebar by grouping the `SidebarItems` based on provided `SidebarGroup`s\n * either rendering them as a link or an overlay menu.\n * If no `SidebarGroup`s are provided the sidebar content is wrapped in an default overlay menu.\n *\n * @public\n */\nexport const MobileSidebar = (props) => {\n const { children } = props;\n const classes = useStyles();\n const location = useLocation();\n const [selectedMenuItemIndex, setSelectedMenuItemIndex] =\n useState(-1);\n\n useEffect(() => {\n setSelectedMenuItemIndex(-1);\n }, [location.pathname]);\n\n // Filter children for SidebarGroups\n //\n // Directly comparing child.type with SidebarSubmenu will not work with in\n // combination with react-hot-loader\n //\n // https://github.com/gaearon/react-hot-loader/issues/304#issuecomment-456569720\n let sidebarGroups = useElementFilter(children, elements =>\n elements.getElements().filter(child => child.type === sidebarGroupType),\n );\n\n if (!children) {\n // If Sidebar has no children the MobileSidebar won't be rendered\n return null;\n } else if (!sidebarGroups.length) {\n // If Sidebar has no SidebarGroup as a children a default\n // SidebarGroup with the complete Sidebar content will be created\n sidebarGroups.push(\n React.createElement(SidebarGroup, { key: \"default_menu\", icon: React.createElement(MenuIcon, null ),}\n , children\n ),\n );\n } else {\n // Sort SidebarGroups for the given Priority\n sidebarGroups = sortSidebarGroupsForPriority(sidebarGroups);\n }\n\n const shouldShowGroupChildren =\n selectedMenuItemIndex >= 0 &&\n !sidebarGroups[selectedMenuItemIndex].props.to;\n\n return (\n React.createElement(SidebarContext.Provider, { value: { isOpen: true, setOpen: () => {} },}\n , React.createElement(MobileSidebarContext.Provider, {\n value: { selectedMenuItemIndex, setSelectedMenuItemIndex },}\n \n , React.createElement(OverlayMenu, {\n label: \n sidebarGroups[selectedMenuItemIndex] &&\n (sidebarGroups[selectedMenuItemIndex].props.label )\n ,\n open: shouldShowGroupChildren,\n onClose: () => setSelectedMenuItemIndex(-1),}\n \n , sidebarGroups[selectedMenuItemIndex] &&\n (sidebarGroups[selectedMenuItemIndex].props\n .children )\n )\n , React.createElement(BottomNavigation, {\n className: classes.root,\n 'data-testid': \"mobile-sidebar-root\",}\n \n , sidebarGroups\n )\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport classnames from 'classnames';\n\nimport React, { useState, useContext, useRef } from 'react';\nimport Button from '@material-ui/core/Button';\n\nimport { sidebarConfig, SidebarContext } from './config';\n\nimport { SidebarPinStateContext, useContent } from './Page';\nimport { MobileSidebar } from './MobileSidebar';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n theme => ({\n drawer: {\n display: 'flex',\n flexFlow: 'column nowrap',\n alignItems: 'flex-start',\n position: 'fixed',\n left: 0,\n top: 0,\n bottom: 0,\n zIndex: theme.zIndex.appBar,\n background: theme.palette.navigation.background,\n overflowX: 'hidden',\n msOverflowStyle: 'none',\n scrollbarWidth: 'none',\n width: sidebarConfig.drawerWidthClosed,\n transition: theme.transitions.create('width', {\n easing: theme.transitions.easing.sharp,\n duration: theme.transitions.duration.shortest,\n }),\n '& > *': {\n flexShrink: 0,\n },\n '&::-webkit-scrollbar': {\n display: 'none',\n },\n },\n drawerOpen: {\n width: sidebarConfig.drawerWidthOpen,\n transition: theme.transitions.create('width', {\n easing: theme.transitions.easing.sharp,\n duration: theme.transitions.duration.shorter,\n }),\n },\n visuallyHidden: {\n top: 0,\n position: 'absolute',\n zIndex: 1000,\n transform: 'translateY(-200%)',\n '&:focus': {\n transform: 'translateY(5px)',\n },\n },\n }),\n { name: 'BackstageSidebar' },\n);\n\nvar State; (function (State) {\n const Closed = 0; State[State[\"Closed\"] = Closed] = \"Closed\";\n const Idle = Closed + 1; State[State[\"Idle\"] = Idle] = \"Idle\";\n const Open = Idle + 1; State[State[\"Open\"] = Open] = \"Open\";\n})(State || (State = {}));\n\n/** @public */\n\n\n\n\n\n\n\n/**\n * Places the Sidebar & wraps the children providing context weather the `Sidebar` is open or not.\n *\n * Handles & delays hover events for expanding the `Sidebar`\n *\n * @param props `disableExpandOnHover` disables the default hover behaviour;\n * `openDelayMs` & `closeDelayMs` set delay until sidebar will open/close on hover\n * @returns\n * @internal\n */\nconst DesktopSidebar = (props) => {\n const {\n openDelayMs = sidebarConfig.defaultOpenDelayMs,\n closeDelayMs = sidebarConfig.defaultCloseDelayMs,\n disableExpandOnHover,\n children,\n } = props;\n const classes = useStyles();\n const isSmallScreen = useMediaQuery(\n theme => theme.breakpoints.down('md'),\n { noSsr: true },\n );\n const [state, setState] = useState(State.Closed);\n const hoverTimerRef = useRef();\n const { isPinned, toggleSidebarPinState } = useContext(\n SidebarPinStateContext,\n );\n\n const handleOpen = () => {\n if (isPinned || disableExpandOnHover) {\n return;\n }\n if (hoverTimerRef.current) {\n clearTimeout(hoverTimerRef.current);\n hoverTimerRef.current = undefined;\n }\n if (state !== State.Open && !isSmallScreen) {\n hoverTimerRef.current = window.setTimeout(() => {\n hoverTimerRef.current = undefined;\n setState(State.Open);\n }, openDelayMs);\n\n setState(State.Idle);\n }\n };\n\n const handleClose = () => {\n if (isPinned || disableExpandOnHover) {\n return;\n }\n if (hoverTimerRef.current) {\n clearTimeout(hoverTimerRef.current);\n hoverTimerRef.current = undefined;\n }\n if (state === State.Idle) {\n setState(State.Closed);\n } else if (state === State.Open) {\n hoverTimerRef.current = window.setTimeout(() => {\n hoverTimerRef.current = undefined;\n setState(State.Closed);\n }, closeDelayMs);\n }\n };\n\n const isOpen = (state === State.Open && !isSmallScreen) || isPinned;\n\n /**\n * Close/Open Sidebar directily without delays. Also toggles `SidebarPinState` to avoid hidden content behind Sidebar.\n */\n const setOpen = (open) => {\n if (open) {\n setState(State.Open);\n toggleSidebarPinState();\n } else {\n setState(State.Closed);\n toggleSidebarPinState();\n }\n };\n\n return (\n React.createElement('div', { style: {},}\n , React.createElement(A11ySkipSidebar, null )\n , React.createElement(SidebarContext.Provider, {\n value: {\n isOpen,\n setOpen,\n },}\n \n , React.createElement('div', {\n className: classes.root,\n 'data-testid': \"sidebar-root\",\n onMouseEnter: disableExpandOnHover ? () => {} : handleOpen,\n onFocus: disableExpandOnHover ? () => {} : handleOpen,\n onMouseLeave: disableExpandOnHover ? () => {} : handleClose,\n onBlur: disableExpandOnHover ? () => {} : handleClose,}\n \n , React.createElement('div', {\n className: classnames(classes.drawer, {\n [classes.drawerOpen]: isOpen,\n }),}\n \n , children\n )\n )\n )\n )\n );\n};\n\n/**\n * Passing children into the desktop or mobile sidebar depending on the context\n *\n * @public\n */\nexport const Sidebar = (props) => {\n const { children, openDelayMs, closeDelayMs, disableExpandOnHover } = props;\n const { isMobile } = useContext(SidebarPinStateContext);\n\n return isMobile ? (\n React.createElement(MobileSidebar, null, children)\n ) : (\n React.createElement(DesktopSidebar, {\n openDelayMs: openDelayMs,\n closeDelayMs: closeDelayMs,\n disableExpandOnHover: disableExpandOnHover,}\n \n , children\n )\n );\n};\n\nfunction A11ySkipSidebar() {\n const { focusContent, contentRef } = useContent();\n const classes = useStyles();\n\n if (!contentRef?.current) {\n return null;\n }\n return (\n React.createElement(Button, {\n onClick: focusContent,\n variant: \"contained\",\n className: classnames(classes.visuallyHidden),}\n , \"Skip to content\"\n\n )\n );\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { isEqual, isMatch } from 'lodash';\nimport qs from 'qs';\n\nexport function isLocationMatch(currentLocation, toLocation) {\n const toDecodedSearch = new URLSearchParams(toLocation.search).toString();\n const toQueryParameters = qs.parse(toDecodedSearch);\n\n const currentDecodedSearch = new URLSearchParams(\n currentLocation.search,\n ).toString();\n const currentQueryParameters = qs.parse(currentDecodedSearch);\n\n const matching =\n isEqual(toLocation.pathname, currentLocation.pathname) &&\n isMatch(currentQueryParameters, toQueryParameters);\n\n return matching;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { useContext, useState } from 'react';\nimport {\n NavLink,\n resolvePath,\n useLocation,\n useResolvedPath,\n} from 'react-router-dom';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport Link from '@material-ui/core/Link';\n\nimport classnames from 'classnames';\n\nimport ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';\nimport ArrowDropUpIcon from '@material-ui/icons/ArrowDropUp';\nimport { SidebarItemWithSubmenuContext } from './config';\nimport { isLocationMatch } from './utils';\n\nconst useStyles = makeStyles(theme => ({\n item: {\n height: 48,\n width: '100%',\n '&:hover': {\n background: '#6f6f6f',\n color: theme.palette.navigation.selectedColor,\n },\n display: 'flex',\n alignItems: 'center',\n color: theme.palette.navigation.color,\n padding: 20,\n cursor: 'pointer',\n position: 'relative',\n background: 'none',\n border: 'none',\n },\n itemContainer: {\n width: '100%',\n },\n selected: {\n background: '#6f6f6f',\n color: '#FFF',\n },\n label: {\n margin: 14,\n marginLeft: 7,\n fontSize: 14,\n },\n dropdownArrow: {\n position: 'absolute',\n right: 21,\n },\n dropdown: {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'end',\n },\n dropdownItem: {\n width: '100%',\n padding: '10px 0 10px 0',\n },\n textContent: {\n color: theme.palette.navigation.color,\n display: 'flex',\n justifyContent: 'center',\n [theme.breakpoints.down('xs')]: {\n display: 'block',\n paddingLeft: theme.spacing(4),\n },\n fontSize: '14px',\n },\n}));\n\n/**\n * Clickable item displayed when submenu item is clicked.\n * title: Text content of item\n * to: Path to navigate to when item is clicked\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Item used inside a submenu within the sidebar.\n *\n * @public\n */\nexport const SidebarSubmenuItem = (props) => {\n const { title, to, icon: Icon, dropdownItems } = props;\n const classes = useStyles();\n const { setIsHoveredOn } = useContext(SidebarItemWithSubmenuContext);\n const closeSubmenu = () => {\n setIsHoveredOn(false);\n };\n const toLocation = useResolvedPath(to);\n const currentLocation = useLocation();\n let isActive = isLocationMatch(currentLocation, toLocation);\n\n const [showDropDown, setShowDropDown] = useState(false);\n const handleClickDropdown = () => {\n setShowDropDown(!showDropDown);\n };\n if (dropdownItems !== undefined) {\n dropdownItems.some(item => {\n const resolvedPath = resolvePath(item.to);\n isActive = isLocationMatch(currentLocation, resolvedPath);\n return isActive;\n });\n return (\n React.createElement('div', { className: classes.itemContainer,}\n , React.createElement('button', {\n onClick: handleClickDropdown,\n onTouchStart: e => e.stopPropagation(),\n className: classnames(\n classes.item,\n isActive ? classes.selected : undefined,\n ),}\n \n , React.createElement(Icon, { fontSize: \"small\",} )\n , React.createElement(Typography, { variant: \"subtitle1\", className: classes.label,}\n , title\n )\n , showDropDown ? (\n React.createElement(ArrowDropUpIcon, { className: classes.dropdownArrow,} )\n ) : (\n React.createElement(ArrowDropDownIcon, { className: classes.dropdownArrow,} )\n )\n )\n , dropdownItems && showDropDown && (\n React.createElement('div', { className: classes.dropdown,}\n , dropdownItems.map((object, key) => (\n React.createElement(Link, {\n component: NavLink,\n to: object.to,\n underline: \"none\",\n className: classes.dropdownItem,\n onClick: closeSubmenu,\n onTouchStart: e => e.stopPropagation(),\n key: key,}\n \n , React.createElement(Typography, { className: classes.textContent,}\n , object.title\n )\n )\n ))\n )\n )\n )\n );\n }\n\n return (\n React.createElement('div', { className: classes.itemContainer,}\n , React.createElement(Link, {\n component: NavLink,\n to: to,\n underline: \"none\",\n className: classnames(\n classes.item,\n isActive ? classes.selected : undefined,\n ),\n onClick: closeSubmenu,\n onTouchStart: e => e.stopPropagation(),}\n \n , React.createElement(Icon, { fontSize: \"small\",} )\n , React.createElement(Typography, { variant: \"subtitle1\", className: classes.label,}\n , title\n )\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { makeStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport classnames from 'classnames';\nimport React, { useContext, useEffect, useState } from 'react';\nimport {\n SidebarItemWithSubmenuContext,\n sidebarConfig,\n SidebarContext,\n submenuConfig,\n} from './config';\n\n\nconst useStyles = (props) =>\n makeStyles(theme => ({\n root: {\n zIndex: 1000,\n position: 'relative',\n overflow: 'visible',\n width: theme.spacing(7) + 1,\n },\n drawer: {\n display: 'flex',\n flexFlow: 'column nowrap',\n alignItems: 'flex-start',\n position: 'fixed',\n [theme.breakpoints.up('sm')]: {\n marginLeft: props.left,\n transition: theme.transitions.create('margin-left', {\n easing: theme.transitions.easing.sharp,\n duration: theme.transitions.duration.shortest,\n }),\n },\n top: 0,\n bottom: 0,\n padding: 0,\n background: theme.palette.navigation.submenu?.background ?? '#404040',\n overflowX: 'hidden',\n msOverflowStyle: 'none',\n scrollbarWidth: 'none',\n cursor: 'default',\n width: submenuConfig.drawerWidthClosed,\n transitionDelay: `${submenuConfig.defaultOpenDelayMs}ms`,\n '& > *': {\n flexShrink: 0,\n },\n '&::-webkit-scrollbar': {\n display: 'none',\n },\n },\n drawerOpen: {\n width: submenuConfig.drawerWidthOpen,\n [theme.breakpoints.down('xs')]: {\n width: '100%',\n position: 'relative',\n paddingLeft: theme.spacing(3),\n left: 0,\n top: 0,\n },\n },\n title: {\n fontSize: 24,\n fontWeight: 500,\n color: '#FFF',\n padding: 20,\n [theme.breakpoints.down('xs')]: {\n display: 'none',\n },\n },\n }));\n\n/**\n * Holds a title for text Header of a sidebar submenu and children\n * components to be rendered inside SidebarSubmenu\n *\n * @public\n */\n\n\n\n\n\n/**\n * Used inside SidebarItem to display an expandable Submenu\n *\n * @public\n */\nexport const SidebarSubmenu = (props) => {\n const { isOpen } = useContext(SidebarContext);\n const left = isOpen\n ? sidebarConfig.drawerWidthOpen\n : sidebarConfig.drawerWidthClosed;\n const classes = useStyles({ left })();\n\n const { isHoveredOn } = useContext(SidebarItemWithSubmenuContext);\n const [isSubmenuOpen, setIsSubmenuOpen] = useState(false);\n\n useEffect(() => {\n setIsSubmenuOpen(isHoveredOn);\n }, [isHoveredOn]);\n\n return (\n React.createElement('div', {\n className: classnames(classes.drawer, {\n [classes.drawerOpen]: isSubmenuOpen,\n }),}\n \n , React.createElement(Typography, { variant: \"h5\", className: classes.title,}\n , props.title\n )\n , props.children\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport ArrowBackIosIcon from '@material-ui/icons/ArrowBackIos';\n\nconst useStyles = makeStyles({\n iconContainer: {\n display: 'flex',\n position: 'relative',\n width: '100%',\n },\n arrow1: {\n right: '6px',\n position: 'absolute',\n },\n});\n\nconst DoubleArrowLeft = () => {\n const classes = useStyles();\n\n return (\n React.createElement('div', { className: classes.iconContainer,}\n , React.createElement('div', { className: classes.arrow1,}\n , React.createElement(ArrowBackIosIcon, { style: { fontSize: '12px' },} )\n )\n , React.createElement('div', null\n , React.createElement(ArrowBackIosIcon, { style: { fontSize: '12px' },} )\n )\n )\n );\n};\n\nexport default DoubleArrowLeft;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';\n\nconst useStyles = makeStyles({\n iconContainer: {\n display: 'flex',\n position: 'relative',\n width: '100%',\n },\n arrow1: {\n right: '6px',\n position: 'absolute',\n },\n});\n\nconst DoubleArrowRight = () => {\n const classes = useStyles();\n\n return (\n React.createElement('div', { className: classes.iconContainer,}\n , React.createElement('div', { className: classes.arrow1,}\n , React.createElement(ArrowForwardIosIcon, { style: { fontSize: '12px' },} )\n )\n , React.createElement('div', null\n , React.createElement(ArrowForwardIosIcon, { style: { fontSize: '12px' },} )\n )\n )\n );\n};\n\nexport default DoubleArrowRight;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useElementFilter } from '@backstage/core-plugin-api';\n\nimport { makeStyles, styled, } from '@material-ui/core/styles';\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport Badge from '@material-ui/core/Badge';\nimport TextField from '@material-ui/core/TextField';\nimport Typography from '@material-ui/core/Typography';\n\nimport ArrowRightIcon from '@material-ui/icons/ArrowRight';\nimport SearchIcon from '@material-ui/icons/Search';\nimport ArrowDropUp from '@material-ui/icons/ArrowDropUp';\nimport ArrowDropDown from '@material-ui/icons/ArrowDropDown';\nimport classnames from 'classnames';\nimport React, {\n forwardRef,\n\n\n useContext,\n useState,\n} from 'react';\nimport {\n Link,\n\n resolvePath,\n useLocation,\n useResolvedPath,\n} from 'react-router-dom';\nimport {\n sidebarConfig,\n SidebarContext,\n SidebarItemWithSubmenuContext,\n} from './config';\nimport {\n\n\n SidebarSubmenu,\n} from '.';\nimport DoubleArrowLeft from './icons/DoubleArrowLeft';\nimport DoubleArrowRight from './icons/DoubleArrowRight';\nimport { isLocationMatch } from './utils';\n\n\n/** @public */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => {\n const {\n selectedIndicatorWidth,\n drawerWidthClosed,\n drawerWidthOpen,\n iconContainerWidth,\n } = sidebarConfig;\n return {\n root: {\n color: theme.palette.navigation.color,\n display: 'flex',\n flexFlow: 'row nowrap',\n alignItems: 'center',\n height: 48,\n cursor: 'pointer',\n },\n buttonItem: {\n background: 'none',\n border: 'none',\n width: '100%',\n margin: 0,\n padding: 0,\n textAlign: 'inherit',\n font: 'inherit',\n },\n closed: {\n width: drawerWidthClosed,\n justifyContent: 'center',\n },\n open: {\n [theme.breakpoints.up('sm')]: {\n width: drawerWidthOpen,\n },\n },\n highlightable: {\n '&:hover': {\n background:\n theme.palette.navigation.navItem?.hoverBackground ?? '#404040',\n },\n },\n highlighted: {\n background:\n theme.palette.navigation.navItem?.hoverBackground ?? '#404040',\n },\n label: {\n // XXX (@koroeskohr): I can't seem to achieve the desired font-weight from the designs\n fontWeight: 'bold',\n whiteSpace: 'nowrap',\n lineHeight: 'auto',\n flex: '3 1 auto',\n width: '110px',\n overflow: 'hidden',\n 'text-overflow': 'ellipsis',\n },\n iconContainer: {\n boxSizing: 'border-box',\n height: '100%',\n width: iconContainerWidth,\n marginRight: -theme.spacing(2),\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n },\n searchRoot: {\n marginBottom: 12,\n },\n searchField: {\n color: '#b5b5b5',\n fontWeight: 'bold',\n fontSize: theme.typography.fontSize,\n },\n searchFieldHTMLInput: {\n padding: theme.spacing(2, 0, 2),\n },\n searchContainer: {\n width: drawerWidthOpen - iconContainerWidth,\n },\n secondaryAction: {\n width: theme.spacing(6),\n textAlign: 'center',\n marginRight: theme.spacing(1),\n },\n closedItemIcon: {\n width: '100%',\n justifyContent: 'center',\n },\n submenuArrow: {\n display: 'flex',\n },\n expandButton: {\n background: 'none',\n border: 'none',\n color: theme.palette.navigation.color,\n width: '100%',\n cursor: 'pointer',\n position: 'relative',\n height: 48,\n },\n arrows: {\n position: 'absolute',\n right: 10,\n },\n selected: {\n '&$root': {\n borderLeft: `solid ${selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`,\n color: theme.palette.navigation.selectedColor,\n },\n '&$closed': {\n width: drawerWidthClosed,\n },\n '& $closedItemIcon': {\n paddingRight: selectedIndicatorWidth,\n },\n '& $iconContainer': {\n marginLeft: -selectedIndicatorWidth,\n },\n },\n };\n },\n { name: 'BackstageSidebarItem' },\n);\n\n/**\n * Evaluates the routes of the SubmenuItems & nested DropdownItems.\n * The reeveluation is only triggered, if the `locationPathname` changes, as `useElementFilter` uses memorization.\n *\n * @param submenu SidebarSubmenu component\n * @param location Location\n * @returns boolean\n */\nconst useLocationMatch = (\n submenu,\n location,\n) =>\n useElementFilter(\n submenu.props.children,\n elements => {\n let active = false;\n elements\n .getElements()\n .forEach(\n ({\n props: { to, dropdownItems },\n }\n\n) => {\n if (!active) {\n if (dropdownItems?.length) {\n dropdownItems.forEach(\n ({ to: _to }) =>\n (active =\n active || isLocationMatch(location, resolvePath(_to))),\n );\n return;\n }\n if (to) {\n active = isLocationMatch(location, resolvePath(to));\n }\n }\n },\n );\n return active;\n },\n [location.pathname],\n );\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nfunction isButtonItem(\n props,\n) {\n return (props ).to === undefined;\n}\n\nconst sidebarSubmenuType = React.createElement(SidebarSubmenu).type;\n\n// TODO(Rugvip): Remove this once NavLink is updated in react-router-dom.\n// This is needed because react-router doesn't handle the path comparison\n// properly yet, matching for example /foobar with /foo.\nexport const WorkaroundNavLink = React.forwardRef\n\n\n(function WorkaroundNavLinkWithRef(\n {\n to,\n end,\n style,\n className,\n activeStyle,\n caseSensitive,\n activeClassName = 'active',\n 'aria-current': ariaCurrentProp = 'page',\n ...rest\n },\n ref,\n) {\n let { pathname: locationPathname } = useLocation();\n let { pathname: toPathname } = useResolvedPath(to);\n\n if (!caseSensitive) {\n locationPathname = locationPathname.toLocaleLowerCase('en-US');\n toPathname = toPathname.toLocaleLowerCase('en-US');\n }\n\n let isActive = locationPathname === toPathname;\n if (!isActive && !end) {\n // This is the behavior that is different from the original NavLink\n isActive = locationPathname.startsWith(`${toPathname}/`);\n }\n\n const ariaCurrent = isActive ? ariaCurrentProp : undefined;\n\n return (\n React.createElement(Link, {\n ...rest,\n to: to,\n ref: ref,\n 'aria-current': ariaCurrent,\n style: { ...style, ...(isActive ? activeStyle : undefined) },\n className: classnames([\n className,\n isActive ? activeClassName : undefined,\n ]),}\n )\n );\n});\n\n/**\n * Common component used by SidebarItem & SidebarItemWithSubmenu\n */\nconst SidebarItemBase = forwardRef((props, ref) => {\n const {\n icon: Icon,\n text,\n hasNotifications = false,\n disableHighlight = false,\n onClick,\n children,\n className,\n ...navLinkProps\n } = props;\n const classes = useStyles();\n // XXX (@koroeskohr): unsure this is optimal. But I just really didn't want to have the item component\n // depend on the current location, and at least have it being optionally forced to selected.\n // Still waiting on a Q answered to fine tune the implementation\n const { isOpen } = useContext(SidebarContext);\n\n const itemIcon = (\n React.createElement(Badge, {\n color: \"secondary\",\n variant: \"dot\",\n overlap: \"circular\",\n invisible: !hasNotifications,\n className: classnames({ [classes.closedItemIcon]: !isOpen }),}\n \n , React.createElement(Icon, { fontSize: \"small\",} )\n )\n );\n\n const openContent = (\n React.createElement(React.Fragment, null\n , React.createElement('div', { 'data-testid': \"login-button\", className: classes.iconContainer,}\n , itemIcon\n )\n , text && (\n React.createElement(Typography, { variant: \"subtitle2\", className: classes.label,}\n , text\n )\n )\n , React.createElement('div', { className: classes.secondaryAction,}, children)\n )\n );\n\n const content = isOpen ? openContent : itemIcon;\n\n const childProps = {\n onClick,\n className: classnames(\n className,\n classes.root,\n isOpen ? classes.open : classes.closed,\n isButtonItem(props) && classes.buttonItem,\n { [classes.highlightable]: !disableHighlight },\n ),\n };\n\n if (isButtonItem(props)) {\n return (\n React.createElement('button', { 'aria-label': text, ...childProps, ref: ref,}\n , content\n )\n );\n }\n\n return (\n React.createElement(WorkaroundNavLink, {\n ...childProps,\n activeClassName: classes.selected,\n to: props.to ? props.to : '',\n ref: ref,\n 'aria-label': text ? text : props.to,\n ...navLinkProps,}\n \n , content\n )\n );\n});\n\nconst SidebarItemWithSubmenu = ({\n children,\n ...props\n}\n\n) => {\n const classes = useStyles();\n const [isHoveredOn, setIsHoveredOn] = useState(false);\n const location = useLocation();\n const isActive = useLocationMatch(children, location);\n const isSmallScreen = useMediaQuery((theme) =>\n theme.breakpoints.down('sm'),\n );\n\n const handleMouseEnter = () => {\n setIsHoveredOn(true);\n };\n const handleMouseLeave = () => {\n setIsHoveredOn(false);\n };\n\n const arrowIcon = () => {\n if (isSmallScreen) {\n return isHoveredOn ? (\n React.createElement(ArrowDropUp, { fontSize: \"small\", className: classes.submenuArrow,} )\n ) : (\n React.createElement(ArrowDropDown, { fontSize: \"small\", className: classes.submenuArrow,} )\n );\n }\n return (\n !isHoveredOn && (\n React.createElement(ArrowRightIcon, { fontSize: \"small\", className: classes.submenuArrow,} )\n )\n );\n };\n\n return (\n React.createElement(SidebarItemWithSubmenuContext.Provider, {\n value: {\n isHoveredOn,\n setIsHoveredOn,\n },}\n \n , React.createElement('div', {\n 'data-testid': \"item-with-submenu\",\n onMouseLeave: handleMouseLeave,\n onTouchStart: isHoveredOn ? handleMouseLeave : handleMouseEnter,\n onMouseEnter: handleMouseEnter,\n className: classnames(isHoveredOn && classes.highlighted),}\n \n , React.createElement(SidebarItemBase, {\n className: isActive ? classes.selected : '',\n ...props,}\n \n , arrowIcon()\n )\n , isHoveredOn && children\n )\n )\n );\n};\n\n/**\n * Creates a `SidebarItem`\n *\n * If children contain a `SidebarSubmenu` component the `SidebarItem` will have a expandable submenu\n */\nexport const SidebarItem = forwardRef((props, ref) => {\n // Filter children for SidebarSubmenu components\n const [submenu] = useElementFilter(props.children, elements =>\n // Directly comparing child.type with SidebarSubmenu will not work with in\n // combination with react-hot-loader\n //\n // https://github.com/gaearon/react-hot-loader/issues/304#issuecomment-456569720\n elements.getElements().filter(child => child.type === sidebarSubmenuType),\n );\n\n if (submenu) {\n return (\n React.createElement(SidebarItemWithSubmenu, { ...props,}\n , submenu \n )\n );\n }\n\n return React.createElement(SidebarItemBase, { ...props, ref: ref,} );\n});\n\n\n\n\n\n\n\nexport function SidebarSearchField(props) {\n const [input, setInput] = useState('');\n const classes = useStyles();\n const Icon = props.icon ? props.icon : SearchIcon;\n\n const search = () => {\n props.onSearch(input);\n setInput('');\n };\n\n const handleEnter = ev => {\n if (ev.key === 'Enter') {\n ev.preventDefault();\n search();\n }\n };\n\n const handleInput = (ev) => {\n setInput(ev.target.value);\n };\n\n const handleInputClick = (ev) => {\n // Clicking into the search fields shouldn't navigate to the search page\n ev.preventDefault();\n ev.stopPropagation();\n };\n\n const handleItemClick = (ev) => {\n // Clicking on the search icon while should execute a query with the current field content\n search();\n ev.preventDefault();\n };\n\n return (\n React.createElement('div', { className: classes.searchRoot,}\n , React.createElement(SidebarItem, {\n icon: Icon,\n to: props.to,\n onClick: handleItemClick,\n disableHighlight: true,}\n \n , React.createElement(TextField, {\n placeholder: \"Search\",\n value: input,\n onClick: handleInputClick,\n onChange: handleInput,\n onKeyDown: handleEnter,\n className: classes.searchContainer,\n InputProps: {\n disableUnderline: true,\n className: classes.searchField,\n },\n inputProps: {\n className: classes.searchFieldHTMLInput,\n },}\n )\n )\n )\n );\n}\n\n\n\nexport const SidebarSpace = styled('div')(\n {\n flex: 1,\n },\n { name: 'BackstageSidebarSpace' },\n);\n\n\n\nexport const SidebarSpacer = styled('div')(\n {\n height: 8,\n },\n { name: 'BackstageSidebarSpacer' },\n);\n\n\n\nexport const SidebarDivider = styled('hr')(\n {\n height: 1,\n width: '100%',\n background: '#383838',\n border: 'none',\n margin: '12px 0px',\n },\n { name: 'BackstageSidebarDivider' },\n);\n\nconst styledScrollbar = (theme) => ({\n overflowY: 'auto',\n '&::-webkit-scrollbar': {\n backgroundColor: theme.palette.background.default,\n width: '5px',\n borderRadius: '5px',\n },\n '&::-webkit-scrollbar-thumb': {\n backgroundColor: theme.palette.text.hint,\n borderRadius: '5px',\n },\n});\n\nexport const SidebarScrollWrapper = styled('div')(({ theme }) => {\n const scrollbarStyles = styledScrollbar(theme);\n return {\n flex: '0 1 auto',\n overflowX: 'hidden',\n // 5px space to the right of the scrollbar\n width: 'calc(100% - 5px)',\n // Display at least one item in the container\n // Question: Can this be a config/theme variable - if so, which? :/\n minHeight: '48px',\n overflowY: 'hidden',\n '@media (hover: none)': scrollbarStyles,\n '&:hover': scrollbarStyles,\n };\n});\n\n/**\n * A button which allows you to expand the sidebar when clicked.\n * Use optionally to replace sidebar's expand-on-hover feature with expand-on-click.\n *\n * If you are using this you might want to set the `disableExpandOnHover` of the `Sidebar` to `true`.\n *\n * @public\n */\nexport const SidebarExpandButton = () => {\n const classes = useStyles();\n const { isOpen, setOpen } = useContext(SidebarContext);\n const isSmallScreen = useMediaQuery(\n theme => theme.breakpoints.down('md'),\n { noSsr: true },\n );\n\n if (isSmallScreen) {\n return null;\n }\n\n const handleClick = () => {\n setOpen(!isOpen);\n };\n\n return (\n React.createElement('button', {\n onClick: handleClick,\n className: classes.expandButton,\n 'aria-label': \"Expand Sidebar\" ,\n 'data-testid': \"sidebar-expand-button\",}\n \n , React.createElement('div', { className: classes.arrows,}\n , isOpen ? React.createElement(DoubleArrowLeft, null ) : React.createElement(DoubleArrowRight, null )\n )\n )\n );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport Collapse from '@material-ui/core/Collapse';\nimport Link from '@material-ui/core/Link';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport CloseIcon from '@material-ui/icons/Close';\nimport React, { useContext, useState } from 'react';\nimport useLocalStorage from 'react-use/lib/useLocalStorage';\nimport {\n sidebarConfig,\n SidebarContext,\n SIDEBAR_INTRO_LOCAL_STORAGE,\n} from './config';\nimport { SidebarDivider } from './Items';\n\n/** @public */\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n introCard: {\n color: '#b5b5b5',\n // XXX (@koroeskohr): should I be using a Mui theme variable?\n fontSize: 12,\n width: sidebarConfig.drawerWidthOpen,\n marginTop: 18,\n marginBottom: 12,\n paddingLeft: sidebarConfig.iconPadding,\n paddingRight: sidebarConfig.iconPadding,\n },\n introDismiss: {\n display: 'flex',\n justifyContent: 'flex-end',\n alignItems: 'center',\n marginTop: 12,\n },\n introDismissLink: {\n color: '#dddddd',\n display: 'flex',\n alignItems: 'center',\n marginBottom: 4,\n '&:hover': {\n color: theme.palette.linkHover,\n transition: theme.transitions.create('color', {\n easing: theme.transitions.easing.sharp,\n duration: theme.transitions.duration.shortest,\n }),\n },\n },\n introDismissText: {\n fontSize: '0.7rem',\n fontWeight: 'bold',\n textTransform: 'uppercase',\n letterSpacing: 1,\n },\n introDismissIcon: {\n width: 18,\n height: 18,\n marginRight: 12,\n },\n }),\n { name: 'BackstageSidebarIntro' },\n);\n\n\n\n\n\n\n/**\n * Closable card with information from Navigation Sidebar\n *\n * @public\n *\n */\n\nexport function IntroCard(props) {\n const classes = useStyles();\n const { text, onClose } = props;\n const handleClose = () => onClose();\n\n return (\n React.createElement('div', { className: classes.introCard,}\n , React.createElement(Typography, { variant: \"subtitle2\",}, text)\n , React.createElement('div', { className: classes.introDismiss,}\n , React.createElement(Link, {\n component: \"button\",\n onClick: handleClose,\n underline: \"none\",\n className: classes.introDismissLink,}\n \n , React.createElement(CloseIcon, { className: classes.introDismissIcon,} )\n , React.createElement(Typography, { component: \"span\", className: classes.introDismissText,}, \"Dismiss\"\n\n )\n )\n )\n )\n );\n}\n\n\n\n\n\n\n\n\n\n\n\nconst SidebarIntroCard = (props) => {\n const { text, onDismiss } = props;\n const [collapsing, setCollapsing] = useState(false);\n const startDismissing = () => {\n setCollapsing(true);\n };\n return (\n React.createElement(Collapse, { in: !collapsing, onExited: onDismiss,}\n , React.createElement(IntroCard, { text: text, onClose: startDismissing,} )\n )\n );\n};\n\nconst starredIntroText = `Fun fact! As you explore all the awesome plugins in Backstage, you can actually pin them to this side nav.\nKeep an eye out for the little star icon (⭐) next to the plugin name and give it a click!`;\nconst recentlyViewedIntroText =\n 'And your recently viewed plugins will pop up here!';\n\nexport function SidebarIntro(_props) {\n const { isOpen } = useContext(SidebarContext);\n const defaultValue = {\n starredItemsDismissed: false,\n recentlyViewedItemsDismissed: false,\n };\n const [dismissedIntro, setDismissedIntro] =\n useLocalStorage(SIDEBAR_INTRO_LOCAL_STORAGE);\n\n const { starredItemsDismissed, recentlyViewedItemsDismissed } =\n dismissedIntro ?? {};\n\n const dismissStarred = () => {\n setDismissedIntro(state => ({\n ...defaultValue,\n ...state,\n starredItemsDismissed: true,\n }));\n };\n const dismissRecentlyViewed = () => {\n setDismissedIntro(state => ({\n ...defaultValue,\n ...state,\n recentlyViewedItemsDismissed: true,\n }));\n };\n\n if (!isOpen) {\n return null;\n }\n\n return (\n React.createElement(React.Fragment, null\n , !starredItemsDismissed && (\n React.createElement(React.Fragment, null\n , React.createElement(SidebarIntroCard, {\n text: starredIntroText,\n onDismiss: dismissStarred,}\n )\n , React.createElement(SidebarDivider, null )\n )\n )\n , !recentlyViewedItemsDismissed && (\n React.createElement(SidebarIntroCard, {\n text: recentlyViewedIntroText,\n onDismiss: dismissRecentlyViewed,}\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { makeStyles, } from '@material-ui/core/styles';\nimport classNames from 'classnames';\nimport React, { } from 'react';\nimport { useContent } from '../Sidebar';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n (theme) => ({\n root: {\n gridArea: 'pageContent',\n minWidth: 0,\n paddingTop: theme.spacing(3),\n paddingBottom: theme.spacing(3),\n paddingLeft: theme.spacing(2),\n paddingRight: theme.spacing(2),\n [theme.breakpoints.up('sm')]: {\n paddingLeft: theme.spacing(3),\n paddingRight: theme.spacing(3),\n },\n },\n stretch: {\n display: 'flex',\n flexDirection: 'column',\n flexGrow: 1,\n },\n noPadding: {\n padding: 0,\n },\n }),\n { name: 'BackstageContent' },\n);\n\n\n\n\n\n\n\n/**\n * The main content part inside a {@link Page}.\n *\n * @public\n *\n */\n\nexport function Content(props) {\n const { className, stretch, noPadding, children, ...restProps } = props;\n\n const { contentRef } = useContent();\n\n const classes = useStyles();\n return (\n React.createElement('article', {\n ref: contentRef,\n tabIndex: -1,\n ...restProps,\n className: classNames(classes.root, className, {\n [classes.stretch]: stretch,\n [classes.noPadding]: noPadding,\n }),}\n \n , children\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// TODO(blam): Remove this implementation when the Tabs are ready\n// This is just a temporary solution to implementing tabs for now\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport TabUI, { } from '@material-ui/core/Tab';\nimport Tabs from '@material-ui/core/Tabs';\nimport React, { useEffect, useState } from 'react';\n\n/** @public */\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n tabsWrapper: {\n gridArea: 'pageSubheader',\n backgroundColor: theme.palette.background.paper,\n paddingLeft: theme.spacing(3),\n },\n defaultTab: {\n padding: theme.spacing(3, 3),\n ...theme.typography.caption,\n textTransform: 'uppercase',\n fontWeight: 'bold',\n color: theme.palette.text.secondary,\n },\n selected: {\n color: theme.palette.text.primary,\n },\n tabRoot: {\n '&:hover': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n },\n }),\n { name: 'BackstageHeaderTabs' },\n);\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Horizontal Tabs component\n *\n * @public\n *\n */\nexport function HeaderTabs(props) {\n const { tabs, onChange, selectedIndex } = props;\n const [selectedTab, setSelectedTab] = useState(selectedIndex ?? 0);\n const styles = useStyles();\n\n const handleChange = (_, index) => {\n if (selectedIndex === undefined) {\n setSelectedTab(index);\n }\n if (onChange) onChange(index);\n };\n\n useEffect(() => {\n if (selectedIndex !== undefined) {\n setSelectedTab(selectedIndex);\n }\n }, [selectedIndex]);\n\n return (\n React.createElement('div', { className: styles.tabsWrapper,}\n , React.createElement(Tabs, {\n selectionFollowsFocus: true,\n indicatorColor: \"primary\",\n textColor: \"inherit\",\n variant: \"scrollable\",\n scrollButtons: \"auto\",\n 'aria-label': \"scrollable auto tabs example\" ,\n onChange: handleChange,\n value: selectedTab,}\n \n , tabs.map((tab, index) => (\n React.createElement(TabUI, {\n ...tab.tabProps,\n 'data-testid': `header-tab-${index}`,\n label: tab.label,\n key: tab.id,\n value: index,\n className: styles.defaultTab,\n classes: { selected: styles.selected, root: styles.tabRoot },}\n )\n ))\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { useMemo } from 'react';\nimport { Helmet } from 'react-helmet';\nimport { matchRoutes, useNavigate, useParams, useRoutes } from 'react-router';\nimport { Content } from '../../layout/Content';\nimport { HeaderTabs } from '../../layout/HeaderTabs';\n\n\nexport function useSelectedSubRoute(subRoutes)\n\n\n\n {\n const params = useParams();\n\n const routes = subRoutes.map(({ path, children }) => ({\n caseSensitive: false,\n path: `${path}/*`,\n element: children,\n }));\n\n // TODO: remove once react-router updated\n const sortedRoutes = routes.sort((a, b) =>\n // remove \"/*\" symbols from path end before comparing\n b.path.replace(/\\/\\*$/, '').localeCompare(a.path.replace(/\\/\\*$/, '')),\n );\n\n const element = useRoutes(sortedRoutes) ?? subRoutes[0].children;\n\n const [matchedRoute] = matchRoutes(sortedRoutes, `/${params['*']}`) ?? [];\n const foundIndex = matchedRoute\n ? subRoutes.findIndex(t => `${t.path}/*` === matchedRoute.route.path)\n : 0;\n\n return {\n index: foundIndex === -1 ? 0 : foundIndex,\n element,\n route: subRoutes[foundIndex] ?? subRoutes[0],\n };\n}\n\nexport function RoutedTabs(props) {\n const { routes } = props;\n const navigate = useNavigate();\n const { index, route, element } = useSelectedSubRoute(routes);\n const headerTabs = useMemo(\n () =>\n routes.map(t => ({\n id: t.path,\n label: t.title,\n tabProps: t.tabProps,\n })),\n [routes],\n );\n\n const onTabChange = (tabIndex) =>\n // Remove trailing /*\n // And remove leading / for relative navigation\n // Note! route resolves relative to the position in the React tree,\n // not relative to current location\n navigate(routes[tabIndex].path.replace(/\\/\\*$/, '').replace(/^\\//, ''));\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(HeaderTabs, {\n tabs: headerTabs,\n selectedIndex: index,\n onChange: onTabChange,}\n )\n , React.createElement(Content, null\n , React.createElement(Helmet, { title: route.title,} )\n , element\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { attachComponentData } from '@backstage/core-plugin-api';\nimport React, {\n Children,\n Fragment,\n isValidElement,\n\n\n} from 'react';\nimport { RoutedTabs } from './RoutedTabs';\n\n\n\n\n\n\n\n\n\nconst Route = () => null;\n\n// This causes all mount points that are discovered within this route to use the path of the route itself\nattachComponentData(Route, 'core.gatherMountPoints', true);\n\nexport function createSubRoutesFromChildren(\n childrenProps,\n) {\n // Directly comparing child.type with Route will not work with in\n // combination with react-hot-loader in storybook\n // https://github.com/gaearon/react-hot-loader/issues/304\n const routeType = (\n React.createElement(Route, { path: \"\", title: \"\",}\n , React.createElement('div', null )\n )\n ).type;\n\n return Children.toArray(childrenProps).flatMap(child => {\n if (!isValidElement(child)) {\n return [];\n }\n\n if (child.type === Fragment) {\n return createSubRoutesFromChildren(child.props.children);\n }\n\n if (child.type !== routeType) {\n throw new Error('Child of TabbedLayout must be an TabbedLayout.Route');\n }\n\n const { path, title, children, tabProps } = child.props;\n return [{ path, title, children, tabProps }];\n });\n}\n\n/**\n * TabbedLayout is a compound component, which allows you to define a layout for\n * pages using a sub-navigation mechanism.\n *\n * Consists of two parts: TabbedLayout and TabbedLayout.Route\n *\n * @example\n * ```jsx\n * <TabbedLayout>\n * <TabbedLayout.Route path=\"/example\" title=\"Example tab\">\n * <div>This is rendered under /example/anything-here route</div>\n * </TabbedLayout.Route>\n * </TabbedLayout>\n * ```\n */\nexport function TabbedLayout(props) {\n const routes = createSubRoutesFromChildren(props.children);\n\n return React.createElement(RoutedTabs, { routes: routes,} );\n}\n\nTabbedLayout.Route = Route;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport { makeStyles } from '@material-ui/core/styles';\n\n\n\nconst useSubvalueCellStyles = makeStyles(\n theme => ({\n value: {\n marginBottom: '6px',\n },\n subvalue: {\n color: theme.palette.textSubtle,\n fontWeight: 'normal',\n },\n }),\n { name: 'BackstageSubvalueCell' },\n);\n\n\n\n\n\n\nexport function SubvalueCell(props) {\n const { value, subvalue } = props;\n const classes = useSubvalueCellStyles();\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement('div', { className: classes.value,}, value)\n , React.createElement('div', { className: classes.subvalue,}, subvalue)\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect, useState } from 'react';\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport Button from '@material-ui/core/Button';\nimport { Select } from '../Select';\n\n\n\n\nconst useFilterStyles = makeStyles(\n theme => ({\n root: {\n height: '100%',\n width: '315px',\n display: 'flex',\n flexDirection: 'column',\n marginRight: theme.spacing(3),\n },\n value: {\n fontWeight: 'bold',\n fontSize: 18,\n },\n header: {\n display: 'flex',\n alignItems: 'center',\n height: '60px',\n justifyContent: 'space-between',\n borderBottom: `1px solid ${theme.palette.grey[500]}`,\n },\n filters: {\n display: 'flex',\n flexDirection: 'column',\n '& > *': {\n marginTop: theme.spacing(2),\n },\n },\n }),\n { name: 'BackstageTableFilters' },\n);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const Filters = (props) => {\n const classes = useFilterStyles();\n\n const { onChangeFilters } = props;\n\n const [selectedFilters, setSelectedFilters] = useState({\n ...props.selectedFilters,\n });\n const [reset, triggerReset] = useState(false);\n\n // Trigger re-rendering\n const handleClick = () => {\n setSelectedFilters({});\n triggerReset(el => !el);\n };\n\n useEffect(() => {\n onChangeFilters(selectedFilters);\n }, [selectedFilters, onChangeFilters]);\n\n // As material table doesn't provide a way to add a column filter tab we will make our own filter logic\n return (\n React.createElement('div', { className: classes.root,}\n , React.createElement('div', { className: classes.header,}\n , React.createElement('div', { className: classes.value,}, \"Filters\")\n , React.createElement(Button, { color: \"primary\", onClick: handleClick,}, \"Clear all\"\n\n )\n )\n , React.createElement('div', { className: classes.filters,}\n , props.filters?.length &&\n props.filters.map(filter => (\n React.createElement(Select, {\n triggerReset: reset,\n key: filter.element.label,\n ...(filter.element ),\n selected: selectedFilters[filter.element.label],\n onChange: el =>\n setSelectedFilters({\n ...selectedFilters,\n [filter.element.label]: el ,\n })\n ,}\n )\n ))\n )\n )\n );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { makeStyles, useTheme, withStyles } from '@material-ui/core/styles';\nimport IconButton from '@material-ui/core/IconButton';\nimport Typography from '@material-ui/core/Typography';\n// Material-table is not using the standard icons available in in material-ui. https://github.com/mbrn/material-table/issues/51\nimport AddBox from '@material-ui/icons/AddBox';\nimport ArrowUpward from '@material-ui/icons/ArrowUpward';\nimport Check from '@material-ui/icons/Check';\nimport ChevronLeft from '@material-ui/icons/ChevronLeft';\nimport ChevronRight from '@material-ui/icons/ChevronRight';\nimport Clear from '@material-ui/icons/Clear';\nimport DeleteOutline from '@material-ui/icons/DeleteOutline';\nimport Edit from '@material-ui/icons/Edit';\nimport FilterList from '@material-ui/icons/FilterList';\nimport FirstPage from '@material-ui/icons/FirstPage';\nimport LastPage from '@material-ui/icons/LastPage';\nimport Remove from '@material-ui/icons/Remove';\nimport SaveAlt from '@material-ui/icons/SaveAlt';\nimport ViewColumn from '@material-ui/icons/ViewColumn';\nimport { isEqual, transform } from 'lodash';\nimport MTable, {\n\n\n\n MTableBody,\n MTableHeader,\n MTableToolbar,\n\n} from '@material-table/core';\nimport React, {\n forwardRef,\n\n\n useCallback,\n useEffect,\n useState,\n} from 'react';\n\nimport { Filters, } from './Filters';\n\nconst tableIcons = {\n Add: forwardRef((props, ref) => React.createElement(AddBox, { ...props, ref: ref,} )),\n Check: forwardRef((props, ref) => React.createElement(Check, { ...props, ref: ref,} )),\n Clear: forwardRef((props, ref) => React.createElement(Clear, { ...props, ref: ref,} )),\n Delete: forwardRef((props, ref) => React.createElement(DeleteOutline, { ...props, ref: ref,} )),\n DetailPanel: forwardRef((props, ref) => (\n React.createElement(ChevronRight, { ...props, ref: ref,} )\n )),\n Edit: forwardRef((props, ref) => React.createElement(Edit, { ...props, ref: ref,} )),\n Export: forwardRef((props, ref) => React.createElement(SaveAlt, { ...props, ref: ref,} )),\n Filter: forwardRef((props, ref) => React.createElement(FilterList, { ...props, ref: ref,} )),\n FirstPage: forwardRef((props, ref) => React.createElement(FirstPage, { ...props, ref: ref,} )),\n LastPage: forwardRef((props, ref) => React.createElement(LastPage, { ...props, ref: ref,} )),\n NextPage: forwardRef((props, ref) => React.createElement(ChevronRight, { ...props, ref: ref,} )),\n PreviousPage: forwardRef((props, ref) => (\n React.createElement(ChevronLeft, { ...props, ref: ref,} )\n )),\n ResetSearch: forwardRef((props, ref) => React.createElement(Clear, { ...props, ref: ref,} )),\n Search: forwardRef((props, ref) => React.createElement(FilterList, { ...props, ref: ref,} )),\n SortArrow: forwardRef((props, ref) => React.createElement(ArrowUpward, { ...props, ref: ref,} )),\n ThirdStateCheck: forwardRef((props, ref) => React.createElement(Remove, { ...props, ref: ref,} )),\n ViewColumn: forwardRef((props, ref) => React.createElement(ViewColumn, { ...props, ref: ref,} )),\n};\n\n// TODO: Material table might already have such a function internally that we can use?\nfunction extractValueByField(data, field) {\n const path = field.split('.');\n let value = data[path[0]];\n\n for (let i = 1; i < path.length; ++i) {\n if (value === undefined) {\n return value;\n }\n\n const f = path[i];\n value = value[f];\n }\n\n return value;\n}\n\n\n\nconst StyledMTableHeader = withStyles(\n theme => ({\n header: {\n padding: theme.spacing(1, 2, 1, 2.5),\n borderTop: `1px solid ${theme.palette.grey.A100}`,\n borderBottom: `1px solid ${theme.palette.grey.A100}`,\n // withStyles hasn't a generic overload for theme\n color: (theme ).palette.textSubtle,\n fontWeight: theme.typography.fontWeightBold,\n position: 'static',\n wordBreak: 'normal',\n },\n }),\n { name: 'BackstageTableHeader' },\n)(MTableHeader);\n\n\n\nconst StyledMTableToolbar = withStyles(\n theme => ({\n root: {\n padding: theme.spacing(3, 0, 2.5, 2.5),\n },\n title: {\n '& > h6': {\n fontWeight: 'bold',\n },\n },\n searchField: {\n paddingRight: theme.spacing(2),\n },\n }),\n { name: 'BackstageTableToolbar' },\n)(MTableToolbar);\n\n/** @public */\n\n\nconst useFilterStyles = makeStyles(\n () => ({\n root: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n },\n title: {\n fontWeight: 'bold',\n fontSize: 18,\n whiteSpace: 'nowrap',\n },\n }),\n { name: 'BackstageTableFiltersContainer' },\n);\n\n\n\nconst useTableStyles = makeStyles(\n () => ({\n root: {\n display: 'flex',\n alignItems: 'start',\n },\n }),\n { name: 'BackstageTable' },\n);\n\nfunction convertColumns(\n columns,\n theme,\n) {\n return columns.map(column => {\n const headerStyle = {};\n\n let cellStyle = column.cellStyle || {};\n\n if (column.highlight) {\n headerStyle.color = theme.palette.textContrast;\n\n if (typeof cellStyle === 'object') {\n (cellStyle ).fontWeight =\n theme.typography.fontWeightBold;\n } else {\n const cellStyleFn = cellStyle \n\n\n\n;\n cellStyle = (data, rowData, rowColumn) => {\n const style = cellStyleFn(data, rowData, rowColumn);\n return { ...style, fontWeight: theme.typography.fontWeightBold };\n };\n }\n }\n\n return {\n ...column,\n headerStyle,\n cellStyle,\n };\n });\n}\n\nfunction removeDefaultValues(state, defaultState) {\n return transform(state, (result, value, key) => {\n if (!isEqual(value, defaultState[key])) {\n result[key] = value;\n }\n });\n}\n\nconst defaultInitialState = {\n search: '',\n filtersOpen: false,\n filters: {},\n};\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport function TableToolbar(toolbarProps\n\n\n\n\n\n\n) {\n const {\n toolbarRef,\n setSearch,\n hasFilters,\n selectedFiltersLength,\n toggleFilters,\n } = toolbarProps;\n const filtersClasses = useFilterStyles();\n const onSearchChanged = useCallback(\n (searchText) => {\n toolbarProps.onSearchChanged(searchText);\n setSearch(searchText);\n },\n [toolbarProps, setSearch],\n );\n\n if (hasFilters) {\n return (\n React.createElement('div', { className: filtersClasses.root,}\n , React.createElement('div', { className: filtersClasses.root,}\n , React.createElement(IconButton, { onClick: toggleFilters, 'aria-label': \"filter list\" ,}\n , React.createElement(FilterList, null )\n )\n , React.createElement(Typography, { className: filtersClasses.title,}, \"Filters (\"\n , selectedFiltersLength, \")\"\n )\n )\n , React.createElement(StyledMTableToolbar, {\n ...toolbarProps,\n ref: toolbarRef,\n onSearchChanged: onSearchChanged,}\n )\n )\n );\n }\n\n return (\n React.createElement(StyledMTableToolbar, {\n ...toolbarProps,\n ref: toolbarRef,\n onSearchChanged: onSearchChanged,}\n )\n );\n}\n\nexport function Table(props) {\n const {\n data,\n columns,\n options,\n title,\n subtitle,\n filters,\n initialState,\n emptyContent,\n onStateChange,\n ...restProps\n } = props;\n const tableClasses = useTableStyles();\n\n const theme = useTheme();\n\n const calculatedInitialState = { ...defaultInitialState, ...initialState };\n\n const [filtersOpen, setFiltersOpen] = useState(\n calculatedInitialState.filtersOpen,\n );\n const toggleFilters = useCallback(\n () => setFiltersOpen(v => !v),\n [setFiltersOpen],\n );\n const [selectedFiltersLength, setSelectedFiltersLength] = useState(0);\n const [tableData, setTableData] = useState(data );\n const [selectedFilters, setSelectedFilters] = useState(\n calculatedInitialState.filters,\n );\n\n const MTColumns = convertColumns(columns, theme);\n\n const [search, setSearch] = useState(calculatedInitialState.search);\n\n useEffect(() => {\n if (onStateChange) {\n const state = removeDefaultValues(\n {\n search,\n filtersOpen,\n filters: selectedFilters,\n },\n defaultInitialState,\n );\n\n onStateChange(state);\n }\n }, [search, filtersOpen, selectedFilters, onStateChange]);\n\n const defaultOptions = {\n headerStyle: {\n textTransform: 'uppercase',\n },\n };\n\n const getFieldByTitle = useCallback(\n (titleValue) =>\n columns.find(el => el.title === titleValue)?.field,\n [columns],\n );\n\n useEffect(() => {\n if (typeof data === 'function') {\n return;\n }\n if (!selectedFilters) {\n setTableData(data );\n return;\n }\n\n const selectedFiltersArray = Object.values(selectedFilters);\n if (data && selectedFiltersArray.flat().length) {\n const newData = (data ).filter(\n el =>\n !!Object.entries(selectedFilters)\n .filter(([, value]) => !!value.length)\n .every(([key, filterValue]) => {\n const fieldValue = extractValueByField(\n el,\n getFieldByTitle(key) ,\n );\n\n if (Array.isArray(fieldValue) && Array.isArray(filterValue)) {\n return fieldValue.some(v => filterValue.includes(v));\n } else if (Array.isArray(fieldValue)) {\n return fieldValue.includes(filterValue);\n } else if (Array.isArray(filterValue)) {\n return filterValue.includes(fieldValue);\n }\n\n return fieldValue === filterValue;\n }),\n );\n setTableData(newData);\n } else {\n setTableData(data );\n }\n setSelectedFiltersLength(selectedFiltersArray.flat().length);\n }, [data, selectedFilters, getFieldByTitle]);\n\n const constructFilters = (\n filterConfig,\n dataValue,\n ) => {\n const extractDistinctValues = (field) => {\n const distinctValues = new Set();\n const addValue = (value) => {\n if (value !== undefined && value !== null) {\n distinctValues.add(value);\n }\n };\n\n if (dataValue) {\n dataValue.forEach(el => {\n const value = extractValueByField(\n el,\n getFieldByTitle(field) ,\n );\n\n if (Array.isArray(value)) {\n (value ).forEach(addValue);\n } else {\n addValue(value);\n }\n });\n }\n\n return distinctValues;\n };\n\n const constructSelect = (\n filter,\n ) => {\n return {\n placeholder: 'All results',\n label: filter.column,\n multiple: filter.type === 'multiple-select',\n items: [...extractDistinctValues(filter.column)].sort().map(value => ({\n label: value,\n value,\n })),\n };\n };\n\n return filterConfig.map(filter => ({\n type: filter.type,\n element: constructSelect(filter),\n }));\n };\n\n const hasFilters = !!filters?.length;\n const Toolbar = useCallback(\n toolbarProps => {\n return (\n React.createElement(TableToolbar, {\n setSearch: setSearch,\n hasFilters: hasFilters,\n selectedFiltersLength: selectedFiltersLength,\n toggleFilters: toggleFilters,\n ...toolbarProps,}\n )\n );\n },\n [toggleFilters, hasFilters, selectedFiltersLength, setSearch],\n );\n\n const hasNoRows = typeof data !== 'function' && data.length === 0;\n const columnCount = columns.length;\n const Body = useCallback(\n bodyProps => {\n if (emptyContent && hasNoRows) {\n return (\n React.createElement('tbody', null\n , React.createElement('tr', null\n , React.createElement('td', { colSpan: columnCount,}, emptyContent)\n )\n )\n );\n }\n\n return React.createElement(MTableBody, { ...bodyProps,} );\n },\n [hasNoRows, emptyContent, columnCount],\n );\n\n return (\n React.createElement('div', { className: tableClasses.root,}\n , filtersOpen && data && typeof data !== 'function' && filters?.length && (\n React.createElement(Filters, {\n filters: constructFilters(filters, data ),\n selectedFilters: selectedFilters,\n onChangeFilters: setSelectedFilters,}\n )\n )\n , React.createElement(MTable, {\n components: {\n Header: StyledMTableHeader,\n Toolbar,\n Body,\n },\n options: { ...defaultOptions, ...options },\n columns: MTColumns,\n icons: tableIcons,\n title: \n React.createElement(React.Fragment, null\n , React.createElement(Typography, { variant: \"h5\", component: \"h3\",}\n , title\n )\n , subtitle && (\n React.createElement(Typography, { color: \"textSecondary\", variant: \"body1\",}\n , subtitle\n )\n )\n )\n ,\n data: typeof data === 'function' ? data : tableData,\n style: { width: '100%' },\n localization: { toolbar: { searchPlaceholder: 'Filter' } },\n ...restProps,}\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\nimport Box from '@material-ui/core/Box';\n\n\n\n\n\n\nexport const TabPanel = (props) => {\n const { children, value, index, ...other } = props;\n\n return (\n React.createElement('div', {\n role: \"tabpanel\",\n hidden: value !== index,\n 'aria-labelledby': `scrollable-auto-tab-${index}`,\n ...other,}\n \n , value === index && React.createElement(Box, { p: 3,}, children)\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport IconButton from '@material-ui/core/IconButton';\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n () => ({\n root: {\n color: '#6E6E6E',\n overflow: 'visible',\n fontSize: '1.5rem',\n textAlign: 'center',\n borderRadius: '50%',\n backgroundColor: '#E6E6E6',\n marginLeft: props => (props.isNext ? 'auto' : '0'),\n marginRight: props => (props.isNext ? '0' : '10px'),\n '&:hover': {\n backgroundColor: '#E6E6E6',\n opacity: '1',\n },\n },\n }),\n { name: 'BackstageTabIcon' },\n);\n\nexport const StyledIcon = (props) => {\n const classes = useStyles(props);\n const { ariaLabel, onClick } = props;\n return (\n React.createElement(IconButton, {\n onClick: onClick,\n className: classes.root,\n size: \"small\",\n disableRipple: true,\n disableFocusRipple: true,\n 'aria-label': ariaLabel,}\n \n , props.children\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Tab from '@material-ui/core/Tab';\n\n\n\n\n\n\n\n\n\n\nconst tabMarginLeft = (isFirstNav, isFirstIndex) => {\n if (isFirstIndex) {\n if (isFirstNav) {\n return '20px';\n }\n return '0';\n }\n return '40px';\n};\n\nconst useStyles = makeStyles(theme => ({\n root: {\n textTransform: 'none',\n height: '64px',\n fontWeight: theme.typography.fontWeightBold,\n fontSize: theme.typography.pxToRem(13),\n color: theme.palette.textSubtle,\n marginLeft: props =>\n tabMarginLeft(props.isFirstNav , props.isFirstIndex ),\n width: '130px',\n minWidth: '130px',\n '&:hover': {\n outline: 'none',\n backgroundColor: 'transparent',\n color: theme.palette.textSubtle,\n },\n },\n}));\n\nexport const StyledTab = (props) => {\n const classes = useStyles(props);\n const { isFirstNav, isFirstIndex, ...rest } = props;\n return React.createElement(Tab, { className: classes.root, disableRipple: true, ...rest,} );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Tabs from '@material-ui/core/Tabs';\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n indicator: {\n display: 'flex',\n justifyContent: 'center',\n backgroundColor: theme.palette.tabbar.indicator,\n height: '4px',\n },\n flexContainer: {\n alignItems: 'center',\n },\n root: {\n '&:last-child': {\n marginLeft: 'auto',\n },\n },\n }),\n { name: 'BackstageTabBar' },\n);\n\nexport const StyledTabs = (props) => {\n const classes = useStyles(props);\n return (\n React.createElement(Tabs, {\n classes: classes,\n ...props,\n TabIndicatorProps: { children: React.createElement('span', null ) },}\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useRef, useEffect, useState } from 'react';\n\nimport AppBar from '@material-ui/core/AppBar';\nimport { makeStyles } from '@material-ui/core/styles';\nimport NavigateBeforeIcon from '@material-ui/icons/NavigateBefore';\nimport NavigateNextIcon from '@material-ui/icons/NavigateNext';\nimport { chunkArray } from './utils';\nimport useWindowSize from 'react-use/lib/useWindowSize';\n\n/* Import Components */\n\nimport { TabPanel } from './TabPanel';\nimport { StyledIcon } from './TabIcon';\nimport { StyledTab } from './Tab';\nimport { StyledTabs } from './TabBar';\n\n/* Props Types */\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n flexGrow: 1,\n width: '100%',\n },\n styledTabs: {\n backgroundColor: theme.palette.background.paper,\n },\n appbar: {\n boxShadow: 'none',\n backgroundColor: theme.palette.background.paper,\n paddingLeft: '10px',\n paddingRight: '10px',\n },\n }),\n { name: 'BackstageTabs' },\n);\n\nexport function Tabs(props) {\n const { tabs } = props;\n const classes = useStyles();\n const [value, setValue] = useState([0, 0]); // [selectedChunkedNavIndex, selectedIndex]\n const [navIndex, setNavIndex] = useState(0);\n const [numberOfChunkedElement, setNumberOfChunkedElement] = useState(0);\n const [chunkedTabs, setChunkedTabs] = useState([[]]);\n const wrapper = useRef() ;\n\n const { width } = useWindowSize();\n\n const handleChange = (_, newValue) => {\n setValue([navIndex, newValue]);\n };\n\n const navigateToPrevChunk = () => {\n setNavIndex(navIndex - 1);\n };\n\n const navigateToNextChunk = () => {\n setNavIndex(navIndex + 1);\n };\n\n const hasNextNavIndex = () => navIndex + 1 < chunkedTabs.length;\n\n useEffect(() => {\n // Each time the window is resized we calculate how many tabs we can render given the window width\n const padding = 20; // The AppBar padding\n\n const numberOfTabIcons = navIndex === 0 ? 1 : 2;\n const wrapperWidth =\n wrapper.current.offsetWidth - padding - numberOfTabIcons * 30;\n const flattenIndex = value[0] * numberOfChunkedElement + value[1];\n const newChunkedElementSize = Math.floor(wrapperWidth / 170);\n\n setNumberOfChunkedElement(newChunkedElementSize);\n setChunkedTabs(chunkArray(tabs, newChunkedElementSize));\n setValue([\n Math.floor(flattenIndex / newChunkedElementSize),\n flattenIndex % newChunkedElementSize,\n ]);\n // eslint-disable-next-line\n }, [width, tabs]);\n\n const currentIndex = navIndex === value[0] ? value[1] : false;\n\n return (\n React.createElement('div', { className: classes.root,}\n , React.createElement(AppBar, { ref: wrapper, className: classes.appbar, position: \"static\",}\n , React.createElement('div', null\n , React.createElement(StyledTabs, {\n value: currentIndex,\n onChange: handleChange,\n selectionFollowsFocus: true,}\n \n , navIndex !== 0 && (\n React.createElement(StyledIcon, {\n onClick: navigateToPrevChunk,\n ariaLabel: \"navigate-before\",}\n \n , React.createElement(NavigateBeforeIcon, null )\n )\n )\n , chunkedTabs[navIndex].map((tab, index) => (\n React.createElement(StyledTab, {\n value: index,\n isFirstIndex: index === 0,\n isFirstNav: navIndex === 0,\n key: index,\n icon: tab.icon || undefined,\n label: tab.label || undefined,}\n )\n ))\n , hasNextNavIndex() && (\n React.createElement(StyledIcon, {\n isNext: true,\n onClick: navigateToNextChunk,\n ariaLabel: \"navigate-next\",}\n \n , React.createElement(NavigateNextIcon, null )\n )\n )\n )\n )\n )\n , currentIndex !== false ? (\n chunkedTabs[navIndex].map((tab, index) => (\n React.createElement(TabPanel, { key: index, value: index, index: currentIndex,}\n , tab.content\n )\n ))\n ) : (\n // Render if the selected tab index is outside the current rendered chunked array\n React.createElement(TabPanel, {\n key: \"panel_outside_chunked_array\",\n value: value[1],\n index: value[1],}\n \n , chunkedTabs[value[0]][value[1]].content\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport {\n Sparklines,\n SparklinesLine,\n\n\n} from 'react-sparklines';\nimport { useTheme } from '@material-ui/core/styles';\n\n\nfunction color(data, theme) {\n const lastNum = data[data.length - 1];\n if (!lastNum) return undefined;\n if (lastNum >= 0.9) return theme.palette.status.ok;\n if (lastNum >= 0.5) return theme.palette.status.warning;\n return theme.palette.status.error;\n}\n\nexport function TrendLine(\n props\n,\n) {\n const theme = useTheme();\n\n if (!props.data) return null;\n return (\n React.createElement(Sparklines, { width: 120, height: 30, min: 0, max: 1, ...props,}\n , props.title && React.createElement('title', null, props.title)\n , React.createElement(SparklinesLine, { color: props.color ?? color(props.data, theme),} )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * TODO favoriteable capability\n */\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport React, { } from 'react';\nimport { Helmet } from 'react-helmet';\n\n/** @public */\n\n\n\n\n\n\n\nconst useStyles = (props) =>\n makeStyles(\n theme => ({\n container: {\n width: '100%',\n display: 'flex',\n flexDirection: 'row',\n flexWrap: 'wrap',\n justifyContent: 'flex-end',\n alignItems: 'center',\n marginBottom: theme.spacing(2),\n textAlign: props.textAlign,\n },\n leftItemsBox: {\n flex: '1 1 auto',\n minWidth: 0,\n overflow: 'visible',\n },\n rightItemsBox: {\n flex: '0 1 auto',\n display: 'flex',\n flexDirection: 'row',\n flexWrap: 'wrap',\n alignItems: 'center',\n marginLeft: theme.spacing(1),\n minWidth: 0,\n overflow: 'visible',\n },\n description: {},\n title: {\n display: 'inline-flex',\n marginBottom: 0,\n },\n }),\n { name: 'BackstageContentHeader' },\n );\n\n\n\n\n\n\nconst ContentHeaderTitle = ({\n title = 'Unknown page',\n className,\n}) => (\n React.createElement(Typography, {\n variant: \"h4\",\n component: \"h2\",\n className: className,\n 'data-testid': \"header-title\",}\n \n , title\n )\n);\n\n\n\n\n\n\n\n\n/**\n * A header at the top inside a {@link Content}.\n *\n * @public\n *\n */\n\nexport function ContentHeader(props) {\n const {\n description,\n title,\n titleComponent: TitleComponent = undefined,\n children,\n textAlign = 'left',\n } = props;\n const classes = useStyles({ textAlign })();\n\n const renderedTitle = TitleComponent ? (\n TitleComponent\n ) : (\n React.createElement(ContentHeaderTitle, { title: title, className: classes.title,} )\n );\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(Helmet, { title: title,} )\n , React.createElement('div', { className: classes.container,}\n , React.createElement('div', { className: classes.leftItemsBox,}\n , renderedTitle\n , description && (\n React.createElement(Typography, { className: classes.description, variant: \"body2\",}\n , description\n )\n )\n )\n , React.createElement('div', { className: classes.rightItemsBox,}, children)\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport MicDropSvgUrl from './mic-drop.svg';\n\nconst useStyles = makeStyles(\n theme => ({\n micDrop: {\n maxWidth: '60%',\n position: 'absolute',\n bottom: theme.spacing(2),\n right: theme.spacing(2),\n [theme.breakpoints.down('xs')]: {\n maxWidth: '96%',\n position: 'relative',\n bottom: 'unset',\n right: 'unset',\n margin: `${theme.spacing(10)}px auto ${theme.spacing(4)}px`,\n },\n },\n }),\n { name: 'BackstageErrorPageMicDrop' },\n);\n\n\n\nexport const MicDrop = () => {\n const classes = useStyles();\n return (\n React.createElement('img', {\n src: MicDropSvgUrl,\n className: classes.micDrop,\n alt: \"Girl dropping mic from her hands\" ,}\n )\n );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport Grid from '@material-ui/core/Grid';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport React from 'react';\nimport { useNavigate } from 'react-router';\nimport { Link } from '../../components/Link';\nimport { useSupportConfig } from '../../hooks';\nimport { MicDrop } from './MicDrop';\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n container: {\n padding: theme.spacing(8),\n [theme.breakpoints.down('xs')]: {\n padding: theme.spacing(2),\n },\n },\n title: {\n paddingBottom: theme.spacing(5),\n [theme.breakpoints.down('xs')]: {\n paddingBottom: theme.spacing(4),\n fontSize: 32,\n },\n },\n subtitle: {\n color: theme.palette.textSubtle,\n },\n }),\n { name: 'BackstageErrorPage' },\n);\n\n/**\n * Error page with status and description\n *\n * @public\n *\n */\nexport function ErrorPage(props) {\n const { status, statusMessage, additionalInfo, supportUrl } = props;\n const classes = useStyles();\n const navigate = useNavigate();\n const support = useSupportConfig();\n\n return (\n React.createElement(Grid, { container: true, spacing: 0, className: classes.container,}\n , React.createElement(MicDrop, null )\n , React.createElement(Grid, { item: true, xs: 12, sm: 8, md: 4,}\n , React.createElement(Typography, {\n 'data-testid': \"error\",\n variant: \"body1\",\n className: classes.subtitle,}\n , \"ERROR \"\n , status, \": \" , statusMessage\n )\n , React.createElement(Typography, { variant: \"body1\", className: classes.subtitle,}\n , additionalInfo\n )\n , React.createElement(Typography, { variant: \"h2\", className: classes.title,}, \"Looks like someone dropped the mic!\"\n\n )\n , React.createElement(Typography, { variant: \"h6\",}\n , React.createElement(Link, { to: \"#\", 'data-testid': \"go-back-link\", onClick: () => navigate(-1),}, \"Go back\"\n\n ), \"... or please\"\n , ' '\n , React.createElement(Link, { to: supportUrl || support.url,}, \"contact support\" ), \" if you think this is a bug.\"\n\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Box from '@material-ui/core/Box';\nimport MaterialBreadcrumbs from '@material-ui/core/Breadcrumbs';\nimport List from '@material-ui/core/List';\nimport ListItem from '@material-ui/core/ListItem';\nimport Popover from '@material-ui/core/Popover';\nimport { withStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport React, { Fragment } from 'react';\n\n\n\n\n\n\nconst ClickableText = withStyles(\n {\n root: {\n textDecoration: 'underline',\n cursor: 'pointer',\n },\n },\n { name: 'BackstageBreadcrumbsClickableText' },\n)(Typography);\n\n/** @public */\n\n\nconst StyledBox = withStyles(\n {\n root: {\n textDecoration: 'underline',\n color: 'inherit',\n },\n },\n { name: 'BackstageBreadcrumbsStyledBox' },\n)(Box);\n\n/**\n * Breadcrumbs component to show navigation hierarchical structure\n *\n * @public\n *\n */\nexport function Breadcrumbs(props) {\n const { children, ...restProps } = props;\n const [anchorEl, setAnchorEl] = React.useState(\n null,\n );\n\n const childrenArray = React.Children.toArray(children);\n\n const [firstPage, secondPage, ...expandablePages] = childrenArray;\n const currentPage = expandablePages.length\n ? expandablePages.pop()\n : childrenArray[childrenArray.length - 1];\n const hasHiddenBreadcrumbs = childrenArray.length > 3;\n\n const handleClick = (event) => {\n setAnchorEl(event.currentTarget);\n };\n\n const handleClose = () => {\n setAnchorEl(null);\n };\n\n const open = Boolean(anchorEl);\n return (\n React.createElement(Fragment, null\n , React.createElement(MaterialBreadcrumbs, { 'aria-label': \"breadcrumb\", ...restProps,}\n , childrenArray.length > 1 && React.createElement(StyledBox, { clone: true,}, firstPage)\n , childrenArray.length > 2 && React.createElement(StyledBox, { clone: true,}, secondPage)\n , hasHiddenBreadcrumbs && (\n React.createElement(ClickableText, { onClick: handleClick,}, \"...\")\n )\n , React.createElement(Box, { style: { fontStyle: 'italic' },}, currentPage)\n )\n , React.createElement(Popover, {\n open: open,\n anchorEl: anchorEl,\n onClose: handleClose,\n anchorOrigin: {\n vertical: 'bottom',\n horizontal: 'left',\n },\n transformOrigin: {\n vertical: 'top',\n horizontal: 'left',\n },}\n \n , React.createElement(List, null\n , expandablePages.map((pageLink, index) => (\n React.createElement(ListItem, { key: index, button: true,}\n , React.createElement(StyledBox, { clone: true,}, pageLink)\n )\n ))\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Typography from '@material-ui/core/Typography';\nimport React, { } from 'react';\nimport { Helmet } from 'react-helmet';\nimport { Link } from '../../components/Link';\nimport { Breadcrumbs } from '../Breadcrumbs';\n\n/** @public */\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n header: {\n gridArea: 'pageHeader',\n padding: theme.spacing(3),\n width: '100%',\n boxShadow: theme.shadows[4],\n position: 'relative',\n zIndex: 100,\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n backgroundImage: theme.page.backgroundImage,\n backgroundPosition: 'center',\n backgroundSize: 'cover',\n [theme.breakpoints.down('sm')]: {\n flexWrap: 'wrap',\n },\n },\n leftItemsBox: {\n maxWidth: '100%',\n flexGrow: 1,\n },\n rightItemsBox: {\n width: 'auto',\n },\n title: {\n color: theme.palette.bursts.fontColor,\n wordBreak: 'break-all',\n fontSize: theme.typography.h3.fontSize,\n marginBottom: 0,\n },\n subtitle: {\n color: theme.palette.bursts.fontColor,\n opacity: 0.8,\n display: 'inline-block', // prevents margin collapse of adjacent siblings\n marginTop: theme.spacing(1),\n maxWidth: '75ch',\n },\n type: {\n textTransform: 'uppercase',\n fontSize: 11,\n opacity: 0.8,\n marginBottom: theme.spacing(1),\n color: theme.palette.bursts.fontColor,\n },\n breadcrumb: {\n color: theme.palette.bursts.fontColor,\n },\n breadcrumbType: {\n fontSize: 'inherit',\n opacity: 0.7,\n marginRight: -theme.spacing(0.3),\n marginBottom: theme.spacing(0.3),\n },\n breadcrumbTitle: {\n fontSize: 'inherit',\n marginLeft: -theme.spacing(0.3),\n marginBottom: theme.spacing(0.3),\n },\n }),\n { name: 'BackstageHeader' },\n);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst TypeFragment = ({\n type,\n typeLink,\n classes,\n pageTitle,\n}) => {\n if (!type) {\n return null;\n }\n\n if (!typeLink) {\n return React.createElement(Typography, { className: classes.type,}, type);\n }\n\n return (\n React.createElement(Breadcrumbs, { className: classes.breadcrumb,}\n , React.createElement(Link, { to: typeLink,}, type)\n , React.createElement(Typography, null, pageTitle)\n )\n );\n};\n\nconst TitleFragment = ({ pageTitle, classes, tooltip }) => {\n const FinalTitle = (\n React.createElement(Typography, { className: classes.title, variant: \"h1\",}\n , pageTitle\n )\n );\n\n if (!tooltip) {\n return FinalTitle;\n }\n\n return (\n React.createElement(Tooltip, { title: tooltip, placement: \"top-start\",}\n , FinalTitle\n )\n );\n};\n\nconst SubtitleFragment = ({ classes, subtitle }) => {\n if (!subtitle) {\n return null;\n }\n\n if (typeof subtitle !== 'string') {\n return React.createElement(React.Fragment, null, subtitle);\n }\n\n return (\n React.createElement(Typography, {\n className: classes.subtitle,\n variant: \"subtitle2\",\n component: \"span\",}\n \n , subtitle\n )\n );\n};\n/**\n * Backstage main header with abstract color background in multiple variants\n *\n * @public\n *\n */\nexport function Header(props) {\n const {\n children,\n pageTitleOverride,\n style,\n subtitle,\n title,\n tooltip,\n type,\n typeLink,\n } = props;\n const classes = useStyles();\n const configApi = useApi(configApiRef);\n const appTitle = configApi.getOptionalString('app.title') || 'Backstage';\n const documentTitle = pageTitleOverride || title;\n const pageTitle = title || pageTitleOverride;\n const titleTemplate = `${documentTitle} | %s | ${appTitle}`;\n const defaultTitle = `${documentTitle} | ${appTitle}`;\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(Helmet, { titleTemplate: titleTemplate, defaultTitle: defaultTitle,} )\n , React.createElement('header', { style: style, className: classes.header,}\n , React.createElement(Box, { className: classes.leftItemsBox,}\n , React.createElement(TypeFragment, {\n classes: classes,\n type: type,\n typeLink: typeLink,\n pageTitle: pageTitle,}\n )\n , React.createElement(TitleFragment, {\n classes: classes,\n pageTitle: pageTitle,\n tooltip: tooltip,}\n )\n , React.createElement(SubtitleFragment, { classes: classes, subtitle: subtitle,} )\n )\n , React.createElement(Grid, { container: true, className: classes.rightItemsBox, spacing: 4,}\n , children\n )\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Grid from '@material-ui/core/Grid';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport React from 'react';\nimport { Link } from '../../components/Link';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n textAlign: 'left',\n },\n label: {\n color: theme.palette.common.white,\n fontWeight: 'bold',\n letterSpacing: 0,\n fontSize: theme.typography.fontSize,\n marginBottom: theme.spacing(1) / 2,\n lineHeight: 1,\n },\n value: {\n color: 'rgba(255, 255, 255, 0.8)',\n fontSize: theme.typography.fontSize,\n lineHeight: 1,\n },\n }),\n { name: 'BackstageHeaderLabel' },\n);\n\n\n\n\n\n\nconst HeaderLabelContent = ({ value, className }) => (\n React.createElement(Typography, { className: className,}, value)\n);\n\n\n\n\n\n\n\n/**\n * Additional label to main {@link Header}\n *\n * @public\n *\n */\nexport function HeaderLabel(props) {\n const { label, value, url } = props;\n const classes = useStyles();\n const content = (\n React.createElement(HeaderLabelContent, {\n className: classes.value,\n value: value || '<Unknown>',}\n )\n );\n return (\n React.createElement(Grid, { item: true,}\n , React.createElement('span', { className: classes.root,}\n , React.createElement(Typography, { className: classes.label,}, label)\n , url ? React.createElement(Link, { to: url,}, content) : content\n )\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { HeaderLabel } from '../HeaderLabel';\nimport { useApi, configApiRef } from '@backstage/core-plugin-api';\n\nconst timeFormat = {\n hour: '2-digit',\n minute: '2-digit',\n};\n\n\n\n\n\n\nfunction getTimes(configApi) {\n const d = new Date();\n const lang = window.navigator.language;\n\n const clocks = [];\n\n if (!configApi.has('homepage.clocks')) {\n return clocks;\n }\n\n const clockConfigs = configApi.getConfigArray('homepage.clocks');\n\n for (const clock of clockConfigs) {\n if (clock.has('label') && clock.has('timezone')) {\n let label = clock.getString('label');\n\n const options = {\n timeZone: clock.getString('timezone'),\n ...timeFormat,\n };\n\n try {\n new Date().toLocaleString(lang, options);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `The timezone ${options.timeZone} is invalid. Defaulting to GMT`,\n );\n options.timeZone = 'GMT';\n label = 'GMT';\n }\n\n const time = d.toLocaleTimeString(lang, options);\n clocks.push({ time, label });\n }\n }\n return clocks;\n}\n\n/**\n * Please use the HeaderWorldClock in the home plugin\n *\n * @public\n * @deprecated in favor of the HeaderWorldClock which is found in the to home plugin\n */\nexport function HomepageTimer(_props) {\n const configApi = useApi(configApiRef);\n\n const defaultTimes = [];\n const [clocks, setTimes] = React.useState(defaultTimes);\n\n React.useEffect(() => {\n setTimes(getTimes(configApi));\n\n const intervalId = setInterval(() => {\n setTimes(getTimes(configApi));\n }, 1000);\n\n return () => {\n clearInterval(intervalId);\n };\n }, [configApi]);\n\n if (clocks.length !== 0) {\n return (\n React.createElement(React.Fragment, null\n , clocks.map(clock => (\n React.createElement(HeaderLabel, {\n label: clock.label,\n value: clock.time,\n key: clock.label,}\n )\n ))\n )\n );\n }\n return null;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createStyles, makeStyles, } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport React from 'react';\n\n\n/** @public */\n\n\nconst styles = (theme) =>\n createStyles({\n root: {\n color: theme.palette.common.white,\n padding: theme.spacing(2, 2, 3),\n backgroundImage: theme.palette.bursts.gradient.linear,\n backgroundPosition: 0,\n backgroundSize: 'inherit',\n },\n });\n\nconst useStyles = makeStyles(styles, { name: 'BackstageItemCardHeader' });\n\n/** @public */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * A simple card header, rendering a default look for \"item cards\" - cards that\n * are arranged in a grid for users to select among several options.\n *\n * This component expects to be placed within a MUI <CardMedia>.\n *\n * Styles for the header can be overridden using the `classes` prop, e.g.:\n *\n * `<ItemCardHeader title=\"Hello\" classes={{ root: myClassName }} />`\n *\n * @public\n */\nexport function ItemCardHeader(props) {\n const { title, subtitle, children } = props;\n const classes = useStyles(props);\n return (\n React.createElement('div', { className: classes.root,}\n , subtitle && (\n React.createElement(Typography, { variant: \"subtitle2\", component: \"h3\",}\n , subtitle\n )\n )\n , title && (\n React.createElement(Typography, { variant: \"h6\", component: \"h4\",}\n , title\n )\n )\n , children\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Box from '@material-ui/core/Box';\nimport Card from '@material-ui/core/Card';\nimport CardActions from '@material-ui/core/CardActions';\nimport CardContent from '@material-ui/core/CardContent';\nimport CardMedia from '@material-ui/core/CardMedia';\nimport Chip from '@material-ui/core/Chip';\nimport React, { } from 'react';\nimport { Button } from '../../components';\nimport { ItemCardHeader } from './ItemCardHeader';\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * This card type has been deprecated. Instead use plain MUI Card and helpers\n * where appropriate.\n *\n * ```\n * <Card>\n * <CardMedia>\n * <ItemCardHeader title=\"My Card\" subtitle=\"neat!\" />\n * </CardMedia>\n * <CardContent>\n * Some text\n * </CardContent>\n * <CardActions>\n * <Button color=\"primary\" to=\"https://backstage.io\">\n * Get Started\n * </Button>\n * </CardActions>\n * </Card>\n * ```\n *\n * @deprecated Use plain MUI `<Card>` and composable helpers instead.\n * @see https://material-ui.com/components/cards/\n */\nexport function ItemCard(props) {\n const { description, tags, title, type, subtitle, label, onClick, href } =\n props;\n return (\n React.createElement(Card, null\n , React.createElement(CardMedia, null\n , React.createElement(ItemCardHeader, { title: title, subtitle: subtitle || type,} )\n )\n , React.createElement(CardContent, null\n , tags?.length ? (\n React.createElement(Box, null\n , tags.map((tag, i) => (\n React.createElement(Chip, { size: \"small\", label: tag, key: i,} )\n ))\n )\n ) : null\n , description\n )\n , React.createElement(CardActions, null\n , !href && (\n React.createElement(Button, { to: \"#\", onClick: onClick, color: \"primary\",}\n , label\n )\n )\n , href && (\n React.createElement(Button, { to: href, color: \"primary\",}\n , label\n )\n )\n )\n )\n );\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createStyles,\n makeStyles,\n\n\n} from '@material-ui/core/styles';\nimport React from 'react';\n\n/** @public */\n\n\nconst styles = (theme) =>\n createStyles({\n root: {\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(22em, 1fr))',\n gridAutoRows: '1fr',\n gridGap: theme.spacing(2),\n },\n });\n\nconst useStyles = makeStyles(styles, { name: 'BackstageItemCardGrid' });\n\n/** @public */\n\n\n\n\n\n\n\n/**\n * A default grid to use when arranging \"item cards\" - cards that let users\n * select among several options.\n *\n * The immediate children are expected to be MUI Card components.\n *\n * Styles for the grid can be overridden using the `classes` prop, e.g.:\n *\n * `<ItemCardGrid title=\"Hello\" classes={{ root: myClassName }} />`\n *\n * This can be useful for e.g. overriding gridTemplateColumns to adapt the\n * minimum size of the cells to fit the content better.\n *\n * @public\n */\nexport function ItemCardGrid(props) {\n const { children, ...otherProps } = props;\n const classes = useStyles(otherProps);\n return (\n React.createElement('div', { className: classes.root, ...otherProps,}\n , children\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useContext } from 'react';\n\nimport { makeStyles, ThemeProvider } from '@material-ui/core/styles';\nimport { SidebarPinStateContext } from '../Sidebar/Page';\n\n\n\nconst useStyles = makeStyles(\n () => ({\n root: ({ isMobile }) => ({\n display: 'grid',\n gridTemplateAreas:\n \"'pageHeader pageHeader pageHeader' 'pageSubheader pageSubheader pageSubheader' 'pageNav pageContent pageSidebar'\",\n gridTemplateRows: 'max-content auto 1fr',\n gridTemplateColumns: 'auto 1fr auto',\n height: isMobile ? '100%' : '100vh',\n overflowY: 'auto',\n }),\n }),\n { name: 'BackstagePage' },\n);\n\n\n\n\n\n\nexport function Page(props) {\n const { themeId, children } = props;\n const { isMobile } = useContext(SidebarPinStateContext);\n const classes = useStyles({ isMobile });\n return (\n React.createElement(ThemeProvider, {\n theme: (baseTheme) => ({\n ...baseTheme,\n page: baseTheme.getPageTheme({ themeId }),\n }),}\n \n , React.createElement('div', { className: classes.root,}, children)\n )\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\n\nimport { Header } from '../Header';\nimport { Page } from './Page';\n\n\n\n\n\nexport function PageWithHeader(props) {\n const { themeId, children, ...restProps } = props;\n return (\n React.createElement(Page, { themeId: themeId,}\n , React.createElement(Header, { ...restProps,} )\n , children\n )\n );\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { z } from 'zod';\n\nexport const proxiedSessionSchema = z.object({\n providerInfo: z.object({}).catchall(z.unknown()).optional(),\n profile: z.object({\n email: z.string().optional(),\n displayName: z.string().optional(),\n picture: z.string().optional(),\n }),\n backstageIdentity: z.object({\n token: z.string(),\n identity: z.object({\n type: z.literal('user'),\n userEntityRef: z.string(),\n ownershipEntityRefs: z.array(z.string()),\n }),\n }),\n});\n\n/**\n * Generic session information for proxied sign-in providers, e.g. common\n * reverse authenticating proxy implementations.\n *\n * @public\n */\n\n\n\n\n\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { ResponseError } from '@backstage/errors';\nimport { proxiedSessionSchema } from './types';\n\nexport const DEFAULTS = {\n // The amount of time between token refreshes, if we fail to get an actual\n // value out of the exp claim\n defaultTokenExpiryMillis: 5 * 60 * 1000,\n // The amount of time before the actual expiry of the Backstage token, that we\n // shall start trying to get a new one\n tokenExpiryMarginMillis: 5 * 60 * 1000,\n} ;\n\n// When the token expires, with some margin\nexport function tokenToExpiry(jwtToken) {\n const fallback = new Date(Date.now() + DEFAULTS.defaultTokenExpiryMillis);\n if (!jwtToken) {\n return fallback;\n }\n\n const [_header, rawPayload, _signature] = jwtToken.split('.');\n const payload = JSON.parse(atob(rawPayload));\n if (typeof payload.exp !== 'number') {\n return fallback;\n }\n\n return new Date(payload.exp * 1000 - DEFAULTS.tokenExpiryMarginMillis);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * An identity API that gets the user auth information solely based on a\n * provider's `/refresh` endpoint.\n */\nexport class ProxiedSignInIdentity {\n options;\n abortController;\n state;\n\n constructor(options) {\n this.options = options;\n this.abortController = new AbortController();\n this.state = { type: 'empty' };\n }\n\n async start() {\n // Try to make a first fetch, bubble up any errors to the caller\n await this.getSessionAsync();\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getUserId} */\n getUserId() {\n const { backstageIdentity } = this.getSessionSync();\n const ref = backstageIdentity.identity.userEntityRef;\n const match = /^([^:/]+:)?([^:/]+\\/)?([^:/]+)$/.exec(ref);\n if (!match) {\n throw new TypeError(`Invalid user entity reference \"${ref}\"`);\n }\n\n return match[3];\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getIdToken} */\n async getIdToken() {\n const session = await this.getSessionAsync();\n return session.backstageIdentity.token;\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfile} */\n getProfile() {\n const session = this.getSessionSync();\n return session.profile;\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfileInfo} */\n async getProfileInfo() {\n const session = await this.getSessionAsync();\n return session.profile;\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getBackstageIdentity} */\n async getBackstageIdentity() {\n const session = await this.getSessionAsync();\n return session.backstageIdentity.identity;\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getCredentials} */\n async getCredentials() {\n const session = await this.getSessionAsync();\n return {\n token: session.backstageIdentity.token,\n };\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.signOut} */\n async signOut() {\n this.abortController.abort();\n }\n\n getSessionSync() {\n if (this.state.type === 'active') {\n return this.state.session;\n } else if (this.state.type === 'fetching' && this.state.previous) {\n return this.state.previous;\n }\n throw new Error('No session available. Try reloading your browser page.');\n }\n\n async getSessionAsync() {\n if (this.state.type === 'fetching') {\n return this.state.promise;\n } else if (\n this.state.type === 'active' &&\n new Date() < this.state.expiresAt\n ) {\n return this.state.session;\n }\n\n const previous =\n this.state.type === 'active' ? this.state.session : undefined;\n\n const promise = this.fetchSession().then(\n session => {\n this.state = {\n type: 'active',\n session,\n expiresAt: tokenToExpiry(session.backstageIdentity.token),\n };\n return session;\n },\n error => {\n this.state = {\n type: 'failed',\n error,\n };\n throw error;\n },\n );\n\n this.state = {\n type: 'fetching',\n promise,\n previous,\n };\n\n return promise;\n }\n\n async fetchSession() {\n const baseUrl = await this.options.discoveryApi.getBaseUrl('auth');\n\n // Note that we do not use the fetchApi here, since this all happens before\n // sign-in completes so there can be no automatic token injection and\n // similar.\n const response = await fetch(\n `${baseUrl}/${this.options.provider}/refresh`,\n {\n signal: this.abortController.signal,\n headers: { 'x-requested-with': 'XMLHttpRequest' },\n credentials: 'include',\n },\n );\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return proxiedSessionSchema.parse(await response.json());\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n discoveryApiRef,\n\n useApi,\n} from '@backstage/core-plugin-api';\nimport React from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport { ErrorPanel } from '../../components/ErrorPanel';\nimport { Progress } from '../../components/Progress';\nimport { ProxiedSignInIdentity } from './ProxiedSignInIdentity';\n\n/**\n * Props for {@link ProxiedSignInPage}.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n/**\n * A sign-in page that has no user interface of its own. Instead, it relies on\n * sign-in being performed by a reverse authenticating proxy that Backstage is\n * deployed behind, and leverages its session handling.\n *\n * @remarks\n *\n * This sign-in page is useful when you are using products such as Google\n * Identity-Aware Proxy or AWS Application Load Balancer or similar, to front\n * your Backstage installation. This sign-in page implementation will silently\n * and regularly punch through the proxy to the auth backend to refresh your\n * frontend session information, without requiring user interaction.\n *\n * @public\n */\nexport const ProxiedSignInPage = (props) => {\n const discoveryApi = useApi(discoveryApiRef);\n\n const { loading, error } = useAsync(async () => {\n const identity = new ProxiedSignInIdentity({\n provider: props.provider,\n discoveryApi,\n });\n\n await identity.start();\n\n props.onSignInSuccess(identity);\n }, []);\n\n if (loading) {\n return React.createElement(Progress, null );\n } else if (error) {\n return (\n React.createElement(ErrorPanel, {\n title: \"You do not appear to be signed in. Please try reloading the browser page.\" ,\n error: error,}\n )\n );\n }\n\n return null;\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Grid from '@material-ui/core/Grid';\n\n\n\nexport const useStyles = makeStyles(\n {\n container: {\n padding: 0,\n listStyle: 'none',\n },\n item: {\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n maxWidth: '400px',\n margin: 0,\n padding: 0,\n },\n },\n { name: 'BackstageSignInPage' },\n);\n\nexport const GridItem = ({ children }) => {\n const classes = useStyles();\n\n return (\n React.createElement(Grid, { component: \"li\", item: true, classes: classes,}\n , children\n )\n );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport class GuestUserIdentity {\n getUserId() {\n return 'guest';\n }\n\n async getIdToken() {\n return undefined;\n }\n\n getProfile() {\n return {\n email: 'guest@example.com',\n displayName: 'Guest',\n };\n }\n\n async getProfileInfo() {\n return {\n email: 'guest@example.com',\n displayName: 'Guest',\n };\n }\n\n async getBackstageIdentity() {\n const userEntityRef = `user:default/guest`;\n return {\n type: 'user',\n userEntityRef,\n ownershipEntityRefs: [userEntityRef],\n };\n }\n\n async getCredentials() {\n return {};\n }\n\n async signOut() {}\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nfunction parseJwtPayload(token) {\n const [_header, payload, _signature] = token.split('.');\n return JSON.parse(atob(payload));\n}\n\n\n\n\n\n\n\n\n/** @internal */\nexport class LegacyUserIdentity {\n constructor( result) {;this.result = result;}\n\n getUserId() {\n return this.result.userId;\n }\n\n static fromResult(result) {\n return new LegacyUserIdentity(result);\n }\n\n async getIdToken() {\n return this.result.getIdToken?.();\n }\n\n getProfile() {\n return this.result.profile;\n }\n\n async getProfileInfo() {\n return this.result.profile;\n }\n\n async getBackstageIdentity() {\n const token = await this.getIdToken();\n\n if (!token) {\n const userEntityRef = `user:default/${this.getUserId()}`;\n return {\n type: 'user',\n userEntityRef,\n ownershipEntityRefs: [userEntityRef],\n };\n }\n\n const { sub, ent } = parseJwtPayload(token);\n return {\n type: 'user',\n userEntityRef: sub,\n ownershipEntityRefs: ent ?? [],\n };\n }\n\n async getCredentials() {\n const token = await this.result.getIdToken?.();\n return { token };\n }\n\n async signOut() {\n return this.result.signOut?.();\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { GuestUserIdentity } from './GuestUserIdentity';\nimport { LegacyUserIdentity } from './LegacyUserIdentity';\n\n// TODO(Rugvip): This and the other IdentityApi implementations still implement\n// the old removed methods. This is to allow for backwards compatibility\n// with old plugins that still consume this API. We will leave these in\n// place as a hidden compatibility for a couple of months.\n// The AppIdentityProxy warns in case any of these methods are called.\n\n/**\n * An implementation of the IdentityApi that is constructed using\n * various backstage user identity representations.\n *\n * @public\n */\nexport class UserIdentity {\n profilePromise;\n /**\n * Creates a new IdentityApi that acts as a Guest User.\n *\n * @public\n */\n static createGuest() {\n return new GuestUserIdentity();\n }\n\n /**\n * Creates a new IdentityApi using a legacy SignInResult object.\n *\n * @public\n */\n static fromLegacy(result\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n) {\n return LegacyUserIdentity.fromResult(result);\n }\n\n /**\n * Creates a new IdentityApi implementation using a user identity\n * and an auth API that will be used to request backstage tokens.\n *\n * @public\n */\n static create(options\n\n\n\n\n\n\n\n\n\n\n) {\n return new UserIdentity(options.identity, options.authApi, options.profile);\n }\n\n constructor(\n identity,\n authApi\n\n,\n profile,\n ) {;this.identity = identity;this.authApi = authApi;this.profile = profile;}\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getUserId} */\n getUserId() {\n const ref = this.identity.userEntityRef;\n const match = /^([^:/]+:)?([^:/]+\\/)?([^:/]+)$/.exec(ref);\n if (!match) {\n throw new TypeError(`Invalid user entity reference \"${ref}\"`);\n }\n\n return match[3];\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getIdToken} */\n async getIdToken() {\n const identity = await this.authApi.getBackstageIdentity();\n return identity.token;\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfile} */\n getProfile() {\n if (!this.profile) {\n throw new Error(\n 'The identity API does not implement synchronous profile fetching, use getProfileInfo() instead',\n );\n }\n return this.profile;\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfileInfo} */\n async getProfileInfo() {\n if (this.profilePromise) {\n return await this.profilePromise;\n }\n\n try {\n this.profilePromise = this.authApi.getProfile() ;\n return await this.profilePromise;\n } catch (ex) {\n this.profilePromise = undefined;\n throw ex;\n }\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getBackstageIdentity} */\n async getBackstageIdentity() {\n return this.identity;\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getCredentials} */\n async getCredentials() {\n const identity = await this.authApi.getBackstageIdentity();\n return { token: identity.token };\n }\n\n /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.signOut} */\n async signOut() {\n return this.authApi.signOut();\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport Typography from '@material-ui/core/Typography';\nimport Button from '@material-ui/core/Button';\nimport { InfoCard } from '../InfoCard/InfoCard';\n\n\n\n\n\n\nimport { useApi, errorApiRef } from '@backstage/core-plugin-api';\nimport { GridItem } from './styles';\nimport { ForwardedError } from '@backstage/errors';\nimport { UserIdentity } from './UserIdentity';\n\nconst Component = ({ config, onSignInSuccess }) => {\n const { apiRef, title, message } = config ;\n const authApi = useApi(apiRef);\n const errorApi = useApi(errorApiRef);\n\n const handleLogin = async () => {\n try {\n const identityResponse = await authApi.getBackstageIdentity({\n instantPopup: true,\n });\n if (!identityResponse) {\n throw new Error(\n `The ${title} provider is not configured to support sign-in`,\n );\n }\n\n const profile = await authApi.getProfile();\n\n onSignInSuccess(\n UserIdentity.create({\n identity: identityResponse.identity,\n profile,\n authApi,\n }),\n );\n } catch (error) {\n errorApi.post(new ForwardedError('Login failed', error));\n }\n };\n\n return (\n React.createElement(GridItem, null\n , React.createElement(InfoCard, {\n variant: \"fullHeight\",\n title: title,\n actions: \n React.createElement(Button, { color: \"primary\", variant: \"outlined\", onClick: handleLogin,}, \"Sign In\"\n\n )\n ,}\n \n , React.createElement(Typography, { variant: \"body1\",}, message)\n )\n )\n );\n};\n\nconst loader = async (apis, apiRef) => {\n const authApi = apis.get(apiRef);\n\n const identityResponse = await authApi.getBackstageIdentity({\n optional: true,\n });\n\n if (!identityResponse) {\n return undefined;\n }\n\n const profile = await authApi.getProfile();\n\n return UserIdentity.create({\n identity: identityResponse.identity,\n profile,\n authApi,\n });\n};\n\nexport const commonProvider = { Component, loader };\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport Typography from '@material-ui/core/Typography';\nimport Button from '@material-ui/core/Button';\nimport { InfoCard } from '../InfoCard/InfoCard';\nimport { GridItem } from './styles';\n\nimport { GuestUserIdentity } from './GuestUserIdentity';\n\nconst Component = ({ onSignInSuccess }) => (\n React.createElement(GridItem, null\n , React.createElement(InfoCard, {\n title: \"Guest\",\n variant: \"fullHeight\",\n actions: \n React.createElement(Button, {\n color: \"primary\",\n variant: \"outlined\",\n onClick: () => onSignInSuccess(new GuestUserIdentity()),}\n , \"Enter\"\n\n )\n ,}\n \n , React.createElement(Typography, { variant: \"body1\",}, \"Enter as a Guest User.\"\n\n , React.createElement('br', null ), \"You will not have a verified identity,\"\n\n , React.createElement('br', null ), \"meaning some features might be unavailable.\"\n\n )\n )\n )\n);\n\nconst loader = async () => {\n return new GuestUserIdentity();\n};\n\nexport const guestProvider = { Component, loader };\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { useForm, } from 'react-hook-form';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport Button from '@material-ui/core/Button';\nimport FormControl from '@material-ui/core/FormControl';\nimport TextField from '@material-ui/core/TextField';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport isEmpty from 'lodash/isEmpty';\nimport { InfoCard } from '../InfoCard/InfoCard';\n\nimport { GridItem } from './styles';\nimport { UserIdentity } from './UserIdentity';\n\n// accept base64url format according to RFC7515 (https://tools.ietf.org/html/rfc7515#section-3)\nconst ID_TOKEN_REGEX = /^[a-z0-9_\\-]+\\.[a-z0-9_\\-]+\\.[a-z0-9_\\-]+$/i;\n\n/** @public */\n\n\nconst useFormStyles = makeStyles(\n theme => ({\n form: {\n display: 'flex',\n flexFlow: 'column nowrap',\n },\n button: {\n alignSelf: 'center',\n marginTop: theme.spacing(2),\n },\n }),\n { name: 'BackstageCustomProvider' },\n);\n\n\n\n\n\n\nconst asInputRef = (renderResult) => {\n const { ref, ...rest } = renderResult;\n return {\n inputRef: ref,\n ...rest,\n };\n};\n\nconst Component = ({ onSignInSuccess }) => {\n const classes = useFormStyles();\n const { register, handleSubmit, formState } = useForm({\n mode: 'onChange',\n });\n\n const { errors } = formState;\n\n const handleResult = ({ userId }) => {\n onSignInSuccess(\n UserIdentity.fromLegacy({\n userId,\n profile: {\n email: `${userId}@example.com`,\n },\n }),\n );\n };\n\n return (\n React.createElement(GridItem, null\n , React.createElement(InfoCard, { title: \"Custom User\" , variant: \"fullHeight\",}\n , React.createElement(Typography, { variant: \"body1\",}, \"Enter your own User ID and credentials.\"\n\n , React.createElement('br', null ), \"This selection will not be stored.\"\n\n )\n\n , React.createElement('form', { className: classes.form, onSubmit: handleSubmit(handleResult),}\n , React.createElement(FormControl, null\n , React.createElement(TextField, {\n ...asInputRef(register('userId', { required: true })),\n label: \"User ID\" ,\n margin: \"normal\",\n error: Boolean(errors.userId),}\n )\n , errors.userId && (\n React.createElement(FormHelperText, { error: true,}, errors.userId.message)\n )\n )\n , React.createElement(FormControl, null\n , React.createElement(TextField, {\n ...asInputRef(\n register('idToken', {\n required: false,\n validate: token =>\n !token ||\n ID_TOKEN_REGEX.test(token) ||\n 'Token is not a valid OpenID Connect JWT Token',\n }),\n ),\n label: \"ID Token (optional)\" ,\n margin: \"normal\",\n autoComplete: \"off\",\n error: Boolean(errors.idToken),}\n )\n , errors.idToken && (\n React.createElement(FormHelperText, { error: true,}, errors.idToken.message)\n )\n )\n , React.createElement(Button, {\n type: \"submit\",\n color: \"primary\",\n variant: \"outlined\",\n className: classes.button,\n disabled: !formState?.isDirty || !isEmpty(errors),}\n , \"Continue\"\n\n )\n )\n )\n )\n );\n};\n\n// Custom provider doesn't store credentials\nconst loader = async () => undefined;\n\nexport const customProvider = { Component, loader };\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useLayoutEffect, useState, useMemo, useCallback } from 'react';\nimport {\n\n useApi,\n useApiHolder,\n errorApiRef,\n\n} from '@backstage/core-plugin-api';\n\n\n\n\n\nimport { commonProvider } from './commonProvider';\nimport { guestProvider } from './guestProvider';\nimport { customProvider } from './customProvider';\nimport { IdentityApiSignOutProxy } from './IdentityApiSignOutProxy';\n\nconst PROVIDER_STORAGE_KEY = '@backstage/core:SignInPage:provider';\n\n\n\n\n\n\n\n\n\nconst signInProviders = {\n guest: guestProvider,\n custom: customProvider,\n common: commonProvider,\n};\n\nfunction validateIDs(id, providers) {\n if (id in providers)\n throw new Error(\n `\"${id}\" ID is duplicated. IDs of identity providers have to be unique.`,\n );\n}\n\nexport function getSignInProviders(\n identityProviders,\n) {\n const providers = identityProviders.reduce(\n (acc, config) => {\n if (typeof config === 'string') {\n validateIDs(config, acc);\n acc[config] = { components: signInProviders[config], id: config };\n\n return acc;\n }\n\n const { id } = config ;\n validateIDs(id, acc);\n\n acc[id] = { components: signInProviders.common, id, config };\n\n return acc;\n },\n {},\n );\n\n return providers;\n}\n\nexport const useSignInProviders = (\n providers,\n onSignInSuccess,\n) => {\n const errorApi = useApi(errorApiRef);\n const apiHolder = useApiHolder();\n const [loading, setLoading] = useState(true);\n\n // This decorates the result with sign out logic from this hook\n const handleWrappedResult = useCallback(\n (identityApi) => {\n onSignInSuccess(\n IdentityApiSignOutProxy.from({\n identityApi,\n signOut: async () => {\n localStorage.removeItem(PROVIDER_STORAGE_KEY);\n await identityApi.signOut?.();\n },\n }),\n );\n },\n [onSignInSuccess],\n );\n\n // In this effect we check if the user has already selected an existing login\n // provider, and in that case try to load an existing session for the provider.\n useLayoutEffect(() => {\n if (!loading) {\n return undefined;\n }\n\n // We can't use storageApi here, as it might have a dependency on the IdentityApi\n const selectedProviderId = localStorage.getItem(\n PROVIDER_STORAGE_KEY,\n ) ;\n\n // No provider selected, let the user pick one\n if (selectedProviderId === null) {\n setLoading(false);\n return undefined;\n }\n\n const provider = providers[selectedProviderId];\n if (!provider) {\n setLoading(false);\n return undefined;\n }\n\n let didCancel = false;\n\n provider.components\n .loader(apiHolder, provider.config?.apiRef)\n .then(result => {\n if (didCancel) {\n return;\n }\n if (result) {\n handleWrappedResult(result);\n } else {\n setLoading(false);\n }\n })\n .catch(error => {\n if (didCancel) {\n return;\n }\n localStorage.removeItem(PROVIDER_STORAGE_KEY);\n errorApi.post(error);\n setLoading(false);\n });\n\n return () => {\n didCancel = true;\n };\n }, [\n loading,\n errorApi,\n onSignInSuccess,\n apiHolder,\n providers,\n handleWrappedResult,\n ]);\n\n // This renders all available sign-in providers\n const elements = useMemo(\n () =>\n Object.keys(providers).map(key => {\n const provider = providers[key];\n\n const { Component } = provider.components;\n\n const handleSignInSuccess = (result) => {\n localStorage.setItem(PROVIDER_STORAGE_KEY, provider.id);\n\n handleWrappedResult(result);\n };\n\n return (\n React.createElement(Component, {\n key: provider.id,\n config: provider.config,\n onSignInSuccess: handleSignInSuccess,}\n )\n );\n }),\n [providers, handleWrappedResult],\n );\n\n return [loading, elements];\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n configApiRef,\n\n useApi,\n} from '@backstage/core-plugin-api';\nimport { UserIdentity } from './UserIdentity';\nimport Button from '@material-ui/core/Button';\nimport Grid from '@material-ui/core/Grid';\nimport Typography from '@material-ui/core/Typography';\nimport React, { useState } from 'react';\nimport useMount from 'react-use/lib/useMount';\nimport { Progress } from '../../components/Progress';\nimport { Content } from '../Content/Content';\nimport { ContentHeader } from '../ContentHeader/ContentHeader';\nimport { Header } from '../Header';\nimport { InfoCard } from '../InfoCard';\nimport { Page } from '../Page';\nimport { getSignInProviders, useSignInProviders } from './providers';\nimport { GridItem, useStyles } from './styles';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const MultiSignInPage = ({\n onSignInSuccess,\n providers = [],\n title,\n align = 'left',\n}) => {\n const configApi = useApi(configApiRef);\n const classes = useStyles();\n\n const signInProviders = getSignInProviders(providers);\n const [loading, providerElements] = useSignInProviders(\n signInProviders,\n onSignInSuccess,\n );\n\n if (loading) {\n return React.createElement(Progress, null );\n }\n\n return (\n React.createElement(Page, { themeId: \"home\",}\n , React.createElement(Header, { title: configApi.getString('app.title'),} )\n , React.createElement(Content, null\n , title && React.createElement(ContentHeader, { title: title, textAlign: align,} )\n , React.createElement(Grid, {\n container: true,\n justifyContent: align === 'center' ? align : 'flex-start',\n spacing: 2,\n component: \"ul\",\n classes: classes,}\n \n , providerElements\n )\n )\n )\n );\n};\n\nexport const SingleSignInPage = ({\n provider,\n auto,\n onSignInSuccess,\n}) => {\n const classes = useStyles();\n const authApi = useApi(provider.apiRef);\n const configApi = useApi(configApiRef);\n\n const [error, setError] = useState();\n\n // The SignIn component takes some time to decide whether the user is logged-in or not.\n // showLoginPage is used to prevent a glitch-like experience where the sign-in page is\n // displayed for a split second when the user is already logged-in.\n const [showLoginPage, setShowLoginPage] = useState(false);\n\n \n const login = async ({ checkExisting, showPopup }) => {\n try {\n let identityResponse;\n if (checkExisting) {\n // Do an initial check if any logged-in session exists\n identityResponse = await authApi.getBackstageIdentity({\n optional: true,\n });\n }\n\n // If no session exists, show the sign-in page\n if (!identityResponse && (showPopup || auto)) {\n // Unless auto is set to true, this step should not happen.\n // When user intentionally clicks the Sign In button, autoShowPopup is set to true\n setShowLoginPage(true);\n identityResponse = await authApi.getBackstageIdentity({\n instantPopup: true,\n });\n if (!identityResponse) {\n throw new Error(\n `The ${provider.title} provider is not configured to support sign-in`,\n );\n }\n }\n\n if (!identityResponse) {\n setShowLoginPage(true);\n return;\n }\n\n const profile = await authApi.getProfile();\n onSignInSuccess(\n UserIdentity.create({\n identity: identityResponse.identity,\n authApi,\n profile,\n }),\n );\n } catch (err) {\n // User closed the sign-in modal\n setError(err);\n setShowLoginPage(true);\n }\n };\n\n useMount(() => login({ checkExisting: true }));\n\n return showLoginPage ? (\n React.createElement(Page, { themeId: \"home\",}\n , React.createElement(Header, { title: configApi.getString('app.title'),} )\n , React.createElement(Content, null\n , React.createElement(Grid, {\n container: true,\n justifyContent: \"center\",\n spacing: 2,\n component: \"ul\",\n classes: classes,}\n \n , React.createElement(GridItem, null\n , React.createElement(InfoCard, {\n variant: \"fullHeight\",\n title: provider.title,\n actions: \n React.createElement(Button, {\n color: \"primary\",\n variant: \"outlined\",\n onClick: () => {\n login({ showPopup: true });\n },}\n , \"Sign In\"\n\n )\n ,}\n \n , React.createElement(Typography, { variant: \"body1\",}, provider.message)\n , error && error.name !== 'PopupRejectedError' && (\n React.createElement(Typography, { variant: \"body1\", color: \"error\",}\n , error.message\n )\n )\n )\n )\n )\n )\n )\n ) : (\n React.createElement(Progress, null )\n );\n};\n\nexport function SignInPage(props) {\n if ('provider' in props) {\n return React.createElement(SingleSignInPage, { ...props,} );\n }\n\n return React.createElement(MultiSignInPage, { ...props,} );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Card from '@material-ui/core/Card';\nimport CardContent from '@material-ui/core/CardContent';\nimport CardHeader from '@material-ui/core/CardHeader';\nimport Divider from '@material-ui/core/Divider';\nimport { makeStyles, withStyles } from '@material-ui/core/styles';\nimport Tab, { } from '@material-ui/core/Tab';\nimport Tabs from '@material-ui/core/Tabs';\nimport React, {\n\n\n\n useState,\n} from 'react';\nimport { BottomLink, } from '../BottomLink';\nimport { ErrorBoundary, } from '../ErrorBoundary';\n\n\n\nconst useTabsStyles = makeStyles(\n theme => ({\n root: {\n padding: theme.spacing(0, 2, 0, 2.5),\n minHeight: theme.spacing(3),\n },\n indicator: {\n backgroundColor: theme.palette.info.main,\n height: theme.spacing(0.3),\n },\n }),\n { name: 'BackstageTabbedCard' },\n);\n\n/** @public */\n\n\nconst BoldHeader = withStyles(\n theme => ({\n root: { padding: theme.spacing(2, 2, 2, 2.5), display: 'inline-block' },\n title: { fontWeight: 700 },\n subheader: { paddingTop: theme.spacing(1) },\n }),\n { name: 'BackstageTabbedCardBoldHeader' },\n)(CardHeader);\n\n\n\n\n\n\n\n\n\n\n\n\nexport function TabbedCard(props) {\n const {\n slackChannel,\n errorBoundaryProps,\n children,\n title,\n deepLink,\n value,\n onChange,\n } = props;\n const tabsClasses = useTabsStyles();\n const [selectedIndex, selectIndex] = useState(0);\n\n const handleChange = onChange\n ? onChange\n : (_ev, newSelectedIndex) => selectIndex(newSelectedIndex);\n\n let selectedTabContent;\n if (!value) {\n React.Children.map(children, (child, index) => {\n if (index === selectedIndex) selectedTabContent = child?.props.children;\n });\n } else {\n React.Children.map(children, child => {\n if (child?.props.value === value)\n selectedTabContent = child?.props.children;\n });\n }\n\n const errProps =\n errorBoundaryProps || (slackChannel ? { slackChannel } : {});\n\n return (\n React.createElement(Card, null\n , React.createElement(ErrorBoundary, { ...errProps,}\n , title && React.createElement(BoldHeader, { title: title,} )\n , React.createElement(Tabs, {\n selectionFollowsFocus: true,\n classes: tabsClasses,\n value: value || selectedIndex,\n onChange: handleChange,}\n \n , children\n )\n , React.createElement(Divider, null )\n , React.createElement(CardContent, null, selectedTabContent)\n , deepLink && React.createElement(BottomLink, { ...deepLink,} )\n )\n )\n );\n}\n\n/** @public */\n\n\nconst useCardTabStyles = makeStyles(\n theme => ({\n root: {\n minWidth: theme.spacing(6),\n minHeight: theme.spacing(3),\n margin: theme.spacing(0, 2, 0, 0),\n padding: theme.spacing(0.5, 0, 0.5, 0),\n textTransform: 'none',\n '&:hover': {\n opacity: 1,\n backgroundColor: 'transparent',\n color: theme.palette.text.primary,\n },\n },\n selected: {\n fontWeight: 'bold',\n },\n }),\n { name: 'BackstageCardTab' },\n);\n\n\n\n\n\n/**\n * Card tab component used in {@link TabbedCard}\n *\n * @public\n *\n */\nexport function CardTab(props) {\n const { children, ...restProps } = props;\n const classes = useCardTabStyles();\n\n return React.createElement(Tab, { disableRipple: true, classes: classes, ...restProps,} );\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createVersionedContext,\n createVersionedValueMap,\n} from '@backstage/version-bridge';\nimport React, { useContext } from 'react';\n\n\nconst AnalyticsReactContext =\n createVersionedContext('analytics-context');\n\n/**\n * A \"private\" (to this package) hook that enables context inheritance and a\n * way to read Analytics Context values at event capture-time.\n *\n * @internal\n */\nexport const useAnalyticsContext = () => {\n const theContext = useContext(AnalyticsReactContext);\n\n // Provide a default value if no value exists.\n if (theContext === undefined) {\n return {\n routeRef: 'unknown',\n pluginId: 'root',\n extension: 'App',\n };\n }\n\n // This should probably never happen, but check for it.\n const theValue = theContext.atVersion(1);\n if (theValue === undefined) {\n throw new Error('No context found for version 1.');\n }\n\n return theValue;\n};\n\n/**\n * Provides components in the child react tree an Analytics Context, ensuring\n * all analytics events captured within the context have relevant attributes.\n *\n * @remarks\n *\n * Analytics contexts are additive, meaning the context ultimately emitted with\n * an event is the combination of all contexts in the parent tree.\n *\n * @alpha\n */\nexport const AnalyticsContext = (options\n\n\n) => {\n const { attributes, children } = options;\n\n const parentValues = useAnalyticsContext();\n const combinedValue = {\n ...parentValues,\n ...attributes,\n };\n\n const versionedCombinedValue = createVersionedValueMap({ 1: combinedValue });\n return (\n React.createElement(AnalyticsReactContext.Provider, { value: versionedCombinedValue,}\n , children\n )\n );\n};\n\n/**\n * Returns an HOC wrapping the provided component in an Analytics context with\n * the given values.\n *\n * @param Component - Component to be wrapped with analytics context attributes\n * @param values - Analytics context key/value pairs.\n * @internal\n */\nexport function withAnalyticsContext(\n Component,\n values,\n) {\n const ComponentWithAnalyticsContext = (props) => {\n return (\n React.createElement(AnalyticsContext, { attributes: values,}\n , React.createElement(Component, { ...props,} )\n )\n );\n };\n ComponentWithAnalyticsContext.displayName = `WithAnalyticsContext(${\n Component.displayName || Component.name || 'Component'\n })`;\n return ComponentWithAnalyticsContext;\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport class Tracker {\n constructor(\n analyticsApi,\n context = {\n routeRef: 'unknown',\n pluginId: 'root',\n extension: 'App',\n },\n ) {;this.analyticsApi = analyticsApi;this.context = context;}\n\n setContext(context) {\n this.context = context;\n }\n\n captureEvent(\n action,\n subject,\n {\n value,\n attributes,\n } = {},\n ) {\n try {\n this.analyticsApi.captureEvent({\n action,\n subject,\n value,\n attributes,\n context: this.context,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useAnalyticsContext } from './AnalyticsContext';\nimport {\n analyticsApiRef,\n\n\n useApi,\n} from '../apis';\nimport { useRef } from 'react';\nimport { Tracker } from './Tracker';\n\nfunction useAnalyticsApi() {\n try {\n return useApi(analyticsApiRef);\n } catch {\n return { captureEvent: () => {} };\n }\n}\n\n/**\n * Gets a pre-configured analytics tracker.\n *\n * @alpha\n */\nexport function useAnalytics() {\n const trackerRef = useRef(null);\n const context = useAnalyticsContext();\n // Our goal is to make this API truly optional for any/all consuming code\n // (including tests). This hook runs last to ensure hook order is, as much as\n // possible, maintained.\n const analyticsApi = useAnalyticsApi();\n\n function getTracker() {\n if (trackerRef.current === null) {\n trackerRef.current = new Tracker(analyticsApi);\n }\n return trackerRef.current;\n }\n\n const tracker = getTracker();\n tracker.setContext(context);\n\n return tracker;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createApiRef } from '../system';\n\n\n\n/**\n * This file contains declarations for common interfaces of auth-related APIs.\n * The declarations should be used to signal which type of authentication and\n * authorization methods each separate auth provider supports.\n *\n * For example, a Google OAuth provider that supports OAuth 2 and OpenID Connect,\n * would be declared as follows:\n *\n * const googleAuthApiRef = createApiRef<OAuthApi & OpenIDConnectApi>({ ... })\n */\n\n/**\n * Information about the auth provider.\n *\n * @remarks\n *\n * This information is used both to connect the correct auth provider in the backend, as\n * well as displaying the provider to the user.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Session state values passed to subscribers of the SessionApi.\n *\n * @public\n */\nexport var SessionState; (function (SessionState) {\n /**\n * User signed in.\n */\n const SignedIn = 'SignedIn'; SessionState[\"SignedIn\"] = SignedIn;\n /**\n * User not signed in.\n */\n const SignedOut = 'SignedOut'; SessionState[\"SignedOut\"] = SignedOut;\n})(SessionState || (SessionState = {}));\n\n/**\n * The SessionApi provides basic controls for any auth provider that is tied to a persistent session.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Provides authentication towards Google APIs and identities.\n *\n * @alpha This API is **EXPERIMENTAL** and might change in the future.\n *\n * @remarks\n *\n * See {@link https://developers.google.com/identity/protocols/googlescopes} for a full list of supported scopes.\n *\n * Note that the ID token payload is only guaranteed to contain the user's numerical Google ID,\n * email and expiration information. Do not rely on any other fields, as they might not be present.\n */\nexport const googleAuthApiRef\n\n\n\n\n\n = createApiRef({\n id: 'core.auth.google',\n});\n\n/**\n * Provides authentication towards GitHub APIs.\n *\n * @alpha This API is **EXPERIMENTAL** and might change in the future.\n *\n * @remarks\n *\n * See {@link https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/}\n * for a full list of supported scopes.\n */\nexport const githubAuthApiRef\n\n = createApiRef({\n id: 'core.auth.github',\n});\n\n/**\n * Provides authentication towards Okta APIs.\n *\n * @alpha This API is **EXPERIMENTAL** and might change in the future.\n *\n * @remarks\n *\n * See {@link https://developer.okta.com/docs/guides/implement-oauth-for-okta/scopes/}\n * for a full list of supported scopes.\n */\nexport const oktaAuthApiRef\n\n\n\n\n\n = createApiRef({\n id: 'core.auth.okta',\n});\n\n/**\n * Provides authentication towards GitLab APIs.\n *\n * @alpha This API is **EXPERIMENTAL** and might change in the future.\n *\n * @remarks\n *\n * See {@link https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#limiting-scopes-of-a-personal-access-token}\n * for a full list of supported scopes.\n */\nexport const gitlabAuthApiRef\n\n = createApiRef({\n id: 'core.auth.gitlab',\n});\n\n/**\n * Provides authentication towards Auth0 APIs.\n *\n * @remarks\n *\n * See {@link https://auth0.com/docs/scopes/current/oidc-scopes}\n * for a full list of supported scopes.\n *\n * @public\n * @deprecated See https://backstage.io/docs/api/deprecations#generic-auth-api-refs\n */\nexport const auth0AuthApiRef\n\n = createApiRef({\n id: 'core.auth.auth0',\n});\n\n/**\n * Provides authentication towards Microsoft APIs and identities.\n *\n * @alpha This API is **EXPERIMENTAL** and might change in the future.\n *\n * @remarks\n *\n * For more info and a full list of supported scopes, see:\n * - {@link https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent}\n * - {@link https://docs.microsoft.com/en-us/graph/permissions-reference}\n */\nexport const microsoftAuthApiRef\n\n\n\n\n\n = createApiRef({\n id: 'core.auth.microsoft',\n});\n\n/**\n * Provides authentication for custom identity providers.\n *\n * @public\n * @deprecated See https://backstage.io/docs/api/deprecations#generic-auth-api-refs\n */\nexport const oauth2ApiRef\n\n\n\n\n\n = createApiRef({\n id: 'core.auth.oauth2',\n});\n\n/**\n * Provides authentication for custom OpenID Connect identity providers.\n *\n * @public\n * @deprecated See https://backstage.io/docs/api/deprecations#generic-auth-api-refs\n */\nexport const oidcAuthApiRef\n\n\n\n\n\n = createApiRef({\n id: 'core.auth.oidc',\n});\n\n/**\n * Provides authentication for SAML-based identity providers.\n *\n * @public\n * @deprecated See https://backstage.io/docs/api/deprecations#generic-auth-api-refs\n */\nexport const samlAuthApiRef\n\n = createApiRef({\n id: 'core.auth.saml',\n});\n\n/**\n * Provides authentication towards OneLogin APIs.\n *\n * @alpha This API is **EXPERIMENTAL** and might change in the future.\n */\nexport const oneloginAuthApiRef\n\n\n\n\n\n = createApiRef({\n id: 'core.auth.onelogin',\n});\n\n/**\n * Provides authentication towards Bitbucket APIs.\n *\n * @alpha This API is **EXPERIMENTAL** and might change in the future.\n * @remarks\n *\n * See {@link https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/}\n * for a full list of supported scopes.\n */\nexport const bitbucketAuthApiRef\n\n = createApiRef({\n id: 'core.auth.bitbucket',\n});\n\n/**\n * Provides authentication towards Atlassian APIs.\n *\n * @alpha This API is **EXPERIMENTAL** and might change in the future.\n * @remarks\n *\n * See {@link https://developer.atlassian.com/cloud/jira/platform/scopes-for-connect-and-oauth-2-3LO-apps/}\n * for a full list of supported scopes.\n */\nexport const atlassianAuthApiRef\n\n = createApiRef({\n id: 'core.auth.atlassian',\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createApiRef, } from '../system';\n\n\n/**\n * Message handled by the {@link AlertApi}.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * The {@link ApiRef} of {@link AlertApi}.\n *\n * @public\n */\nexport const alertApiRef = createApiRef({\n id: 'core.alert',\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createApiRef } from '../system';\n\n\n/**\n * Represents an event worth tracking in an analytics system that could inform\n * how users of a Backstage instance are using its features.\n *\n * @alpha\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * **EXPERIMENTAL**\n *\n * The {@link ApiRef} of {@link AnalyticsApi}.\n *\n * @alpha\n */\nexport const analyticsApiRef = createApiRef({\n id: 'core.analytics',\n});\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { createApiRef } from '../system';\n\n\n/**\n * Describes a theme provided by the app.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * The {@link ApiRef} of {@link AppThemeApi}.\n *\n * @public\n */\nexport const appThemeApiRef = createApiRef({\n id: 'core.apptheme',\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createApiRef } from '../system';\n\n\n/**\n * The Config API is used to provide a mechanism to access the\n * runtime configuration of the system.\n *\n * @public\n */\n\n\n/**\n * The {@link ApiRef} of {@link ConfigApi}.\n *\n * @public\n */\nexport const configApiRef = createApiRef({\n id: 'core.config',\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createApiRef } from '../system';\n\n/**\n * The discovery API is used to provide a mechanism for plugins to\n * discover the endpoint to use to talk to their backend counterpart.\n *\n * @remarks\n *\n * The purpose of the discovery API is to allow for many different deployment\n * setups and routing methods through a central configuration, instead\n * of letting each individual plugin manage that configuration.\n *\n * Implementations of the discovery API can be a simple as a URL pattern\n * using the pluginId, but could also have overrides for individual plugins,\n * or query a separate discovery service.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * The {@link ApiRef} of {@link DiscoveryApi}.\n *\n * @public\n */\nexport const discoveryApiRef = createApiRef({\n id: 'core.discovery',\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createApiRef } from '../system';\n\n\n/**\n * Mirrors the JavaScript Error class, for the purpose of\n * providing documentation and optional fields.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * The {@link ApiRef} of {@link ErrorApi}.\n *\n * @public\n */\nexport const errorApiRef = createApiRef({\n id: 'core.error',\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createApiRef } from '../system';\n\n/**\n * Fetaure flag descriptor.\n *\n * @public\n */\n\n\n\n\n\n/**\n * Enum representing the state of a feature flag (inactive/active).\n *\n * @public\n */\nexport var FeatureFlagState; (function (FeatureFlagState) {\n /**\n * Feature flag inactive (disabled).\n */\n const None = 0; FeatureFlagState[FeatureFlagState[\"None\"] = None] = \"None\";\n /**\n * Feature flag active (enabled).\n */\n const Active = 1; FeatureFlagState[FeatureFlagState[\"Active\"] = Active] = \"Active\";\n})(FeatureFlagState || (FeatureFlagState = {}));\n\n/**\n * Options to use when saving feature flags.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * The {@link ApiRef} of {@link FeatureFlagsApi}.\n *\n * @public\n */\nexport const featureFlagsApiRef = createApiRef({\n id: 'core.featureflags',\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createApiRef } from '../system';\n\n/**\n * A wrapper for the fetch API, that has additional behaviors such as the\n * ability to automatically inject auth information where necessary.\n *\n * @public\n */\n\n\n\n\n\n\n\n/**\n * The {@link ApiRef} of {@link FetchApi}.\n *\n * @remarks\n *\n * This is a wrapper for the fetch API, that has additional behaviors such as\n * the ability to automatically inject auth information where necessary.\n *\n * @public\n */\nexport const fetchApiRef = createApiRef({\n id: 'core.fetch',\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createApiRef } from '../system';\n\n\n/**\n * The Identity API used to identify and get information about the signed in user.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * The {@link ApiRef} of {@link IdentityApi}.\n *\n * @public\n */\nexport const identityApiRef = createApiRef({\n id: 'core.identity',\n});\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { createApiRef } from '../system';\n\n\n/**\n * Describes how to handle auth requests. Both how to show them to the user, and what to do when\n * the user accesses the auth request.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * The {@link ApiRef} of {@link OAuthRequestApi}.\n *\n * @public\n */\nexport const oauthRequestApiRef = createApiRef({\n id: 'core.oauthrequest',\n});\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createApiRef } from '../system';\n\n\n/**\n * A snapshot in time of the current known value of a storage key.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * The {@link ApiRef} of {@link StorageApi}.\n *\n * @public\n */\nexport const storageApiRef = createApiRef({\n id: 'core.storage',\n});\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * API reference configuration - holds an ID of the referenced API.\n *\n * @public\n */\n\n\n\n\nclass ApiRefImpl {\n constructor( config) {;this.config = config;\n const valid = config.id\n .split('.')\n .flatMap(part => part.split('-'))\n .every(part => part.match(/^[a-z][a-z0-9]*$/));\n if (!valid) {\n throw new Error(\n `API id must only contain period separated lowercase alphanum tokens with dashes, got '${config.id}'`,\n );\n }\n }\n\n get id() {\n return this.config.id;\n }\n\n // Utility for getting type of an api, using `typeof apiRef.T`\n get T() {\n throw new Error(`tried to read ApiRef.T of ${this}`);\n }\n\n toString() {\n return `apiRef{${this.config.id}}`;\n }\n}\n\n/**\n * Creates a reference to an API.\n *\n * @param config - The descriptor of the API to reference.\n * @returns An API reference.\n * @public\n */\nexport function createApiRef(config) {\n return new ApiRefImpl(config);\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Used to infer types for a standalone {@link ApiFactory} that isn't immediately passed\n * to another function.\n *\n * @remarks\n *\n * This function doesn't actually do anything, it's only used to infer types.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Used to infer types for a standalone {@link ApiFactory} that isn't immediately passed\n * to another function.\n *\n * @remarks\n *\n * Creates factory from {@link ApiRef} or returns the factory itself if provided.\n *\n * @param factory - Existing factory or {@link ApiRef}.\n * @param instance - The instance to be returned by the factory.\n * @public\n */\nexport function createApiFactory\n\n\n\n(\n factory,\n instance,\n) {\n if ('id' in factory) {\n return {\n api: factory,\n deps: {} ,\n factory: () => instance,\n };\n }\n return factory;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\n\nimport { useVersionedContext } from '@backstage/version-bridge';\n\n/**\n * React hook for retrieving {@link ApiHolder}, an API catalog.\n *\n * @public\n */\nexport function useApiHolder() {\n const versionedHolder = useVersionedContext('api-context');\n if (!versionedHolder) {\n throw new Error('API context is not available');\n }\n\n const apiHolder = versionedHolder.atVersion(1);\n if (!apiHolder) {\n throw new Error('ApiContext v1 not available');\n }\n return apiHolder;\n}\n\n/**\n * React hook for retrieving APIs.\n *\n * @param apiRef - Reference of the API to use.\n * @public\n */\nexport function useApi(apiRef) {\n const apiHolder = useApiHolder();\n\n const api = apiHolder.get(apiRef);\n if (!api) {\n throw new Error(`No implementation available for ${apiRef}`);\n }\n return api;\n}\n\n/**\n * Wrapper for giving component an API context.\n *\n * @param apis - APIs for the context.\n * @public\n */\nexport function withApis(apis) {\n return function withApisWrapper(\n WrappedComponent,\n ) {\n const Hoc = (props) => {\n const apiHolder = useApiHolder();\n\n const impls = {} ;\n\n for (const key in apis) {\n if (apis.hasOwnProperty(key)) {\n const ref = apis[key];\n\n const api = apiHolder.get(ref);\n if (!api) {\n throw new Error(`No implementation available for ${ref}`);\n }\n impls[key] = api;\n }\n }\n\n return React.createElement(WrappedComponent, { ...(props ), ...impls,} );\n };\n const displayName =\n WrappedComponent.displayName || WrappedComponent.name || 'Component';\n\n Hoc.displayName = `withApis(${displayName})`;\n\n return Hoc;\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useVersionedContext } from '@backstage/version-bridge';\n\n\n/**\n * React hook providing {@link AppContext}.\n *\n * @public\n */\nexport const useApp = () => {\n const versionedContext =\n useVersionedContext('app-context');\n if (!versionedContext) {\n throw new Error('App context is not available');\n }\n\n const appContext = versionedContext.atVersion(1);\n if (!appContext) {\n throw new Error('AppContext v1 not available');\n }\n return appContext;\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\n\n\n\n\n\n// This method of storing the component data was deprecated in September 2021, it\n// will be removed in the future for the reasons described below.\nconst globalStore = getOrCreateGlobalSingleton(\n 'component-data-store',\n () => new WeakMap(),\n);\n\n// This key is used to attach component data to the component type (function or class)\n// itself. This method is used because it has better compatibility component wrappers\n// like react-hot-loader, as opposed to the WeakMap method or using a symbol.\nconst componentDataKey = '__backstage_data';\n\n\n\n\n\n\n\n\n\n/**\n * Stores data related to a component in a global store.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#component-data}.\n *\n * @param component - The component to attach the data to.\n * @param type - The key under which the data will be stored.\n * @param data - Arbitrary value.\n * @public\n */\nexport function attachComponentData(\n component,\n type,\n data,\n) {\n const dataComponent = component ;\n\n let container = dataComponent[componentDataKey] ?? globalStore.get(component);\n if (!container) {\n container = { map: new Map() };\n Object.defineProperty(dataComponent, componentDataKey, {\n enumerable: false,\n configurable: true,\n writable: false,\n value: container,\n });\n globalStore.set(component, container);\n }\n\n if (container.map.has(type)) {\n const name = component.displayName || component.name;\n throw new Error(\n `Attempted to attach duplicate data \"${type}\" to component \"${name}\"`,\n );\n }\n\n container.map.set(type, data);\n}\n\n/**\n * Retrieves data attached to a component.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#component-data}.\n *\n * @param node - React component to look up.\n * @param type - Key of the data to retrieve.\n * @returns Data stored using {@link attachComponentData}.\n * @public\n */\nexport function getComponentData(\n node,\n type,\n) {\n if (!node) {\n return undefined;\n }\n\n const component = (node ).type;\n if (!component) {\n return undefined;\n }\n\n const container = component[componentDataKey] ?? globalStore.get(component);\n if (!container) {\n return undefined;\n }\n\n return container.map.get(type) ;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\n\n\n\n\n\n\n\n\n\nexport class PluginErrorBoundary extends React.Component {\n static getDerivedStateFromError(error) {\n return { error };\n }\n\n state = { error: undefined };\n\n handleErrorReset = () => {\n this.setState({ error: undefined });\n };\n\n render() {\n const { error } = this.state;\n const { app, plugin } = this.props;\n const { ErrorBoundaryFallback } = app.getComponents();\n\n if (error) {\n return (\n React.createElement(ErrorBoundaryFallback, {\n error: error,\n resetError: this.handleErrorReset,\n plugin: plugin,}\n )\n );\n }\n\n return this.props.children;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { lazy, Suspense } from 'react';\nimport { AnalyticsContext } from '../analytics/AnalyticsContext';\nimport { useApp } from '../app';\nimport { useRouteRef } from '../routing';\nimport { attachComponentData } from './componentData';\n\nimport { PluginErrorBoundary } from './PluginErrorBoundary';\n\n/**\n * Lazy or synchronous retrieving of extension components.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n/**\n * Extension for components that can have its own URL route (top-level pages, tabs etc.).\n *\n * @remarks\n *\n * We do not use ComponentType as the return type, since it doesn't let us convey the children prop.\n * ComponentType inserts children as an optional prop whether the inner component accepts it or not,\n * making it impossible to make the usage of children type safe.\n *\n * See {@link https://backstage.io/docs/plugins/composability#extensions}.\n *\n * @public\n */\nexport function createRoutableExtension\n\n(options\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n) {\n const { component, mountPoint, name } = options;\n return createReactExtension({\n component: {\n lazy: () =>\n component().then(\n InnerComponent => {\n const RoutableExtensionWrapper = (props) => {\n // Validate that the routing is wired up correctly in the App.tsx\n try {\n useRouteRef(mountPoint);\n } catch (error) {\n if (typeof error === 'object' && error !== null) {\n const { message } = error ;\n if (\n typeof message === 'string' &&\n message.startsWith('No path for ')\n ) {\n throw new Error(\n `Routable extension component with mount point ${mountPoint} was not discovered in the app element tree. ` +\n 'Routable extension components may not be rendered by other components and must be ' +\n 'directly available as an element within the App provider component.',\n );\n }\n }\n throw error;\n }\n return React.createElement(InnerComponent, { ...props,} );\n };\n\n const componentName =\n name ||\n (InnerComponent ).displayName ||\n InnerComponent.name ||\n 'LazyComponent';\n\n RoutableExtensionWrapper.displayName = `RoutableExtension(${componentName})`;\n\n return RoutableExtensionWrapper ;\n },\n error => {\n const RoutableExtensionWrapper = (_) => {\n const app = useApp();\n const { BootErrorPage } = app.getComponents();\n\n return React.createElement(BootErrorPage, { step: \"load-chunk\", error: error,} );\n };\n return RoutableExtensionWrapper;\n },\n ),\n },\n data: {\n 'core.mountPoint': mountPoint,\n },\n name,\n });\n}\n\n/**\n * Plain React component extension.\n *\n * @remarks\n *\n * We do not use ComponentType as the return type, since it doesn't let us convey the children prop.\n * ComponentType inserts children as an optional prop whether the inner component accepts it or not,\n * making it impossible to make the usage of children type safe.\n *\n * See {@link https://backstage.io/docs/plugins/composability#extensions}.\n *\n * @public\n */\nexport function createComponentExtension\n\n(options\n\n\n\n\n\n\n\n\n\n\n\n\n\n) {\n const { component, name } = options;\n return createReactExtension({ component, name });\n}\n\n/**\n * Used by {@link createComponentExtension} and {@link createRoutableExtension}.\n *\n * @remarks\n *\n * We do not use ComponentType as the return type, since it doesn't let us convey the children prop.\n * ComponentType inserts children as an optional prop whether the inner component accepts it or not,\n * making it impossible to make the usage of children type safe.\n *\n * See {@link https://backstage.io/docs/plugins/composability#extensions}.\n *\n * @public\n */\nexport function createReactExtension\n\n(options\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n) {\n const { data = {}, name } = options;\n if (!name) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Declaring extensions without name is DEPRECATED. ' +\n 'Make sure that all usages of createReactExtension, createComponentExtension and createRoutableExtension provide a name.',\n );\n }\n\n let Component;\n if ('lazy' in options.component) {\n const lazyLoader = options.component.lazy;\n Component = lazy(() =>\n lazyLoader().then(component => ({ default: component })),\n ) ;\n } else {\n Component = options.component.sync;\n }\n const componentName =\n name ||\n (Component ).displayName ||\n Component.name ||\n 'Component';\n\n return {\n expose(plugin) {\n const Result = (props) => {\n const app = useApp();\n const { Progress } = app.getComponents();\n // todo(iamEAP): Account for situations where this is attached via\n // separate calls to attachComponentData().\n const mountPoint = data?.['core.mountPoint'] \n\n;\n\n return (\n React.createElement(Suspense, { fallback: React.createElement(Progress, null ),}\n , React.createElement(PluginErrorBoundary, { app: app, plugin: plugin,}\n , React.createElement(AnalyticsContext, {\n attributes: {\n pluginId: plugin.getId(),\n ...(name && { extension: name }),\n ...(mountPoint && { routeRef: mountPoint.id }),\n },}\n \n , React.createElement(Component, { ...props,} )\n )\n )\n )\n );\n };\n\n attachComponentData(Result, 'core.plugin', plugin);\n for (const [key, value] of Object.entries(data)) {\n attachComponentData(Result, key, value);\n }\n\n Result.displayName = `Extension(${componentName})`;\n return Result;\n },\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n Children,\n Fragment,\n isValidElement,\n\n\n useMemo,\n} from 'react';\nimport { getComponentData } from './componentData';\nimport { useApi, featureFlagsApiRef } from '../apis';\n\nfunction selectChildren(\n rootNode,\n featureFlagsApi,\n selector,\n strictError,\n) {\n return Children.toArray(rootNode).flatMap(node => {\n if (!isValidElement(node)) {\n return [];\n }\n\n if (node.type === Fragment) {\n return selectChildren(\n node.props.children,\n featureFlagsApi,\n selector,\n strictError,\n );\n }\n\n if (getComponentData(node, 'core.featureFlagged')) {\n const props = node.props ;\n const isEnabled =\n 'with' in props\n ? featureFlagsApi.isActive(props.with)\n : !featureFlagsApi.isActive(props.without);\n if (isEnabled) {\n return selectChildren(\n node.props.children,\n featureFlagsApi,\n selector,\n strictError,\n );\n }\n return [];\n }\n\n if (selector === undefined || selector(node)) {\n return [node];\n }\n\n if (strictError) {\n throw new Error(strictError);\n }\n\n return selectChildren(\n node.props.children,\n featureFlagsApi,\n selector,\n strictError,\n );\n });\n}\n\n/**\n * A querying interface tailored to traversing a set of selected React elements\n * and extracting data.\n *\n * @remarks\n *\n * Methods prefixed with `selectBy` are used to narrow the set of selected elements.\n *\n * Methods prefixed with `find` return concrete data using a deep traversal of the set.\n *\n * Methods prefixed with `get` return concrete data using a shallow traversal of the set.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nclass Collection {\n constructor(\n node,\n featureFlagsApi,\n ) {;this.node = node;this.featureFlagsApi = featureFlagsApi;}\n\n selectByComponentData(query) {\n const selection = selectChildren(\n this.node,\n this.featureFlagsApi,\n node => getComponentData(node, query.key) !== undefined,\n query.withStrictError,\n );\n return new Collection(selection, this.featureFlagsApi);\n }\n\n findComponentData(query) {\n const selection = selectChildren(\n this.node,\n this.featureFlagsApi,\n node => getComponentData(node, query.key) !== undefined,\n );\n return selection\n .map(node => getComponentData(node, query.key))\n .filter((data) => data !== undefined);\n }\n\n getElements()\n\n {\n return selectChildren(this.node, this.featureFlagsApi) \n\n;\n }\n}\n\n/**\n * useElementFilter is a utility that helps you narrow down and retrieve data\n * from a React element tree, typically operating on the `children` property\n * passed in to a component.\n *\n * @remarks\n *\n * A common use-case is to construct declarative APIs\n * where a React component defines its behavior based on its children, such as\n * the relationship between `Routes` and `Route` in `react-router`.\n *\n * The purpose of this hook is similar to `React.Children.map`, and it expands upon\n * it to also handle traversal of fragments and Backstage specific things like the\n * `FeatureFlagged` component.\n *\n * The return value of the hook is computed by the provided filter function, but\n * with added memoization based on the input `node`. If further memoization\n * dependencies are used in the filter function, they should be added to the\n * third `dependencies` argument, just like `useMemo`, `useEffect`, etc.\n *\n * @public\n */\nexport function useElementFilter(\n node,\n filterFn,\n dependencies = [],\n) {\n const featureFlagsApi = useApi(featureFlagsApiRef);\n const elements = new Collection(node, featureFlagsApi);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => filterFn(elements), [node, ...dependencies]);\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * @internal\n */\nexport class PluginImpl\n\n\n\n{\n constructor( config) {;this.config = config;}\n\n getId() {\n return this.config.id;\n }\n\n getApis() {\n return this.config.apis ?? [];\n }\n\n getFeatureFlags() {\n return this.config.featureFlags?.slice() ?? [];\n }\n\n get routes() {\n return this.config.routes ?? ({} );\n }\n\n get externalRoutes() {\n return this.config.externalRoutes ?? ({} );\n }\n\n provide(extension) {\n return extension.expose(this);\n }\n\n toString() {\n return `plugin{${this.config.id}}`;\n }\n}\n\n/**\n * Creates Backstage Plugin from config.\n *\n * @param config - Plugin configuration.\n * @public\n */\nexport function createPlugin\n\n\n(\n config,\n) {\n return new PluginImpl(config);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\n\n/**\n * Catch-all type for route params.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * This symbol is what we use at runtime to determine whether a given object\n * is a type of RouteRef or not. It doesn't work well in TypeScript though since\n * the `unique symbol` will refer to different values between package versions.\n * For that reason we use the marker $$routeRefType to represent the symbol at\n * compile-time instead of using the symbol directly.\n *\n * @internal\n */\nexport const routeRefType = getOrCreateGlobalSingleton(\n 'route-ref-type',\n () => Symbol('route-ref-type'),\n);\n\n/**\n * Absolute route reference.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n routeRefType,\n\n\n\n} from './types';\n\n/**\n * @internal\n */\nexport class RouteRefImpl\n\n{\n // The marker is used for type checking while the symbol is used at runtime.\n ;\n [routeRefType] = 'absolute';\n\n constructor(\n id,\n params,\n ) {;this.id = id;this.params = params;}\n\n get title() {\n return this.id;\n }\n\n toString() {\n return `routeRef{type=absolute,id=${this.id}}`;\n }\n}\n\n/**\n * Create a {@link RouteRef} from a route descriptor.\n *\n * @param config - Description of the route reference to be created.\n * @public\n */\nexport function createRouteRef\n\n\n\n\n\n\n\n(config\n\n\n\n\n) {\n return new RouteRefImpl(\n config.id,\n (config.params ?? []) ,\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n\n\n\n routeRefType,\n\n} from './types';\n\n// Should match the pattern in react-router\nconst PARAM_PATTERN = /^\\w+$/;\n\n/**\n * @internal\n */\nexport class SubRouteRefImpl\n\n{\n // The marker is used for type checking while the symbol is used at runtime.\n ;\n [routeRefType] = 'sub';\n\n constructor(\n id,\n path,\n parent,\n params,\n ) {;this.id = id;this.path = path;this.parent = parent;this.params = params;}\n\n toString() {\n return `routeRef{type=sub,id=${this.id}}`;\n }\n}\n\n/**\n * Used in {@link PathParams} type declaration.\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Create a {@link SubRouteRef} from a route descriptor.\n *\n * @param config - Description of the route reference to be created.\n * @public\n */\nexport function createSubRouteRef\n\n\n(config\n\n\n\n) {\n const { id, path, parent } = config;\n \n\n // Collect runtime parameters from the path, e.g. ['bar', 'baz'] from '/foo/:bar/:baz'\n const pathParams = path\n .split('/')\n .filter(p => p.startsWith(':'))\n .map(p => p.substring(1));\n const params = [...parent.params, ...pathParams];\n\n if (parent.params.some(p => pathParams.includes(p ))) {\n throw new Error(\n 'SubRouteRef may not have params that overlap with its parent',\n );\n }\n if (!path.startsWith('/')) {\n throw new Error(`SubRouteRef path must start with '/', got '${path}'`);\n }\n if (path.endsWith('/')) {\n throw new Error(`SubRouteRef path must not end with '/', got '${path}'`);\n }\n for (const param of pathParams) {\n if (!PARAM_PATTERN.test(param)) {\n throw new Error(`SubRouteRef path has invalid param, got '${param}'`);\n }\n }\n\n // We ensure that the type of the return type is sane here\n const subRouteRef = new SubRouteRefImpl(\n id,\n path,\n parent,\n params ,\n ) ;\n\n // But skip type checking of the return value itself, because the conditional\n // type checking of the parent parameter overlap is tricky to express.\n return subRouteRef ;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n routeRefType,\n\n\n\n} from './types';\n\n/**\n * @internal\n */\nexport class ExternalRouteRefImpl\n\n\n\n{\n // The marker is used for type checking while the symbol is used at runtime.\n ;\n [routeRefType] = 'external';\n\n constructor(\n id,\n params,\n optional,\n ) {;this.id = id;this.params = params;this.optional = optional;}\n\n toString() {\n return `routeRef{type=external,id=${this.id}}`;\n }\n}\n\n/**\n * Creates a route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @param options - Description of the route reference to be created.\n * @public\n */\nexport function createExternalRouteRef\n\n\n\n(options\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n) {\n return new ExternalRouteRefImpl(\n options.id,\n (options.params ?? []) ,\n Boolean(options.optional) ,\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useMemo } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { useVersionedContext } from '@backstage/version-bridge';\n\n\n\n\n\n\n\n\n/**\n * @internal\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * React hook for constructing URLs to routes.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}\n *\n * @param routeRef - The ref to route that should be converted to URL.\n * @returns A function that will in turn return the concrete URL of the `routeRef`.\n * @public\n */\nexport function useRouteRef(\n routeRef\n\n\n,\n) {\n const sourceLocation = useLocation();\n const versionedContext =\n useVersionedContext('routing-context');\n if (!versionedContext) {\n throw new Error('Routing context is not available');\n }\n\n const resolver = versionedContext.atVersion(1);\n const routeFunc = useMemo(\n () => resolver && resolver.resolve(routeRef, sourceLocation),\n [resolver, routeRef, sourceLocation],\n );\n\n if (!versionedContext) {\n throw new Error('useRouteRef used outside of routing context');\n }\n if (!resolver) {\n throw new Error('RoutingContext v1 not available');\n }\n\n const isOptional = 'optional' in routeRef && routeRef.optional;\n if (!routeFunc && !isOptional) {\n throw new Error(`No path for ${routeRef}`);\n }\n\n return routeFunc;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useParams } from 'react-router-dom';\n\n\n/**\n * React hook for retrieving dynamic params from the current URL.\n * @param _routeRef - Ref of the current route.\n * @public\n */\nexport function useRouteRefParams(\n _routeRef,\n) {\n return useParams() ;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * An object that is shaped like an `Error`.\n *\n * @public\n */\n\n\n\n\n\n\n\n/**\n * Checks whether an unknown value is an {@link ErrorLike} object, which guarantees that it's\n * an object that has at least two string properties: a non-empty `name` and `message`.\n *\n * @public\n * @param value - an unknown value\n * @returns true if the value is an {@link ErrorLike} object, false otherwise\n */\nexport function isError(value) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false;\n }\n const maybe = value ;\n if (typeof maybe.name !== 'string' || maybe.name === '') {\n return false;\n }\n if (typeof maybe.message !== 'string') {\n return false;\n }\n return true;\n}\n\n/**\n * Asserts that an unknown value is an {@link ErrorLike} object, which guarantees that it's\n * an object that has at least two string properties: a non-empty `name` and `message`.\n *\n * If the value is not an {@link ErrorLike} object, an error is thrown.\n *\n * @public\n * @param value - an unknown value\n */\nexport function assertError(value) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new Error(`Encountered invalid error, not an object, got '${value}'`);\n }\n const maybe = value ;\n if (typeof maybe.name !== 'string' || maybe.name === '') {\n throw new Error(`Encountered error object without a name, got '${value}'`);\n }\n if (typeof maybe.message !== 'string') {\n throw new Error(\n `Encountered error object without a message, got '${value}'`,\n );\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport {\n deserializeError as deserializeErrorInternal,\n serializeError as serializeErrorInternal,\n} from 'serialize-error';\nimport { isError } from '../errors';\n\n/**\n * The serialized form of an Error.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Serializes an error object to a JSON friendly form.\n *\n * @public\n * @param error - The error.\n * @param options - Optional serialization options.\n */\nexport function serializeError(\n error,\n options\n\n\n,\n) {\n const serialized = serializeErrorInternal(error);\n const result = {\n name: 'Unknown',\n message: '<no reason given>',\n ...serialized,\n };\n\n if (!options?.includeStack) {\n delete result.stack;\n }\n\n return result;\n}\n\n/**\n * Deserializes a serialized error object back to an Error.\n *\n * @public\n */\nexport function deserializeError(\n data,\n) {\n const result = deserializeErrorInternal(data) ;\n if (!data.stack) {\n result.stack = undefined;\n }\n return result;\n}\n\n/**\n * Stringifies an error, including its name and message where available.\n *\n * @param error - The error.\n * @public\n */\nexport function stringifyError(error) {\n if (isError(error)) {\n // Prefer error.toString, but if it's not implemented we use a nicer fallback\n const str = String(error);\n return str !== '[object Object]' ? str : `${error.name}: ${error.message}`;\n }\n\n return `unknown error '${error}'`;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { stringifyError } from '../serialization';\nimport { isError } from './assertion';\n\n/**\n * A base class that custom Error classes can inherit from.\n *\n * @public\n * @example\n *```ts\n * class MyCustomError extends CustomErrorBase {}\n *\n * const e = new MyCustomError('Some message', cause);\n * // e.name === 'MyCustomError'\n * // e.message === 'Some message'\n * // e.cause === cause\n * // e.stack is set if the runtime supports it\n * ```\n */\nexport class CustomErrorBase extends Error {\n /**\n * An inner error that caused this error to be thrown, if any.\n */\n cause;\n\n constructor(message, cause) {\n let fullMessage = message;\n if (cause !== undefined) {\n const causeStr = stringifyError(cause);\n if (fullMessage) {\n fullMessage += `; caused by ${causeStr}`;\n } else {\n fullMessage = `caused by ${causeStr}`;\n }\n }\n\n super(fullMessage);\n\n Error.captureStackTrace?.(this, this.constructor);\n\n this.name = this.constructor.name;\n this.cause = isError(cause) ? cause : undefined;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isError } from './assertion';\nimport { CustomErrorBase } from './CustomErrorBase';\n\n/*\n * A set of common business logic errors.\n *\n * A backend error handler middleware would understand these and translate them\n * to well formed HTTP responses.\n *\n * While these are intentionally analogous to HTTP errors, they are not\n * intended to be thrown by the request handling layer. In those places, please\n * use e.g. the http-errors library.\n */\n\n/**\n * The given inputs are malformed and cannot be processed.\n *\n * @public\n */\nexport class InputError extends CustomErrorBase {}\n\n/**\n * The request requires authentication, which was not properly supplied.\n *\n * @public\n */\nexport class AuthenticationError extends CustomErrorBase {}\n\n/**\n * The authenticated caller is not allowed to perform this request.\n *\n * @public\n */\nexport class NotAllowedError extends CustomErrorBase {}\n\n/**\n * The requested resource could not be found.\n *\n * Note that this error usually is used to indicate that an entity with a given\n * ID does not exist, rather than signalling that an entire route is missing.\n *\n * @public\n */\nexport class NotFoundError extends CustomErrorBase {}\n\n/**\n * The request could not complete due to a conflict in the current state of the\n * resource.\n *\n * @public\n */\nexport class ConflictError extends CustomErrorBase {}\n\n/**\n * The requested resource has not changed since last request.\n *\n * @public\n */\nexport class NotModifiedError extends CustomErrorBase {}\n\n/**\n * An error that forwards an underlying cause with additional context in the message.\n *\n * The `name` property of the error will be inherited from the `cause` if\n * possible, and will otherwise be set to `'Error'`.\n *\n * @public\n */\nexport class ForwardedError extends CustomErrorBase {\n constructor(message, cause) {\n super(message, cause);\n\n this.name = isError(cause) ? cause.name : 'Error';\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * A standard shape of JSON data returned as the body of backend errors.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Attempts to construct an ErrorResponseBody out of a failed server request.\n * Assumes that the response has already been checked to be not ok. This\n * function consumes the body of the response, and assumes that it hasn't\n * been consumed before.\n *\n * The code is forgiving, and constructs a useful synthetic body as best it can\n * if the response body wasn't on the expected form.\n *\n * @public\n * @param response - The response of a failed request\n */\nexport async function parseErrorResponseBody(\n response,\n) {\n try {\n const text = await response.text();\n if (text) {\n if (\n response.headers.get('content-type')?.startsWith('application/json')\n ) {\n try {\n const body = JSON.parse(text);\n if (body.error && body.response) {\n return body;\n }\n } catch {\n // ignore\n }\n }\n\n return {\n error: {\n name: 'Error',\n message: `Request failed with status ${response.status} ${response.statusText}, ${text}`,\n },\n response: {\n statusCode: response.status,\n },\n };\n }\n } catch {\n // ignore\n }\n\n return {\n error: {\n name: 'Error',\n message: `Request failed with status ${response.status} ${response.statusText}`,\n },\n response: {\n statusCode: response.status,\n },\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { deserializeError } from '../serialization';\nimport {\n\n parseErrorResponseBody,\n} from '../serialization/response';\n\n/**\n * An error thrown as the result of a failed server request.\n *\n * The server is expected to respond on the ErrorResponseBody format.\n *\n * @public\n */\nexport class ResponseError extends Error {\n /**\n * The actual response, as seen by the client.\n *\n * Note that the body of this response is always consumed. Its parsed form is\n * in the `body` field.\n */\n response;\n\n /**\n * The parsed JSON error body, as sent by the server.\n */\n body;\n\n /**\n * The Error cause, as seen by the remote server. This is parsed out of the\n * JSON error body.\n *\n * This error always has the plain Error constructor, however all\n * serializable enumerable fields on the remote error including its name are\n * preserved. Therefore, if you want to check the error type, use its name\n * property rather than checking typeof or its constructor or prototype.\n */\n cause;\n\n /**\n * Constructs a ResponseError based on a failed response.\n *\n * Assumes that the response has already been checked to be not ok. This\n * function consumes the body of the response, and assumes that it hasn't\n * been consumed before.\n */\n static async fromResponse(response) {\n const data = await parseErrorResponseBody(response);\n\n const status = data.response.statusCode || response.status;\n const statusText = data.error.name || response.statusText;\n const message = `Request failed with ${status} ${statusText}`;\n const cause = deserializeError(data.error);\n\n return new ResponseError({\n message,\n response,\n data,\n cause,\n });\n }\n\n constructor(props\n\n\n\n\n) {\n super(props.message);\n this.name = 'ResponseError';\n this.response = props.response;\n this.body = props.data;\n this.cause = props.cause;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n createApiRef,\n\n} from '@backstage/core-plugin-api';\n\n/**\n * The options that control a {@link ScmAuthApi.getCredentials} call.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * The ApiRef for the ScmAuthApi.\n *\n * @public\n */\nexport const scmAuthApiRef = createApiRef({\n id: 'core.scmauth',\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n bitbucketAuthApiRef,\n createApiFactory,\n githubAuthApiRef,\n gitlabAuthApiRef,\n microsoftAuthApiRef,\n\n} from '@backstage/core-plugin-api';\nimport {\n\n scmAuthApiRef,\n\n\n} from './ScmAuthApi';\n\n\n\n\n\n\n\n\n\n\n\nclass ScmAuthMux {\n #providers;\n\n constructor(providers) {\n this.#providers = providers;\n }\n\n async getCredentials(\n options,\n ) {\n const url = new URL(options.url);\n const provider = this.#providers.find(p => p.isUrlSupported(url));\n if (!provider) {\n throw new Error(\n `No authentication provider available for access to '${options.url}'`,\n );\n }\n\n return provider.getCredentials(options);\n }\n}\n\n/**\n * An implementation of the ScmAuthApi that merges together OAuthApi instances\n * to form a single instance that can handles authentication for multiple providers.\n *\n * @public\n *\n * @example\n * ```\n * // Supports authentication towards both public GitHub and GHE:\n * createApiFactory({\n * api: scmAuthApiRef,\n * deps: {\n * gheAuthApi: gheAuthApiRef,\n * githubAuthApi: githubAuthApiRef,\n * },\n * factory: ({ githubAuthApi, gheAuthApi }) =>\n * ScmAuth.merge(\n * ScmAuth.forGithub(githubAuthApi),\n * ScmAuth.forGithub(gheAuthApi, {\n * host: 'ghe.example.com',\n * }),\n * )\n * })\n * ```\n */\nexport class ScmAuth {\n /**\n * Creates an API factory that enables auth for each of the default SCM providers.\n */\n static createDefaultApiFactory() {\n return createApiFactory({\n api: scmAuthApiRef,\n deps: {\n github: githubAuthApiRef,\n gitlab: gitlabAuthApiRef,\n azure: microsoftAuthApiRef,\n bitbucket: bitbucketAuthApiRef,\n },\n factory: ({ github, gitlab, azure, bitbucket }) =>\n ScmAuth.merge(\n ScmAuth.forGithub(github),\n ScmAuth.forGitlab(gitlab),\n ScmAuth.forAzure(azure),\n ScmAuth.forBitbucket(bitbucket),\n ),\n });\n }\n\n /**\n * Creates a general purpose ScmAuth instance with a custom scope mapping.\n */\n static forAuthApi(\n authApi,\n options\n\n\n\n\n\n,\n ) {\n return new ScmAuth('generic', authApi, options.host, options.scopeMapping);\n }\n\n /**\n * Creates a new ScmAuth instance that handles authentication towards GitHub.\n *\n * The host option determines which URLs that are handled by this instance and defaults to `github.com`.\n *\n * The default scopes are:\n *\n * `repo read:org read:user`\n *\n * If the additional `repoWrite` permission is requested, these scopes are added:\n *\n * `gist`\n */\n static forGithub(\n githubAuthApi,\n options\n\n,\n ) {\n const host = options?.host ?? 'github.com';\n return new ScmAuth('github', githubAuthApi, host, {\n default: ['repo', 'read:org', 'read:user'],\n repoWrite: ['gist'],\n });\n }\n\n /**\n * Creates a new ScmAuth instance that handles authentication towards GitLab.\n *\n * The host option determines which URLs that are handled by this instance and defaults to `gitlab.com`.\n *\n * The default scopes are:\n *\n * `read_user read_api read_repository`\n *\n * If the additional `repoWrite` permission is requested, these scopes are added:\n *\n * `write_repository api`\n */\n static forGitlab(\n gitlabAuthApi,\n options\n\n,\n ) {\n const host = options?.host ?? 'gitlab.com';\n return new ScmAuth('gitlab', gitlabAuthApi, host, {\n default: ['read_user', 'read_api', 'read_repository'],\n repoWrite: ['write_repository', 'api'],\n });\n }\n\n /**\n * Creates a new ScmAuth instance that handles authentication towards Azure.\n *\n * The host option determines which URLs that are handled by this instance and defaults to `dev.azure.com`.\n *\n * The default scopes are:\n *\n * `vso.build vso.code vso.graph vso.project vso.profile`\n *\n * If the additional `repoWrite` permission is requested, these scopes are added:\n *\n * `vso.code_manage`\n */\n static forAzure(\n microsoftAuthApi,\n options\n\n,\n ) {\n const host = options?.host ?? 'dev.azure.com';\n return new ScmAuth('azure', microsoftAuthApi, host, {\n default: [\n 'vso.build',\n 'vso.code',\n 'vso.graph',\n 'vso.project',\n 'vso.profile',\n ],\n repoWrite: ['vso.code_manage'],\n });\n }\n\n /**\n * Creates a new ScmAuth instance that handles authentication towards Bitbucket.\n *\n * The host option determines which URLs that are handled by this instance and defaults to `bitbucket.org`.\n *\n * The default scopes are:\n *\n * `account team pullrequest snippet issue`\n *\n * If the additional `repoWrite` permission is requested, these scopes are added:\n *\n * `pullrequest:write snippet:write issue:write`\n */\n static forBitbucket(\n bitbucketAuthApi,\n options\n\n,\n ) {\n const host = options?.host ?? 'bitbucket.org';\n return new ScmAuth('bitbucket', bitbucketAuthApi, host, {\n default: ['account', 'team', 'pullrequest', 'snippet', 'issue'],\n repoWrite: ['pullrequest:write', 'snippet:write', 'issue:write'],\n });\n }\n\n /**\n * Merges together multiple ScmAuth instances into one that\n * routes requests to the correct instance based on the URL.\n */\n static merge(...providers) {\n return new ScmAuthMux(providers);\n }\n\n #api;\n #host;\n #scopeMapping;\n #providerName;\n\n constructor(\n providerName,\n api,\n host,\n scopeMapping,\n ) {\n this.#api = api;\n this.#host = host;\n this.#scopeMapping = scopeMapping;\n this.#providerName = providerName;\n }\n\n /**\n * Checks whether the implementation is able to provide authentication for the given URL.\n */\n isUrlSupported(url) {\n return url.host === this.#host;\n }\n\n getAdditionalScopesForProvider(\n additionalScopes,\n ) {\n if (!additionalScopes?.customScopes || this.#providerName === 'generic') {\n return [];\n }\n\n return additionalScopes.customScopes?.[this.#providerName] ?? [];\n }\n\n /**\n * Fetches credentials for the given resource.\n */\n async getCredentials(\n options,\n ) {\n const { url, additionalScope, ...restOptions } = options;\n\n const scopes = this.#scopeMapping.default.slice();\n if (additionalScope?.repoWrite) {\n scopes.push(...this.#scopeMapping.repoWrite);\n }\n\n const additionalScopes =\n this.getAdditionalScopesForProvider(additionalScope);\n\n if (additionalScopes.length) {\n scopes.push(...additionalScopes);\n }\n\n const uniqueScopes = [...new Set(scopes)];\n\n const token = await this.#api.getAccessToken(uniqueScopes, restOptions);\n\n return {\n token,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n };\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport {\n\n ScmIntegrations,\n} from '@backstage/integration';\nimport { createApiRef } from '@backstage/core-plugin-api';\n\n/**\n * Factory class for creating {@link @backstage/integration#ScmIntegrationRegistry} instances.\n *\n * @public\n */\nexport class ScmIntegrationsApi {\n /**\n * Instantiates an {@link @backstage/integration#ScmIntegrationRegistry}.\n *\n * @param config - The root of the config hierarchy.\n */\n static fromConfig(config) {\n return ScmIntegrations.fromConfig(config);\n }\n}\n\n/**\n * The API that holds all configured SCM integrations.\n *\n * @public\n */\nexport const scmIntegrationsApiRef =\n createApiRef({\n id: 'integration.scmintegrations',\n });\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport CodeIcon from '@material-ui/icons/Code';\nimport React from 'react';\nimport { useApp } from '@backstage/core-plugin-api';\n\n/**\n * Props for {@link ScmIntegrationIcon}.\n *\n * @public\n */\n\n\n\n\n\n\n\n/**\n * An icon that represents a certain SCM integration.\n *\n * @public\n */\nexport const ScmIntegrationIcon = (props) => {\n const { type } = props;\n const app = useApp();\n const DefaultIcon = CodeIcon;\n const Icon = type ? app.getSystemIcon(type) ?? DefaultIcon : DefaultIcon;\n return React.createElement(Icon, null );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport parseGitUrl from 'git-url-parse';\nimport { trimEnd } from 'lodash';\n\n\n/** Checks whether the given argument is a valid URL hostname */\nexport function isValidHost(host) {\n const check = new URL('http://example.com');\n check.host = host;\n return check.host === host;\n}\n\n/** Checks whether the given argument is a valid URL */\nexport function isValidUrl(url) {\n try {\n // eslint-disable-next-line no-new\n new URL(url);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function basicIntegrations(\n integrations,\n getHost,\n) {\n return {\n list() {\n return integrations;\n },\n byUrl(url) {\n try {\n const parsed = typeof url === 'string' ? new URL(url) : url;\n return integrations.find(i => getHost(i) === parsed.host);\n } catch {\n return undefined;\n }\n },\n byHost(host) {\n return integrations.find(i => getHost(i) === host);\n },\n };\n}\n\n/**\n * Default implementation of {@link ScmIntegration} `resolveUrl`, that only\n * works with URL pathname based providers.\n *\n * @public\n */\nexport function defaultScmResolveUrl(options\n\n\n\n) {\n const { url, base, lineNumber } = options;\n\n // If it is a fully qualified URL - then return it verbatim\n try {\n // eslint-disable-next-line no-new\n new URL(url);\n return url;\n } catch {\n // ignore intentionally\n }\n\n let updated;\n\n if (url.startsWith('/')) {\n // If it is an absolute path, move relative to the repo root\n const { filepath } = parseGitUrl(base);\n updated = new URL(base);\n const repoRootPath = trimEnd(\n updated.pathname.substring(0, updated.pathname.length - filepath.length),\n '/',\n );\n updated.pathname = `${repoRootPath}${url}`;\n } else {\n // For relative URLs, just let the default URL constructor handle the\n // resolving. Note that this essentially will treat the last segment of the\n // base as a file - NOT a folder - unless the url ends in a slash.\n updated = new URL(url, base);\n }\n\n updated.search = new URL(base).search;\n if (lineNumber) {\n updated.hash = `L${lineNumber}`;\n }\n return updated.toString();\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst VERSION_PREFIX_GIT_BRANCH = 'GB';\n\nexport class AzureUrl {\n /**\n * Parses an azure URL as copied from the browser address bar.\n *\n * Throws an error if the URL is not a valid azure repo URL.\n */\n static fromRepoUrl(repoUrl) {\n const url = new URL(repoUrl);\n\n let owner;\n let project;\n let repo;\n\n const parts = url.pathname.split('/').map(part => decodeURIComponent(part));\n if (parts[2] === '_git') {\n owner = parts[1];\n project = repo = parts[3];\n } else if (parts[3] === '_git') {\n owner = parts[1];\n project = parts[2];\n repo = parts[4];\n }\n\n if (!owner || !project || !repo) {\n throw new Error('Azure URL must point to a git repository');\n }\n\n const path = url.searchParams.get('path') ?? undefined;\n\n let ref;\n const version = url.searchParams.get('version');\n if (version) {\n const prefix = version.slice(0, 2);\n if (prefix !== 'GB') {\n throw new Error('Azure URL version must point to a git branch');\n }\n ref = version.slice(2);\n }\n\n return new AzureUrl(url.origin, owner, project, repo, path, ref);\n }\n\n #origin;\n #owner;\n #project;\n #repo;\n #path;\n #ref;\n\n constructor(\n origin,\n owner,\n project,\n repo,\n path,\n ref,\n ) {\n this.#origin = origin;\n this.#owner = owner;\n this.#project = project;\n this.#repo = repo;\n this.#path = path;\n this.#ref = ref;\n }\n\n #baseUrl = (...parts) => {\n const url = new URL(this.#origin);\n url.pathname = parts.map(part => encodeURIComponent(part)).join('/');\n return url;\n };\n\n /**\n * Returns a repo URL that can be used to navigate to the resource in azure.\n *\n * Throws an error if the URL is not a valid azure repo URL.\n */\n toRepoUrl() {\n let url;\n if (this.#project === this.#repo) {\n url = this.#baseUrl(this.#owner, '_git', this.#repo);\n } else {\n url = this.#baseUrl(this.#owner, this.#project, '_git', this.#repo);\n }\n\n if (this.#path) {\n url.searchParams.set('path', this.#path);\n }\n if (this.#ref) {\n url.searchParams.set('version', VERSION_PREFIX_GIT_BRANCH + this.#ref);\n }\n\n return url.toString();\n }\n\n /**\n * Returns the file download URL for this azure resource.\n *\n * Throws an error if the URL does not point to a file.\n */\n toFileUrl() {\n if (!this.#path) {\n throw new Error(\n 'Azure URL must point to a specific path to be able to download a file',\n );\n }\n\n const url = this.#baseUrl(\n this.#owner,\n this.#project,\n '_apis',\n 'git',\n 'repositories',\n this.#repo,\n 'items',\n );\n url.searchParams.set('api-version', '6.0');\n url.searchParams.set('path', this.#path);\n\n if (this.#ref) {\n url.searchParams.set('version', this.#ref);\n }\n\n return url.toString();\n }\n\n /**\n * Returns the archive download URL for this azure resource.\n *\n * Throws an error if the URL does not point to a repo.\n */\n toArchiveUrl() {\n const url = this.#baseUrl(\n this.#owner,\n this.#project,\n '_apis',\n 'git',\n 'repositories',\n this.#repo,\n 'items',\n );\n url.searchParams.set('recursionLevel', 'full');\n url.searchParams.set('download', 'true');\n url.searchParams.set('api-version', '6.0');\n\n if (this.#path) {\n url.searchParams.set('scopePath', this.#path);\n }\n if (this.#ref) {\n url.searchParams.set('version', this.#ref);\n }\n\n return url.toString();\n }\n\n /**\n * Returns the API url for fetching commits from a branch for this azure resource.\n *\n * Throws an error if the URL does not point to a commit.\n */\n toCommitsUrl() {\n const url = this.#baseUrl(\n this.#owner,\n this.#project,\n '_apis',\n 'git',\n 'repositories',\n this.#repo,\n 'commits',\n );\n url.searchParams.set('api-version', '6.0');\n\n if (this.#ref) {\n url.searchParams.set('searchCriteria.itemVersion.version', this.#ref);\n }\n\n return url.toString();\n }\n\n /**\n * Returns the name of the owner, a user or an organization.\n */\n getOwner() {\n return this.#owner;\n }\n\n /**\n * Returns the name of the project.\n */\n getProject() {\n return this.#project;\n }\n\n /**\n * Returns the name of the repo.\n */\n getRepo() {\n return this.#repo;\n }\n\n /**\n * Returns the file path within the repo if the URL contains one.\n */\n getPath() {\n return this.#path;\n }\n\n /**\n * Returns the git ref in the repo if the URL contains one.\n */\n getRef() {\n return this.#ref;\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { isValidHost } from '../helpers';\n\nconst AZURE_HOST = 'dev.azure.com';\n\n/**\n * The configuration parameters for a single Azure provider.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Reads a single Azure integration config.\n *\n * @param config - The config object of a single integration\n * @public\n */\nexport function readAzureIntegrationConfig(\n config,\n) {\n const host = config.getOptionalString('host') ?? AZURE_HOST;\n const token = config.getOptionalString('token');\n\n if (!isValidHost(host)) {\n throw new Error(\n `Invalid Azure integration config, '${host}' is not a valid host`,\n );\n }\n\n return { host, token };\n}\n\n/**\n * Reads a set of Azure integration configs, and inserts some defaults for\n * public Azure if not specified.\n *\n * @param configs - All of the integration config objects\n * @public\n */\nexport function readAzureIntegrationConfigs(\n configs,\n) {\n // First read all the explicit integrations\n const result = configs.map(readAzureIntegrationConfig);\n\n // If no explicit dev.azure.com integration was added, put one in the list as\n // a convenience\n if (!result.some(c => c.host === AZURE_HOST)) {\n result.push({ host: AZURE_HOST });\n }\n\n return result;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { basicIntegrations, isValidUrl } from '../helpers';\n\nimport { AzureUrl } from './AzureUrl';\nimport { readAzureIntegrationConfigs } from './config';\n\n/**\n * Microsoft Azure based integration.\n *\n * @public\n */\nexport class AzureIntegration {\n static factory = ({ config }) => {\n const configs = readAzureIntegrationConfigs(\n config.getOptionalConfigArray('integrations.azure') ?? [],\n );\n return basicIntegrations(\n configs.map(c => new AzureIntegration(c)),\n i => i.config.host,\n );\n };\n\n constructor( integrationConfig) {;this.integrationConfig = integrationConfig;}\n\n get type() {\n return 'azure';\n }\n\n get title() {\n return this.integrationConfig.host;\n }\n\n get config() {\n return this.integrationConfig;\n }\n\n /*\n * Azure repo URLs on the form with a `path` query param are treated specially.\n *\n * Example base URL: https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml\n */\n resolveUrl(options\n\n\n\n) {\n const { url, base } = options;\n\n // If we can parse the url, it is absolute - then return it verbatim\n if (isValidUrl(url)) {\n return url;\n }\n\n try {\n const azureUrl = AzureUrl.fromRepoUrl(base);\n const newUrl = new URL(base);\n\n // We lean on the URL path resolution logic to resolve the path param\n const mockBaseUrl = new URL(`https://a.com${azureUrl.getPath() ?? ''}`);\n const updatedPath = new URL(url, mockBaseUrl).pathname;\n newUrl.searchParams.set('path', updatedPath);\n\n if (options.lineNumber) {\n newUrl.searchParams.set('line', String(options.lineNumber));\n newUrl.searchParams.set('lineEnd', String(options.lineNumber + 1));\n newUrl.searchParams.set('lineStartColumn', '1');\n newUrl.searchParams.set('lineEndColumn', '1');\n }\n\n return newUrl.toString();\n } catch {\n // If not an actual file path within a repo, treat the URL as raw\n return new URL(url, base).toString();\n }\n }\n\n resolveEditUrl(url) {\n // TODO: Implement edit URL for Azure, fallback to view url as I don't know\n // how azure works.\n return url;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AzureUrl } from './AzureUrl';\n\n\n/**\n * Given a URL pointing to a file on a provider, returns a URL that is suitable\n * for fetching the contents of the data.\n *\n * @remarks\n *\n * Converts\n * - from: `https://dev.azure.com/{organization}/{project}/_git/reponame?path={path}&version=GB{commitOrBranch}&_a=contents`\n * - to: `https://dev.azure.com/{organization}/{project}/_apis/git/repositories/reponame/items?path={path}&version={commitOrBranch}`\n *\n * @param url - A URL pointing to a file\n * @public\n */\nexport function getAzureFileFetchUrl(url) {\n return AzureUrl.fromRepoUrl(url).toFileUrl();\n}\n\n/**\n * Given a URL pointing to a path on a provider, returns a URL that is suitable\n * for downloading the subtree.\n *\n * @param url - A URL pointing to a path\n * @public\n */\nexport function getAzureDownloadUrl(url) {\n return AzureUrl.fromRepoUrl(url).toArchiveUrl();\n}\n\n/**\n * Given a URL, return the API URL to fetch commits on the branch.\n *\n * @param url - A URL pointing to a repository or a sub-path\n * @public\n */\nexport function getAzureCommitsUrl(url) {\n return AzureUrl.fromRepoUrl(url).toCommitsUrl();\n}\n\n/**\n * Gets the request options necessary to make requests to a given provider.\n *\n * @param config - The relevant provider config\n * @public\n */\nexport function getAzureRequestOptions(\n config,\n additionalHeaders,\n) {\n const headers = additionalHeaders\n ? { ...additionalHeaders }\n : {};\n\n if (config.token) {\n const buffer = Buffer.from(`:${config.token}`, 'utf8');\n headers.Authorization = `Basic ${buffer.toString('base64')}`;\n }\n\n return { headers };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { trimEnd } from 'lodash';\nimport { isValidHost } from '../helpers';\n\nconst BITBUCKET_HOST = 'bitbucket.org';\nconst BITBUCKET_API_BASE_URL = 'https://api.bitbucket.org/2.0';\n\n/**\n * The configuration parameters for a single Bitbucket API provider.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Reads a single Bitbucket integration config.\n *\n * @param config - The config object of a single integration\n * @public\n */\nexport function readBitbucketIntegrationConfig(\n config,\n) {\n const host = config.getOptionalString('host') ?? BITBUCKET_HOST;\n let apiBaseUrl = config.getOptionalString('apiBaseUrl');\n const token = config.getOptionalString('token');\n const username = config.getOptionalString('username');\n const appPassword = config.getOptionalString('appPassword');\n\n if (!isValidHost(host)) {\n throw new Error(\n `Invalid Bitbucket integration config, '${host}' is not a valid host`,\n );\n }\n\n if (apiBaseUrl) {\n apiBaseUrl = trimEnd(apiBaseUrl, '/');\n } else if (host === BITBUCKET_HOST) {\n apiBaseUrl = BITBUCKET_API_BASE_URL;\n }\n\n return {\n host,\n apiBaseUrl,\n token,\n username,\n appPassword,\n };\n}\n\n/**\n * Reads a set of Bitbucket integration configs, and inserts some defaults for\n * public Bitbucket if not specified.\n *\n * @param configs - All of the integration config objects\n * @public\n */\nexport function readBitbucketIntegrationConfigs(\n configs,\n) {\n // First read all the explicit integrations\n const result = configs.map(readBitbucketIntegrationConfig);\n\n // If no explicit bitbucket.org integration was added, put one in the list as\n // a convenience\n if (!result.some(c => c.host === BITBUCKET_HOST)) {\n result.push({\n host: BITBUCKET_HOST,\n apiBaseUrl: BITBUCKET_API_BASE_URL,\n });\n }\n\n return result;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport parseGitUrl from 'git-url-parse';\nimport { basicIntegrations, defaultScmResolveUrl } from '../helpers';\n\nimport {\n\n readBitbucketIntegrationConfigs,\n} from './config';\n\n/**\n * A Bitbucket based integration.\n *\n * @public\n */\nexport class BitbucketIntegration {\n static factory = ({\n config,\n }) => {\n const configs = readBitbucketIntegrationConfigs(\n config.getOptionalConfigArray('integrations.bitbucket') ?? [],\n );\n return basicIntegrations(\n configs.map(c => new BitbucketIntegration(c)),\n i => i.config.host,\n );\n };\n\n constructor( integrationConfig) {;this.integrationConfig = integrationConfig;}\n\n get type() {\n return 'bitbucket';\n }\n\n get title() {\n return this.integrationConfig.host;\n }\n\n get config() {\n return this.integrationConfig;\n }\n\n resolveUrl(options\n\n\n\n) {\n const resolved = defaultScmResolveUrl(options);\n\n // Bitbucket line numbers use the syntax #example.txt-42, rather than #L42\n if (options.lineNumber) {\n const url = new URL(resolved);\n\n const filename = url.pathname.split('/').slice(-1)[0];\n url.hash = `${filename}-${options.lineNumber}`;\n return url.toString();\n }\n\n return resolved;\n }\n\n resolveEditUrl(url) {\n const urlData = parseGitUrl(url);\n const editUrl = new URL(url);\n\n editUrl.searchParams.set('mode', 'edit');\n // TODO: Not sure what spa=0 does, at least bitbucket.org doesn't support it\n // but this is taken over from the initial implementation.\n editUrl.searchParams.set('spa', '0');\n editUrl.searchParams.set('at', urlData.ref);\n return editUrl.toString();\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fetch from 'cross-fetch';\nimport parseGitUrl from 'git-url-parse';\n\n\n/**\n * Given a URL pointing to a path on a provider, returns the default branch.\n *\n * @param url - A URL pointing to a path\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketDefaultBranch(\n url,\n config,\n) {\n const { name: repoName, owner: project, resource } = parseGitUrl(url);\n\n const isHosted = resource === 'bitbucket.org';\n // Bitbucket Server https://docs.atlassian.com/bitbucket-server/rest/7.9.0/bitbucket-rest.html#idp184\n let branchUrl = isHosted\n ? `${config.apiBaseUrl}/repositories/${project}/${repoName}`\n : `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/default-branch`;\n\n let response = await fetch(branchUrl, getBitbucketRequestOptions(config));\n\n if (response.status === 404 && !isHosted) {\n // First try the new format, and then if it gets specifically a 404 it should try the old format\n // (to support old Atlassian Bitbucket v5.11.1 format )\n branchUrl = `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/branches/default`;\n response = await fetch(branchUrl, getBitbucketRequestOptions(config));\n }\n\n if (!response.ok) {\n const message = `Failed to retrieve default branch from ${branchUrl}, ${response.status} ${response.statusText}`;\n throw new Error(message);\n }\n\n let defaultBranch;\n if (isHosted) {\n const repoInfo = await response.json();\n defaultBranch = repoInfo.mainbranch.name;\n } else {\n const { displayId } = await response.json();\n defaultBranch = displayId;\n }\n if (!defaultBranch) {\n throw new Error(\n `Failed to read default branch from ${branchUrl}. ` +\n `Response ${response.status} ${response.json()}`,\n );\n }\n return defaultBranch;\n}\n\n/**\n * Given a URL pointing to a path on a provider, returns a URL that is suitable\n * for downloading the subtree.\n *\n * @param url - A URL pointing to a path\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketDownloadUrl(\n url,\n config,\n) {\n const {\n name: repoName,\n owner: project,\n ref,\n protocol,\n resource,\n filepath,\n } = parseGitUrl(url);\n\n const isHosted = resource === 'bitbucket.org';\n\n let branch = ref;\n if (!branch) {\n branch = await getBitbucketDefaultBranch(url, config);\n }\n // path will limit the downloaded content\n // /docs will only download the docs folder and everything below it\n // /docs/index.md will download the docs folder and everything below it\n const path = filepath ? `&path=${encodeURIComponent(filepath)}` : '';\n const archiveUrl = isHosted\n ? `${protocol}://${resource}/${project}/${repoName}/get/${branch}.tar.gz`\n : `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/archive?format=tgz&at=${branch}&prefix=${project}-${repoName}${path}`;\n\n return archiveUrl;\n}\n\n/**\n * Given a URL pointing to a file on a provider, returns a URL that is suitable\n * for fetching the contents of the data.\n *\n * @remarks\n *\n * Converts\n * from: https://bitbucket.org/orgname/reponame/src/master/file.yaml\n * to: https://api.bitbucket.org/2.0/repositories/orgname/reponame/src/master/file.yaml\n *\n * @param url - A URL pointing to a file\n * @param config - The relevant provider config\n * @public\n */\nexport function getBitbucketFileFetchUrl(\n url,\n config,\n) {\n try {\n const { owner, name, ref, filepathtype, filepath } = parseGitUrl(url);\n if (\n !owner ||\n !name ||\n (filepathtype !== 'browse' &&\n filepathtype !== 'raw' &&\n filepathtype !== 'src')\n ) {\n throw new Error('Invalid Bitbucket URL or file path');\n }\n\n const pathWithoutSlash = filepath.replace(/^\\//, '');\n\n if (config.host === 'bitbucket.org') {\n if (!ref) {\n throw new Error('Invalid Bitbucket URL or file path');\n }\n return `${config.apiBaseUrl}/repositories/${owner}/${name}/src/${ref}/${pathWithoutSlash}`;\n }\n return `${config.apiBaseUrl}/projects/${owner}/repos/${name}/raw/${pathWithoutSlash}?at=${ref}`;\n } catch (e) {\n throw new Error(`Incorrect URL: ${url}, ${e}`);\n }\n}\n\n/**\n * Gets the request options necessary to make requests to a given provider.\n *\n * @param config - The relevant provider config\n * @public\n */\nexport function getBitbucketRequestOptions(\n config,\n) {\n const headers = {};\n\n if (config.token) {\n headers.Authorization = `Bearer ${config.token}`;\n } else if (config.username && config.appPassword) {\n const buffer = Buffer.from(\n `${config.username}:${config.appPassword}`,\n 'utf8',\n );\n headers.Authorization = `Basic ${buffer.toString('base64')}`;\n }\n\n return {\n headers,\n };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { trimEnd } from 'lodash';\nimport { isValidHost } from '../helpers';\n\nconst GITHUB_HOST = 'github.com';\nconst GITHUB_API_BASE_URL = 'https://api.github.com';\nconst GITHUB_RAW_BASE_URL = 'https://raw.githubusercontent.com';\n\n/**\n * The configuration parameters for a single GitHub integration.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Reads a single GitHub integration config.\n *\n * @param config - The config object of a single integration\n * @public\n */\nexport function readGitHubIntegrationConfig(\n config,\n) {\n const host = config.getOptionalString('host') ?? GITHUB_HOST;\n let apiBaseUrl = config.getOptionalString('apiBaseUrl');\n let rawBaseUrl = config.getOptionalString('rawBaseUrl');\n const token = config.getOptionalString('token');\n const apps = config.getOptionalConfigArray('apps')?.map(c => ({\n appId: c.getNumber('appId'),\n clientId: c.getString('clientId'),\n clientSecret: c.getString('clientSecret'),\n webhookSecret: c.getString('webhookSecret'),\n privateKey: c.getString('privateKey'),\n allowedInstallationOwners: c.getOptionalStringArray(\n 'allowedInstallationOwners',\n ),\n }));\n\n if (!isValidHost(host)) {\n throw new Error(\n `Invalid GitHub integration config, '${host}' is not a valid host`,\n );\n }\n\n if (apiBaseUrl) {\n apiBaseUrl = trimEnd(apiBaseUrl, '/');\n } else if (host === GITHUB_HOST) {\n apiBaseUrl = GITHUB_API_BASE_URL;\n }\n\n if (rawBaseUrl) {\n rawBaseUrl = trimEnd(rawBaseUrl, '/');\n } else if (host === GITHUB_HOST) {\n rawBaseUrl = GITHUB_RAW_BASE_URL;\n }\n\n return { host, apiBaseUrl, rawBaseUrl, token, apps };\n}\n\n/**\n * Reads a set of GitHub integration configs, and inserts some defaults for\n * public GitHub if not specified.\n *\n * @param configs - All of the integration config objects\n * @public\n */\nexport function readGitHubIntegrationConfigs(\n configs,\n) {\n // First read all the explicit integrations\n const result = configs.map(readGitHubIntegrationConfig);\n\n // If no explicit github.com integration was added, put one in the list as\n // a convenience\n if (!result.some(c => c.host === GITHUB_HOST)) {\n result.push({\n host: GITHUB_HOST,\n apiBaseUrl: GITHUB_API_BASE_URL,\n rawBaseUrl: GITHUB_RAW_BASE_URL,\n });\n }\n\n return result;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport parseGitUrl from 'git-url-parse';\n\n\n\n/**\n * Given a URL pointing to a file on a provider, returns a URL that is suitable\n * for fetching the contents of the data.\n *\n * @remarks\n *\n * Converts\n * from: https://github.com/a/b/blob/branchname/path/to/c.yaml\n * to: https://api.github.com/repos/a/b/contents/path/to/c.yaml?ref=branchname\n * or: https://raw.githubusercontent.com/a/b/branchname/c.yaml\n *\n * @param url - A URL pointing to a file\n * @param config - The relevant provider config\n * @public\n */\nexport function getGitHubFileFetchUrl(\n url,\n config,\n credentials,\n) {\n try {\n const { owner, name, ref, filepathtype, filepath } = parseGitUrl(url);\n if (\n !owner ||\n !name ||\n !ref ||\n // GitHub is automatically redirecting tree urls to blob urls so it's\n // fine to pass a tree url.\n (filepathtype !== 'blob' &&\n filepathtype !== 'raw' &&\n filepathtype !== 'tree')\n ) {\n throw new Error('Invalid GitHub URL or file path');\n }\n\n const pathWithoutSlash = filepath.replace(/^\\//, '');\n if (chooseEndpoint(config, credentials) === 'api') {\n return `${config.apiBaseUrl}/repos/${owner}/${name}/contents/${pathWithoutSlash}?ref=${ref}`;\n }\n return `${config.rawBaseUrl}/${owner}/${name}/${ref}/${pathWithoutSlash}`;\n } catch (e) {\n throw new Error(`Incorrect URL: ${url}, ${e}`);\n }\n}\n\n/**\n * Gets the request options necessary to make requests to a given provider.\n *\n * @deprecated This function is no longer used internally\n * @param config - The relevant provider config\n * @public\n */\nexport function getGitHubRequestOptions(\n config,\n credentials,\n) {\n const headers = {};\n\n if (chooseEndpoint(config, credentials) === 'api') {\n headers.Accept = 'application/vnd.github.v3.raw';\n }\n\n if (credentials.token) {\n headers.Authorization = `token ${credentials.token}`;\n }\n\n return { headers };\n}\n\nexport function chooseEndpoint(\n config,\n credentials,\n) {\n if (config.apiBaseUrl && (credentials.token || !config.rawBaseUrl)) {\n return 'api';\n }\n return 'raw';\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport parseGitUrl from 'git-url-parse';\n\nimport { createAppAuth } from '@octokit/auth-app';\nimport { Octokit, } from '@octokit/rest';\nimport { DateTime } from 'luxon';\n\n\n\n\n\n\n\n\n\n\n\nclass Cache {\n tokenCache = new Map\n\n\n();\n\n async getOrCreateToken(\n key,\n supplier,\n ) {\n const item = this.tokenCache.get(key);\n if (item && this.isNotExpired(item.expiresAt)) {\n return { accessToken: item.token };\n }\n\n const result = await supplier();\n this.tokenCache.set(key, result);\n return { accessToken: result.token };\n }\n\n // consider timestamps older than 50 minutes to be expired.\n isNotExpired = (date) =>\n date.diff(DateTime.local(), 'minutes').minutes > 50;\n}\n\n/**\n * This accept header is required when calling App APIs in GitHub Enterprise.\n * It has no effect on calls to github.com and can probably be removed entirely\n * once GitHub Apps is out of preview.\n */\nconst HEADERS = {\n Accept: 'application/vnd.github.machine-man-preview+json',\n};\n\n/**\n * GithubAppManager issues and caches tokens for a specific GitHub App.\n */\nclass GithubAppManager {\n appClient;\n baseUrl;\n baseAuthConfig;\n cache = new Cache();\n allowedInstallationOwners; // undefined allows all installations\n\n constructor(config, baseUrl) {\n this.allowedInstallationOwners = config.allowedInstallationOwners;\n this.baseUrl = baseUrl;\n this.baseAuthConfig = {\n appId: config.appId,\n privateKey: config.privateKey.replace(/\\\\n/gm, '\\n'),\n };\n this.appClient = new Octokit({\n baseUrl,\n headers: HEADERS,\n authStrategy: createAppAuth,\n auth: this.baseAuthConfig,\n });\n }\n\n async getInstallationCredentials(\n owner,\n repo,\n ) {\n const { installationId, suspended } = await this.getInstallationData(owner);\n if (this.allowedInstallationOwners) {\n if (!this.allowedInstallationOwners?.includes(owner)) {\n return { accessToken: undefined }; // An empty token allows anonymous access to public repos\n }\n }\n if (suspended) {\n throw new Error(`The GitHub application for ${owner} is suspended`);\n }\n\n const cacheKey = repo ? `${owner}/${repo}` : owner;\n\n // Go and grab an access token for the app scoped to a repository if provided, if not use the organisation installation.\n return this.cache.getOrCreateToken(cacheKey, async () => {\n const result = await this.appClient.apps.createInstallationAccessToken({\n installation_id: installationId,\n headers: HEADERS,\n });\n if (repo && result.data.repository_selection === 'selected') {\n const installationClient = new Octokit({\n baseUrl: this.baseUrl,\n auth: result.data.token,\n });\n const repos = await installationClient.paginate(\n installationClient.apps.listReposAccessibleToInstallation,\n );\n const hasRepo = repos.some(repository => {\n return repository.name === repo;\n });\n if (!hasRepo) {\n throw new Error(\n `The Backstage GitHub application used in the ${owner} organization does not have access to a repository with the name ${repo}`,\n );\n }\n }\n return {\n token: result.data.token,\n expiresAt: DateTime.fromISO(result.data.expires_at),\n };\n });\n }\n\n getInstallations()\n\n {\n return this.appClient.paginate(this.appClient.apps.listInstallations);\n }\n\n async getInstallationData(owner) {\n const allInstallations = await this.getInstallations();\n const installation = allInstallations.find(\n inst =>\n inst.account?.login?.toLocaleLowerCase('en-US') ===\n owner.toLocaleLowerCase('en-US'),\n );\n if (installation) {\n return {\n installationId: installation.id,\n suspended: Boolean(installation.suspended_by),\n };\n }\n const notFoundError = new Error(\n `No app installation found for ${owner} in ${this.baseAuthConfig.appId}`,\n );\n notFoundError.name = 'NotFoundError';\n throw notFoundError;\n }\n}\n\n/**\n * Corresponds to a Github installation which internally could hold several GitHub Apps.\n *\n * @public\n */\nexport class GithubAppCredentialsMux {\n apps;\n\n constructor(config) {\n this.apps =\n config.apps?.map(ac => new GithubAppManager(ac, config.apiBaseUrl)) ?? [];\n }\n\n async getAllInstallations()\n\n {\n if (!this.apps.length) {\n return [];\n }\n\n const installs = await Promise.all(\n this.apps.map(app => app.getInstallations()),\n );\n\n return installs.flat();\n }\n\n async getAppToken(owner, repo) {\n if (this.apps.length === 0) {\n return undefined;\n }\n\n const results = await Promise.all(\n this.apps.map(app =>\n app.getInstallationCredentials(owner, repo).then(\n credentials => ({ credentials, error: undefined }),\n error => ({ credentials: undefined, error }),\n ),\n ),\n );\n\n const result = results.find(resultItem => resultItem.credentials);\n if (result) {\n return result.credentials.accessToken;\n }\n\n const errors = results.map(r => r.error);\n const notNotFoundError = errors.find(err => err.name !== 'NotFoundError');\n if (notNotFoundError) {\n throw notNotFoundError;\n }\n\n return undefined;\n }\n}\n\n/**\n * Handles the creation and caching of credentials for GitHub integrations.\n *\n * @public\n * @remarks\n *\n * TODO: Possibly move this to a backend only package so that it's not used in the frontend by mistake\n */\nexport class SingleInstanceGithubCredentialsProvider\n \n{\n static create\n\n = config => {\n return new SingleInstanceGithubCredentialsProvider(\n new GithubAppCredentialsMux(config),\n config.token,\n );\n };\n\n constructor(\n githubAppCredentialsMux,\n token,\n ) {;this.githubAppCredentialsMux = githubAppCredentialsMux;this.token = token;}\n\n /**\n * Returns {@link GithubCredentials} for a given URL.\n *\n * @remarks\n *\n * Consecutive calls to this method with the same URL will return cached\n * credentials.\n *\n * The shortest lifetime for a token returned is 10 minutes.\n *\n * @example\n * ```ts\n * const { token, headers } = await getCredentials({\n * url: 'github.com/backstage/foobar'\n * })\n * ```\n *\n * @param opts - The organization or repository URL\n * @returns A promise of {@link GithubCredentials}.\n */\n async getCredentials(opts) {\n const parsed = parseGitUrl(opts.url);\n\n const owner = parsed.owner || parsed.name;\n const repo = parsed.owner ? parsed.name : undefined;\n\n let type = 'app';\n let token = await this.githubAppCredentialsMux.getAppToken(owner, repo);\n if (!token) {\n type = 'token';\n token = this.token;\n }\n\n return {\n headers: token ? { Authorization: `Bearer ${token}` } : undefined,\n token,\n type,\n };\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { SingleInstanceGithubCredentialsProvider } from './SingleInstanceGithubCredentialsProvider';\n\n/**\n * Handles the creation and caching of credentials for GitHub integrations.\n *\n * @public\n * @remarks\n *\n * TODO: Possibly move this to a backend only package so that it's not used in the frontend by mistake\n */\nexport class DefaultGithubCredentialsProvider\n \n{\n static fromIntegrations(integrations) {\n const credentialsProviders =\n new Map();\n\n integrations.github.list().forEach(integration => {\n const credentialsProvider =\n SingleInstanceGithubCredentialsProvider.create(integration.config);\n credentialsProviders.set(integration.config.host, credentialsProvider);\n });\n return new DefaultGithubCredentialsProvider(credentialsProviders);\n }\n\n constructor(\n providers,\n ) {;this.providers = providers;}\n\n /**\n * Returns {@link GithubCredentials} for a given URL.\n *\n * @remarks\n *\n * Consecutive calls to this method with the same URL will return cached\n * credentials.\n *\n * The shortest lifetime for a token returned is 10 minutes.\n *\n * @example\n * ```ts\n * const { token, headers } = await getCredentials({\n * url: 'https://github.com/backstage/foobar'\n * })\n *\n * const { token, headers } = await getCredentials({\n * url: 'https://github.com/backstage'\n * })\n * ```\n *\n * @param opts - The organization or repository URL\n * @returns A promise of {@link GithubCredentials}.\n */\n async getCredentials(opts) {\n const parsed = new URL(opts.url);\n const provider = this.providers.get(parsed.host);\n\n if (!provider) {\n throw new Error(\n `There is no GitHub integration that matches ${opts.url}. Please add a configuration for an integration.`,\n );\n }\n\n return provider.getCredentials(opts);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { basicIntegrations, defaultScmResolveUrl } from '../helpers';\n\nimport {\n\n readGitHubIntegrationConfigs,\n} from './config';\n\n/**\n * A GitHub based integration.\n *\n * @public\n */\nexport class GitHubIntegration {\n static factory = ({ config }) => {\n const configs = readGitHubIntegrationConfigs(\n config.getOptionalConfigArray('integrations.github') ?? [],\n );\n return basicIntegrations(\n configs.map(c => new GitHubIntegration(c)),\n i => i.config.host,\n );\n };\n\n constructor( integrationConfig) {;this.integrationConfig = integrationConfig;}\n\n get type() {\n return 'github';\n }\n\n get title() {\n return this.integrationConfig.host;\n }\n\n get config() {\n return this.integrationConfig;\n }\n\n resolveUrl(options\n\n\n\n) {\n // GitHub uses blob URLs for files and tree urls for directory listings. But\n // there is a redirect from tree to blob for files, so we can always return\n // tree urls here.\n return replaceGitHubUrlType(defaultScmResolveUrl(options), 'tree');\n }\n\n resolveEditUrl(url) {\n return replaceGitHubUrlType(url, 'edit');\n }\n}\n\n/**\n * Takes a GitHub URL and replaces the type part (blob, tree etc).\n *\n * @param url - The original URL\n * @param type - The desired type, e.g. \"blob\"\n * @public\n */\nexport function replaceGitHubUrlType(\n url,\n type,\n) {\n return url.replace(\n /\\/\\/([^/]+)\\/([^/]+)\\/([^/]+)\\/(blob|tree|edit)\\//,\n (_, host, owner, repo) => {\n return `//${host}/${owner}/${repo}/${type}/`;\n },\n );\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { trimEnd } from 'lodash';\nimport { isValidHost, isValidUrl } from '../helpers';\n\nconst GITLAB_HOST = 'gitlab.com';\nconst GITLAB_API_BASE_URL = 'https://gitlab.com/api/v4';\n\n/**\n * The configuration parameters for a single GitLab integration.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Reads a single GitLab integration config.\n *\n * @param config - The config object of a single integration\n * @public\n */\nexport function readGitLabIntegrationConfig(\n config,\n) {\n const host = config.getString('host');\n let apiBaseUrl = config.getOptionalString('apiBaseUrl');\n const token = config.getOptionalString('token');\n let baseUrl = config.getOptionalString('baseUrl');\n\n if (apiBaseUrl) {\n apiBaseUrl = trimEnd(apiBaseUrl, '/');\n } else if (host === GITLAB_HOST) {\n apiBaseUrl = GITLAB_API_BASE_URL;\n }\n\n if (baseUrl) {\n baseUrl = trimEnd(baseUrl, '/');\n } else {\n baseUrl = `https://${host}`;\n }\n\n if (host.includes(':')) {\n throw new Error(\n `Invalid GitLab integration config, host '${host}' should just be the host name (e.g. \"github.com\"), not a URL`,\n );\n } else if (!isValidHost(host)) {\n throw new Error(\n `Invalid GitLab integration config, '${host}' is not a valid host`,\n );\n } else if (!apiBaseUrl || !isValidUrl(apiBaseUrl)) {\n throw new Error(\n `Invalid GitLab integration config, '${apiBaseUrl}' is not a valid apiBaseUrl`,\n );\n } else if (!isValidUrl(baseUrl)) {\n throw new Error(\n `Invalid GitLab integration config, '${baseUrl}' is not a valid baseUrl`,\n );\n }\n\n return { host, token, apiBaseUrl, baseUrl };\n}\n\n/**\n * Reads a set of GitLab integration configs, and inserts some defaults for\n * public GitLab if not specified.\n *\n * @param configs - All of the integration config objects\n * @public\n */\nexport function readGitLabIntegrationConfigs(\n configs,\n) {\n // First read all the explicit integrations\n const result = configs.map(readGitLabIntegrationConfig);\n\n // As a convenience we always make sure there's at least an unauthenticated\n // reader for public gitlab repos.\n if (!result.some(c => c.host === GITLAB_HOST)) {\n result.push({\n host: GITLAB_HOST,\n apiBaseUrl: GITLAB_API_BASE_URL,\n baseUrl: `https://${GITLAB_HOST}`,\n });\n }\n\n return result;\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport fetch from 'cross-fetch';\n\n/**\n * Given a URL pointing to a file on a provider, returns a URL that is suitable\n * for fetching the contents of the data.\n *\n * @remarks\n *\n * Converts\n * from: https://gitlab.example.com/a/b/blob/master/c.yaml\n * to: https://gitlab.example.com/a/b/raw/master/c.yaml\n * -or-\n * from: https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath\n * to: https://gitlab.com/api/v4/projects/projectId/repository/files/filepath?ref=branch\n *\n * @param url - A URL pointing to a file\n * @param config - The relevant provider config\n * @public\n */\nexport async function getGitLabFileFetchUrl(\n url,\n config,\n) {\n // TODO(Rugvip): From the old GitlabReaderProcessor; used\n // the existence of /-/blob/ to switch the logic. Don't know if this\n // makes sense and it might require some more work.\n if (url.includes('/-/blob/')) {\n const projectID = await getProjectId(url, config);\n return buildProjectUrl(url, projectID).toString();\n }\n return buildRawUrl(url).toString();\n}\n\n/**\n * Gets the request options necessary to make requests to a given provider.\n *\n * @param config - The relevant provider config\n * @public\n */\nexport function getGitLabRequestOptions(config)\n\n {\n const { token = '' } = config;\n return {\n headers: {\n 'PRIVATE-TOKEN': token,\n },\n };\n}\n\n// Converts\n// from: https://gitlab.example.com/a/b/blob/master/c.yaml\n// to: https://gitlab.example.com/a/b/raw/master/c.yaml\nexport function buildRawUrl(target) {\n try {\n const url = new URL(target);\n\n const [empty, userOrOrg, repoName, blobKeyword, ...restOfPath] =\n url.pathname.split('/');\n\n if (\n empty !== '' ||\n userOrOrg === '' ||\n repoName === '' ||\n blobKeyword !== 'blob' ||\n !restOfPath.join('/').match(/\\.(yaml|yml)$/)\n ) {\n throw new Error('Wrong GitLab URL');\n }\n\n // Replace 'blob' with 'raw'\n url.pathname = [empty, userOrOrg, repoName, 'raw', ...restOfPath].join('/');\n\n return url;\n } catch (e) {\n throw new Error(`Incorrect url: ${target}, ${e}`);\n }\n}\n\n// Converts\n// from: https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath\n// to: https://gitlab.com/api/v4/projects/projectId/repository/files/filepath?ref=branch\nexport function buildProjectUrl(target, projectID) {\n try {\n const url = new URL(target);\n\n const branchAndFilePath = url.pathname.split('/-/blob/')[1];\n const [branch, ...filePath] = branchAndFilePath.split('/');\n\n url.pathname = [\n '/api/v4/projects',\n projectID,\n 'repository/files',\n encodeURIComponent(decodeURIComponent(filePath.join('/'))),\n 'raw',\n ].join('/');\n url.search = `?ref=${branch}`;\n\n return url;\n } catch (e) {\n throw new Error(`Incorrect url: ${target}, ${e}`);\n }\n}\n\n// Convert\n// from: https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath\n// to: The project ID that corresponds to the URL\nexport async function getProjectId(\n target,\n config,\n) {\n const url = new URL(target);\n\n if (!url.pathname.includes('/-/blob/')) {\n throw new Error('Please provide full path to yaml file from GitLab');\n }\n\n try {\n const repo = url.pathname.split('/-/blob/')[0];\n\n // Convert\n // to: https://gitlab.com/api/v4/projects/groupA%2Fteams%2FsubgroupA%2FteamA%2Frepo\n const repoIDLookup = new URL(\n `${url.protocol + url.hostname}/api/v4/projects/${encodeURIComponent(\n repo.replace(/^\\//, ''),\n )}`,\n );\n const response = await fetch(\n repoIDLookup.toString(),\n getGitLabRequestOptions(config),\n );\n const data = await response.json();\n\n if (!response.ok) {\n throw new Error(\n `GitLab Error '${data.error}', ${data.error_description}`,\n );\n }\n\n return Number(data.id);\n } catch (e) {\n throw new Error(`Could not get GitLab project ID for: ${target}, ${e}`);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { basicIntegrations, defaultScmResolveUrl } from '../helpers';\n\nimport {\n\n readGitLabIntegrationConfigs,\n} from './config';\n\n/**\n * A GitLab based integration.\n *\n * @public\n */\nexport class GitLabIntegration {\n static factory = ({ config }) => {\n const configs = readGitLabIntegrationConfigs(\n config.getOptionalConfigArray('integrations.gitlab') ?? [],\n );\n return basicIntegrations(\n configs.map(c => new GitLabIntegration(c)),\n i => i.config.host,\n );\n };\n\n constructor( integrationConfig) {;this.integrationConfig = integrationConfig;}\n\n get type() {\n return 'gitlab';\n }\n\n get title() {\n return this.integrationConfig.host;\n }\n\n get config() {\n return this.integrationConfig;\n }\n\n resolveUrl(options\n\n\n\n) {\n return defaultScmResolveUrl(options);\n }\n\n resolveEditUrl(url) {\n return replaceUrlType(url, 'edit');\n }\n}\n\nexport function replaceUrlType(\n url,\n type,\n) {\n return url.replace(/\\/\\-\\/(blob|tree|edit)\\//, `/-/${type}/`);\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst AMAZON_AWS_HOST = 'amazonaws.com';\n\n/**\n * The configuration parameters for a single AWS S3 provider.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Reads a single Aws S3 integration config.\n *\n * @param config - The config object of a single integration\n * @public\n */\n\nexport function readAwsS3IntegrationConfig(\n config,\n) {\n const endpoint = config.getOptionalString('endpoint');\n const s3ForcePathStyle =\n config.getOptionalBoolean('s3ForcePathStyle') ?? false;\n let host;\n let pathname;\n if (endpoint) {\n try {\n const url = new URL(endpoint);\n host = url.host;\n pathname = url.pathname;\n } catch {\n throw new Error(\n `invalid awsS3 integration config, endpoint '${endpoint}' is not a valid URL`,\n );\n }\n if (pathname !== '/') {\n throw new Error(\n `invalid awsS3 integration config, endpoints cannot contain path, got '${endpoint}'`,\n );\n }\n } else {\n host = AMAZON_AWS_HOST;\n }\n\n const accessKeyId = config.getOptionalString('accessKeyId');\n const secretAccessKey = config.getOptionalString('secretAccessKey');\n const roleArn = config.getOptionalString('roleArn');\n\n return {\n host,\n endpoint,\n s3ForcePathStyle,\n accessKeyId,\n secretAccessKey,\n roleArn,\n };\n}\n\n/**\n * Reads a set of AWS S3 integration configs, and inserts some defaults for\n * public Amazon AWS if not specified.\n *\n * @param configs - The config objects of the integrations\n * @public\n */\nexport function readAwsS3IntegrationConfigs(\n configs,\n) {\n // First read all the explicit integrations\n const result = configs.map(readAwsS3IntegrationConfig);\n\n // If no explicit amazonaws.com integration was added, put one in the list as\n // a convenience\n if (!result.some(c => c.host === AMAZON_AWS_HOST)) {\n result.push({\n host: AMAZON_AWS_HOST,\n });\n }\n return result;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { basicIntegrations, defaultScmResolveUrl } from '../helpers';\n\nimport { readAwsS3IntegrationConfigs } from './config';\n\n/**\n * Integrates with AWS S3 or compatible solutions.\n *\n * @public\n */\nexport class AwsS3Integration {\n static factory = ({ config }) => {\n const configs = readAwsS3IntegrationConfigs(\n config.getOptionalConfigArray('integrations.awsS3') ?? [],\n );\n return basicIntegrations(\n configs.map(c => new AwsS3Integration(c)),\n i => i.config.host,\n );\n };\n\n get type() {\n return 'awsS3';\n }\n\n get title() {\n return this.integrationConfig.host;\n }\n\n get config() {\n return this.integrationConfig;\n }\n\n constructor( integrationConfig) {;this.integrationConfig = integrationConfig;}\n\n resolveUrl(options\n\n\n\n) {\n const resolved = defaultScmResolveUrl(options);\n return resolved;\n }\n\n resolveEditUrl(url) {\n // TODO: Implement edit URL for awsS3\n return url;\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { AwsS3Integration } from './awsS3/AwsS3Integration';\nimport { AzureIntegration } from './azure/AzureIntegration';\nimport { BitbucketIntegration } from './bitbucket/BitbucketIntegration';\nimport { GitHubIntegration } from './github/GitHubIntegration';\nimport { GitLabIntegration } from './gitlab/GitLabIntegration';\nimport { defaultScmResolveUrl } from './helpers';\n\n\n\n/**\n * The set of supported integrations.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n/**\n * Exposes the set of supported integrations.\n *\n * @public\n */\nexport class ScmIntegrations {\n byType;\n\n static fromConfig(config) {\n return new ScmIntegrations({\n awsS3: AwsS3Integration.factory({ config }),\n azure: AzureIntegration.factory({ config }),\n bitbucket: BitbucketIntegration.factory({ config }),\n github: GitHubIntegration.factory({ config }),\n gitlab: GitLabIntegration.factory({ config }),\n });\n }\n\n constructor(integrationsByType) {\n this.byType = integrationsByType;\n }\n\n get awsS3() {\n return this.byType.awsS3;\n }\n\n get azure() {\n return this.byType.azure;\n }\n\n get bitbucket() {\n return this.byType.bitbucket;\n }\n\n get github() {\n return this.byType.github;\n }\n\n get gitlab() {\n return this.byType.gitlab;\n }\n\n list() {\n return Object.values(this.byType).flatMap(\n i => i.list() ,\n );\n }\n\n byUrl(url) {\n return Object.values(this.byType)\n .map(i => i.byUrl(url))\n .find(Boolean);\n }\n\n byHost(host) {\n return Object.values(this.byType)\n .map(i => i.byHost(host))\n .find(Boolean);\n }\n\n resolveUrl(options\n\n\n\n) {\n const integration = this.byUrl(options.base);\n if (!integration) {\n return defaultScmResolveUrl(options);\n }\n\n return integration.resolveUrl(options);\n }\n\n resolveEditUrl(url) {\n const integration = this.byUrl(url);\n if (!integration) {\n return url;\n }\n\n return integration.resolveEditUrl(url);\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AlertApiForwarder,\n NoOpAnalyticsApi,\n ErrorApiForwarder,\n ErrorAlerter,\n GoogleAuth,\n GithubAuth,\n OAuth2,\n OktaAuth,\n GitlabAuth,\n Auth0Auth,\n MicrosoftAuth,\n BitbucketAuth,\n OAuthRequestManager,\n WebStorage,\n UrlPatternDiscovery,\n SamlAuth,\n OneLoginAuth,\n UnhandledErrorForwarder,\n AtlassianAuth,\n createFetchApi,\n FetchMiddlewares,\n} from '@backstage/core-app-api';\n\nimport {\n createApiFactory,\n alertApiRef,\n analyticsApiRef,\n errorApiRef,\n discoveryApiRef,\n fetchApiRef,\n identityApiRef,\n oauthRequestApiRef,\n googleAuthApiRef,\n githubAuthApiRef,\n oauth2ApiRef,\n oktaAuthApiRef,\n gitlabAuthApiRef,\n auth0AuthApiRef,\n microsoftAuthApiRef,\n storageApiRef,\n configApiRef,\n samlAuthApiRef,\n oneloginAuthApiRef,\n oidcAuthApiRef,\n bitbucketAuthApiRef,\n atlassianAuthApiRef,\n} from '@backstage/core-plugin-api';\nimport {\n permissionApiRef,\n IdentityPermissionApi,\n} from '@backstage/plugin-permission-react';\n\nexport const apis = [\n createApiFactory({\n api: discoveryApiRef,\n deps: { configApi: configApiRef },\n factory: ({ configApi }) =>\n UrlPatternDiscovery.compile(\n `${configApi.getString('backend.baseUrl')}/api/{{ pluginId }}`,\n ),\n }),\n createApiFactory({\n api: alertApiRef,\n deps: {},\n factory: () => new AlertApiForwarder(),\n }),\n createApiFactory({\n api: analyticsApiRef,\n deps: {},\n factory: () => new NoOpAnalyticsApi(),\n }),\n createApiFactory({\n api: errorApiRef,\n deps: { alertApi: alertApiRef },\n factory: ({ alertApi }) => {\n const errorApi = new ErrorAlerter(alertApi, new ErrorApiForwarder());\n UnhandledErrorForwarder.forward(errorApi, { hidden: false });\n return errorApi;\n },\n }),\n createApiFactory({\n api: storageApiRef,\n deps: { errorApi: errorApiRef },\n factory: ({ errorApi }) => WebStorage.create({ errorApi }),\n }),\n createApiFactory({\n api: fetchApiRef,\n deps: {\n configApi: configApiRef,\n identityApi: identityApiRef,\n discoveryApi: discoveryApiRef,\n },\n factory: ({ configApi, identityApi, discoveryApi }) => {\n return createFetchApi({\n middleware: [\n FetchMiddlewares.resolvePluginProtocol({\n discoveryApi,\n }),\n FetchMiddlewares.injectIdentityAuth({\n identityApi,\n config: configApi,\n }),\n ],\n });\n },\n }),\n createApiFactory({\n api: oauthRequestApiRef,\n deps: {},\n factory: () => new OAuthRequestManager(),\n }),\n createApiFactory({\n api: googleAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n GoogleAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: microsoftAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n MicrosoftAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: githubAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n GithubAuth.create({\n discoveryApi,\n oauthRequestApi,\n defaultScopes: ['read:user'],\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: oktaAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n OktaAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: gitlabAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n GitlabAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: auth0AuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n Auth0Auth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: oauth2ApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: samlAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, configApi }) =>\n SamlAuth.create({\n discoveryApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: oneloginAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n OneLoginAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: oidcAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n OAuth2.create({\n discoveryApi,\n oauthRequestApi,\n provider: {\n id: 'oidc',\n title: 'Your Identity Provider',\n icon: () => null,\n },\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: bitbucketAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) =>\n BitbucketAuth.create({\n discoveryApi,\n oauthRequestApi,\n defaultScopes: ['team'],\n environment: configApi.getOptionalString('auth.environment'),\n }),\n }),\n createApiFactory({\n api: atlassianAuthApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n oauthRequestApi: oauthRequestApiRef,\n configApi: configApiRef,\n },\n factory: ({ discoveryApi, oauthRequestApi, configApi }) => {\n return AtlassianAuth.create({\n discoveryApi,\n oauthRequestApi,\n environment: configApi.getOptionalString('auth.environment'),\n });\n },\n }),\n createApiFactory({\n api: permissionApiRef,\n deps: {\n discovery: discoveryApiRef,\n identity: identityApiRef,\n config: configApiRef,\n },\n factory: ({ config, discovery, identity }) =>\n IdentityPermissionApi.create({ config, discovery, identity }),\n }),\n];\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\nimport Button from '@material-ui/core/Button';\nimport { ErrorPanel, Progress, ErrorPage } from '@backstage/core-components';\nimport {\n MemoryRouter,\n useInRouterContext,\n BrowserRouter,\n} from 'react-router-dom';\n\n\n\n\n\n\nexport function OptionallyWrapInRouter({ children }) {\n if (useInRouterContext()) {\n return React.createElement(React.Fragment, null, children);\n }\n return React.createElement(MemoryRouter, null, children);\n}\n\nconst DefaultNotFoundPage = () => (\n React.createElement(ErrorPage, { status: \"404\", statusMessage: \"PAGE NOT FOUND\" ,} )\n);\n\nconst DefaultBootErrorPage = ({ step, error }) => {\n let message = '';\n if (step === 'load-config') {\n message = `The configuration failed to load, someone should have a look at this error: ${error.message}`;\n } else if (step === 'load-chunk') {\n message = `Lazy loaded chunk failed to load, try to reload the page: ${error.message}`;\n }\n // TODO: figure out a nicer way to handle routing on the error page, when it can be done.\n return (\n React.createElement(OptionallyWrapInRouter, null\n , React.createElement(ErrorPage, { status: \"501\", statusMessage: message,} )\n )\n );\n};\n\nconst DefaultErrorBoundaryFallback = ({\n error,\n resetError,\n plugin,\n}) => {\n return (\n React.createElement(ErrorPanel, {\n title: `Error in ${plugin?.getId()}`,\n defaultExpanded: true,\n error: error,}\n \n , React.createElement(Button, { variant: \"outlined\", onClick: resetError,}, \"Retry\"\n\n )\n )\n );\n};\n\n/**\n * Creates a set of default components to pass along to {@link @backstage/core-app-api#createSpecializedApp}.\n *\n * @public\n */\nexport const components = {\n Progress,\n Router: BrowserRouter,\n NotFoundErrorPage: DefaultNotFoundPage,\n BootErrorPage: DefaultBootErrorPage,\n ErrorBoundaryFallback: DefaultErrorBoundaryFallback,\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport MuiApartmentIcon from '@material-ui/icons/Apartment';\nimport MuiBrokenImageIcon from '@material-ui/icons/BrokenImage';\nimport MuiCategoryIcon from '@material-ui/icons/Category';\nimport MuiCreateNewFolderIcon from '@material-ui/icons/CreateNewFolder';\nimport MuiSubjectIcon from '@material-ui/icons/Subject';\nimport MuiSearchIcon from '@material-ui/icons/Search';\nimport MuiChatIcon from '@material-ui/icons/Chat';\nimport MuiDashboardIcon from '@material-ui/icons/Dashboard';\nimport MuiDocsIcon from '@material-ui/icons/Description';\nimport MuiEmailIcon from '@material-ui/icons/Email';\nimport MuiExtensionIcon from '@material-ui/icons/Extension';\nimport MuiGitHubIcon from '@material-ui/icons/GitHub';\nimport MuiHelpIcon from '@material-ui/icons/Help';\nimport MuiLocationOnIcon from '@material-ui/icons/LocationOn';\nimport MuiMemoryIcon from '@material-ui/icons/Memory';\nimport MuiMenuBookIcon from '@material-ui/icons/MenuBook';\nimport MuiPeopleIcon from '@material-ui/icons/People';\nimport MuiPersonIcon from '@material-ui/icons/Person';\nimport MuiWarningIcon from '@material-ui/icons/Warning';\n\nexport const icons = {\n brokenImage: MuiBrokenImageIcon ,\n // To be confirmed: see https://github.com/backstage/backstage/issues/4970\n catalog: MuiMenuBookIcon ,\n scaffolder: MuiCreateNewFolderIcon ,\n techdocs: MuiSubjectIcon ,\n search: MuiSearchIcon ,\n chat: MuiChatIcon ,\n dashboard: MuiDashboardIcon ,\n docs: MuiDocsIcon ,\n email: MuiEmailIcon ,\n github: MuiGitHubIcon ,\n group: MuiPeopleIcon ,\n help: MuiHelpIcon ,\n 'kind:api': MuiExtensionIcon ,\n 'kind:component': MuiMemoryIcon ,\n 'kind:domain': MuiApartmentIcon ,\n 'kind:group': MuiPeopleIcon ,\n 'kind:location': MuiLocationOnIcon ,\n 'kind:system': MuiCategoryIcon ,\n 'kind:user': MuiPersonIcon ,\n user: MuiPersonIcon ,\n warning: MuiWarningIcon ,\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * The default predefined burst shapes.\n *\n * @public\n * @remarks\n *\n * How to add a shape:\n *\n * 1. Get the svg shape from figma, should be ~1400 wide, ~400 high\n * and only the white-to-transparent mask, no colors.\n * 2. Run it through https://jakearchibald.github.io/svgomg/\n * 3. Run that through https://github.com/tigt/mini-svg-data-uri\n * with something like https://npm.runkit.com/mini-svg-data-uri\n * 4. Wrap the output in `url(\"\")`\n * 5. Give it a name and paste it into the `shapes` object below.\n */\nexport const shapes = {\n wave: `url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='1368' height='400' fill='none'%3e%3cmask id='a' width='1368' height='401' x='0' y='0' maskUnits='userSpaceOnUse'%3e%3cpath fill='url(%23paint0_linear)' d='M437 116C223 116 112 0 112 0h1256v400c-82 0-225-21-282-109-112-175-436-175-649-175z'/%3e%3cpath fill='url(%23paint1_linear)' d='M1368 400V282C891-29 788 40 711 161 608 324 121 372 0 361v39h1368z'/%3e%3cpath fill='url(%23paint2_linear)' d='M1368 244v156H0V94c92-24 198-46 375 0l135 41c176 51 195 109 858 109z'/%3e%3cpath fill='url(%23paint3_linear)' d='M1252 400h116c-14-7-35-14-116-16-663-14-837-128-1013-258l-85-61C98 28 46 8 0 0v400h1252z'/%3e%3c/mask%3e%3cg mask='url(%23a)'%3e%3cpath fill='white' d='M-172-98h1671v601H-172z'/%3e%3c/g%3e%3cdefs%3e%3clinearGradient id='paint0_linear' x1='602' x2='1093.5' y1='-960.5' y2='272' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint1_linear' x1='482' x2='480' y1='1058.5' y2='70.5' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint2_linear' x1='424' x2='446.1' y1='-587.5' y2='274.6' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint3_linear' x1='587' x2='349' y1='-1120.5' y2='341' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e\")`,\n wave2: `url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='1368' height='400' fill='none'%3e%3cmask id='a' width='1764' height='479' x='-229' y='-6' maskUnits='userSpaceOnUse'%3e%3cpath fill='url(%23paint0_linear)' d='M0 400h1350C1321 336 525 33 179-2c-345-34-395 236-408 402H0z'/%3e%3cpath fill='url(%23paint1_linear)' d='M1378 177v223H0V217s219 75 327 52C436 246 717-35 965 45s254 144 413 132z'/%3e%3cpath fill='url(%23paint2_linear)' d='M26 400l-78-16c-170 205-44-6-137-30l-4-1 4 1 137 30c37-45 89-110 159-201 399-514-45 238 1176-50 275-65 354-39 91 267H26z'/%3e%3c/mask%3e%3cg mask='url(%23a)'%3e%3cpath fill='white' d='M0 0h1368v400H0z'/%3e%3c/g%3e%3cdefs%3e%3clinearGradient id='paint0_linear' x1='431' x2='397.3' y1='-599' y2='372.8' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint1_linear' x1='236.5' x2='446.6' y1='-586' y2='381.5' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint2_linear' x1='851.8' x2='640.4' y1='-867.2' y2='363.7' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e\")`,\n round: `url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='1368' height='400' fill='none'%3e%3cmask id='a' width='2269' height='1408' x='-610' y='-509' maskUnits='userSpaceOnUse'%3e%3ccircle cx='1212.8' cy='74.8' r='317.5' fill='url(%23paint0_linear)' transform='rotate(-52 1213 75)'/%3e%3ccircle cx='737.8' cy='445.8' r='317.5' fill='url(%23paint1_linear)' transform='rotate(-116 738 446)'/%3e%3ccircle cx='601.8' cy='52.8' r='418.6' fill='url(%23paint2_linear)' transform='rotate(-117 602 53)'/%3e%3ccircle cx='999.8' cy='364' r='389.1' fill='url(%23paint3_linear)' transform='rotate(31 1000 364)'/%3e%3cellipse cx='-109.2' cy='263.5' fill='url(%23paint4_linear)' rx='429.2' ry='465.8' transform='rotate(-85 -109 264)'/%3e%3c/mask%3e%3cg mask='url(%23a)'%3e%3cpath fill='white' d='M0 0h1368v400H0z'/%3e%3c/g%3e%3cdefs%3e%3clinearGradient id='paint0_linear' x1='1301.2' x2='161.4' y1='-1879.7' y2='-969.6' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint1_linear' x1='826.2' x2='-313.6' y1='-1508.7' y2='-598.6' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint2_linear' x1='718.4' x2='-784.3' y1='-2524' y2='-1324.2' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint3_linear' x1='1108.2' x2='-288.6' y1='-2031.1' y2='-915.9' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3clinearGradient id='paint4_linear' x1='10.4' x2='-1626.5' y1='-2603.8' y2='-1399.5' gradientUnits='userSpaceOnUse'%3e%3cstop stop-color='white'/%3e%3cstop offset='1' stop-color='white' stop-opacity='0'/%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e\")`,\n};\n\n/**\n * The color range variants that are used in e.g. colorful bursts.\n *\n * @public\n */\nexport const colorVariants = {\n darkGrey: ['#171717', '#383838'],\n marineBlue: ['#006D8F', '#0049A1'],\n veryBlue: ['#0027AF', '#270094'],\n rubyRed: ['#98002B', '#8D1134'],\n toastyOrange: ['#BE2200', '#A41D00'],\n purpleSky: ['#8912CA', '#3E00EA'],\n eveningSea: ['#00FFF2', '#035355'],\n teal: ['#005B4B'],\n pinkSea: ['#C8077A', '#C2297D'],\n};\n\n/**\n * Utility to not have to write colors and shapes twice.\n *\n * @public\n * @remarks\n *\n * As the background shapes and colors are decorative, we place them onto the\n * page as a css background-image instead of an html element of its own.\n */\nexport function genPageTheme(colors, shape) {\n const gradientColors = colors.length === 1 ? [colors[0], colors[0]] : colors;\n const gradient = `linear-gradient(90deg, ${gradientColors.join(', ')})`;\n const backgroundImage = `${shape}, ${gradient}`;\n\n return { colors, shape, backgroundImage };\n}\n\n/**\n * All of the builtin page themes.\n *\n * @public\n */\nexport const pageTheme = {\n home: genPageTheme(colorVariants.teal, shapes.wave),\n documentation: genPageTheme(colorVariants.pinkSea, shapes.wave2),\n tool: genPageTheme(colorVariants.purpleSky, shapes.round),\n service: genPageTheme(colorVariants.marineBlue, shapes.wave),\n website: genPageTheme(colorVariants.veryBlue, shapes.wave),\n library: genPageTheme(colorVariants.rubyRed, shapes.wave),\n other: genPageTheme(colorVariants.darkGrey, shapes.wave),\n app: genPageTheme(colorVariants.toastyOrange, shapes.wave),\n apis: genPageTheme(colorVariants.teal, shapes.wave2),\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTheme as createMuiTheme } from '@material-ui/core/styles';\nimport { darken, lighten } from '@material-ui/core/styles/colorManipulator';\n\n\n\n\n\n\nimport { pageTheme as defaultPageThemes } from './pageTheme';\n\nconst DEFAULT_FONT_FAMILY =\n '\"Helvetica Neue\", Helvetica, Roboto, Arial, sans-serif';\n\n/**\n * A helper for creating theme options.\n *\n * @public\n */\nexport function createThemeOptions(\n options,\n) {\n const {\n palette,\n fontFamily = DEFAULT_FONT_FAMILY,\n defaultPageTheme,\n pageTheme = defaultPageThemes,\n } = options;\n\n if (!pageTheme[defaultPageTheme]) {\n throw new Error(`${defaultPageTheme} is not defined in pageTheme.`);\n }\n\n return {\n palette,\n props: {\n MuiGrid: {\n spacing: 2,\n },\n MuiSwitch: {\n color: 'primary',\n },\n },\n typography: {\n fontFamily,\n h5: {\n fontWeight: 700,\n },\n h4: {\n fontWeight: 700,\n fontSize: 28,\n marginBottom: 6,\n },\n h3: {\n fontSize: 32,\n fontWeight: 700,\n marginBottom: 6,\n },\n h2: {\n fontSize: 40,\n fontWeight: 700,\n marginBottom: 8,\n },\n h1: {\n fontSize: 54,\n fontWeight: 700,\n marginBottom: 10,\n },\n },\n page: pageTheme[defaultPageTheme],\n getPageTheme: ({ themeId }) =>\n pageTheme[themeId] ?? pageTheme[defaultPageTheme],\n };\n}\n\n/**\n * A helper for creating theme overrides.\n *\n * @public\n */\nexport function createThemeOverrides(theme) {\n return {\n MuiCssBaseline: {\n '@global': {\n html: {\n height: '100%',\n fontFamily: theme.typography.fontFamily,\n },\n body: {\n height: '100%',\n fontFamily: theme.typography.fontFamily,\n 'overscroll-behavior-y': 'none',\n },\n a: {\n color: 'inherit',\n textDecoration: 'none',\n },\n },\n },\n MuiTableRow: {\n // Alternating row backgrounds\n root: {\n '&:nth-of-type(odd)': {\n backgroundColor: theme.palette.background.default,\n },\n },\n // Use pointer for hoverable rows\n hover: {\n '&:hover': {\n cursor: 'pointer',\n },\n },\n // Alternating head backgrounds\n head: {\n '&:nth-of-type(odd)': {\n backgroundColor: theme.palette.background.paper,\n },\n },\n },\n // Tables are more dense than default mui tables\n MuiTableCell: {\n root: {\n wordBreak: 'break-word',\n overflow: 'hidden',\n verticalAlign: 'middle',\n lineHeight: '1',\n margin: 0,\n padding: theme.spacing(3, 2, 3, 2.5),\n borderBottom: 0,\n },\n sizeSmall: {\n padding: theme.spacing(1.5, 2, 1.5, 2.5),\n },\n head: {\n wordBreak: 'break-word',\n overflow: 'hidden',\n color: 'rgb(179, 179, 179)',\n fontWeight: 'normal',\n lineHeight: '1',\n },\n },\n MuiTabs: {\n // Tabs are smaller than default mui tab rows\n root: {\n minHeight: 24,\n },\n },\n MuiTab: {\n // Tabs are smaller and have a hover background\n root: {\n color: theme.palette.link,\n minHeight: 24,\n textTransform: 'initial',\n letterSpacing: '0.07em',\n '&:hover': {\n color: darken(theme.palette.link, 0.3),\n background: lighten(theme.palette.link, 0.95),\n },\n [theme.breakpoints.up('md')]: {\n minWidth: 120,\n fontSize: theme.typography.pxToRem(14),\n fontWeight: 500,\n },\n },\n textColorPrimary: {\n color: theme.palette.link,\n },\n },\n MuiTableSortLabel: {\n // No color change on hover, just rely on the arrow showing up instead.\n root: {\n color: 'inherit',\n '&:hover': {\n color: 'inherit',\n },\n '&:focus': {\n color: 'inherit',\n },\n },\n // Bold font for highlighting selected column\n active: {\n fontWeight: 'bold',\n color: 'inherit',\n },\n },\n MuiListItemText: {\n dense: {\n // Default dense list items to adding ellipsis for really long str...\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n },\n },\n MuiButton: {\n text: {\n // Text buttons have less padding by default, but we want to keep the original padding\n padding: undefined,\n },\n },\n MuiChip: {\n root: {\n backgroundColor: '#D9D9D9',\n // By default there's no margin, but it's usually wanted, so we add some trailing margin\n marginRight: theme.spacing(1),\n marginBottom: theme.spacing(1),\n color: theme.palette.grey[900],\n },\n outlined: {\n color: theme.palette.text.primary,\n },\n label: {\n lineHeight: `${theme.spacing(2.5)}px`,\n fontWeight: theme.typography.fontWeightMedium,\n fontSize: `${theme.spacing(1.75)}px`,\n },\n labelSmall: {\n fontSize: `${theme.spacing(1.5)}px`,\n },\n deleteIcon: {\n color: theme.palette.grey[500],\n width: `${theme.spacing(3)}px`,\n height: `${theme.spacing(3)}px`,\n margin: `0 ${theme.spacing(0.75)}px 0 -${theme.spacing(0.75)}px`,\n },\n deleteIconSmall: {\n width: `${theme.spacing(2)}px`,\n height: `${theme.spacing(2)}px`,\n margin: `0 ${theme.spacing(0.5)}px 0 -${theme.spacing(0.5)}px`,\n },\n },\n MuiCard: {\n root: {\n // When cards have a forced size, such as when they are arranged in a\n // CSS grid, the content needs to flex such that the actions (buttons\n // etc) end up at the bottom of the card instead of just below the body\n // contents.\n display: 'flex',\n flexDirection: 'column',\n },\n },\n MuiCardHeader: {\n root: {\n // Reduce padding between header and content\n paddingBottom: 0,\n },\n },\n MuiCardContent: {\n root: {\n // When cards have a forced size, such as when they are arranged in a\n // CSS grid, the content needs to flex such that the actions (buttons\n // etc) end up at the bottom of the card instead of just below the body\n // contents.\n flexGrow: 1,\n '&:last-child': {\n paddingBottom: undefined,\n },\n },\n },\n MuiCardActions: {\n root: {\n // We default to putting the card actions at the end\n justifyContent: 'flex-end',\n },\n },\n };\n}\n\n/**\n * Creates a Backstage MUI theme using a palette. The theme is created with the\n * common Backstage options and component styles.\n *\n * @public\n */\nexport function createTheme(options) {\n const themeOptions = createThemeOptions(options);\n const baseTheme = createMuiTheme(themeOptions) ;\n const overrides = createThemeOverrides(baseTheme);\n const theme = { ...baseTheme, overrides };\n return theme;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createTheme } from './baseTheme';\nimport { pageTheme } from './pageTheme';\nimport { yellow } from '@material-ui/core/colors';\n\n/**\n * The default Backstage light theme.\n *\n * @public\n */\nexport const lightTheme = createTheme({\n palette: {\n type: 'light',\n background: {\n default: '#F8F8F8',\n },\n status: {\n ok: '#1DB954',\n warning: '#FF9800',\n error: '#E22134',\n running: '#2E77D0',\n pending: '#FFED51',\n aborted: '#757575',\n },\n bursts: {\n fontColor: '#FEFEFE',\n slackChannelText: '#ddd',\n backgroundColor: {\n default: '#7C3699',\n },\n gradient: {\n linear: 'linear-gradient(-137deg, #4BB8A5 0%, #187656 100%)',\n },\n },\n primary: {\n main: '#2E77D0',\n },\n banner: {\n info: '#2E77D0',\n error: '#E22134',\n text: '#FFFFFF',\n link: '#000000',\n warning: '#FF9800',\n },\n border: '#E6E6E6',\n textContrast: '#000000',\n textVerySubtle: '#DDD',\n textSubtle: '#6E6E6E',\n highlight: '#FFFBCC',\n errorBackground: '#FFEBEE',\n warningBackground: '#F59B23',\n infoBackground: '#ebf5ff',\n errorText: '#CA001B',\n infoText: '#004e8a',\n warningText: '#000000',\n linkHover: '#2196F3',\n link: '#0A6EBE',\n gold: yellow.A700,\n navigation: {\n background: '#171717',\n indicator: '#9BF0E1',\n color: '#b5b5b5',\n selectedColor: '#FFF',\n navItem: {\n hoverBackground: '#404040',\n },\n submenu: {\n background: '#404040',\n },\n },\n pinSidebarButton: {\n icon: '#181818',\n background: '#BDBDBD',\n },\n tabbar: {\n indicator: '#9BF0E1',\n },\n },\n defaultPageTheme: 'home',\n pageTheme,\n});\n\n/**\n * The default Backstage dark theme.\n *\n * @public\n */\nexport const darkTheme = createTheme({\n palette: {\n type: 'dark',\n background: {\n default: '#333333',\n },\n status: {\n ok: '#71CF88',\n warning: '#FFB84D',\n error: '#F84C55',\n running: '#3488E3',\n pending: '#FEF071',\n aborted: '#9E9E9E',\n },\n bursts: {\n fontColor: '#FEFEFE',\n slackChannelText: '#ddd',\n backgroundColor: {\n default: '#7C3699',\n },\n gradient: {\n linear: 'linear-gradient(-137deg, #4BB8A5 0%, #187656 100%)',\n },\n },\n primary: {\n main: '#9CC9FF',\n dark: '#82BAFD',\n },\n secondary: {\n main: '#FF88B2',\n },\n banner: {\n info: '#2E77D0',\n error: '#E22134',\n text: '#FFFFFF',\n link: '#000000',\n warning: '#FF9800',\n },\n border: '#E6E6E6',\n textContrast: '#FFFFFF',\n textVerySubtle: '#727272',\n textSubtle: '#CCCCCC',\n highlight: '#FFFBCC',\n errorBackground: '#FFEBEE',\n warningBackground: '#F59B23',\n infoBackground: '#ebf5ff',\n errorText: '#CA001B',\n infoText: '#004e8a',\n warningText: '#000000',\n linkHover: '#82BAFD',\n link: '#9CC9FF',\n gold: yellow.A700,\n navigation: {\n background: '#424242',\n indicator: '#9BF0E1',\n color: '#b5b5b5',\n selectedColor: '#FFF',\n navItem: {\n hoverBackground: '#404040',\n },\n submenu: {\n background: '#404040',\n },\n },\n pinSidebarButton: {\n icon: '#404040',\n background: '#BDBDBD',\n },\n tabbar: {\n indicator: '#9BF0E1',\n },\n },\n defaultPageTheme: 'home',\n pageTheme,\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { darkTheme, lightTheme } from '@backstage/theme';\nimport DarkIcon from '@material-ui/icons/Brightness2';\nimport LightIcon from '@material-ui/icons/WbSunny';\nimport { ThemeProvider } from '@material-ui/core/styles';\nimport CssBaseline from '@material-ui/core/CssBaseline';\n\n\nexport const themes = [\n {\n id: 'light',\n title: 'Light Theme',\n variant: 'light',\n icon: React.createElement(LightIcon, null ),\n Provider: ({ children }) => (\n React.createElement(ThemeProvider, { theme: lightTheme,}\n , React.createElement(CssBaseline, null, children)\n )\n ),\n },\n {\n id: 'dark',\n title: 'Dark Theme',\n variant: 'dark',\n icon: React.createElement(DarkIcon, null ),\n Provider: ({ children }) => (\n React.createElement(ThemeProvider, { theme: darkTheme,}\n , React.createElement(CssBaseline, null, children)\n )\n ),\n },\n];\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { apis, components, icons, themes } from './defaults';\n\n\n\n\n\nimport {\n\n\n\n createSpecializedApp,\n} from '@backstage/core-app-api';\n\n/**\n * Creates a new Backstage App using a default set of components, icons and themes unless\n * they are explicitly provided.\n *\n * @public\n */\nexport function createApp(\n options,\n) {\n return createSpecializedApp({\n ...options,\n apis: options?.apis ?? [],\n bindRoutes: options?.bindRoutes,\n components: {\n ...components,\n ...options?.components,\n },\n configLoader: options?.configLoader,\n defaultApis: apis,\n icons: {\n ...icons,\n ...options?.icons,\n },\n plugins: (options?.plugins ) ?? [],\n themes: options?.themes ?? themes,\n });\n}\n\n/**\n * The set of app options that {@link createApp} will provide defaults for\n * if they are not passed in explicitly.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport {\n Box,\n Chip,\n Divider,\n ListItem,\n ListItemText,\n makeStyles,\n} from '@material-ui/core';\nimport { Link } from '@backstage/core-components';\n\nconst useStyles = makeStyles({\n flexContainer: {\n flexWrap: 'wrap',\n },\n itemText: {\n width: '100%',\n wordBreak: 'break-all',\n marginBottom: '1rem',\n },\n});\n\nexport const CatalogResultListItem = ({ result }) => {\n const classes = useStyles();\n return (\n React.createElement(Link, { to: result.location,}\n , React.createElement(ListItem, { alignItems: \"flex-start\", className: classes.flexContainer,}\n , React.createElement(ListItemText, {\n className: classes.itemText,\n primaryTypographyProps: { variant: 'h6' },\n primary: result.title,\n secondary: result.text,}\n )\n , React.createElement(Box, null\n , result.kind && React.createElement(Chip, { label: `Kind: ${result.kind}`, size: \"small\",} )\n , result.lifecycle && (\n React.createElement(Chip, { label: `Lifecycle: ${result.lifecycle}`, size: \"small\",} )\n )\n )\n )\n , React.createElement(Divider, { component: \"li\",} )\n )\n );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * {@link https://backstage.io/docs/features/software-catalog/software-catalog-overview}\n * @public\n */\nexport const RESOURCE_TYPE_CATALOG_ENTITY = 'catalog-entity';\n\n/**\n * This permission is used to authorize actions that involve reading one or more\n * entities from the catalog.\n *\n * If this permission is not authorized, it will appear that the entity does not\n * exist in the catalog — both in the frontend and in API responses.\n * @public\n */\nexport const catalogEntityReadPermission = {\n name: 'catalog.entity.read',\n attributes: {\n action: 'read',\n },\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n};\n\n/**\n * This permission is used to authorize actions that involve creating a new\n * catalog entity. This includes registering an existing component into the\n * catalog.\n * @public\n */\nexport const catalogEntityCreatePermission = {\n name: 'catalog.entity.create',\n attributes: {\n action: 'create',\n },\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n};\n\n/**\n * This permission is used to designate actions that involve removing one or\n * more entities from the catalog.\n * @public\n */\nexport const catalogEntityDeletePermission = {\n name: 'catalog.entity.delete',\n attributes: {\n action: 'delete',\n },\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n};\n\n/**\n * This permission is used to designate refreshing one or more entities from the\n * catalog.\n * @public\n */\nexport const catalogEntityRefreshPermission = {\n name: 'catalog.entity.refresh',\n attributes: {\n action: 'update',\n },\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n};\n\n/**\n * This permission is used to designate actions that involve reading one or more\n * locations from the catalog.\n *\n * If this permission is not authorized, it will appear that the location does\n * not exist in the catalog — both in the frontend and in API responses.\n * @public\n */\nexport const catalogLocationReadPermission = {\n name: 'catalog.location.read',\n attributes: {\n action: 'read',\n },\n};\n\n/**\n * This permission is used to designate actions that involve creating catalog\n * locations.\n * @public\n */\nexport const catalogLocationCreatePermission = {\n name: 'catalog.location.create',\n attributes: {\n action: 'create',\n },\n};\n\n/**\n * This permission is used to designate actions that involve deleting locations\n * from the catalog.\n * @public\n */\nexport const catalogLocationDeletePermission = {\n name: 'catalog.location.delete',\n attributes: {\n action: 'delete',\n },\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Divider,\n IconButton,\n ListItemIcon,\n ListItemText,\n MenuItem,\n MenuList,\n Popover,\n} from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Cancel from '@material-ui/icons/Cancel';\nimport MoreVert from '@material-ui/icons/MoreVert';\nimport React, { useState } from 'react';\n\nimport { useEntityPermission } from '@backstage/plugin-catalog-react';\nimport { catalogEntityDeletePermission } from '@backstage/plugin-catalog-common';\n\n// TODO(freben): It should probably instead be the case that Header sets the theme text color to white inside itself unconditionally instead\nconst useStyles = makeStyles({\n button: {\n color: 'white',\n },\n});\n\n// NOTE(freben): Intentionally not exported at this point, since it's part of\n// the unstable extra context menu items concept below\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const EntityContextMenu = ({\n UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions,\n onUnregisterEntity,\n}) => {\n const [anchorEl, setAnchorEl] = useState();\n const classes = useStyles();\n const unregisterPermission = useEntityPermission(\n catalogEntityDeletePermission,\n );\n\n const onOpen = (event) => {\n setAnchorEl(event.currentTarget);\n };\n\n const onClose = () => {\n setAnchorEl(undefined);\n };\n\n const extraItems = UNSTABLE_extraContextMenuItems && [\n ...UNSTABLE_extraContextMenuItems.map(item => (\n React.createElement(MenuItem, {\n key: item.title,\n onClick: () => {\n onClose();\n item.onClick();\n },}\n \n , React.createElement(ListItemIcon, null\n , React.createElement(item.Icon, { fontSize: \"small\",} )\n )\n , React.createElement(ListItemText, { primary: item.title,} )\n )\n )),\n React.createElement(Divider, { key: \"the divider is here!\" ,} ),\n ];\n\n const disableUnregister =\n (!unregisterPermission.allowed ||\n UNSTABLE_contextMenuOptions?.disableUnregister) ??\n false;\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(IconButton, {\n 'aria-label': \"more\",\n 'aria-controls': \"long-menu\",\n 'aria-haspopup': \"true\",\n onClick: onOpen,\n 'data-testid': \"menu-button\",\n className: classes.button,}\n \n , React.createElement(MoreVert, null )\n )\n , React.createElement(Popover, {\n open: Boolean(anchorEl),\n onClose: onClose,\n anchorEl: anchorEl,\n anchorOrigin: { vertical: 'bottom', horizontal: 'right' },\n transformOrigin: { vertical: 'top', horizontal: 'right' },}\n \n , React.createElement(MenuList, null\n , extraItems\n , React.createElement(MenuItem, {\n onClick: () => {\n onClose();\n onUnregisterEntity();\n },\n disabled: disableUnregister,}\n \n , React.createElement(ListItemIcon, null\n , React.createElement(Cancel, { fontSize: \"small\",} )\n )\n , React.createElement(ListItemText, { primary: \"Unregister entity\" ,} )\n )\n )\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n ENTITY_DEFAULT_NAMESPACE,\n RELATION_OWNED_BY,\n} from '@backstage/catalog-model';\nimport {\n Content,\n Header,\n HeaderLabel,\n Link,\n Page,\n Progress,\n RoutedTabs,\n WarningPanel,\n} from '@backstage/core-components';\nimport {\n attachComponentData,\n\n useElementFilter,\n} from '@backstage/core-plugin-api';\nimport {\n EntityContext,\n EntityRefLinks,\n FavoriteEntity,\n getEntityRelations,\n UnregisterEntityDialog,\n useEntityCompoundName,\n} from '@backstage/plugin-catalog-react';\nimport { Box, } from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\nimport React, { useContext, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';\n\n\n\n\n\n\n\n\n\nconst dataKey = 'plugin.catalog.entityLayoutRoute';\n\nconst Route = () => null;\nattachComponentData(Route, dataKey, true);\n\n// This causes all mount points that are discovered within this route to use the path of the route itself\nattachComponentData(Route, 'core.gatherMountPoints', true);\n\nconst EntityLayoutTitle = ({\n entity,\n title,\n}\n\n\n) => {\n return (\n React.createElement(Box, { display: \"inline-flex\", alignItems: \"center\", height: \"1em\", maxWidth: \"100%\",}\n , React.createElement(Box, {\n component: \"span\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",}\n \n , title\n )\n , entity && React.createElement(FavoriteEntity, { entity: entity,} )\n )\n );\n};\n\nconst headerProps = (\n paramKind,\n paramNamespace,\n paramName,\n entity,\n) => {\n const kind = paramKind ?? entity?.kind ?? '';\n const namespace = paramNamespace ?? entity?.metadata.namespace ?? '';\n const name =\n entity?.metadata.title ?? paramName ?? entity?.metadata.name ?? '';\n return {\n headerTitle: `${name}${\n namespace && namespace !== ENTITY_DEFAULT_NAMESPACE\n ? ` in ${namespace}`\n : ''\n }`,\n headerType: (() => {\n let t = kind.toLocaleLowerCase('en-US');\n if (entity && entity.spec && 'type' in entity.spec) {\n t += ' — ';\n t += (entity.spec ).type.toLocaleLowerCase('en-US');\n }\n return t;\n })(),\n };\n};\n\nconst EntityLabels = ({ entity }) => {\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n return (\n React.createElement(React.Fragment, null\n , ownedByRelations.length > 0 && (\n React.createElement(HeaderLabel, {\n label: \"Owner\",\n value: \n React.createElement(EntityRefLinks, {\n entityRefs: ownedByRelations,\n defaultKind: \"Group\",\n color: \"inherit\",}\n )\n ,}\n )\n )\n , entity.spec?.lifecycle && (\n React.createElement(HeaderLabel, { label: \"Lifecycle\", value: entity.spec.lifecycle,} )\n )\n )\n );\n};\n\n// NOTE(freben): Intentionally not exported at this point, since it's part of\n// the unstable extra context menu items concept below\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * EntityLayout is a compound component, which allows you to define a layout for\n * entities using a sub-navigation mechanism.\n *\n * Consists of two parts: EntityLayout and EntityLayout.Route\n *\n * @example\n * ```jsx\n * <EntityLayout>\n * <EntityLayout.Route path=\"/example\" title=\"Example tab\">\n * <div>This is rendered under /example/anything-here route</div>\n * </EntityLayout.Route>\n * </EntityLayout>\n * ```\n */\nexport const EntityLayout = ({\n UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions,\n children,\n}) => {\n const { kind, namespace, name } = useEntityCompoundName();\n const { entity, loading, error } = useContext(EntityContext);\n const routes = useElementFilter(\n children,\n elements =>\n elements\n .selectByComponentData({\n key: dataKey,\n withStrictError:\n 'Child of EntityLayout must be an EntityLayout.Route',\n })\n .getElements() // all nodes, element data, maintain structure or not?\n .flatMap(({ props }) => {\n if (props.if && entity && !props.if(entity)) {\n return [];\n }\n\n return [\n {\n path: props.path,\n title: props.title,\n children: props.children,\n tabProps: props.tabProps,\n },\n ];\n }),\n [entity],\n );\n\n const { headerTitle, headerType } = headerProps(\n kind,\n namespace,\n name,\n entity,\n );\n\n const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);\n const navigate = useNavigate();\n const cleanUpAfterRemoval = async () => {\n setConfirmationDialogOpen(false);\n navigate('/');\n };\n\n const showRemovalDialog = () => setConfirmationDialogOpen(true);\n\n return (\n React.createElement(Page, { themeId: entity?.spec?.type?.toString() ?? 'home',}\n , React.createElement(Header, {\n title: React.createElement(EntityLayoutTitle, { title: headerTitle, entity: entity,} ),\n pageTitleOverride: headerTitle,\n type: headerType,}\n \n , entity && (\n React.createElement(React.Fragment, null\n , React.createElement(EntityLabels, { entity: entity,} )\n , React.createElement(EntityContextMenu, {\n UNSTABLE_extraContextMenuItems: UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions: UNSTABLE_contextMenuOptions,\n onUnregisterEntity: showRemovalDialog,}\n )\n )\n )\n )\n\n , loading && React.createElement(Progress, null )\n\n , entity && React.createElement(RoutedTabs, { routes: routes,} )\n\n , error && (\n React.createElement(Content, null\n , React.createElement(Alert, { severity: \"error\",}, error.toString())\n )\n )\n\n , !loading && !error && !entity && (\n React.createElement(Content, null\n , React.createElement(WarningPanel, { title: \"Entity not found\" ,}, \"There is no \"\n , kind, \" with the requested\" , ' '\n , React.createElement(Link, { to: \"https://backstage.io/docs/features/software-catalog/references\",}, \"kind, namespace, and name\"\n\n ), \".\"\n\n )\n )\n )\n\n , React.createElement(UnregisterEntityDialog, {\n open: confirmationDialogOpen,\n entity: entity,\n onConfirm: cleanUpAfterRemoval,\n onClose: () => setConfirmationDialogOpen(false),}\n )\n )\n );\n};\n\nEntityLayout.Route = Route;\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport { Button, Dialog, DialogActions, DialogTitle } from '@material-ui/core';\nimport React, { useState } from 'react';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport { assertError } from '@backstage/errors';\n\n\n\n\n\n\n\n\nexport const DeleteEntityDialog = ({\n open,\n onClose,\n onConfirm,\n entity,\n}) => {\n const [busy, setBusy] = useState(false);\n const catalogApi = useApi(catalogApiRef);\n const alertApi = useApi(alertApiRef);\n\n const onDelete = async () => {\n setBusy(true);\n try {\n const uid = entity.metadata.uid;\n await catalogApi.removeEntityByUid(uid);\n onConfirm();\n } catch (err) {\n assertError(err);\n alertApi.post({ message: err.message });\n } finally {\n setBusy(false);\n }\n };\n\n return (\n React.createElement(Dialog, { open: open, onClose: onClose,}\n , React.createElement(DialogTitle, { id: \"responsive-dialog-title\",}, \"Are you sure you want to delete this entity?\"\n\n )\n , React.createElement(DialogActions, null\n , React.createElement(Button, {\n variant: \"contained\",\n color: \"secondary\",\n disabled: busy,\n onClick: onDelete,}\n , \"Delete\"\n\n )\n , React.createElement(Button, { onClick: onClose, color: \"primary\",}, \"Cancel\"\n\n )\n )\n )\n );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { catalogRouteRef, useEntity } from '@backstage/plugin-catalog-react';\nimport { Alert } from '@material-ui/lab';\nimport React, { useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { DeleteEntityDialog } from './DeleteEntityDialog';\nimport { useRouteRef } from '@backstage/core-plugin-api';\n\nexport const isOrphan = (entity) =>\n entity?.metadata?.annotations?.['backstage.io/orphan'] === 'true';\n\n/**\n * Displays a warning alert if the entity is marked as orphan with the ability to delete said entity.\n */\nexport const EntityOrphanWarning = () => {\n const navigate = useNavigate();\n const catalogLink = useRouteRef(catalogRouteRef);\n const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);\n const { entity } = useEntity();\n\n const cleanUpAfterRemoval = async () => {\n setConfirmationDialogOpen(false);\n navigate(catalogLink());\n };\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(Alert, { severity: \"warning\", onClick: () => setConfirmationDialogOpen(true),}, \"This entity is not referenced by any location and is therefore not receiving updates. Click here to delete.\"\n\n\n )\n , React.createElement(DeleteEntityDialog, {\n open: confirmationDialogOpen,\n entity: entity,\n onConfirm: cleanUpAfterRemoval,\n onClose: () => setConfirmationDialogOpen(false),}\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n\n stringifyEntityRef,\n\n compareEntityToRef,\n} from '@backstage/catalog-model';\nimport {\n catalogApiRef,\n EntityRefLink,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport { Box } from '@material-ui/core';\nimport React from 'react';\nimport { ResponseErrorPanel } from '@backstage/core-components';\nimport {\n\n ENTITY_STATUS_CATALOG_PROCESSING_TYPE,\n} from '@backstage/catalog-client';\nimport { useApi, } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/lib/useAsync';\n\n\nconst errorFilter = (i) =>\n i.error &&\n i.level === 'error' &&\n i.type === ENTITY_STATUS_CATALOG_PROCESSING_TYPE;\n\n\n\n\n\n\n\n\nasync function getOwnAndAncestorsErrors(\n entityRef,\n catalogApi,\n) {\n const ancestors = await catalogApi.getEntityAncestors({ entityRef });\n const items = ancestors.items\n .map(item => {\n const statuses = (item.entity ).status?.items ?? [];\n const errors = statuses\n .filter(errorFilter)\n .map(e => e.error)\n .filter((e) => Boolean(e));\n return { errors: errors, entity: item.entity };\n })\n .filter(item => item.errors.length > 0);\n return { items };\n}\n\nexport const hasCatalogProcessingErrors = async (\n entity,\n context,\n) => {\n const catalogApi = context.apis.get(catalogApiRef);\n if (!catalogApi) {\n throw new Error(`No implementation available for ${catalogApiRef}`);\n }\n\n const errors = await getOwnAndAncestorsErrors(\n stringifyEntityRef(entity),\n catalogApi,\n );\n return errors.items.length > 0;\n};\n\n/**\n * Displays a list of errors from the ancestors of the current entity.\n */\nexport const EntityProcessingErrorsPanel = () => {\n const { entity } = useEntity();\n const entityRef = stringifyEntityRef(entity);\n const catalogApi = useApi(catalogApiRef);\n const { loading, error, value } = useAsync(async () => {\n return getOwnAndAncestorsErrors(entityRef, catalogApi);\n }, [entityRef, catalogApi]);\n\n if (error) {\n return (\n React.createElement(Box, { mb: 1,}\n , React.createElement(ResponseErrorPanel, { error: error,} )\n )\n );\n }\n\n if (loading || !value) {\n return null;\n }\n\n return (\n React.createElement(React.Fragment, null\n , value.items.map((ancestorError, index) => (\n React.createElement(Box, { key: index, mb: 1,}\n , !compareEntityToRef(\n entity,\n stringifyEntityRef(ancestorError.entity),\n ) && (\n React.createElement(Box, { p: 1,}, \"The error below originates from\"\n , ' '\n , React.createElement(EntityRefLink, { entityRef: ancestorError.entity,} )\n )\n )\n , ancestorError.errors.map((e, i) => (\n React.createElement(ResponseErrorPanel, { key: i, error: e,} )\n ))\n )\n ))\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport {\n useParams,\n useNavigate,\n\n matchRoutes,\n\n useRoutes,\n Navigate,\n\n} from 'react-router';\nimport { Helmet } from 'react-helmet';\nimport { HeaderTabs, Content } from '@backstage/core-components';\n\nconst getSelectedIndexOrDefault = (\n matchedRoute,\n tabs,\n defaultIndex = 0,\n) => {\n if (!matchedRoute) return defaultIndex;\n const tabIndex = tabs.findIndex(t => t.id === matchedRoute.route.path);\n return ~tabIndex ? tabIndex : defaultIndex;\n};\n\n/**\n * Compound component, which allows you to define layout\n * for EntityPage using Tabs as a sub-navigation mechanism\n * Consists of 2 parts: Tabbed.Layout and Tabbed.Content.\n * Takes care of: tabs, routes, document titles, spacing around content\n *\n * @example\n * ```jsx\n * <Tabbed.Layout>\n * <Tabbed.Content\n * title=\"Example tab\"\n * route=\"/example/*\"\n * element={<div>This is rendered under /example/anything-here route</div>}\n * />\n * </TabbedLayout>\n * ```\n */\nexport const Tabbed = {\n Layout: ({ children }) => {\n const routes = [];\n const tabs = [];\n const params = useParams();\n const navigate = useNavigate();\n\n React.Children.forEach(children, child => {\n if (!React.isValidElement(child)) {\n // Skip conditionals resolved to falses/nulls/undefineds etc\n return;\n }\n if (child.type !== Tabbed.Content) {\n throw new Error(\n 'This component only accepts Content elements as direct children. Check the code of the EntityPage.',\n );\n }\n const pathAndId = (child ).props.path;\n\n // Child here must be then always a functional component without any wrappers\n tabs.push({\n id: pathAndId,\n label: (child ).props.title,\n });\n\n routes.push({\n path: pathAndId,\n element: child.props.element,\n });\n });\n\n // Add catch-all for incorrect sub-routes\n if ((routes?.[0]?.path ?? '') !== '')\n routes.push({\n path: '/*',\n element: React.createElement(Navigate, { to: routes[0].path,} ),\n });\n\n const [matchedRoute] =\n matchRoutes(routes , `/${params['*']}`) ?? [];\n const selectedIndex = getSelectedIndexOrDefault(matchedRoute, tabs);\n const currentTab = tabs[selectedIndex];\n const title = currentTab?.label;\n\n const onTabChange = (index) =>\n // Remove trailing /*\n // And remove leading / for relative navigation\n // Note! route resolves relative to the position in the React tree,\n // not relative to current location\n navigate(tabs[index].id.replace(/\\/\\*$/, '').replace(/^\\//, ''));\n\n const currentRouteElement = useRoutes(routes);\n\n if (!currentTab) return null;\n return (\n React.createElement(React.Fragment, null\n , React.createElement(HeaderTabs, {\n tabs: tabs,\n selectedIndex: selectedIndex,\n onChange: onTabChange,}\n )\n , React.createElement(Content, null\n , React.createElement(Helmet, { title: title,} )\n , currentRouteElement\n )\n )\n );\n },\n Content: (_props) =>\n null,\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n\n ENTITY_DEFAULT_NAMESPACE,\n RELATION_OWNED_BY,\n} from '@backstage/catalog-model';\nimport {\n EntityContext,\n EntityRefLinks,\n FavoriteEntity,\n getEntityRelations,\n UnregisterEntityDialog,\n useEntityCompoundName,\n} from '@backstage/plugin-catalog-react';\nimport { Box } from '@material-ui/core';\nimport React, { useContext, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';\nimport { Tabbed } from './Tabbed';\n\nimport {\n Content,\n Header,\n HeaderLabel,\n Link,\n Page,\n Progress,\n ResponseErrorPanel,\n WarningPanel,\n} from '@backstage/core-components';\n\n\n\nconst EntityPageTitle = ({\n entity,\n title,\n}\n\n\n) => (\n React.createElement(Box, { display: \"inline-flex\", alignItems: \"center\", height: \"1em\",}\n , title\n , entity && React.createElement(FavoriteEntity, { entity: entity,} )\n )\n);\n\nconst EntityLabels = ({ entity }) => {\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n return (\n React.createElement(React.Fragment, null\n , ownedByRelations.length > 0 && (\n React.createElement(HeaderLabel, {\n label: \"Owner\",\n value: \n React.createElement(EntityRefLinks, {\n entityRefs: ownedByRelations,\n defaultKind: \"Group\",\n color: \"inherit\",}\n )\n ,}\n )\n )\n , entity.spec?.lifecycle && (\n React.createElement(HeaderLabel, { label: \"Lifecycle\", value: entity.spec.lifecycle,} )\n )\n )\n );\n};\n\nconst headerProps = (\n kind,\n namespace,\n name,\n entity,\n) => {\n return {\n headerTitle: `${name}${\n namespace && namespace !== ENTITY_DEFAULT_NAMESPACE\n ? ` in ${namespace}`\n : ''\n }`,\n headerType: (() => {\n let t = kind.toLocaleLowerCase('en-US');\n if (entity && entity.spec && 'type' in entity.spec) {\n t += ' — ';\n t += (entity.spec ).type.toLocaleLowerCase('en-US');\n }\n return t;\n })(),\n };\n};\n\n// NOTE(freben): Intentionally not exported at this point, since it's part of\n// the unstable extra context menu items concept below\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const EntityPageLayout = ({\n children,\n UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions,\n}) => {\n const { kind, namespace, name } = useEntityCompoundName();\n const { entity, loading, error } = useContext(EntityContext);\n const { headerTitle, headerType } = headerProps(\n kind,\n namespace,\n name,\n entity,\n );\n\n const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);\n const navigate = useNavigate();\n const cleanUpAfterRemoval = async () => {\n setConfirmationDialogOpen(false);\n navigate('/');\n };\n\n const showRemovalDialog = () => setConfirmationDialogOpen(true);\n\n return (\n React.createElement(Page, { themeId: entity?.spec?.type?.toString() ?? 'home',}\n , React.createElement(Header, {\n title: React.createElement(EntityPageTitle, { title: headerTitle, entity: entity,} ),\n pageTitleOverride: headerTitle,\n type: headerType,}\n \n /* TODO: Make entity labels configurable for entity kind / type */\n , entity && (\n React.createElement(React.Fragment, null\n , React.createElement(EntityLabels, { entity: entity,} )\n , React.createElement(EntityContextMenu, {\n UNSTABLE_extraContextMenuItems: UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions: UNSTABLE_contextMenuOptions,\n onUnregisterEntity: showRemovalDialog,}\n )\n )\n )\n )\n\n , loading && (\n React.createElement(Content, null\n , React.createElement(Progress, null )\n )\n )\n\n , entity && React.createElement(Tabbed.Layout, null, children)\n\n , error && (\n React.createElement(Content, null\n , React.createElement(ResponseErrorPanel, { error: error,} )\n )\n )\n\n , !loading && !error && !entity && (\n React.createElement(Content, null\n , React.createElement(WarningPanel, { title: \"Entity not found\" ,}, \"There is no \"\n , kind, \" with the requested\" , ' '\n , React.createElement(Link, { to: \"https://backstage.io/docs/features/software-catalog/references\",}, \"kind, namespace, and name\"\n\n ), \".\"\n\n )\n )\n )\n\n , React.createElement(UnregisterEntityDialog, {\n open: confirmationDialogOpen,\n entity: entity,\n onConfirm: cleanUpAfterRemoval,\n onClose: () => setConfirmationDialogOpen(false),}\n )\n )\n );\n};\n\nEntityPageLayout.Content = Tabbed.Content;\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport React, { } from 'react';\nimport {\n attachComponentData,\n useApiHolder,\n useElementFilter,\n\n} from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/lib/useAsync';\n\nconst ENTITY_SWITCH_KEY = 'core.backstage.entitySwitch';\n\nconst EntitySwitchCase = (_\n\n\n\n\n\n) => null;\n\nattachComponentData(EntitySwitchCase, ENTITY_SWITCH_KEY, true);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const EntitySwitch = ({ children }) => {\n const { entity } = useEntity();\n const apis = useApiHolder();\n const results = useElementFilter(\n children,\n collection =>\n collection\n .selectByComponentData({\n key: ENTITY_SWITCH_KEY,\n withStrictError: 'Child of EntitySwitch is not an EntitySwitch.Case',\n })\n .getElements()\n .flatMap((element) => {\n const { if: condition, children: elementsChildren } =\n element.props ;\n return [\n {\n if: condition?.(entity, { apis }) ?? true,\n children: elementsChildren,\n },\n ];\n }),\n [apis, entity],\n );\n const hasAsyncCases = results.some(\n r => typeof r.if === 'object' && 'then' in r.if,\n );\n\n if (hasAsyncCases) {\n return React.createElement(AsyncEntitySwitch, { results: results,} );\n }\n\n return results.find(r => r.if)?.children ?? null;\n};\n\nfunction AsyncEntitySwitch({ results }) {\n const { loading, value } = useAsync(async () => {\n const promises = results.map(\n async ({ if: condition, children: output }) => {\n try {\n if (await condition) {\n return output;\n }\n } catch {\n /* ignored */\n }\n\n return null;\n },\n );\n return (await Promise.all(promises)).find(Boolean) ?? null;\n }, [results]);\n\n if (loading || !value) {\n return null;\n }\n\n return value;\n}\n\nEntitySwitch.Case = EntitySwitchCase;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core';\nimport IlloSvgUrl from './illo.svg';\n\nconst useStyles = makeStyles(theme => ({\n illo: {\n maxWidth: '60%',\n top: 100,\n right: 20,\n position: 'absolute',\n [theme.breakpoints.down('xs')]: {\n maxWidth: '96%',\n position: 'relative',\n top: 'unset',\n right: 'unset',\n margin: `${theme.spacing(10)}px auto ${theme.spacing(4)}px`,\n },\n },\n}));\n\nexport const Illo = () => {\n const classes = useStyles();\n return (\n React.createElement('img', {\n src: IlloSvgUrl,\n className: classes.illo,\n alt: \"Illustration on entity not found page\" ,}\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { Grid, Button, Typography } from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\n\n\nimport { Illo } from './Illo';\n\nconst useStyles = makeStyles(theme => ({\n container: {\n paddingTop: theme.spacing(24),\n paddingLeft: theme.spacing(8),\n [theme.breakpoints.down('xs')]: {\n padding: theme.spacing(2),\n },\n },\n title: {\n paddingBottom: theme.spacing(2),\n [theme.breakpoints.down('xs')]: {\n fontSize: 32,\n },\n },\n body: {\n paddingBottom: theme.spacing(6),\n [theme.breakpoints.down('xs')]: {\n paddingBottom: theme.spacing(5),\n },\n },\n}));\n\nexport const EntityNotFound = () => {\n const classes = useStyles();\n\n return (\n React.createElement(Grid, { container: true, spacing: 0, className: classes.container,}\n , React.createElement(Illo, null )\n , React.createElement(Grid, { item: true, xs: 12, sm: 6,}\n , React.createElement(Typography, { variant: \"h2\", className: classes.title,}, \"Entity was not found\"\n\n )\n , React.createElement(Typography, { variant: \"body1\", className: classes.body,}, \"Want to help us build this? Check out our Getting Started documentation.\"\n\n\n )\n , React.createElement(Button, {\n variant: \"contained\",\n color: \"primary\",\n href: \"https://backstage.io/docs\",}\n , \"DOCS\"\n\n )\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model';\nimport {\n AsyncEntityProvider,\n useEntity,\n useEntityFromUrl,\n} from '@backstage/plugin-catalog-react';\nimport { Typography } from '@material-ui/core';\nimport React, { } from 'react';\nimport { Navigate, Route, Routes, useParams } from 'react-router';\nimport { CatalogPage } from './CatalogPage';\nimport { EntityNotFound } from './EntityNotFound';\nimport { EntityPageLayout } from './EntityPageLayout';\nimport { Content, Link } from '@backstage/core-components';\n\nconst DefaultEntityPage = () => (\n React.createElement(EntityPageLayout, null\n , React.createElement(EntityPageLayout.Content, {\n path: \"/\",\n title: \"Overview\",\n element: \n React.createElement(Content, null\n , React.createElement(Typography, { variant: \"h2\",}, \"This is the default entity page.\" )\n , React.createElement(Typography, { variant: \"body1\",}, \"To override this component with your custom implementation, read docs on\"\n\n , ' '\n , React.createElement(Link, { to: \"https://backstage.io/docs\",}, \"backstage.io/docs\")\n )\n )\n ,}\n )\n )\n);\n\nconst EntityPageSwitch = ({ EntityPage }) => {\n const { entity, loading, error } = useEntity();\n // Loading and error states\n if (loading) return React.createElement(EntityPageLayout, null );\n if (error || !entity) return React.createElement(EntityNotFound, null );\n\n // Otherwise EntityPage provided from the App\n // Note that EntityPage will include EntityPageLayout already\n return React.createElement(EntityPage, null );\n};\n\nconst OldEntityRouteRedirect = () => {\n const { optionalNamespaceAndName, '*': rest } = useParams() ;\n const [name, namespace] = optionalNamespaceAndName.split(':').reverse();\n const namespaceLower =\n namespace?.toLocaleLowerCase('en-US') ?? ENTITY_DEFAULT_NAMESPACE;\n const restWithSlash = rest ? `/${rest}` : '';\n return (\n React.createElement(Navigate, {\n to: `../../${namespaceLower}/component/${name}${restWithSlash}`,}\n )\n );\n};\n\nexport const EntityLoader = (props) => (\n React.createElement(AsyncEntityProvider, { ...useEntityFromUrl(), ...props,} )\n);\n\n/**\n * @deprecated Use plugin extensions instead\n * */\nexport const Router = ({\n EntityPage = DefaultEntityPage,\n}\n\n) => (\n React.createElement(Routes, null\n , React.createElement(Route, { path: \"/\", element: React.createElement(CatalogPage, null ),} )\n , React.createElement(Route, {\n path: \"/:namespace/:kind/:name\",\n element: \n React.createElement(EntityLoader, null\n , React.createElement(EntityPageSwitch, { EntityPage: EntityPage,} )\n )\n ,}\n )\n , React.createElement(Route, {\n path: \"Component/:optionalNamespaceAndName/*\",\n element: React.createElement(OldEntityRouteRedirect, null ),}\n )\n )\n);\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CatalogClient } from '@backstage/catalog-client';\nimport {\n catalogApiRef,\n catalogRouteRef,\n DefaultStarredEntitiesApi,\n entityRouteRef,\n starredEntitiesApiRef,\n} from '@backstage/plugin-catalog-react';\nimport { createComponentRouteRef, viewTechDocRouteRef } from './routes';\nimport {\n createApiFactory,\n createComponentExtension,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n fetchApiRef,\n storageApiRef,\n} from '@backstage/core-plugin-api';\n\nexport const catalogPlugin = createPlugin({\n id: 'catalog',\n apis: [\n createApiFactory({\n api: catalogApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new CatalogClient({ discoveryApi, fetchApi }),\n }),\n createApiFactory({\n api: starredEntitiesApiRef,\n deps: { storageApi: storageApiRef },\n factory: ({ storageApi }) =>\n new DefaultStarredEntitiesApi({ storageApi }),\n }),\n ],\n routes: {\n catalogIndex: catalogRouteRef,\n catalogEntity: entityRouteRef,\n },\n externalRoutes: {\n createComponent: createComponentRouteRef,\n viewTechDoc: viewTechDocRouteRef,\n },\n});\n\nexport const CatalogIndexPage = catalogPlugin.provide(\n createRoutableExtension({\n name: 'CatalogIndexPage',\n component: () =>\n import('./components/CatalogPage').then(m => m.CatalogPage),\n mountPoint: catalogRouteRef,\n }),\n);\n\nexport const CatalogEntityPage = catalogPlugin.provide(\n createRoutableExtension({\n name: 'CatalogEntityPage',\n component: () =>\n import('./components/CatalogEntityPage').then(m => m.CatalogEntityPage),\n mountPoint: entityRouteRef,\n }),\n);\n\nexport const EntityAboutCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityAboutCard',\n component: {\n lazy: () => import('./components/AboutCard').then(m => m.AboutCard),\n },\n }),\n);\n\nexport const EntityLinksCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityLinksCard',\n component: {\n lazy: () =>\n import('./components/EntityLinksCard').then(m => m.EntityLinksCard),\n },\n }),\n);\n\nexport const EntityHasSystemsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasSystemsCard',\n component: {\n lazy: () =>\n import('./components/HasSystemsCard').then(m => m.HasSystemsCard),\n },\n }),\n);\n\nexport const EntityHasComponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasComponentsCard',\n component: {\n lazy: () =>\n import('./components/HasComponentsCard').then(m => m.HasComponentsCard),\n },\n }),\n);\n\nexport const EntityHasSubcomponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasSubcomponentsCard',\n component: {\n lazy: () =>\n import('./components/HasSubcomponentsCard').then(\n m => m.HasSubcomponentsCard,\n ),\n },\n }),\n);\n\nexport const EntityHasResourcesCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasResourcesCard',\n component: {\n lazy: () =>\n import('./components/HasResourcesCard').then(m => m.HasResourcesCard),\n },\n }),\n);\n\nexport const EntityDependsOnComponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityDependsOnComponentsCard',\n component: {\n lazy: () =>\n import('./components/DependsOnComponentsCard').then(\n m => m.DependsOnComponentsCard,\n ),\n },\n }),\n);\n\nexport const EntityDependencyOfComponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityDependencyOfComponentsCard',\n component: {\n lazy: () =>\n import('./components/DependencyOfComponentsCard').then(\n m => m.DependencyOfComponentsCard,\n ),\n },\n }),\n);\n\nexport const EntityDependsOnResourcesCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityDependsOnResourcesCard',\n component: {\n lazy: () =>\n import('./components/DependsOnResourcesCard').then(\n m => m.DependsOnResourcesCard,\n ),\n },\n }),\n);\n\n/**\n * @deprecated This component is replaced by EntityCatalogGraphCard which is imported from `@backstage/plugin-catalog-graph`. This component will be removed in an\n * upcoming release\n */\nexport const EntitySystemDiagramCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntitySystemDiagramCard',\n component: {\n lazy: () =>\n import('./components/SystemDiagramCard').then(m => m.SystemDiagramCard),\n },\n }),\n);\n\nexport const RelatedEntitiesCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'RelatedEntitiesCard',\n component: {\n lazy: () =>\n import('./components/RelatedEntitiesCard').then(\n m => m.RelatedEntitiesCard,\n ),\n },\n }),\n);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { NotFoundError, ResponseError } from '@backstage/errors';\nimport { EventSourcePolyfill } from 'event-source-polyfill';\n\n\n\n/**\n * API to talk to `techdocs-backend`.\n *\n * @public\n */\nexport class TechDocsClient {\n configApi;\n discoveryApi;\n fetchApi;\n\n constructor(options\n\n\n\n) {\n this.configApi = options.configApi;\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n }\n\n async getApiOrigin() {\n return (\n this.configApi.getOptionalString('techdocs.requestUrl') ??\n (await this.discoveryApi.getBaseUrl('techdocs'))\n );\n }\n\n /**\n * Retrieve TechDocs metadata.\n *\n * When docs are built, we generate a techdocs_metadata.json and store it along with the generated\n * static files. It includes necessary data about the docs site. This method requests techdocs-backend\n * which retrieves the TechDocs metadata.\n *\n * @param entityId - Object containing entity data like name, namespace, etc.\n */\n async getTechDocsMetadata(entityId) {\n const { kind, namespace, name } = entityId;\n\n const apiOrigin = await this.getApiOrigin();\n const requestUrl = `${apiOrigin}/metadata/techdocs/${namespace}/${kind}/${name}`;\n const request = await this.fetchApi.fetch(`${requestUrl}`);\n if (!request.ok) {\n throw await ResponseError.fromResponse(request);\n }\n\n return await request.json();\n }\n\n /**\n * Retrieve metadata about an entity.\n *\n * This method requests techdocs-backend which uses the catalog APIs to respond with filtered\n * information required here.\n *\n * @param entityId - Object containing entity data like name, namespace, etc.\n */\n async getEntityMetadata(\n entityId,\n ) {\n const { kind, namespace, name } = entityId;\n\n const apiOrigin = await this.getApiOrigin();\n const requestUrl = `${apiOrigin}/metadata/entity/${namespace}/${kind}/${name}`;\n\n const request = await this.fetchApi.fetch(`${requestUrl}`);\n if (!request.ok) {\n throw await ResponseError.fromResponse(request);\n }\n\n return await request.json();\n }\n}\n\n/**\n * API which talks to TechDocs storage to fetch files to render.\n *\n * @public\n */\nexport class TechDocsStorageClient {\n configApi;\n discoveryApi;\n identityApi;\n fetchApi;\n\n constructor(options\n\n\n\n\n) {\n this.configApi = options.configApi;\n this.discoveryApi = options.discoveryApi;\n this.identityApi = options.identityApi;\n this.fetchApi = options.fetchApi;\n }\n\n async getApiOrigin() {\n return (\n this.configApi.getOptionalString('techdocs.requestUrl') ??\n (await this.discoveryApi.getBaseUrl('techdocs'))\n );\n }\n\n async getStorageUrl() {\n return (\n this.configApi.getOptionalString('techdocs.storageUrl') ??\n `${await this.discoveryApi.getBaseUrl('techdocs')}/static/docs`\n );\n }\n\n async getBuilder() {\n return this.configApi.getString('techdocs.builder');\n }\n\n /**\n * Fetch HTML content as text for an individual docs page in an entity's docs site.\n *\n * @param entityId - Object containing entity data like name, namespace, etc.\n * @param path - The unique path to an individual docs page e.g. overview/what-is-new\n * @returns HTML content of the docs page as string\n * @throws Throws error when the page is not found.\n */\n async getEntityDocs(entityId, path) {\n const { kind, namespace, name } = entityId;\n\n const storageUrl = await this.getStorageUrl();\n const url = `${storageUrl}/${namespace}/${kind}/${name}/${path}`;\n\n const request = await this.fetchApi.fetch(\n `${url.endsWith('/') ? url : `${url}/`}index.html`,\n );\n\n let errorMessage = '';\n switch (request.status) {\n case 404:\n errorMessage = 'Page not found. ';\n // path is empty for the home page of an entity's docs site\n if (!path) {\n errorMessage +=\n 'This could be because there is no index.md file in the root of the docs directory of this repository.';\n }\n throw new NotFoundError(errorMessage);\n case 500:\n errorMessage =\n 'Could not generate documentation or an error in the TechDocs backend. ';\n throw new Error(errorMessage);\n default:\n // Do nothing\n break;\n }\n\n return request.text();\n }\n\n /**\n * Check if docs are on the latest version and trigger rebuild if not\n *\n * @param entityId - Object containing entity data like name, namespace, etc.\n * @param logHandler - Callback to receive log messages from the build process\n * @returns Whether documents are currently synchronized to newest version\n * @throws Throws error on error from sync endpoint in Techdocs Backend\n */\n async syncEntityDocs(\n entityId,\n logHandler = () => {},\n ) {\n const { kind, namespace, name } = entityId;\n\n const apiOrigin = await this.getApiOrigin();\n const url = `${apiOrigin}/sync/${namespace}/${kind}/${name}`;\n const { token } = await this.identityApi.getCredentials();\n\n return new Promise((resolve, reject) => {\n // Polyfill is used to add support for custom headers and auth\n const source = new EventSourcePolyfill(url, {\n withCredentials: true,\n headers: token ? { Authorization: `Bearer ${token}` } : {},\n });\n\n source.addEventListener('log', (e) => {\n if (e.data) {\n logHandler(JSON.parse(e.data));\n }\n });\n\n source.addEventListener('finish', (e) => {\n let updated = false;\n\n if (e.data) {\n ({ updated } = JSON.parse(e.data));\n }\n\n resolve(updated ? 'updated' : 'cached');\n });\n\n source.onerror = (e) => {\n source.close();\n\n switch (e.status) {\n // the endpoint returned a 404 status\n case 404:\n reject(new NotFoundError(e.message));\n return;\n\n // also handles the event-stream close. the reject is ignored if the Promise was already\n // resolved by a finish event.\n default:\n reject(new Error(e.data));\n return;\n }\n };\n });\n }\n\n async getBaseUrl(\n oldBaseUrl,\n entityId,\n path,\n ) {\n const { kind, namespace, name } = entityId;\n\n const apiOrigin = await this.getApiOrigin();\n const newBaseUrl = `${apiOrigin}/static/docs/${namespace}/${kind}/${name}/${path}`;\n\n return new URL(\n oldBaseUrl,\n newBaseUrl.endsWith('/') ? newBaseUrl : `${newBaseUrl}/`,\n ).toString();\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport useCopyToClipboard from 'react-use/lib/useCopyToClipboard';\nimport { capitalize } from 'lodash';\nimport {\n CodeSnippet,\n\n\n WarningPanel,\n} from '@backstage/core-components';\nimport {\n useEntityListProvider,\n useStarredEntities,\n} from '@backstage/plugin-catalog-react';\nimport { DocsTable } from './DocsTable';\nimport * as actionFactories from './actions';\nimport * as columnFactories from './columns';\n\n\nexport const EntityListDocsTable = ({\n columns,\n actions,\n}\n\n\n) => {\n const { loading, error, entities, filters } = useEntityListProvider();\n const { isStarredEntity, toggleStarredEntity } = useStarredEntities();\n const [, copyToClipboard] = useCopyToClipboard();\n\n const title = capitalize(filters.user?.value ?? 'all');\n\n const defaultActions = [\n actionFactories.createCopyDocsUrlAction(copyToClipboard),\n actionFactories.createStarEntityAction(\n isStarredEntity,\n toggleStarredEntity,\n ),\n ];\n\n if (error) {\n return (\n React.createElement(WarningPanel, {\n severity: \"error\",\n title: \"Could not load available documentation.\" ,}\n \n , React.createElement(CodeSnippet, { language: \"text\", text: error.toString(),} )\n )\n );\n }\n\n return (\n React.createElement(DocsTable, {\n title: title,\n entities: entities,\n loading: loading,\n actions: actions || defaultActions,\n columns: columns,}\n )\n );\n};\n\nEntityListDocsTable.columns = columnFactories;\nEntityListDocsTable.actions = actionFactories;\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect } from 'react';\nimport {\n CATALOG_FILTER_EXISTS,\n\n\n useEntityListProvider,\n} from '@backstage/plugin-catalog-react';\n\nclass TechDocsFilter {\n getCatalogFilters() {\n return {\n 'metadata.annotations.backstage.io/techdocs-ref': CATALOG_FILTER_EXISTS,\n };\n }\n}\n\n\n\n\n\nexport const TechDocsPicker = () => {\n const { updateFilters } = useEntityListProvider();\n\n useEffect(() => {\n updateFilters({\n techdocs: new TechDocsFilter(),\n });\n }, [updateFilters]);\n\n return null;\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport {\n Content,\n ContentHeader,\n SupportButton,\n\n\n} from '@backstage/core-components';\nimport {\n EntityListContainer,\n FilterContainer,\n FilteredEntityLayout,\n} from '@backstage/plugin-catalog';\nimport {\n EntityListProvider,\n EntityOwnerPicker,\n EntityTagPicker,\n\n UserListPicker,\n} from '@backstage/plugin-catalog-react';\nimport { EntityListDocsTable } from './EntityListDocsTable';\nimport { TechDocsPageWrapper } from './TechDocsPageWrapper';\nimport { TechDocsPicker } from './TechDocsPicker';\n\n\nexport const DefaultTechDocsHome = ({\n initialFilter = 'all',\n columns,\n actions,\n}\n\n\n\n) => {\n return (\n React.createElement(TechDocsPageWrapper, null\n , React.createElement(Content, null\n , React.createElement(ContentHeader, { title: \"\",}\n , React.createElement(SupportButton, null, \"Discover documentation in your ecosystem.\"\n\n )\n )\n , React.createElement(EntityListProvider, null\n , React.createElement(FilteredEntityLayout, null\n , React.createElement(FilterContainer, null\n , React.createElement(TechDocsPicker, null )\n , React.createElement(UserListPicker, { initialFilter: initialFilter,} )\n , React.createElement(EntityOwnerPicker, null )\n , React.createElement(EntityTagPicker, null )\n )\n , React.createElement(EntityListContainer, null\n , React.createElement(EntityListDocsTable, { actions: actions, columns: columns,} )\n )\n )\n )\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n CodeSnippet,\n Progress,\n WarningPanel,\n} from '@backstage/core-components';\nimport { useEntityListProvider } from '@backstage/plugin-catalog-react';\nimport React from 'react';\nimport { DocsCardGrid } from './DocsCardGrid';\n\nexport const EntityListDocsGrid = () => {\n const { loading, error, entities } = useEntityListProvider();\n\n if (error) {\n return (\n React.createElement(WarningPanel, {\n severity: \"error\",\n title: \"Could not load available documentation.\" ,}\n \n , React.createElement(CodeSnippet, { language: \"text\", text: error.toString(),} )\n )\n );\n }\n\n if (loading || !entities) {\n return React.createElement(Progress, null );\n }\n\n entities.sort((a, b) =>\n (a.metadata.title ?? a.metadata.name).localeCompare(\n b.metadata.title ?? b.metadata.name,\n ),\n );\n\n return React.createElement(DocsCardGrid, { entities: entities,} );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { techdocsApiRef, techdocsStorageApiRef } from './api';\nimport { TechDocsClient, TechDocsStorageClient } from './client';\nimport {\n rootDocsRouteRef,\n rootRouteRef,\n rootCatalogDocsRouteRef,\n} from './routes';\nimport {\n configApiRef,\n createApiFactory,\n createComponentExtension,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n fetchApiRef,\n identityApiRef,\n} from '@backstage/core-plugin-api';\n\nexport const techdocsPlugin = createPlugin({\n id: 'techdocs',\n apis: [\n createApiFactory({\n api: techdocsStorageApiRef,\n deps: {\n configApi: configApiRef,\n discoveryApi: discoveryApiRef,\n identityApi: identityApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ configApi, discoveryApi, identityApi, fetchApi }) =>\n new TechDocsStorageClient({\n configApi,\n discoveryApi,\n identityApi,\n fetchApi,\n }),\n }),\n createApiFactory({\n api: techdocsApiRef,\n deps: {\n configApi: configApiRef,\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ configApi, discoveryApi, fetchApi }) =>\n new TechDocsClient({\n configApi,\n discoveryApi,\n fetchApi,\n }),\n }),\n ],\n routes: {\n root: rootRouteRef,\n docRoot: rootDocsRouteRef,\n entityContent: rootCatalogDocsRouteRef,\n },\n});\n\nexport const TechdocsPage = techdocsPlugin.provide(\n createRoutableExtension({\n name: 'TechdocsPage',\n component: () => import('./Router').then(m => m.Router),\n mountPoint: rootRouteRef,\n }),\n);\n\nexport const EntityTechdocsContent = techdocsPlugin.provide(\n createRoutableExtension({\n name: 'EntityTechdocsContent',\n component: () => import('./Router').then(m => m.EmbeddedDocsRouter),\n mountPoint: rootCatalogDocsRouteRef,\n }),\n);\n\n// takes a list of entities and renders documentation cards\nexport const DocsCardGrid = techdocsPlugin.provide(\n createComponentExtension({\n name: 'DocsCardGrid',\n component: {\n lazy: () =>\n import('./home/components/DocsCardGrid').then(m => m.DocsCardGrid),\n },\n }),\n);\n\n// takes a list of entities and renders table listing documentation\nexport const DocsTable = techdocsPlugin.provide(\n createComponentExtension({\n name: 'DocsTable',\n component: {\n lazy: () => import('./home/components/DocsTable').then(m => m.DocsTable),\n },\n }),\n);\n\n// takes a custom tabs config object and renders a documentation landing page\nexport const TechDocsCustomHome = techdocsPlugin.provide(\n createRoutableExtension({\n name: 'TechDocsCustomHome',\n component: () =>\n import('./home/components/TechDocsCustomHome').then(\n m => m.TechDocsCustomHome,\n ),\n mountPoint: rootRouteRef,\n }),\n);\n\nexport const TechDocsIndexPage = techdocsPlugin.provide(\n createRoutableExtension({\n name: 'TechDocsIndexPage',\n component: () =>\n import('./home/components/TechDocsIndexPage').then(\n m => m.TechDocsIndexPage,\n ),\n mountPoint: rootRouteRef,\n }),\n);\n\nexport const TechDocsReaderPage = techdocsPlugin.provide(\n createRoutableExtension({\n name: 'TechDocsReaderPage',\n component: () =>\n import('./reader/components/TechDocsPage').then(m => m.TechDocsPage),\n mountPoint: rootDocsRouteRef,\n }),\n);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport {\n scmIntegrationsApiRef,\n ScmIntegrationsApi,\n} from '@backstage/integration-react';\nimport {\n\n configApiRef,\n createApiFactory,\n\n discoveryApiRef,\n\n identityApiRef,\n} from '@backstage/core-plugin-api';\nimport {\n\n\n techdocsApiRef,\n\n techdocsStorageApiRef,\n} from '@backstage/plugin-techdocs';\n\n// TODO: Export type from plugin-techdocs and import this here\n// import { ParsedEntityId } from '@backstage/plugin-techdocs'\n\n/**\n * Note: Override TechDocs API to use local mkdocs server instead of techdocs-backend.\n */\n\nclass TechDocsDevStorageApi {\n configApi;\n discoveryApi;\n identityApi;\n\n constructor({\n configApi,\n discoveryApi,\n identityApi,\n }\n\n\n\n) {\n this.configApi = configApi;\n this.discoveryApi = discoveryApi;\n this.identityApi = identityApi;\n }\n\n async getApiOrigin() {\n return (\n this.configApi.getOptionalString('techdocs.requestUrl') ??\n (await this.discoveryApi.getBaseUrl('techdocs'))\n );\n }\n\n async getStorageUrl() {\n return (\n this.configApi.getOptionalString('techdocs.storageUrl') ??\n `${await this.discoveryApi.getBaseUrl('techdocs')}/static/docs`\n );\n }\n\n async getBuilder() {\n return this.configApi.getString('techdocs.builder');\n }\n\n async getEntityDocs(_entityId, path) {\n const apiOrigin = await this.getApiOrigin();\n // Irrespective of the entity, use mkdocs server to find the file for the path.\n const url = `${apiOrigin}/${path}`;\n\n const request = await fetch(\n `${url.endsWith('/') ? url : `${url}/`}index.html`,\n );\n\n if (request.status === 404) {\n throw new Error('Page not found');\n }\n\n return request.text();\n }\n\n async syncEntityDocs(_) {\n // this is just stub of this function as we don't need to check if docs are up to date,\n // we always want to retrigger a new build\n return 'cached';\n }\n\n // Used by transformer to modify the request to assets (CSS, Image) from inside the HTML.\n async getBaseUrl(\n oldBaseUrl,\n _entityId,\n path,\n ) {\n const apiOrigin = await this.getApiOrigin();\n return new URL(oldBaseUrl, `${apiOrigin}/${path}`).toString();\n }\n}\n\nclass TechDocsDevApi {\n configApi;\n discoveryApi;\n identityApi;\n\n constructor({\n configApi,\n discoveryApi,\n identityApi,\n }\n\n\n\n) {\n this.configApi = configApi;\n this.discoveryApi = discoveryApi;\n this.identityApi = identityApi;\n }\n\n async getApiOrigin() {\n return (\n this.configApi.getOptionalString('techdocs.requestUrl') ??\n (await this.discoveryApi.getBaseUrl('techdocs'))\n );\n }\n\n async getEntityMetadata(_entityId) {\n return {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'Component',\n metadata: {\n name: 'local',\n },\n spec: {\n owner: 'test',\n lifecycle: 'experimental',\n },\n };\n }\n\n async getTechDocsMetadata(_entityId) {\n return {\n site_name: 'Live preview environment',\n site_description: '',\n };\n }\n}\n\nexport const apis = [\n createApiFactory({\n api: techdocsStorageApiRef,\n deps: {\n configApi: configApiRef,\n discoveryApi: discoveryApiRef,\n identityApi: identityApiRef,\n },\n factory: ({ configApi, discoveryApi, identityApi }) =>\n new TechDocsDevStorageApi({\n configApi,\n discoveryApi,\n identityApi,\n }),\n }),\n createApiFactory({\n api: techdocsApiRef,\n deps: {\n configApi: configApiRef,\n discoveryApi: discoveryApiRef,\n identityApi: identityApiRef,\n },\n factory: ({ configApi, discoveryApi, identityApi }) =>\n new TechDocsDevApi({\n configApi,\n discoveryApi,\n identityApi,\n }),\n }),\n createApiFactory({\n api: scmIntegrationsApiRef,\n deps: { configApi: configApiRef },\n factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi),\n }),\n];\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core';\n\nconst useStyles = makeStyles({\n svg: {\n width: 'auto',\n height: 30,\n },\n path: {\n fill: '#7df3e1',\n },\n});\nconst LogoFull = () => {\n const classes = useStyles();\n\n return (\n React.createElement('svg', {\n className: classes.svg,\n xmlns: \"http://www.w3.org/2000/svg\",\n viewBox: \"0 0 2079.95 456.05\" ,}\n \n , React.createElement('path', {\n className: classes.path,\n d: \"M302.9,180a80.62,80.62,0,0,0,13.44-10.37c.8-.77,1.55-1.54,2.31-2.31a81.89,81.89,0,0,0,7.92-9.37,62.37,62.37,0,0,0,6.27-10.77,48.6,48.6,0,0,0,4.36-16.4c1.49-19.39-10-38.67-35.62-54.22L198.42,14,78.16,129.22l-78.29,75,108.6,65.9a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.8,66.42-25.69,19.16-18.36,25.52-42.12,13.7-61.87a49.69,49.69,0,0,0-6.8-8.87,89.78,89.78,0,0,0,19.28,2.15H259a85.09,85.09,0,0,0,31-5.79A80.88,80.88,0,0,0,302.9,180Zm-100.59,59.8c-19.32,18.51-50.4,21.24-75.7,5.9l-75.13-45.6,67.44-64.65,76.42,46.39C222.88,198.57,221.36,221.6,202.31,239.84Zm8.94-82.21L140.6,114.74,205,53l69.37,42.11c25.94,15.73,29.31,37.05,10.55,55A60.71,60.71,0,0,1,211.25,157.63Zm29.86,190c-19.57,18.75-46.17,29.08-74.88,29.08a123.84,123.84,0,0,1-64.11-18.19L-.13,296.51v24.67l108.6,65.91a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.81,66.42-25.69,12.88-12.34,20-27.13,19.68-41.49v-1.79A87.85,87.85,0,0,1,241.11,347.67Zm0-39c-19.57,18.76-46.17,29.09-74.88,29.09a123.84,123.84,0,0,1-64.11-18.19L-.13,257.52V282.2l108.6,65.91a111.59,111.59,0,0,0,57.76,16.41c24.92,0,48.8-8.8,66.42-25.68,12.88-12.35,20-27.13,19.68-41.5v-1.79A86.86,86.86,0,0,1,241.11,308.68Zm0-39c-19.57,18.76-46.17,29.09-74.88,29.09a123.84,123.84,0,0,1-64.11-18.19L-.13,218.54v24.68l108.6,65.91a111.59,111.59,0,0,0,57.76,16.41c24.92,0,48.8-8.8,66.42-25.69,12.88-12.34,20-27.12,19.68-41.49v-1.82A87.14,87.14,0,0,1,241.11,269.7Zm83.69,25.74a94.16,94.16,0,0,1-60.19,25.86h0V348a81.6,81.6,0,0,0,51.73-22.37c14-13.38,21.15-28.11,21-42.64v-2.2A95.14,95.14,0,0,1,324.8,295.44Zm-83.69,91.21c-19.57,18.75-46.17,29.09-74.88,29.09a123.76,123.76,0,0,1-64.11-18.2L-.13,335.49v24.67l108.6,65.91a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.81,66.42-25.69,12.88-12.34,20-27.13,19.68-41.49v-1.79A87.35,87.35,0,0,1,241.11,386.65Zm85.75-210.21c-.68.69-1.35,1.38-2.06,2.05a99.19,99.19,0,0,1-22.23,15.69,94.53,94.53,0,0,1-26.24,8.71,97.84,97.84,0,0,1-14.16,1.57c.5,1.61.9,3.25,1.25,4.9a52.7,52.7,0,0,1,1.13,12V231h.05A84.48,84.48,0,0,0,290,225.47a80.83,80.83,0,0,0,26.38-16.82c.81-.77,1.51-1.56,2.27-2.34a82,82,0,0,0,7.92-9.38,62.85,62.85,0,0,0,6.29-10.78,48.5,48.5,0,0,0,4.32-16.44c.09-1.23.2-2.47.19-3.7v-2c-.72,1-1.48,2.06-2.26,3.09A98,98,0,0,1,326.86,176.44Zm0,77.92c-.68.7-1.3,1.41-2,2.1a94.09,94.09,0,0,1-60.19,25.85h0V309h0a81.65,81.65,0,0,0,51.73-22.37,73.51,73.51,0,0,0,16.48-22.49,48.56,48.56,0,0,0,4.32-16.44c.09-1.24.2-2.48.19-3.71v-2.2c-.74,1.08-1.47,2.16-2.27,3.22A95.81,95.81,0,0,1,326.82,254.36Zm0-39c-.68.7-1.3,1.41-2,2.1a92.22,92.22,0,0,1-10.62,8.65,93.53,93.53,0,0,1-11.63,7,95.63,95.63,0,0,1-37.94,10.18h-.05l0,26.67h0a81.63,81.63,0,0,0,51.73-22.37c.81-.77,1.51-1.56,2.27-2.34a82,82,0,0,0,7.92-9.38,63.16,63.16,0,0,0,6.29-10.77,48.55,48.55,0,0,0,4.32-16.45c.09-1.23.2-2.47.19-3.7v-2.2c-.74,1.08-1.47,2.16-2.27,3.22A98.19,98.19,0,0,1,326.82,215.38Zm241-88.84q7.94,0,17.09.17t18.12,1a139.3,139.3,0,0,1,16.74,2.57,42.78,42.78,0,0,1,13.3,5.14,64.27,64.27,0,0,1,20.54,19.89Q662,168,662,186.54q0,19.54-9.49,33.78t-27.1,21.09v.68q22.78,4.82,34.87,20.58t12.08,38.4a72.62,72.62,0,0,1-4.83,26.06,65.29,65.29,0,0,1-14.33,22.46,71.57,71.57,0,0,1-23.47,15.78q-14,6-32.28,6H478.38V126.54Zm9,105.27q28,0,40.21-9.78t12.26-29.31q0-13-4.14-20.58a29.47,29.47,0,0,0-11.4-11.66A45,45,0,0,0,597,155.17a161.2,161.2,0,0,0-20.19-1.2h-65.6v77.84Zm16.57,112.13q21.74,0,34-11.66T639.59,300q0-12-4.48-19.88a34.85,34.85,0,0,0-11.91-12.52,50.14,50.14,0,0,0-17.09-6.52,105,105,0,0,0-20-1.88H511.17v84.7Zm274.79,26.74q-7.61,4.45-21.06,4.46-11.4,0-18.12-6.34t-6.74-20.75a70.17,70.17,0,0,1-28.13,20.75,97.87,97.87,0,0,1-57.65,3.6,53.51,53.51,0,0,1-18.82-8.58A41.19,41.19,0,0,1,705,348.56q-4.65-9.42-4.66-22.8,0-15.09,5.18-24.69a44.92,44.92,0,0,1,13.64-15.6,62.63,62.63,0,0,1,19.33-9.09q10.88-3.08,22.27-5.14,12.08-2.4,23-3.6a128,128,0,0,0,19.16-3.43c5.53-1.48,9.89-3.65,13.12-6.51s4.83-7,4.83-12.52q0-9.6-3.62-15.43a24.94,24.94,0,0,0-9.32-8.92,38.38,38.38,0,0,0-12.78-4.11,96.54,96.54,0,0,0-14-1q-18.63,0-31.07,7T736.6,249.29H707.26q.69-16.46,6.9-27.77a52.21,52.21,0,0,1,16.57-18.35,70,70,0,0,1,23.65-10.11A125.51,125.51,0,0,1,782.86,190a168.63,168.63,0,0,1,24,1.72,63.26,63.26,0,0,1,21.58,7A41.23,41.23,0,0,1,844,213.59q5.87,9.57,5.87,25v91q0,10.26,1.21,15.05t8.11,4.79a35.57,35.57,0,0,0,9-1.37Zm-47.64-90.87c-3.69,2.74-8.52,4.72-14.5,6s-12.26,2.27-18.82,3.07-13.17,1.71-19.85,2.73a73.7,73.7,0,0,0-18,4.94,32.62,32.62,0,0,0-12.94,9.73q-5,6.32-5,17.23a23.31,23.31,0,0,0,2.94,12.11,24.11,24.11,0,0,0,7.59,8,32,32,0,0,0,10.88,4.44,60.94,60.94,0,0,0,13.11,1.36q14.5,0,24.86-3.92a52.49,52.49,0,0,0,16.91-9.9,39.1,39.1,0,0,0,9.67-13,32.53,32.53,0,0,0,3.11-13.14ZM1002.07,225q-11.05-9.25-29.69-9.26-15.89,0-26.58,5.83A47.29,47.29,0,0,0,928.71,237a64.66,64.66,0,0,0-9.15,22.12A119.83,119.83,0,0,0,916.8,285a98.22,98.22,0,0,0,2.93,24,64.18,64.18,0,0,0,9.15,20.74,46.2,46.2,0,0,0,16.23,14.58q10,5.49,23.82,5.48,21.75,0,34-11.31t15-31.89h30q-4.83,32.91-24.68,50.75t-54,17.83q-20.37,0-36.07-6.52A69.86,69.86,0,0,1,907,350.11a79.92,79.92,0,0,1-15.88-28.63A118.64,118.64,0,0,1,885.73,285a129.41,129.41,0,0,1,5.18-37.21,85.63,85.63,0,0,1,15.71-30.17A73.46,73.46,0,0,1,933,197.35Q948.91,190,970,190a108.54,108.54,0,0,1,28.48,3.6,69.59,69.59,0,0,1,23.48,11.15,61,61,0,0,1,16.74,19q6.55,11.49,8.29,27.26h-30.38Q1013.11,234.21,1002.07,225Zm109.77-98.41v145l81.47-77.49h39.36l-70.77,64.46,75.95,112.82h-37.29l-61.1-92.59-27.62,25.38v67.21H1082.5V126.54Zm170.54,205.22a31.07,31.07,0,0,0,10.87,10.63,49,49,0,0,0,15.19,5.66,87.06,87.06,0,0,0,17.44,1.71,109.18,109.18,0,0,0,14.5-1,53.22,53.22,0,0,0,14-3.78,26.27,26.27,0,0,0,10.53-8q4.14-5.32,4.14-13.55,0-11.31-8.63-17.14a73.69,73.69,0,0,0-21.58-9.43q-12.94-3.6-28.13-6.52a146,146,0,0,1-28.14-8.23A58.16,58.16,0,0,1,1261,267.13q-8.64-9.6-8.63-26.75,0-13.38,6-23a49.26,49.26,0,0,1,15.53-15.61,71.76,71.76,0,0,1,21.4-8.91A99.41,99.41,0,0,1,1319,190a141.31,141.31,0,0,1,28,2.58,64.85,64.85,0,0,1,22.62,8.91,46.16,46.16,0,0,1,15.7,17.15q5.87,10.8,6.91,26.91h-29.35q-.69-8.57-4.48-14.23a29.36,29.36,0,0,0-9.67-9.08,44.16,44.16,0,0,0-12.94-5,67.68,67.68,0,0,0-14.33-1.54,87.29,87.29,0,0,0-13.29,1,45.28,45.28,0,0,0-12.26,3.6,24.49,24.49,0,0,0-9,6.86q-3.46,4.29-3.46,11.14a16.32,16.32,0,0,0,5.36,12.52,42.75,42.75,0,0,0,13.63,8.23,120,120,0,0,0,18.64,5.48q10.37,2.24,20.72,4.63,11,2.4,21.57,5.83A70.74,70.74,0,0,1,1382,284.1a44.55,44.55,0,0,1,13.12,14.23q5,8.58,5,21.26,0,16.13-6.73,26.75a52.5,52.5,0,0,1-17.61,17.14,73.89,73.89,0,0,1-24.51,9.09,146.3,146.3,0,0,1-27.1,2.57,126.24,126.24,0,0,1-28.31-3.09A69.56,69.56,0,0,1,1272,361.94a51.74,51.74,0,0,1-16.57-18.52q-6.21-11.49-6.9-27.95h29.34A32.65,32.65,0,0,0,1282.38,331.76Zm226.46-137.67v25.72h-35.56V329.88a31.37,31.37,0,0,0,.87,8.23,8.42,8.42,0,0,0,3.28,4.8,14.61,14.61,0,0,0,6.73,2.23,99.19,99.19,0,0,0,11.22.51h13.46v25.72H1486.4a105.8,105.8,0,0,1-19.5-1.55,28.65,28.65,0,0,1-13.12-5.65,24.09,24.09,0,0,1-7.42-11.66q-2.43-7.54-2.42-19.89V219.81h-30.38V194.09h30.38V140.94h29.34v53.15ZM1699.4,370.68q-7.61,4.45-21.06,4.46-11.4,0-18.12-6.34t-6.74-20.75a70.17,70.17,0,0,1-28.13,20.75,97.87,97.87,0,0,1-57.65,3.6,53.51,53.51,0,0,1-18.82-8.58,41.19,41.19,0,0,1-12.6-15.26q-4.65-9.42-4.66-22.8,0-15.09,5.18-24.69a44.92,44.92,0,0,1,13.64-15.6,62.63,62.63,0,0,1,19.33-9.09q10.88-3.08,22.27-5.14,12.07-2.4,23-3.6a128,128,0,0,0,19.16-3.43c5.53-1.48,9.89-3.65,13.12-6.51s4.83-7,4.83-12.52q0-9.6-3.62-15.43a24.94,24.94,0,0,0-9.32-8.92,38.38,38.38,0,0,0-12.78-4.11,96.54,96.54,0,0,0-14-1q-18.63,0-31.07,7t-13.46,26.57h-29.34q.67-16.46,6.9-27.77A52.21,52.21,0,0,1,1562,203.17a70,70,0,0,1,23.65-10.11,125.51,125.51,0,0,1,28.48-3.09,168.63,168.63,0,0,1,24,1.72,63.26,63.26,0,0,1,21.58,7,41.23,41.23,0,0,1,15.53,14.89q5.87,9.57,5.87,25v91q0,10.26,1.21,15.05t8.11,4.79a35.57,35.57,0,0,0,9-1.37Zm-47.64-90.87c-3.69,2.74-8.52,4.72-14.5,6s-12.26,2.27-18.82,3.07-13.17,1.71-19.85,2.73a73.7,73.7,0,0,0-17.95,4.94,32.62,32.62,0,0,0-12.94,9.73q-5,6.32-5,17.23a23.31,23.31,0,0,0,2.94,12.11,24.11,24.11,0,0,0,7.59,8,32,32,0,0,0,10.88,4.44,60.94,60.94,0,0,0,13.11,1.36q14.51,0,24.86-3.92a52.49,52.49,0,0,0,16.91-9.9,39.1,39.1,0,0,0,9.67-13,32.53,32.53,0,0,0,3.11-13.14Zm208.85,141.62q-20,21.6-62.83,21.6a122.11,122.11,0,0,1-25.37-2.74,78,78,0,0,1-23.48-8.92,54.41,54.41,0,0,1-17.43-16.11q-6.91-10-7.6-24.35h29.35a21.47,21.47,0,0,0,5,13.38,36.67,36.67,0,0,0,11.4,8.91,55.52,55.52,0,0,0,14.67,5,79.51,79.51,0,0,0,15.19,1.55q14.49,0,24.51-5A46,46,0,0,0,1840.59,401a56.53,56.53,0,0,0,9.49-21.09,117.46,117.46,0,0,0,2.94-27.09V341.19h-.7q-7.59,16.46-23,24.18a71.8,71.8,0,0,1-32.63,7.71q-20,0-34.86-7.2A72.88,72.88,0,0,1,1737,346.51a82.13,82.13,0,0,1-15-28.46,116.62,116.62,0,0,1-5-34.47,133.92,133.92,0,0,1,4.14-32.4A88.17,88.17,0,0,1,1735,221a75.49,75.49,0,0,1,25.55-22.29q15.87-8.75,39-8.75a66.21,66.21,0,0,1,31.07,7.38,52.13,52.13,0,0,1,22.09,22.11h.35V194.09h27.61V356.28Q1880.63,399.83,1860.61,421.43Zm-37.46-79.72a47.94,47.94,0,0,0,16.4-15.78,71.89,71.89,0,0,0,9.15-22.11,106.77,106.77,0,0,0,2.93-24.69,96.71,96.71,0,0,0-2.76-23,64,64,0,0,0-8.8-20.4,45.76,45.76,0,0,0-15.71-14.57q-9.66-5.49-23.47-5.49-14.16,0-24.17,5.32a46.77,46.77,0,0,0-16.4,14.23,60.14,60.14,0,0,0-9.32,20.57,99.69,99.69,0,0,0-2.93,24.35,120.63,120.63,0,0,0,2.42,24,67.5,67.5,0,0,0,8.28,21.77,46.37,46.37,0,0,0,15.54,15.78q9.66,6,24.16,6T1823.15,341.71Zm228,18.34q-20,15.09-50.41,15.09-21.4,0-37.11-6.86a73.16,73.16,0,0,1-26.41-19.2,81.52,81.52,0,0,1-16-29.49,141.12,141.12,0,0,1-6-37.38,106.1,106.1,0,0,1,6.21-37A88.56,88.56,0,0,1,1938.8,216a79.09,79.09,0,0,1,26.58-19.2A81.66,81.66,0,0,1,1999,190q23.82,0,39.53,9.78a78,78,0,0,1,25.2,24.86,98.18,98.18,0,0,1,13.12,32.91,140.6,140.6,0,0,1,2.93,34h-133.6a70,70,0,0,0,2.76,22.12,49.9,49.9,0,0,0,10,18.51A49.1,49.1,0,0,0,1976.6,345q10.7,4.82,25.2,4.8,18.65,0,30.55-8.57t15.71-26.06h29Q2071.18,345,2051.17,360.05Zm-7.08-113.84a50,50,0,0,0-10.7-16,53.1,53.1,0,0,0-56.62-10.63,47.48,47.48,0,0,0-15.71,10.81,51.69,51.69,0,0,0-10.35,15.94,60.18,60.18,0,0,0-4.49,19.37h102.53A59.47,59.47,0,0,0,2044.09,246.21ZM302.9,180a80.62,80.62,0,0,0,13.44-10.37c.8-.77,1.55-1.54,2.31-2.31a81.89,81.89,0,0,0,7.92-9.37,62.37,62.37,0,0,0,6.27-10.77,48.6,48.6,0,0,0,4.36-16.4c1.49-19.39-10-38.67-35.62-54.22L198.42,14,78.16,129.22l-78.29,75,108.6,65.9a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.8,66.42-25.69,19.16-18.36,25.52-42.12,13.7-61.87a49.69,49.69,0,0,0-6.8-8.87,89.78,89.78,0,0,0,19.28,2.15H259a85.09,85.09,0,0,0,31-5.79A80.88,80.88,0,0,0,302.9,180Zm-100.59,59.8c-19.32,18.51-50.4,21.24-75.7,5.9l-75.13-45.6,67.44-64.65,76.42,46.39C222.88,198.57,221.36,221.6,202.31,239.84Zm8.94-82.21L140.6,114.74,205,53l69.37,42.11c25.94,15.73,29.31,37.05,10.55,55A60.71,60.71,0,0,1,211.25,157.63Zm29.86,190c-19.57,18.75-46.17,29.08-74.88,29.08a123.84,123.84,0,0,1-64.11-18.19L-.13,296.51v24.67l108.6,65.91a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.81,66.42-25.69,12.88-12.34,20-27.13,19.68-41.49v-1.79A87.85,87.85,0,0,1,241.11,347.67Zm0-39c-19.57,18.76-46.17,29.09-74.88,29.09a123.84,123.84,0,0,1-64.11-18.19L-.13,257.52V282.2l108.6,65.91a111.59,111.59,0,0,0,57.76,16.41c24.92,0,48.8-8.8,66.42-25.68,12.88-12.35,20-27.13,19.68-41.5v-1.79A86.86,86.86,0,0,1,241.11,308.68Zm0-39c-19.57,18.76-46.17,29.09-74.88,29.09a123.84,123.84,0,0,1-64.11-18.19L-.13,218.54v24.68l108.6,65.91a111.59,111.59,0,0,0,57.76,16.41c24.92,0,48.8-8.8,66.42-25.69,12.88-12.34,20-27.12,19.68-41.49v-1.82A87.14,87.14,0,0,1,241.11,269.7Zm83.69,25.74a94.16,94.16,0,0,1-60.19,25.86h0V348a81.6,81.6,0,0,0,51.73-22.37c14-13.38,21.15-28.11,21-42.64v-2.2A95.14,95.14,0,0,1,324.8,295.44Zm-83.69,91.21c-19.57,18.75-46.17,29.09-74.88,29.09a123.76,123.76,0,0,1-64.11-18.2L-.13,335.49v24.67l108.6,65.91a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.81,66.42-25.69,12.88-12.34,20-27.13,19.68-41.49v-1.79A87.35,87.35,0,0,1,241.11,386.65Zm85.75-210.21c-.68.69-1.35,1.38-2.06,2.05a99.19,99.19,0,0,1-22.23,15.69,94.53,94.53,0,0,1-26.24,8.71,97.84,97.84,0,0,1-14.16,1.57c.5,1.61.9,3.25,1.25,4.9a52.7,52.7,0,0,1,1.13,12V231h.05A84.48,84.48,0,0,0,290,225.47a80.83,80.83,0,0,0,26.38-16.82c.81-.77,1.51-1.56,2.27-2.34a82,82,0,0,0,7.92-9.38,62.85,62.85,0,0,0,6.29-10.78,48.5,48.5,0,0,0,4.32-16.44c.09-1.23.2-2.47.19-3.7v-2c-.72,1-1.48,2.06-2.26,3.09A98,98,0,0,1,326.86,176.44Zm0,77.92c-.68.7-1.3,1.41-2,2.1a94.09,94.09,0,0,1-60.19,25.85h0V309h0a81.65,81.65,0,0,0,51.73-22.37,73.51,73.51,0,0,0,16.48-22.49,48.56,48.56,0,0,0,4.32-16.44c.09-1.24.2-2.48.19-3.71v-2.2c-.74,1.08-1.47,2.16-2.27,3.22A95.81,95.81,0,0,1,326.82,254.36Zm0-39c-.68.7-1.3,1.41-2,2.1a92.22,92.22,0,0,1-10.62,8.65,93.53,93.53,0,0,1-11.63,7,95.63,95.63,0,0,1-37.94,10.18h-.05l0,26.67h0a81.63,81.63,0,0,0,51.73-22.37c.81-.77,1.51-1.56,2.27-2.34a82,82,0,0,0,7.92-9.38,63.16,63.16,0,0,0,6.29-10.77,48.55,48.55,0,0,0,4.32-16.45c.09-1.23.2-2.47.19-3.7v-2.2c-.74,1.08-1.47,2.16-2.27,3.22A98.19,98.19,0,0,1,326.82,215.38Z\",}\n )\n )\n );\n};\n\nexport default LogoFull;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core';\n\nconst useStyles = makeStyles({\n svg: {\n width: 'auto',\n height: 28,\n },\n path: {\n fill: '#7df3e1',\n },\n});\n\nconst LogoIcon = () => {\n const classes = useStyles();\n\n return (\n React.createElement('svg', {\n className: classes.svg,\n xmlns: \"http://www.w3.org/2000/svg\",\n viewBox: \"0 0 337.46 428.5\" ,}\n \n , React.createElement('path', {\n className: classes.path,\n d: \"M303,166.05a80.69,80.69,0,0,0,13.45-10.37c.79-.77,1.55-1.53,2.3-2.3a83.12,83.12,0,0,0,7.93-9.38A63.69,63.69,0,0,0,333,133.23a48.58,48.58,0,0,0,4.35-16.4c1.49-19.39-10-38.67-35.62-54.22L198.56,0,78.3,115.23,0,190.25l108.6,65.91a111.59,111.59,0,0,0,57.76,16.41c24.92,0,48.8-8.8,66.42-25.69,19.16-18.36,25.52-42.12,13.7-61.87a49.22,49.22,0,0,0-6.8-8.87A89.17,89.17,0,0,0,259,178.29h.15a85.08,85.08,0,0,0,31-5.79A80.88,80.88,0,0,0,303,166.05ZM202.45,225.86c-19.32,18.51-50.4,21.23-75.7,5.9L51.61,186.15l67.45-64.64,76.41,46.38C223,184.58,221.49,207.61,202.45,225.86Zm8.93-82.22-70.65-42.89L205.14,39,274.51,81.1c25.94,15.72,29.31,37,10.55,55A60.69,60.69,0,0,1,211.38,143.64Zm29.86,190c-19.57,18.75-46.17,29.09-74.88,29.09a123.73,123.73,0,0,1-64.1-18.2L0,282.52v24.67L108.6,373.1a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.81,66.42-25.69,12.88-12.34,20-27.13,19.68-41.49v-1.79A87.27,87.27,0,0,1,241.24,333.68Zm0-39c-19.57,18.75-46.17,29.08-74.88,29.08a123.81,123.81,0,0,1-64.1-18.19L0,243.53v24.68l108.6,65.91a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.81,66.42-25.69,12.88-12.34,20-27.13,19.68-41.5v-1.78A87.27,87.27,0,0,1,241.24,294.7Zm0-39c-19.57,18.76-46.17,29.09-74.88,29.09a123.81,123.81,0,0,1-64.1-18.19L0,204.55v24.68l108.6,65.91a111.59,111.59,0,0,0,57.76,16.41c24.92,0,48.8-8.8,66.42-25.68,12.88-12.35,20-27.13,19.68-41.5v-1.82A86.09,86.09,0,0,1,241.24,255.71Zm83.7,25.74a94.15,94.15,0,0,1-60.2,25.86h0V334a81.6,81.6,0,0,0,51.74-22.37c14-13.38,21.14-28.11,21-42.64v-2.19A94.92,94.92,0,0,1,324.94,281.45Zm-83.7,91.21c-19.57,18.76-46.17,29.09-74.88,29.09a123.73,123.73,0,0,1-64.1-18.2L0,321.5v24.68l108.6,65.9a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.8,66.42-25.69,12.88-12.34,20-27.13,19.68-41.49v-1.79A86.29,86.29,0,0,1,241.24,372.66ZM327,162.45c-.68.69-1.35,1.38-2.05,2.06a94.37,94.37,0,0,1-10.64,8.65,91.35,91.35,0,0,1-11.6,7,94.53,94.53,0,0,1-26.24,8.71,97.69,97.69,0,0,1-14.16,1.57c.5,1.61.9,3.25,1.25,4.9a53.27,53.27,0,0,1,1.14,12V217h.05a84.41,84.41,0,0,0,25.35-5.55,81,81,0,0,0,26.39-16.82c.8-.77,1.5-1.56,2.26-2.34a82.08,82.08,0,0,0,7.93-9.38A63.76,63.76,0,0,0,333,172.17a48.55,48.55,0,0,0,4.32-16.45c.09-1.23.2-2.47.19-3.7V150q-1.08,1.54-2.25,3.09A96.73,96.73,0,0,1,327,162.45Zm0,77.92c-.69.7-1.31,1.41-2,2.1a94.2,94.2,0,0,1-60.2,25.86h0l0,26.67h0a81.6,81.6,0,0,0,51.74-22.37A73.51,73.51,0,0,0,333,250.13a48.56,48.56,0,0,0,4.32-16.44c.09-1.24.2-2.47.19-3.71v-2.19c-.74,1.07-1.46,2.15-2.27,3.21A95.68,95.68,0,0,1,327,240.37Zm0-39c-.69.7-1.31,1.41-2,2.1a93.18,93.18,0,0,1-10.63,8.65,91.63,91.63,0,0,1-11.63,7,95.47,95.47,0,0,1-37.94,10.18h0V256h0a81.65,81.65,0,0,0,51.74-22.37c.8-.77,1.5-1.56,2.26-2.34a82.08,82.08,0,0,0,7.93-9.38A63.76,63.76,0,0,0,333,211.15a48.56,48.56,0,0,0,4.32-16.44c.09-1.24.2-2.48.19-3.71v-2.2c-.74,1.08-1.46,2.16-2.27,3.22A95.68,95.68,0,0,1,327,201.39Z\",}\n )\n )\n );\n};\n\nexport default LogoIcon;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useContext, } from 'react';\nimport { Link, makeStyles } from '@material-ui/core';\nimport LibraryBooks from '@material-ui/icons/LibraryBooks';\nimport LogoFull from './LogoFull';\nimport LogoIcon from './LogoIcon';\nimport {\n Sidebar,\n SidebarPage,\n sidebarConfig,\n SidebarContext,\n SidebarItem,\n SidebarDivider,\n} from '@backstage/core-components';\nimport { NavLink } from 'react-router-dom';\n\nconst useSidebarLogoStyles = makeStyles({\n root: {\n width: sidebarConfig.drawerWidthClosed,\n height: 3 * sidebarConfig.logoHeight,\n display: 'flex',\n flexFlow: 'row nowrap',\n alignItems: 'center',\n marginBottom: -14,\n },\n link: {\n width: sidebarConfig.drawerWidthClosed,\n marginLeft: 24,\n },\n});\n\nconst SidebarLogo = () => {\n const classes = useSidebarLogoStyles();\n const { isOpen } = useContext(SidebarContext);\n\n return (\n React.createElement('div', { className: classes.root,}\n , React.createElement(Link, {\n component: NavLink,\n to: \"/docs/default/component/local/\",\n underline: \"none\",\n className: classes.link,}\n \n , isOpen ? React.createElement(LogoFull, null ) : React.createElement(LogoIcon, null )\n )\n )\n );\n};\n\nexport const Root = ({ children }) => (\n React.createElement(SidebarPage, null\n , React.createElement(Sidebar, null\n , React.createElement(SidebarLogo, null )\n , React.createElement(SidebarDivider, null )\n /* Global nav, not org-specific */\n , React.createElement(SidebarItem, {\n icon: LibraryBooks,\n to: \"docs/default/component/local/\",\n text: \"Docs Preview\" ,}\n )\n /* End global nav */\n )\n , children\n )\n);\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport { Content } from '@backstage/core-components';\n\nimport {\n Reader,\n TechDocsPage,\n TechDocsPageHeader,\n} from '@backstage/plugin-techdocs';\n\nconst DefaultTechDocsPage = () => {\n const techDocsMetadata = {\n site_name: 'Live preview environment',\n site_description: '',\n };\n\n return (\n React.createElement(TechDocsPage, null\n , ({ entityRef, onReady }) => (\n React.createElement(React.Fragment, null\n , React.createElement(TechDocsPageHeader, {\n techDocsMetadata: techDocsMetadata,\n entityRef: entityRef,}\n )\n , React.createElement(Content, { 'data-testid': \"techdocs-content\",}\n , React.createElement(Reader, {\n onReady: onReady,\n entityRef: entityRef,\n withSearch: false,}\n )\n )\n )\n )\n )\n );\n};\n\nexport const techDocsPage = React.createElement(DefaultTechDocsPage, null );\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { defaultConfigLoader } from '@backstage/core-app-api';\n\nconst PRODUCTION_CONFIG = {\n backend: {\n baseUrl: 'http://localhost:3000',\n },\n techdocs: {\n builder: 'external',\n requestUrl: 'http://localhost:3000/api',\n },\n};\n\nconst DEVELOPMENT_CONFIG = {\n backend: {\n baseUrl: 'http://localhost:7007',\n },\n techdocs: {\n builder: 'external',\n requestUrl: 'http://localhost:7007/api',\n },\n};\n\nasync function isProductionServe() {\n const res = await fetch('/.detect');\n if (!res.ok) {\n return false;\n }\n const text = await res.text();\n return text.trim() === 'techdocs-cli-server';\n}\n\nexport async function configLoader() {\n const defaultConfigs = await defaultConfigLoader();\n const isProduction = await isProductionServe();\n\n return [\n ...defaultConfigs,\n {\n context: 'detected',\n data: isProduction ? PRODUCTION_CONFIG : DEVELOPMENT_CONFIG,\n },\n ];\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { Navigate, Route } from 'react-router';\nimport { createApp } from '@backstage/app-defaults';\nimport { FlatRoutes } from '@backstage/core-app-api';\nimport { CatalogEntityPage } from '@backstage/plugin-catalog';\n\nimport {\n DefaultTechDocsHome,\n TechDocsIndexPage,\n TechDocsReaderPage,\n} from '@backstage/plugin-techdocs';\nimport { apis } from './apis';\nimport { Root } from './components/Root';\nimport { techDocsPage } from './components/TechDocsPage';\nimport * as plugins from './plugins';\nimport { configLoader } from './config';\n\nconst app = createApp({\n apis,\n configLoader,\n plugins: Object.values(plugins),\n});\n\nconst AppProvider = app.getProvider();\nconst AppRouter = app.getRouter();\n\nconst routes = (\n React.createElement(FlatRoutes, null\n , React.createElement(Navigate, { key: \"/\", to: \"/docs/default/component/local/\",} )\n /* we need this route as TechDocs header links relies on it */\n , React.createElement(Route, {\n path: \"/catalog/:namespace/:kind/:name\",\n element: React.createElement(CatalogEntityPage, null ),}\n )\n , React.createElement(Route, { path: \"/docs\", element: React.createElement(TechDocsIndexPage, null ),}\n , React.createElement(DefaultTechDocsHome, null )\n )\n , React.createElement(Route, {\n path: \"/docs/:namespace/:kind/:name/*\",\n element: React.createElement(TechDocsReaderPage, null ),}\n \n , techDocsPage\n )\n )\n);\n\nconst App = () => (\n React.createElement(AppProvider, null\n , React.createElement(AppRouter, null\n , React.createElement(Root, null, routes)\n )\n )\n);\n\nexport default App;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport '@backstage/cli/asset-types';\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from './App';\n\nReactDOM.render(React.createElement(App, null ), document.getElementById('root'));\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028\nfunction getGlobalObject() {\n if (typeof window !== 'undefined' && window.Math === Math) {\n return window;\n }\n if (typeof self !== 'undefined' && self.Math === Math) {\n return self;\n }\n // eslint-disable-next-line no-new-func\n return Function('return this')();\n}\n\nconst globalObject = getGlobalObject();\n\nconst makeKey = (id) => `__@backstage/${id}__`;\n\n/**\n * Serializes access to a global singleton value, with the first caller creating the value.\n *\n * @public\n */\nexport function getOrCreateGlobalSingleton(\n id,\n supplier,\n) {\n const key = makeKey(id);\n\n let value = globalObject[key];\n if (value) {\n return value;\n }\n\n value = supplier();\n globalObject[key] = value;\n return value;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createContext, useContext, } from 'react';\nimport { getOrCreateGlobalSingleton } from './globalObject';\nimport { createVersionedValueMap, } from './VersionedValue';\n\n/**\n * Get the existing or create a new versioned React context that's\n * stored inside a global singleton.\n *\n * @param key - A key that uniquely identifies the context.\n * @public\n * @example\n *\n * ```ts\n * const MyContext = createVersionedContext<{ 1: string }>('my-context');\n *\n * const MyContextProvider = ({children}) => (\n * <MyContext.Provider value={createVersionedValueMap({ 1: 'value-for-version-1' })}>\n * {children}\n * <MyContext.Provider>\n * )\n * ```\n */\nexport function createVersionedContext\n\n(key) {\n return getOrCreateGlobalSingleton(key, () =>\n createContext(undefined),\n );\n}\n\n/**\n * A hook that simplifies the consumption of a versioned contexts that's\n * stored inside a global singleton.\n *\n * @param key - A key that uniquely identifies the context.\n * @public\n * @example\n *\n * ```ts\n * const versionedHolder = useVersionedContext<{ 1: string }>('my-context');\n *\n * if (!versionedHolder) {\n * throw new Error('My context is not available!')\n * }\n *\n * const myValue = versionedHolder.atVersion(1);\n *\n * // ...\n * ```\n */\nexport function useVersionedContext\n\n(key) {\n return useContext(createVersionedContext(key));\n}\n\n/**\n * Creates a helper for writing tests towards multiple different\n * combinations of versions provided from a context.\n *\n * @param key - A key that uniquely identifies the context.\n * @public\n * @example\n *\n * ```ts\n * const context = createVersionedContextForTesting('my-context');\n *\n * afterEach(() => {\n * context.reset();\n * });\n *\n * it('should work when provided with version 1', () => {\n * context.set({1: 'value-for-version-1'})\n *\n * // ...\n * })\n * ```\n */\nexport function createVersionedContextForTesting(key) {\n return {\n set(versions) {\n (globalThis )[`__@backstage/${key}__`] = createContext(\n createVersionedValueMap(versions),\n );\n },\n reset() {\n delete (globalThis )[`__@backstage/${key}__`];\n },\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The versioned value interface is a container for a set of values that\n * can be looked up by version. It is intended to be used as a container\n * for values that can be versioned independently of package versions.\n *\n * @public\n */\n\n\n\n\n\n\n/**\n * Creates a container for a map of versioned values that implements VersionedValue.\n *\n * @public\n */\nexport function createVersionedValueMap\n\n(versions) {\n Object.freeze(versions);\n return {\n atVersion(version) {\n return versions[version];\n },\n };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { createApiRef } from '@backstage/core-plugin-api';\n\nexport const catalogApiRef = createApiRef({\n id: 'plugin.catalog.service',\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { stringifyEntityRef } from '@backstage/catalog-model';\n\nimport { isArray, isString } from 'lodash';\n\n/**\n * Migrate the starred entities from the old format (entity:<kind>:<namespace>:<name>) from the\n * old storage location (/settings/starredEntities) to entity references in the new location\n * (/starredEntities/entityRefs).\n *\n * This will only be executed once since the old location is cleared.\n *\n * @param storageApi - the StorageApi to migrate\n */\nexport async function performMigrationToTheNewBucket({\n storageApi,\n}\n\n) {\n const source = storageApi.forBucket('settings');\n const target = storageApi.forBucket('starredEntities');\n\n const oldStarredEntities = source.get('starredEntities');\n\n if (!isArray(oldStarredEntities)) {\n // nothing to do\n return;\n }\n const targetEntities = new Set(target.get('entityRefs') ?? []);\n\n oldStarredEntities\n .filter(isString)\n // extract the old format 'entity:<kind>:<namespace>:<name>'\n .map(old => old.split(':'))\n // check if the format is valid\n .filter(split => split.length === 4 && split[0] === 'entity')\n // convert to entity references\n .map(([_, kind, namespace, name]) =>\n stringifyEntityRef({ kind, namespace, name }),\n )\n .forEach(e => targetEntities.add(e));\n\n await target.set('entityRefs', Array.from(targetEntities));\n\n await source.remove('starredEntities');\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport ObservableImpl from 'zen-observable';\nimport { performMigrationToTheNewBucket } from './migration';\n\n\n/**\n * Default implementation of the StarredEntitiesApi that is backed by the StorageApi.\n *\n * @public\n */\nexport class DefaultStarredEntitiesApi {\n settingsStore;\n starredEntities;\n\n constructor(opts) {\n // no need to await. The updated content will be caught by the observe$\n performMigrationToTheNewBucket(opts).then();\n\n this.settingsStore = opts.storageApi.forBucket('starredEntities');\n\n this.starredEntities = new Set(\n this.settingsStore.get('entityRefs') ?? [],\n );\n\n this.settingsStore.observe$('entityRefs').subscribe({\n next: next => {\n this.starredEntities = new Set(next.newValue ?? []);\n this.notifyChanges();\n },\n });\n }\n\n async toggleStarred(entityRef) {\n if (this.starredEntities.has(entityRef)) {\n this.starredEntities.delete(entityRef);\n } else {\n this.starredEntities.add(entityRef);\n }\n\n await this.settingsStore.set(\n 'entityRefs',\n Array.from(this.starredEntities),\n );\n }\n\n starredEntitie$() {\n return this.observable;\n }\n\n isStarred(entityRef) {\n return this.starredEntities.has(entityRef);\n }\n\n subscribers = new Set\n\n();\n\n observable = new ObservableImpl(subscriber => {\n // forward the the latest value\n subscriber.next(this.starredEntities);\n\n this.subscribers.add(subscriber);\n return () => {\n this.subscribers.delete(subscriber);\n };\n });\n\n notifyChanges() {\n for (const subscription of this.subscribers) {\n subscription.next(this.starredEntities);\n }\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createApiRef } from '@backstage/core-plugin-api';\n\n\n/**\n * An API to store starred entities\n *\n * @public\n */\nexport const starredEntitiesApiRef = createApiRef({\n id: 'catalog-react.starred-entities',\n});\n\n/**\n * An API to store and retrieve starred entities\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model';\nimport { createRouteRef } from '@backstage/core-plugin-api';\nimport { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\n\n// TODO(Rugvip): Move these route refs back to the catalog plugin once we're all ported to using external routes\n/**\n * @deprecated Use an `ExternalRouteRef` instead, which can point to `catalogPlugin.routes.catalogIndex`.\n */\nexport const rootRoute = createRouteRef({\n id: 'catalog',\n});\n\n/**\n * @deprecated Use an `ExternalRouteRef` instead, which can point to `catalogPlugin.routes.catalogIndex`.\n */\nexport const catalogRouteRef = rootRoute;\n\n/**\n * A stable route ref that points to the catalog page for an individual entity.\n *\n * This `RouteRef` can be imported and used directly, and does not need to be referenced\n * via an `ExternalRouteRef`.\n *\n * If you want to replace the `EntityPage` from `@backstage/catalog-plugin` in your app,\n * you need to use the `entityRouteRef` as the mount point instead of your own.\n */\nexport const entityRouteRef = getOrCreateGlobalSingleton(\n 'catalog:entity-route-ref',\n () =>\n createRouteRef({\n id: 'catalog:entity',\n params: ['namespace', 'kind', 'name'],\n }),\n);\n\n/**\n * @deprecated use `entityRouteRef` instead.\n */\nexport const entityRoute = entityRouteRef;\n\n// Utility function to get suitable route params for entityRoute, given an\n// entity instance\nexport function entityRouteParams(entity) {\n return {\n kind: entity.kind.toLocaleLowerCase('en-US'),\n namespace:\n entity.metadata.namespace?.toLocaleLowerCase('en-US') ??\n ENTITY_DEFAULT_NAMESPACE,\n name: entity.metadata.name,\n } ;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { entityRouteRef } from '../routes';\nimport { useRouteRefParams } from '@backstage/core-plugin-api';\n\n/**\n * Grabs entity kind, namespace, and name from the location\n */\nexport const useEntityCompoundName = () => {\n const { kind, namespace, name } = useRouteRefParams(entityRouteRef);\n return { kind, namespace, name };\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { errorApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n createVersionedContext,\n createVersionedValueMap,\n useVersionedContext,\n} from '@backstage/version-bridge';\nimport React, {\n\n useEffect,\n createContext,\n\n\n} from 'react';\nimport { useNavigate } from 'react-router';\nimport useAsyncRetry from 'react-use/lib/useAsyncRetry';\nimport { catalogApiRef } from '../api';\nimport { useEntityCompoundName } from './useEntityCompoundName';\n\n\n\n\n\n\n\n\n/**\n * @public\n * @deprecated use `useEntity` and `EntityProvider` or `AsyncEntityProvider` instead.\n */\nexport const EntityContext =\n createContext({\n entity: undefined,\n loading: true,\n error: undefined,\n refresh: () => {},\n });\n// We grab this for use in the new provider, since we're overriding it later on\nconst OldEntityProvider = EntityContext.Provider;\n\n// This context has support for multiple concurrent versions of this package.\n// It is currently used in parallel with the old context in order to provide\n// a smooth transition, but will eventually be the only context we use.\nconst NewEntityContext =\n createVersionedContext('entity-context');\n\n/**\n * Properties for the AsyncEntityProvider component.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n/**\n * Provides a loaded entity to be picked up by the `useEntity` hook.\n *\n * @public\n */\nexport const AsyncEntityProvider = ({\n children,\n entity,\n loading,\n error,\n refresh,\n}) => {\n const value = { entity, loading, error, refresh };\n // We provide both the old and the new context, since\n // consumers might be doing things like `useContext(EntityContext)`\n return (\n React.createElement(OldEntityProvider, { value: value,}\n , React.createElement(NewEntityContext.Provider, { value: createVersionedValueMap({ 1: value }),}\n , children\n )\n )\n );\n};\n\n/**\n * Properties for the EntityProvider component.\n *\n * @public\n */\n\n\n\n\n\n/**\n * Provides an entity to be picked up by the `useEntity` hook.\n *\n * @public\n */\nexport const EntityProvider = ({ entity, children }) => (\n React.createElement(AsyncEntityProvider, {\n entity: entity,\n loading: !Boolean(entity),\n error: undefined,\n refresh: undefined,\n children: children,}\n )\n);\n\n// This is used for forwards compatibility with the new entity context\nconst CompatibilityProvider = ({\n value,\n children,\n}\n\n\n) => {\n return React.createElement(AsyncEntityProvider, { ...value, children: children,} );\n};\nEntityContext.Provider = CompatibilityProvider ;\n\nexport const useEntityFromUrl = () => {\n const { kind, namespace, name } = useEntityCompoundName();\n const navigate = useNavigate();\n const errorApi = useApi(errorApiRef);\n const catalogApi = useApi(catalogApiRef);\n\n const {\n value: entity,\n error,\n loading,\n retry: refresh,\n } = useAsyncRetry(\n () => catalogApi.getEntityByName({ kind, namespace, name }),\n [catalogApi, kind, namespace, name],\n );\n\n useEffect(() => {\n if (!name) {\n errorApi.post(new Error('No name provided!'));\n navigate('/');\n }\n }, [errorApi, navigate, error, loading, entity, name]);\n\n return { entity, loading, error, refresh };\n};\n\n/**\n * Grab the current entity from the context and its current loading state.\n *\n * @public\n */\nexport function useEntity() {\n const versionedHolder =\n useVersionedContext('entity-context');\n\n if (!versionedHolder) {\n // TODO(Rugvip): Throw this once we fully migrate to the new context\n // throw new Error('Entity context is not available');\n\n return {\n entity: undefined ,\n loading: true,\n error: undefined,\n refresh: () => {},\n };\n }\n\n const value = versionedHolder.atVersion(1);\n if (!value) {\n throw new Error('EntityContext v1 not available');\n }\n\n const { entity, loading, error, refresh } = value;\n return { entity: entity , loading, error, refresh };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport function reduceCatalogFilters(\n filters,\n) {\n return filters.reduce((compoundFilter, filter) => {\n return {\n ...compoundFilter,\n ...(filter.getCatalogFilters ? filter.getCatalogFilters() : {}),\n };\n }, {} );\n}\n\nexport function reduceEntityFilters(\n filters,\n) {\n return (entity) =>\n filters.every(\n filter => !filter.filterEntity || filter.filterEntity(entity),\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n EDIT_URL_ANNOTATION,\n\n VIEW_URL_ANNOTATION,\n} from '@backstage/catalog-model';\n\nexport function getEntityMetadataViewUrl(entity) {\n return entity.metadata.annotations?.[VIEW_URL_ANNOTATION];\n}\n\nexport function getEntityMetadataEditUrl(entity) {\n return entity.metadata.annotations?.[EDIT_URL_ANNOTATION];\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Get the related entity references.\n */\nexport function getEntityRelations(\n entity,\n relationType,\n filter,\n) {\n let entityNames =\n entity?.relations\n ?.filter(r => r.type === relationType)\n ?.map(r => r.target) || [];\n\n if (filter?.kind) {\n entityNames = entityNames?.filter(\n e =>\n e.kind.toLocaleLowerCase('en-US') ===\n filter.kind.toLocaleLowerCase('en-US'),\n );\n }\n\n return entityNames;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n parseLocationReference,\n SOURCE_LOCATION_ANNOTATION,\n} from '@backstage/catalog-model';\n\n\n\n\n\n\n\nexport function getEntitySourceLocation(\n entity,\n scmIntegrationsApi,\n) {\n const sourceLocation =\n entity.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION];\n\n if (!sourceLocation) {\n return undefined;\n }\n\n try {\n const sourceLocationRef = parseLocationReference(sourceLocation);\n const integration = scmIntegrationsApi.byUrl(sourceLocationRef.target);\n return {\n locationTargetUrl: sourceLocationRef.target,\n integrationType: integration?.type,\n };\n } catch {\n return undefined;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n getEntityName,\n RELATION_MEMBER_OF,\n RELATION_OWNED_BY,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { getEntityRelations } from './getEntityRelations';\n\n/**\n * Get the related entity references.\n */\nexport function isOwnerOf(owner, owned) {\n const possibleOwners = new Set(\n [\n ...getEntityRelations(owner, RELATION_MEMBER_OF, { kind: 'group' }),\n ...(owner ? [getEntityName(owner)] : []),\n ].map(stringifyEntityRef),\n );\n\n const owners = getEntityRelations(owned, RELATION_OWNED_BY).map(\n stringifyEntityRef,\n );\n\n for (const ownerItem of owners) {\n if (possibleOwners.has(ownerItem)) {\n return true;\n }\n }\n\n return false;\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { compact, isEqual } from 'lodash';\nimport qs from 'qs';\nimport React, {\n createContext,\n\n useCallback,\n useContext,\n useMemo,\n useState,\n} from 'react';\nimport { useLocation } from 'react-router';\nimport useAsyncFn from 'react-use/lib/useAsyncFn';\nimport useDebounce from 'react-use/lib/useDebounce';\nimport useMountedState from 'react-use/lib/useMountedState';\nimport { catalogApiRef } from '../api';\n\n\n\n\n\n\n\n\n\n\nimport { reduceCatalogFilters, reduceEntityFilters } from '../utils';\nimport { useApi } from '@backstage/core-plugin-api';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const EntityListContext = createContext\n\n(undefined);\n\n\n\n\n\n\n\nexport const EntityListProvider = ({\n children,\n}) => {\n const isMounted = useMountedState();\n const catalogApi = useApi(catalogApiRef);\n const [requestedFilters, setRequestedFilters] = useState(\n {} ,\n );\n\n // We use react-router's useLocation hook so updates from external sources trigger an update to\n // the queryParameters in outputState. Updates from this hook use replaceState below and won't\n // trigger a useLocation change; this would instead come from an external source, such as a manual\n // update of the URL or two catalog sidebar links with different catalog filters.\n const location = useLocation();\n const queryParameters = useMemo(\n () =>\n (qs.parse(location.search, {\n ignoreQueryPrefix: true,\n }).filters ?? {}) ,\n [location],\n );\n\n const [outputState, setOutputState] = useState(\n () => {\n return {\n appliedFilters: {} ,\n entities: [],\n backendEntities: [],\n };\n },\n );\n\n // The main async filter worker. Note that while it has a lot of dependencies\n // in terms of its implementation, the triggering only happens (debounced)\n // based on the requested filters changing.\n const [{ loading, error }, refresh] = useAsyncFn(\n async () => {\n const compacted = compact(Object.values(requestedFilters));\n const entityFilter = reduceEntityFilters(compacted);\n const backendFilter = reduceCatalogFilters(compacted);\n const previousBackendFilter = reduceCatalogFilters(\n compact(Object.values(outputState.appliedFilters)),\n );\n\n const queryParams = Object.keys(requestedFilters).reduce(\n (params, key) => {\n const filter =\n requestedFilters[key ];\n if (filter?.toQueryValue) {\n params[key] = filter.toQueryValue();\n }\n return params;\n },\n {} ,\n );\n\n // TODO(mtlewis): currently entities will never be requested unless\n // there's at least one filter, we should allow an initial request\n // to happen with no filters.\n if (!isEqual(previousBackendFilter, backendFilter)) {\n // TODO(timbonicus): should limit fields here, but would need filter\n // fields + table columns\n const response = await catalogApi.getEntities({\n filter: backendFilter,\n });\n setOutputState({\n appliedFilters: requestedFilters,\n backendEntities: response.items,\n entities: response.items.filter(entityFilter),\n });\n } else {\n setOutputState({\n appliedFilters: requestedFilters,\n backendEntities: outputState.backendEntities,\n entities: outputState.backendEntities.filter(entityFilter),\n });\n }\n\n if (isMounted()) {\n const oldParams = qs.parse(location.search, {\n ignoreQueryPrefix: true,\n });\n const newParams = qs.stringify(\n { ...oldParams, filters: queryParams },\n { addQueryPrefix: true },\n );\n const newUrl = `${window.location.pathname}${newParams}`;\n // We use direct history manipulation since useSearchParams and\n // useNavigate in react-router-dom cause unnecessary extra rerenders.\n // Also make sure to replace the state rather than pushing, since we\n // don't want there to be back/forward slots for every single filter\n // change.\n window.history?.replaceState(null, document.title, newUrl);\n }\n },\n [catalogApi, queryParameters, requestedFilters, outputState],\n { loading: true },\n );\n\n // Slight debounce on the refresh, since (especially on page load) several\n // filters will be calling this in rapid succession.\n useDebounce(refresh, 10, [requestedFilters]);\n\n const updateFilters = useCallback(\n (\n update\n\n,\n ) => {\n setRequestedFilters(prevFilters => {\n const newFilters =\n typeof update === 'function' ? update(prevFilters) : update;\n return { ...prevFilters, ...newFilters };\n });\n },\n [],\n );\n\n const value = useMemo(\n () => ({\n filters: outputState.appliedFilters,\n entities: outputState.entities,\n backendEntities: outputState.backendEntities,\n updateFilters,\n queryParameters,\n loading,\n error,\n }),\n [outputState, updateFilters, queryParameters, loading, error],\n );\n\n return (\n React.createElement(EntityListContext.Provider, { value: value,}\n , children\n )\n );\n};\n\nexport function useEntityListProvider\n\n() {\n const context = useContext(EntityListContext);\n if (!context)\n throw new Error(\n 'useEntityListProvider must be used within EntityListProvider',\n );\n return context;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n\n ENTITY_DEFAULT_NAMESPACE,\n serializeEntityRef,\n} from '@backstage/catalog-model';\n\nexport function formatEntityRefTitle(\n entityRef,\n opts,\n) {\n const defaultKind = opts?.defaultKind;\n let kind;\n let namespace;\n let name;\n\n if ('metadata' in entityRef) {\n kind = entityRef.kind;\n namespace = entityRef.metadata.namespace;\n name = entityRef.metadata.name;\n } else {\n kind = entityRef.kind;\n namespace = entityRef.namespace;\n name = entityRef.name;\n }\n\n if (namespace === ENTITY_DEFAULT_NAMESPACE) {\n namespace = undefined;\n }\n\n kind = kind.toLocaleLowerCase('en-US');\n\n return `${serializeEntityRef({\n kind:\n defaultKind && defaultKind.toLocaleLowerCase('en-US') === kind\n ? undefined\n : kind,\n name,\n namespace,\n })}`;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n\n ENTITY_DEFAULT_NAMESPACE,\n} from '@backstage/catalog-model';\nimport React, { forwardRef } from 'react';\nimport { entityRouteRef } from '../../routes';\nimport { formatEntityRefTitle } from './format';\nimport { Link, } from '@backstage/core-components';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport { Tooltip } from '@material-ui/core';\n\n/**\n * Props for {@link EntityRefLink}.\n *\n * @public\n */\n\n\n\n\n\n\n\n/**\n * Shows a clickable link to an entity.\n *\n * @public\n */\nexport const EntityRefLink = forwardRef(\n (props, ref) => {\n const { entityRef, defaultKind, title, children, ...linkProps } = props;\n const entityRoute = useRouteRef(entityRouteRef);\n\n let kind;\n let namespace;\n let name;\n\n if ('metadata' in entityRef) {\n kind = entityRef.kind;\n namespace = entityRef.metadata.namespace;\n name = entityRef.metadata.name;\n } else {\n kind = entityRef.kind;\n namespace = entityRef.namespace;\n name = entityRef.name;\n }\n\n kind = kind.toLocaleLowerCase('en-US');\n\n const routeParams = {\n kind,\n namespace:\n namespace?.toLocaleLowerCase('en-US') ?? ENTITY_DEFAULT_NAMESPACE,\n name,\n };\n const formattedEntityRefTitle = formatEntityRefTitle(entityRef, {\n defaultKind,\n });\n\n const link = (\n React.createElement(Link, { ...linkProps, ref: ref, to: entityRoute(routeParams),}\n , children\n , !children && (title ?? formattedEntityRefTitle)\n )\n );\n\n return title ? (\n React.createElement(Tooltip, { title: formattedEntityRefTitle,}, link)\n ) : (\n link\n );\n },\n);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport React from 'react';\nimport { EntityRefLink } from './EntityRefLink';\n\n\n/**\n * Props for {@link EntityRefLink}.\n *\n * @public\n */\n\n\n\n\n\n/**\n * Shows a list of clickable links to entities.\n *\n * @public\n */\nexport const EntityRefLinks = ({\n entityRefs,\n defaultKind,\n ...linkProps\n}) => (\n React.createElement(React.Fragment, null\n , entityRefs.map((r, i) => (\n React.createElement(React.Fragment, { key: i,}\n , i > 0 && ', '\n , React.createElement(EntityRefLink, { ...linkProps, entityRef: r, defaultKind: defaultKind,} )\n )\n ))\n )\n);\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RELATION_OWNED_BY } from '@backstage/catalog-model';\nimport { formatEntityRefTitle } from './components/EntityRefLink';\n\nimport { getEntityRelations } from './utils';\n\nexport class EntityKindFilter {\n constructor( value) {;this.value = value;}\n\n getCatalogFilters() {\n return { kind: this.value };\n }\n\n toQueryValue() {\n return this.value;\n }\n}\n\nexport class EntityTypeFilter {\n constructor( value) {;this.value = value;}\n\n // Simplify `string | string[]` for consumers, always returns an array\n getTypes() {\n return Array.isArray(this.value) ? this.value : [this.value];\n }\n\n getCatalogFilters() {\n return { 'spec.type': this.getTypes() };\n }\n\n toQueryValue() {\n return this.getTypes();\n }\n}\n\nexport class EntityTagFilter {\n constructor( values) {;this.values = values;}\n\n filterEntity(entity) {\n return this.values.every(v => (entity.metadata.tags ?? []).includes(v));\n }\n\n toQueryValue() {\n return this.values;\n }\n}\n\nexport class EntityTextFilter {\n constructor( value) {;this.value = value;}\n\n filterEntity(entity) {\n const upperCaseValue = this.value.toLocaleUpperCase('en-US');\n\n return (\n entity.metadata.name\n .toLocaleUpperCase('en-US')\n .includes(upperCaseValue) ||\n `${entity.metadata.title}`\n .toLocaleUpperCase('en-US')\n .includes(upperCaseValue) ||\n entity.metadata.tags\n ?.join('')\n .toLocaleUpperCase('en-US')\n .indexOf(upperCaseValue) !== -1\n );\n }\n}\n\nexport class EntityOwnerFilter {\n constructor( values) {;this.values = values;}\n\n filterEntity(entity) {\n return this.values.some(v =>\n getEntityRelations(entity, RELATION_OWNED_BY).some(\n o => formatEntityRefTitle(o, { defaultKind: 'group' }) === v,\n ),\n );\n }\n\n toQueryValue() {\n return this.values;\n }\n}\n\nexport class EntityLifecycleFilter {\n constructor( values) {;this.values = values;}\n\n filterEntity(entity) {\n return this.values.some(v => entity.spec?.lifecycle === v);\n }\n\n toQueryValue() {\n return this.values;\n }\n}\n\nexport class UserListFilter {\n constructor(\n value,\n isOwnedEntity,\n isStarredEntity,\n ) {;this.value = value;this.isOwnedEntity = isOwnedEntity;this.isStarredEntity = isStarredEntity;}\n\n filterEntity(entity) {\n switch (this.value) {\n case 'owned':\n return this.isOwnedEntity(entity);\n case 'starred':\n return this.isStarredEntity(entity);\n default:\n return true;\n }\n }\n\n toQueryValue() {\n return this.value;\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport isEqual from 'lodash/isEqual';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '../api';\nimport { useEntityListProvider } from './useEntityListProvider';\nimport { EntityTypeFilter } from '../filters';\n\n\n\n\n\n\n\n\n\n/**\n * A hook built on top of `useEntityListProvider` for enabling selection of valid `spec.type` values\n * based on the selected EntityKindFilter.\n */\nexport function useEntityTypeFilter() {\n const catalogApi = useApi(catalogApiRef);\n const {\n filters: { kind: kindFilter, type: typeFilter },\n queryParameters,\n updateFilters,\n } = useEntityListProvider();\n\n const queryParamTypes = useMemo(\n () => [queryParameters.type].flat().filter(Boolean) ,\n [queryParameters],\n );\n\n const [selectedTypes, setSelectedTypes] = useState(\n queryParamTypes.length ? queryParamTypes : typeFilter?.getTypes() ?? [],\n );\n\n // Set selected types on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (queryParamTypes.length) {\n setSelectedTypes(queryParamTypes);\n }\n }, [queryParamTypes]);\n\n const [availableTypes, setAvailableTypes] = useState([]);\n const kind = useMemo(() => kindFilter?.value, [kindFilter]);\n\n // Load all valid spec.type values straight from the catalogApi, paying attention to only the\n // kind filter for a complete list.\n const {\n error,\n loading,\n value: entities,\n } = useAsync(async () => {\n if (kind) {\n const items = await catalogApi\n .getEntities({\n filter: { kind },\n fields: ['spec.type'],\n })\n .then(response => response.items);\n return items;\n }\n return [];\n }, [kind, catalogApi]);\n\n const entitiesRef = useRef(entities);\n useEffect(() => {\n const oldEntities = entitiesRef.current;\n entitiesRef.current = entities;\n // Delay processing hook until kind and entity load updates have settled to generate list of types;\n // This prevents reseting the type filter due to saved type value from query params not matching the\n // empty set of type values while values are still being loaded; also only run this hook on changes\n // to entities\n if (loading || !kind || oldEntities === entities) {\n return;\n }\n\n // Resolve the unique set of types from returned entities; could be optimized by a new endpoint\n // in the catalog-backend that does this, rather than loading entities with redundant types.\n if (!entities) return;\n\n // Sort by entity count descending, so the most common types appear on top\n const countByType = entities.reduce((acc, entity) => {\n if (typeof entity.spec?.type !== 'string') return acc;\n\n const entityType = entity.spec.type.toLocaleLowerCase('en-US');\n if (!acc[entityType]) {\n acc[entityType] = 0;\n }\n acc[entityType] += 1;\n return acc;\n }, {} );\n\n const newTypes = Object.entries(countByType)\n .sort(([, count1], [, count2]) => count2 - count1)\n .map(([type]) => type);\n setAvailableTypes(newTypes);\n\n // Update type filter to only valid values when the list of available types has changed\n const stillValidTypes = selectedTypes.filter(value =>\n newTypes.includes(value),\n );\n if (!isEqual(selectedTypes, stillValidTypes)) {\n setSelectedTypes(stillValidTypes);\n }\n }, [loading, kind, selectedTypes, setSelectedTypes, entities]);\n\n useEffect(() => {\n updateFilters({\n type: selectedTypes.length\n ? new EntityTypeFilter(selectedTypes)\n : undefined,\n });\n }, [selectedTypes, updateFilters]);\n\n return {\n loading,\n error,\n availableTypes,\n selectedTypes,\n setSelectedTypes,\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport useAsync from 'react-use/lib/useAsync';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '../api';\n\n// Retrieve a list of unique entity kinds present in the catalog\nexport function useEntityKinds() {\n const catalogApi = useApi(catalogApiRef);\n\n const {\n error,\n loading,\n value: kinds,\n } = useAsync(async () => {\n const entities = await catalogApi\n .getEntities({ fields: ['kind'] })\n .then(response => response.items);\n\n return [...new Set(entities.map(e => e.kind))].sort();\n });\n return { error, loading, kinds };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ENTITY_DEFAULT_NAMESPACE,\n parseEntityRef,\n\n} from '@backstage/catalog-model';\nimport useAsync, { } from 'react-use/lib/useAsync';\nimport { catalogApiRef } from '../api';\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\n\n/**\n * Get the catalog User entity (if any) that matches the logged-in user.\n */\nexport function useOwnUser() {\n const catalogApi = useApi(catalogApiRef);\n const identityApi = useApi(identityApiRef);\n\n return useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n return catalogApi.getEntityByName(\n parseEntityRef(identity.userEntityRef, {\n defaultKind: 'User',\n defaultNamespace: ENTITY_DEFAULT_NAMESPACE,\n }),\n ) ;\n }, [catalogApi, identityApi]);\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { useApi } from '@backstage/core-plugin-api';\nimport { chunk, groupBy } from 'lodash';\nimport useAsync from 'react-use/lib/useAsync';\nimport { catalogApiRef } from '../api';\n\nconst BATCH_SIZE = 20;\n\nexport function useRelatedEntities(\n entity,\n { type, kind },\n)\n\n\n\n {\n const catalogApi = useApi(catalogApiRef);\n const {\n loading,\n value: entities,\n error,\n } = useAsync(async () => {\n const relations =\n entity.relations &&\n entity.relations.filter(\n r =>\n (!type ||\n r.type.toLocaleLowerCase('en-US') ===\n type.toLocaleLowerCase('en-US')) &&\n (!kind ||\n r.target.kind.toLocaleLowerCase('en-US') ===\n kind.toLocaleLowerCase('en-US')),\n );\n\n if (!relations) {\n return [];\n }\n\n // Group the relations by kind and namespace to reduce the size of the request query string.\n // Without this grouping, the kind and namespace would need to be specified for each relation, e.g.\n // `filter=kind=component,namespace=default,name=example1&filter=kind=component,namespace=default,name=example2`\n // with grouping, we can generate a query a string like\n // `filter=kind=component,namespace=default,name=example1,example2`\n const relationsByKindAndNamespace = Object.values(\n groupBy(relations, ({ target }) => {\n return `${target.kind}:${target.namespace}`.toLocaleLowerCase('en-US');\n }),\n );\n\n // Split the names within each group into batches to further reduce the query string length.\n const batchedRelationsByKindAndNamespace\n\n\n\n = [];\n for (const rs of relationsByKindAndNamespace) {\n batchedRelationsByKindAndNamespace.push({\n // All relations in a group have the same kind and namespace, so its arbitrary which we pick\n kind: rs[0].target.kind,\n namespace: rs[0].target.namespace,\n nameBatches: chunk(\n rs.map(r => r.target.name),\n BATCH_SIZE,\n ),\n });\n }\n\n const results = await Promise.all(\n batchedRelationsByKindAndNamespace.flatMap(rs => {\n return rs.nameBatches.map(names => {\n return catalogApi.getEntities({\n filter: {\n kind: rs.kind,\n 'metadata.namespace': rs.namespace,\n 'metadata.name': names,\n },\n });\n });\n }),\n );\n\n return results.flatMap(r => r.items);\n }, [entity, type]);\n\n return {\n entities,\n loading,\n error,\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useCallback } from 'react';\nimport useObservable from 'react-use/lib/useObservable';\nimport { starredEntitiesApiRef } from '../apis';\n\nfunction getEntityRef(entityOrRef) {\n return typeof entityOrRef === 'string'\n ? entityOrRef\n : stringifyEntityRef(entityOrRef);\n}\n\nexport function useStarredEntities()\n\n\n\n {\n const starredEntitiesApi = useApi(starredEntitiesApiRef);\n\n const starredEntities = useObservable(\n starredEntitiesApi.starredEntitie$(),\n new Set(),\n );\n\n const isStarredEntity = useCallback(\n (entityOrRef) =>\n starredEntities.has(getEntityRef(entityOrRef)),\n [starredEntities],\n );\n\n const toggleStarredEntity = useCallback(\n (entityOrRef) =>\n starredEntitiesApi.toggleStarred(getEntityRef(entityOrRef)).then(),\n [starredEntitiesApi],\n );\n\n return {\n starredEntities,\n toggleStarredEntity,\n isStarredEntity,\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useCallback, useEffect, useState } from 'react';\nimport { starredEntitiesApiRef } from '../apis';\n\nfunction getEntityRef(entityOrRef) {\n return typeof entityOrRef === 'string'\n ? entityOrRef\n : stringifyEntityRef(entityOrRef);\n}\n\nexport function useStarredEntity(entityOrRef)\n\n\n {\n const starredEntitiesApi = useApi(starredEntitiesApiRef);\n\n const [isStarredEntity, setIsStarredEntity] = useState(false);\n\n useEffect(() => {\n const subscription = starredEntitiesApi.starredEntitie$().subscribe({\n next(starredEntities) {\n setIsStarredEntity(starredEntities.has(getEntityRef(entityOrRef)));\n },\n });\n\n return () => {\n subscription.unsubscribe();\n };\n }, [entityOrRef, starredEntitiesApi]);\n\n const toggleStarredEntity = useCallback(\n () => starredEntitiesApi.toggleStarred(getEntityRef(entityOrRef)).then(),\n [entityOrRef, starredEntitiesApi],\n );\n\n return {\n toggleStarredEntity,\n isStarredEntity,\n };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport {\n\n\n parseEntityRef,\n RELATION_MEMBER_OF,\n RELATION_OWNED_BY,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport {\n\n identityApiRef,\n useApi,\n} from '@backstage/core-plugin-api';\nimport { useMemo } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport { catalogApiRef } from '../api';\nimport { getEntityRelations } from '../utils/getEntityRelations';\n\n/**\n * Takes the relevant parts of the Backstage identity, and translates them into\n * a list of entity refs on string form that represent the user's ownership\n * connections.\n *\n * @public\n * @deprecated Use `ownershipEntityRefs` from `identityApi.getBackstageIdentity()` instead.\n *\n * @param identityApi - The IdentityApi implementation\n * @returns IdentityOwner refs as a string array\n */\nexport async function loadIdentityOwnerRefs(\n identityApi,\n) {\n const identity = await identityApi.getBackstageIdentity();\n return identity.ownershipEntityRefs;\n}\n\n/**\n * Takes the relevant parts of the User entity corresponding to the Backstage\n * identity, and translates them into a list of entity refs on string form that\n * represent the user's ownership connections.\n *\n * @public\n *\n * @param catalogApi - The Catalog API implementation\n * @param identityOwnerRefs - List of identity owner refs as strings\n * @returns OwnerRefs as a string array\n */\nexport async function loadCatalogOwnerRefs(\n catalogApi,\n identityOwnerRefs,\n) {\n const result = new Array();\n\n const primaryUserRef = identityOwnerRefs.find(ref => ref.startsWith('user:'));\n if (primaryUserRef) {\n const entity = await catalogApi.getEntityByName(\n parseEntityRef(primaryUserRef),\n );\n if (entity) {\n const memberOf = getEntityRelations(entity, RELATION_MEMBER_OF, {\n kind: 'Group',\n });\n for (const group of memberOf) {\n result.push(stringifyEntityRef(group));\n }\n }\n }\n\n return result;\n}\n\n/**\n * Returns a function that checks whether the currently signed-in user is an\n * owner of a given entity. When the hook is initially mounted, the loading\n * flag will be true and the results returned from the function will always be\n * false.\n *\n * @public\n *\n * @returns a function that checks if the signed in user owns an entity\n */\nexport function useEntityOwnership()\n\n\n {\n const identityApi = useApi(identityApiRef);\n const catalogApi = useApi(catalogApiRef);\n\n // Trigger load only on mount\n const { loading, value: refs } = useAsync(async () => {\n const { ownershipEntityRefs } = await identityApi.getBackstageIdentity();\n const catalogRefs = await loadCatalogOwnerRefs(\n catalogApi,\n ownershipEntityRefs,\n );\n return new Set([...ownershipEntityRefs, ...catalogRefs]);\n }, []);\n\n const isOwnedEntity = useMemo(() => {\n const myOwnerRefs = new Set(refs ?? []);\n return (entity) => {\n const entityOwnerRefs = (\n 'metadata' in entity\n ? getEntityRelations(entity, RELATION_OWNED_BY)\n : [entity]\n ).map(stringifyEntityRef);\n for (const ref of entityOwnerRefs) {\n if (myOwnerRefs.has(ref)) {\n return true;\n }\n }\n return false;\n };\n }, [refs]);\n\n return useMemo(() => ({ loading, isOwnedEntity }), [loading, isOwnedEntity]);\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { catalogApiRef } from './../api';\nimport {\n loadCatalogOwnerRefs,\n loadIdentityOwnerRefs,\n} from './useEntityOwnership';\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\nimport { RELATION_OWNED_BY } from '@backstage/catalog-model';\n\nimport useAsync from 'react-use/lib/useAsync';\nimport { useMemo } from 'react';\n\n/**\n * Takes the relevant parts of the Backstage identity, and translates them into\n * a list of entities which are owned by the user. Takes an optional parameter\n * to filter the entities based on allowedKinds\n *\n * @public\n *\n * @param allowedKinds - Array of allowed kinds to filter the entities\n * @returns CatalogListResponse<Entity>\n */\nexport function useOwnedEntities(allowedKinds)\n\n\n {\n const identityApi = useApi(identityApiRef);\n const catalogApi = useApi(catalogApiRef);\n\n const { loading, value: refs } = useAsync(async () => {\n const identityRefs = await loadIdentityOwnerRefs(identityApi);\n const catalogRefs = await loadCatalogOwnerRefs(catalogApi, identityRefs);\n const catalogs = await catalogApi.getEntities(\n allowedKinds\n ? {\n filter: {\n kind: allowedKinds,\n [`relations.${RELATION_OWNED_BY}`]:\n [...identityRefs, ...catalogRefs] || [],\n },\n }\n : {\n filter: {\n [`relations.${RELATION_OWNED_BY}`]:\n [...identityRefs, ...catalogRefs] || [],\n },\n },\n );\n return catalogs;\n }, []);\n\n const ownedEntities = useMemo(() => {\n return refs;\n }, [refs]);\n\n return useMemo(() => ({ loading, ownedEntities }), [loading, ownedEntities]);\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { stringifyEntityRef } from '@backstage/catalog-model';\n\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport { useEntity } from './useEntity';\n\n/**\n * A thin wrapper around the\n * {@link @backstage/plugin-permission-react#usePermission} hook which uses the\n * current entity in context to make an authorization request for the given\n * permission.\n *\n * Note: this hook blocks the permission request until the entity has loaded in\n * context. If you have the entityRef and need concurrent requests, use the\n * `usePermission` hook directly.\n * @public\n */\nexport function useEntityPermission(permission)\n\n\n\n {\n const { entity, loading: loadingEntity, error: entityError } = useEntity();\n const {\n allowed,\n loading: loadingPermission,\n error: permissionError,\n } = usePermission(\n permission,\n entity ? stringifyEntityRef(entity) : undefined,\n );\n\n if (loadingEntity || loadingPermission) {\n return { loading: true, allowed: false };\n }\n if (entityError) {\n return { loading: false, allowed: false, error: entityError };\n }\n return { loading: false, allowed, error: permissionError };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect, useState } from 'react';\nimport { Alert } from '@material-ui/lab';\nimport { useEntityListProvider } from '../../hooks';\nimport { EntityKindFilter } from '../../filters';\n\n/**\n * Props for {@link EntityKindPicker}.\n *\n * @public\n */\n\n\n\n\n\n/** @public */\nexport const EntityKindPicker = (props) => {\n const { initialFilter, hidden } = props;\n\n const { updateFilters, queryParameters } = useEntityListProvider();\n const [selectedKind] = useState(\n [queryParameters.kind].flat()[0] ?? initialFilter,\n );\n\n useEffect(() => {\n updateFilters({\n kind: selectedKind ? new EntityKindFilter(selectedKind) : undefined,\n });\n }, [selectedKind, updateFilters]);\n\n if (hidden) return null;\n\n // TODO(timbonicus): This should load available kinds from the catalog-backend, similar to\n // EntityTypePicker.\n\n return React.createElement(Alert, { severity: \"warning\",}, \"Kind filter not yet available\" );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport {\n Box,\n Checkbox,\n FormControlLabel,\n makeStyles,\n TextField,\n Typography,\n} from '@material-ui/core';\nimport CheckBoxIcon from '@material-ui/icons/CheckBox';\nimport CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport { Autocomplete } from '@material-ui/lab';\nimport React, { useEffect, useMemo, useState } from 'react';\nimport { useEntityListProvider } from '../../hooks/useEntityListProvider';\nimport { EntityLifecycleFilter } from '../../filters';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n {\n input: {},\n },\n {\n name: 'CatalogReactEntityLifecyclePicker',\n },\n);\n\nconst icon = React.createElement(CheckBoxOutlineBlankIcon, { fontSize: \"small\",} );\nconst checkedIcon = React.createElement(CheckBoxIcon, { fontSize: \"small\",} );\n\n/** @public */\nexport const EntityLifecyclePicker = () => {\n const classes = useStyles();\n const { updateFilters, backendEntities, filters, queryParameters } =\n useEntityListProvider();\n\n const queryParamLifecycles = useMemo(\n () => [queryParameters.lifecycles].flat().filter(Boolean) ,\n [queryParameters],\n );\n\n const [selectedLifecycles, setSelectedLifecycles] = useState(\n queryParamLifecycles.length\n ? queryParamLifecycles\n : filters.lifecycles?.values ?? [],\n );\n\n // Set selected lifecycles on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (queryParamLifecycles.length) {\n setSelectedLifecycles(queryParamLifecycles);\n }\n }, [queryParamLifecycles]);\n\n useEffect(() => {\n updateFilters({\n lifecycles: selectedLifecycles.length\n ? new EntityLifecycleFilter(selectedLifecycles)\n : undefined,\n });\n }, [selectedLifecycles, updateFilters]);\n\n const availableLifecycles = useMemo(\n () =>\n [\n ...new Set(\n backendEntities\n .map((e) => e.spec?.lifecycle)\n .filter(Boolean) ,\n ),\n ].sort(),\n [backendEntities],\n );\n\n if (!availableLifecycles.length) return null;\n\n return (\n React.createElement(Box, { pb: 1, pt: 1,}\n , React.createElement(Typography, { variant: \"button\",}, \"Lifecycle\")\n , React.createElement(Autocomplete, {\n 'aria-label': \"Lifecycle\",\n multiple: true,\n options: availableLifecycles,\n value: selectedLifecycles,\n onChange: (_, value) => setSelectedLifecycles(value),\n renderOption: (option, { selected }) => (\n React.createElement(FormControlLabel, {\n control: \n React.createElement(Checkbox, {\n icon: icon,\n checkedIcon: checkedIcon,\n checked: selected,}\n )\n ,\n label: option,}\n )\n ),\n size: \"small\",\n popupIcon: React.createElement(ExpandMoreIcon, { 'data-testid': \"lifecycle-picker-expand\",} ),\n renderInput: params => (\n React.createElement(TextField, { ...params, className: classes.input, variant: \"outlined\",} )\n ),}\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RELATION_OWNED_BY } from '@backstage/catalog-model';\nimport {\n Box,\n Checkbox,\n FormControlLabel,\n makeStyles,\n TextField,\n Typography,\n} from '@material-ui/core';\nimport CheckBoxIcon from '@material-ui/icons/CheckBox';\nimport CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport { Autocomplete } from '@material-ui/lab';\nimport React, { useEffect, useMemo, useState } from 'react';\nimport { useEntityListProvider } from '../../hooks/useEntityListProvider';\nimport { EntityOwnerFilter } from '../../filters';\nimport { getEntityRelations } from '../../utils';\nimport { formatEntityRefTitle } from '../EntityRefLink';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n {\n input: {},\n },\n {\n name: 'CatalogReactEntityOwnerPicker',\n },\n);\n\nconst icon = React.createElement(CheckBoxOutlineBlankIcon, { fontSize: \"small\",} );\nconst checkedIcon = React.createElement(CheckBoxIcon, { fontSize: \"small\",} );\n\n/** @public */\nexport const EntityOwnerPicker = () => {\n const classes = useStyles();\n const { updateFilters, backendEntities, filters, queryParameters } =\n useEntityListProvider();\n\n const queryParamOwners = useMemo(\n () => [queryParameters.owners].flat().filter(Boolean) ,\n [queryParameters],\n );\n\n const [selectedOwners, setSelectedOwners] = useState(\n queryParamOwners.length ? queryParamOwners : filters.owners?.values ?? [],\n );\n\n // Set selected owners on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (queryParamOwners.length) {\n setSelectedOwners(queryParamOwners);\n }\n }, [queryParamOwners]);\n\n useEffect(() => {\n updateFilters({\n owners: selectedOwners.length\n ? new EntityOwnerFilter(selectedOwners)\n : undefined,\n });\n }, [selectedOwners, updateFilters]);\n\n const availableOwners = useMemo(\n () =>\n [\n ...new Set(\n backendEntities\n .flatMap((e) =>\n getEntityRelations(e, RELATION_OWNED_BY).map(o =>\n formatEntityRefTitle(o, { defaultKind: 'group' }),\n ),\n )\n .filter(Boolean) ,\n ),\n ].sort(),\n [backendEntities],\n );\n\n if (!availableOwners.length) return null;\n\n return (\n React.createElement(Box, { pb: 1, pt: 1,}\n , React.createElement(Typography, { variant: \"button\",}, \"Owner\")\n , React.createElement(Autocomplete, {\n multiple: true,\n 'aria-label': \"Owner\",\n options: availableOwners,\n value: selectedOwners,\n onChange: (_, value) => setSelectedOwners(value),\n renderOption: (option, { selected }) => (\n React.createElement(FormControlLabel, {\n control: \n React.createElement(Checkbox, {\n icon: icon,\n checkedIcon: checkedIcon,\n checked: selected,}\n )\n ,\n label: option,}\n )\n ),\n size: \"small\",\n popupIcon: React.createElement(ExpandMoreIcon, { 'data-testid': \"owner-picker-expand\",} ),\n renderInput: params => (\n React.createElement(TextField, { ...params, className: classes.input, variant: \"outlined\",} )\n ),}\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FormControl,\n IconButton,\n Input,\n InputAdornment,\n makeStyles,\n Toolbar,\n} from '@material-ui/core';\nimport Clear from '@material-ui/icons/Clear';\nimport Search from '@material-ui/icons/Search';\nimport React, { useState } from 'react';\nimport useDebounce from 'react-use/lib/useDebounce';\nimport { useEntityListProvider } from '../../hooks/useEntityListProvider';\nimport { EntityTextFilter } from '../../filters';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n _theme => ({\n searchToolbar: {\n paddingLeft: 0,\n paddingRight: 0,\n },\n input: {},\n }),\n {\n name: 'CatalogReactEntitySearchBar',\n },\n);\n\n/** @public */\nexport const EntitySearchBar = () => {\n const classes = useStyles();\n\n const { filters, updateFilters } = useEntityListProvider();\n const [search, setSearch] = useState(filters.text?.value ?? '');\n\n useDebounce(\n () => {\n updateFilters({\n text: search.length ? new EntityTextFilter(search) : undefined,\n });\n },\n 250,\n [search, updateFilters],\n );\n\n return (\n React.createElement(Toolbar, { className: classes.searchToolbar,}\n , React.createElement(FormControl, null\n , React.createElement(Input, {\n id: \"input-with-icon-adornment\",\n className: classes.input,\n placeholder: \"Search\",\n autoComplete: \"off\",\n onChange: event => setSearch(event.target.value),\n value: search,\n startAdornment: \n React.createElement(InputAdornment, { position: \"start\",}\n , React.createElement(Search, null )\n )\n ,\n endAdornment: \n React.createElement(InputAdornment, { position: \"end\",}\n , React.createElement(IconButton, {\n 'aria-label': \"clear search\" ,\n onClick: () => setSearch(''),\n edge: \"end\",\n disabled: search.length === 0,}\n \n , React.createElement(Clear, null )\n )\n )\n ,}\n )\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n\n RELATION_OWNED_BY,\n RELATION_PART_OF,\n} from '@backstage/catalog-model';\nimport { OverflowTooltip, } from '@backstage/core-components';\nimport React from 'react';\nimport { getEntityRelations } from '../../utils';\nimport {\n EntityRefLink,\n EntityRefLinks,\n formatEntityRefTitle,\n} from '../EntityRefLink';\n\n/** @public */\nexport function createEntityRefColumn(options\n\n) {\n const { defaultKind } = options;\n function formatContent(entity) {\n return (\n entity.metadata?.title ||\n formatEntityRefTitle(entity, {\n defaultKind,\n })\n );\n }\n\n return {\n title: 'Name',\n highlight: true,\n customFilterAndSearch(filter, entity) {\n // TODO: We could implement this more efficiently, like searching over\n // each field that is displayed individually (kind, namespace, name).\n // but that might confuse the user as it will behave different than a\n // simple text search.\n // Another alternative would be to cache the values. But writing them\n // into the entity feels bad too.\n return formatContent(entity).includes(filter);\n },\n customSort(entity1, entity2) {\n // TODO: We could implement this more efficiently by comparing field by field.\n // This has similar issues as above.\n return formatContent(entity1).localeCompare(formatContent(entity2));\n },\n render: entity => (\n React.createElement(EntityRefLink, {\n entityRef: entity,\n defaultKind: defaultKind,\n title: entity.metadata?.title,}\n )\n ),\n };\n}\n\n/** @public */\nexport function createEntityRelationColumn({\n title,\n relation,\n defaultKind,\n filter: entityFilter,\n}\n\n\n\n\n) {\n function getRelations(entity) {\n return getEntityRelations(entity, relation, entityFilter);\n }\n\n function formatContent(entity) {\n return getRelations(entity)\n .map(r => formatEntityRefTitle(r, { defaultKind }))\n .join(', ');\n }\n\n return {\n title,\n customFilterAndSearch(filter, entity) {\n return formatContent(entity).includes(filter);\n },\n customSort(entity1, entity2) {\n return formatContent(entity1).localeCompare(formatContent(entity2));\n },\n render: entity => {\n return (\n React.createElement(EntityRefLinks, {\n entityRefs: getRelations(entity),\n defaultKind: defaultKind,}\n )\n );\n },\n };\n}\n\n/** @public */\nexport function createOwnerColumn() {\n return createEntityRelationColumn({\n title: 'Owner',\n relation: RELATION_OWNED_BY,\n defaultKind: 'group',\n });\n}\n\n/** @public */\nexport function createDomainColumn() {\n return createEntityRelationColumn({\n title: 'Domain',\n relation: RELATION_PART_OF,\n defaultKind: 'domain',\n filter: {\n kind: 'domain',\n },\n });\n}\n\n/** @public */\nexport function createSystemColumn() {\n return createEntityRelationColumn({\n title: 'System',\n relation: RELATION_PART_OF,\n defaultKind: 'system',\n filter: {\n kind: 'system',\n },\n });\n}\n\n/** @public */\nexport function createMetadataDescriptionColumn\n\n() {\n return {\n title: 'Description',\n field: 'metadata.description',\n render: entity => (\n React.createElement(OverflowTooltip, {\n text: entity.metadata.description,\n placement: \"bottom-start\",\n line: 2,}\n )\n ),\n width: 'auto',\n };\n}\n\n/** @public */\nexport function createSpecLifecycleColumn() {\n return {\n title: 'Lifecycle',\n field: 'spec.lifecycle',\n };\n}\n\n/** @public */\nexport function createSpecTypeColumn() {\n return {\n title: 'Type',\n field: 'spec.type',\n };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport {\n createDomainColumn,\n createEntityRefColumn,\n createMetadataDescriptionColumn,\n createOwnerColumn,\n createSpecLifecycleColumn,\n createSpecTypeColumn,\n createSystemColumn,\n} from './columns';\n\n\nexport const systemEntityColumns = [\n createEntityRefColumn({ defaultKind: 'system' }),\n createDomainColumn(),\n createOwnerColumn(),\n createMetadataDescriptionColumn(),\n];\n\nexport const componentEntityColumns = [\n createEntityRefColumn({ defaultKind: 'component' }),\n createSystemColumn(),\n createOwnerColumn(),\n createSpecTypeColumn(),\n createSpecLifecycleColumn(),\n createMetadataDescriptionColumn(),\n];\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { makeStyles } from '@material-ui/core';\nimport React, { } from 'react';\nimport * as columnFactories from './columns';\nimport { componentEntityColumns, systemEntityColumns } from './presets';\nimport { Table, } from '@backstage/core-components';\n\n/**\n * Props for {@link EntityTable}.\n *\n * @public\n */\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(theme => ({\n empty: {\n padding: theme.spacing(2),\n display: 'flex',\n justifyContent: 'center',\n },\n}));\n\n/**\n * A general entity table component, that can be used for composing more\n * specific entity tables.\n *\n * @public\n */\nexport function EntityTable(props) {\n const {\n entities,\n title,\n emptyContent,\n variant = 'gridItem',\n columns,\n } = props;\n\n const classes = useStyles();\n const tableStyle = {\n minWidth: '0',\n width: '100%',\n };\n\n if (variant === 'gridItem') {\n tableStyle.height = 'calc(100% - 10px)';\n }\n\n return (\n React.createElement(Table, {\n columns: columns,\n title: title,\n style: tableStyle,\n emptyContent: \n emptyContent && React.createElement('div', { className: classes.empty,}, emptyContent)\n ,\n options: {\n // TODO: Toolbar padding if off compared to other cards, should be: padding: 16px 24px;\n search: false,\n paging: false,\n actionsColumnIndex: -1,\n padding: 'dense',\n },\n data: entities,}\n )\n );\n}\n\nEntityTable.columns = columnFactories;\n\nEntityTable.systemEntityColumns = systemEntityColumns;\n\nEntityTable.componentEntityColumns = componentEntityColumns;\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport {\n Box,\n Checkbox,\n FormControlLabel,\n makeStyles,\n TextField,\n Typography,\n} from '@material-ui/core';\nimport CheckBoxIcon from '@material-ui/icons/CheckBox';\nimport CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport { Autocomplete } from '@material-ui/lab';\nimport React, { useEffect, useMemo, useState } from 'react';\nimport { useEntityListProvider } from '../../hooks/useEntityListProvider';\nimport { EntityTagFilter } from '../../filters';\n\n/** @public */\n\n\nconst useStyles = makeStyles(\n {\n input: {},\n },\n {\n name: 'CatalogReactEntityTagPicker',\n },\n);\n\nconst icon = React.createElement(CheckBoxOutlineBlankIcon, { fontSize: \"small\",} );\nconst checkedIcon = React.createElement(CheckBoxIcon, { fontSize: \"small\",} );\n\n/** @public */\nexport const EntityTagPicker = () => {\n const classes = useStyles();\n const { updateFilters, backendEntities, filters, queryParameters } =\n useEntityListProvider();\n\n const queryParamTags = useMemo(\n () => [queryParameters.tags].flat().filter(Boolean) ,\n [queryParameters],\n );\n\n const [selectedTags, setSelectedTags] = useState(\n queryParamTags.length ? queryParamTags : filters.tags?.values ?? [],\n );\n\n // Set selected tags on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (queryParamTags.length) {\n setSelectedTags(queryParamTags);\n }\n }, [queryParamTags]);\n\n useEffect(() => {\n updateFilters({\n tags: selectedTags.length ? new EntityTagFilter(selectedTags) : undefined,\n });\n }, [selectedTags, updateFilters]);\n\n const availableTags = useMemo(\n () =>\n [\n ...new Set(\n backendEntities\n .flatMap((e) => e.metadata.tags)\n .filter(Boolean) ,\n ),\n ].sort(),\n [backendEntities],\n );\n\n if (!availableTags.length) return null;\n\n return (\n React.createElement(Box, { pb: 1, pt: 1,}\n , React.createElement(Typography, { variant: \"button\",}, \"Tags\")\n , React.createElement(Autocomplete, {\n multiple: true,\n 'aria-label': \"Tags\",\n options: availableTags,\n value: selectedTags,\n onChange: (_, value) => setSelectedTags(value),\n renderOption: (option, { selected }) => (\n React.createElement(FormControlLabel, {\n control: \n React.createElement(Checkbox, {\n icon: icon,\n checkedIcon: checkedIcon,\n checked: selected,}\n )\n ,\n label: option,}\n )\n ),\n size: \"small\",\n popupIcon: React.createElement(ExpandMoreIcon, { 'data-testid': \"tag-picker-expand\",} ),\n renderInput: params => (\n React.createElement(TextField, { ...params, className: classes.input, variant: \"outlined\",} )\n ),}\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect } from 'react';\nimport capitalize from 'lodash/capitalize';\nimport { Box } from '@material-ui/core';\nimport { useEntityTypeFilter } from '../../hooks/useEntityTypeFilter';\n\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport { Select } from '@backstage/core-components';\n\n/**\n * Props for {@link EntityTypePicker}.\n *\n * @public\n */\n\n\n\n\n\n/** @public */\nexport const EntityTypePicker = (props) => {\n const { hidden, initialFilter } = props;\n const alertApi = useApi(alertApiRef);\n const { error, availableTypes, selectedTypes, setSelectedTypes } =\n useEntityTypeFilter();\n\n useEffect(() => {\n if (error) {\n alertApi.post({\n message: `Failed to load entity types`,\n severity: 'error',\n });\n }\n if (initialFilter) {\n setSelectedTypes([initialFilter]);\n }\n }, [error, alertApi, initialFilter, setSelectedTypes]);\n\n if (availableTypes.length === 0 || error) return null;\n\n const items = [\n { value: 'all', label: 'All' },\n ...availableTypes.map((type) => ({\n value: type,\n label: capitalize(type),\n })),\n ];\n\n return hidden ? null : (\n React.createElement(Box, { pb: 1, pt: 1,}\n , React.createElement(Select, {\n label: \"Type\",\n items: items,\n selected: (items.length > 1 ? selectedTypes[0] : undefined) ?? 'all',\n onChange: value =>\n setSelectedTypes(value === 'all' ? [] : [String(value)])\n ,}\n )\n )\n );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { IconButton, Tooltip, withStyles } from '@material-ui/core';\nimport Star from '@material-ui/icons/Star';\nimport StarBorder from '@material-ui/icons/StarBorder';\nimport React, { } from 'react';\nimport { useStarredEntity } from '../../hooks/useStarredEntity';\n\n\n\nconst YellowStar = withStyles({\n root: {\n color: '#f3ba37',\n },\n})(Star);\n\nexport const favoriteEntityTooltip = (isStarred) =>\n isStarred ? 'Remove from favorites' : 'Add to favorites';\n\nexport const favoriteEntityIcon = (isStarred) =>\n isStarred ? React.createElement(YellowStar, null ) : React.createElement(StarBorder, null );\n\n/**\n * IconButton for showing if a current entity is starred and adding/removing it from the favorite entities\n * @param props - MaterialUI IconButton props extended by required `entity` prop\n */\nexport const FavoriteEntity = (props) => {\n const { toggleStarredEntity, isStarredEntity } = useStarredEntity(\n props.entity,\n );\n return (\n React.createElement(IconButton, {\n color: \"inherit\",\n ...props,\n onClick: () => toggleStarredEntity(),}\n \n , React.createElement(Tooltip, { title: favoriteEntityTooltip(isStarredEntity),}\n , favoriteEntityIcon(isStarredEntity)\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n\n getEntityName,\n ORIGIN_LOCATION_ANNOTATION,\n} from '@backstage/catalog-model';\nimport { catalogApiRef } from '../../api';\nimport { useCallback } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport { useApi } from '@backstage/core-plugin-api';\n\n/**\n * Each distinct state that the dialog can be in at any given time.\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Houses the main logic for unregistering entities and their locations.\n */\nexport function useUnregisterEntityDialogState(\n entity,\n) {\n const catalogApi = useApi(catalogApiRef);\n const locationRef = entity.metadata.annotations?.[ORIGIN_LOCATION_ANNOTATION];\n const uid = entity.metadata.uid;\n const isBootstrap = locationRef === 'bootstrap:bootstrap';\n\n // Load the prerequisite data: what entities that are colocated with us, and\n // what location that spawned us\n const prerequisites = useAsync(async () => {\n const locationPromise = catalogApi.getOriginLocationByEntity(entity);\n\n let colocatedEntitiesPromise;\n if (!locationRef) {\n colocatedEntitiesPromise = Promise.resolve([]);\n } else {\n const locationAnnotationFilter = `metadata.annotations.${ORIGIN_LOCATION_ANNOTATION}`;\n colocatedEntitiesPromise = catalogApi\n .getEntities({\n filter: { [locationAnnotationFilter]: locationRef },\n fields: [\n 'kind',\n 'metadata.uid',\n 'metadata.name',\n 'metadata.namespace',\n ],\n })\n .then(response => response.items);\n }\n\n return Promise.all([locationPromise, colocatedEntitiesPromise]).then(\n ([location, colocatedEntities]) => ({\n location,\n colocatedEntities,\n }),\n );\n }, [catalogApi, entity]);\n\n // Unregisters the underlying location and removes all of the entities that\n // are spawned from it. Can only ever be called when the prerequisites have\n // finished loading successfully, and if there was a matching location.\n const unregisterLocation = useCallback(\n async function unregisterLocationFn() {\n const { location, colocatedEntities } = prerequisites.value;\n await catalogApi.removeLocationById(location.id);\n await Promise.allSettled(\n colocatedEntities.map(e =>\n catalogApi.removeEntityByUid(e.metadata.uid),\n ),\n );\n },\n [catalogApi, prerequisites],\n );\n\n // Just removes the entity, without affecting locations in any way.\n const deleteEntity = useCallback(\n async function deleteEntityFn() {\n await catalogApi.removeEntityByUid(uid);\n },\n [catalogApi, uid],\n );\n\n // If this is a bootstrap location entity, don't even block on loading\n // prerequisites. We know that all that we will do is to offer to remove the\n // entity, and that doesn't require anything from the prerequisites.\n if (isBootstrap) {\n return { type: 'bootstrap', location: locationRef, deleteEntity };\n }\n\n // Return early if prerequisites still loading or failing\n const { loading, error, value } = prerequisites;\n if (loading) {\n return { type: 'loading' };\n } else if (error) {\n return { type: 'error', error };\n }\n\n const { location, colocatedEntities } = value;\n if (!location) {\n return { type: 'only-delete', deleteEntity };\n }\n return {\n type: 'unregister',\n location: locationRef,\n colocatedEntities: colocatedEntities.map(getEntityName),\n unregisterLocation,\n deleteEntity,\n };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { EntityRefLink } from '../EntityRefLink';\nimport {\n Box,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n Divider,\n makeStyles,\n} from '@material-ui/core';\nimport Alert from '@material-ui/lab/Alert';\nimport React, { useCallback, useState } from 'react';\nimport { useUnregisterEntityDialogState } from './useUnregisterEntityDialogState';\n\nimport { alertApiRef, configApiRef, useApi } from '@backstage/core-plugin-api';\nimport { Progress, ResponseErrorPanel } from '@backstage/core-components';\nimport { assertError } from '@backstage/errors';\n\nconst useStyles = makeStyles({\n advancedButton: {\n fontSize: '0.7em',\n },\n});\n\n\n\n\n\n\n\n\nconst Contents = ({\n entity,\n onConfirm,\n}\n\n\n) => {\n const alertApi = useApi(alertApiRef);\n const configApi = useApi(configApiRef);\n const classes = useStyles();\n const state = useUnregisterEntityDialogState(entity);\n const [showDelete, setShowDelete] = useState(false);\n const [busy, setBusy] = useState(false);\n const appTitle = configApi.getOptionalString('app.title') ?? 'Backstage';\n\n const onUnregister = useCallback(\n async function onUnregisterFn() {\n if ('unregisterLocation' in state) {\n setBusy(true);\n try {\n await state.unregisterLocation();\n onConfirm();\n } catch (err) {\n assertError(err);\n alertApi.post({ message: err.message });\n } finally {\n setBusy(false);\n }\n }\n },\n [alertApi, onConfirm, state],\n );\n\n const onDelete = useCallback(\n async function onDeleteFn() {\n if ('deleteEntity' in state) {\n setBusy(true);\n try {\n await state.deleteEntity();\n onConfirm();\n } catch (err) {\n assertError(err);\n alertApi.post({ message: err.message });\n } finally {\n setBusy(false);\n }\n }\n },\n [alertApi, onConfirm, state],\n );\n\n if (state.type === 'loading') {\n return React.createElement(Progress, null );\n }\n\n if (state.type === 'error') {\n return React.createElement(ResponseErrorPanel, { error: state.error,} );\n }\n\n if (state.type === 'bootstrap') {\n return (\n React.createElement(React.Fragment, null\n , React.createElement(Alert, { severity: \"info\",}, \"You cannot unregister this entity, since it originates from a protected Backstage configuration (location \\\"\"\n\n , state.location, \"\\\"). If you believe this is in error, please contact the \"\n , appTitle, ' ', \"integrator.\"\n\n )\n\n , React.createElement(Box, { marginTop: 2,}\n , !showDelete && (\n React.createElement(Button, {\n variant: \"text\",\n size: \"small\",\n color: \"primary\",\n className: classes.advancedButton,\n onClick: () => setShowDelete(true),}\n , \"Advanced Options\"\n\n )\n )\n\n , showDelete && (\n React.createElement(React.Fragment, null\n , React.createElement(DialogContentText, null, \"You have the option to delete the entity itself from the catalog. Note that this should only be done if you know that the catalog file has been deleted at, or moved from, its origin location. If that is not the case, the entity will reappear shortly as the next refresh round is performed by the catalog.\"\n\n\n\n\n\n )\n , React.createElement(Button, {\n variant: \"contained\",\n color: \"secondary\",\n disabled: busy,\n onClick: onDelete,}\n , \"Delete Entity\"\n\n )\n )\n )\n )\n )\n );\n }\n\n if (state.type === 'only-delete') {\n return (\n React.createElement(React.Fragment, null\n , React.createElement(DialogContentText, null, \"This entity does not seem to originate from a registered location. You therefore only have the option to delete it outright from the catalog.\"\n\n\n )\n , React.createElement(Button, {\n variant: \"contained\",\n color: \"secondary\",\n disabled: busy,\n onClick: onDelete,}\n , \"Delete Entity\"\n\n )\n )\n );\n }\n\n if (state.type === 'unregister') {\n return (\n React.createElement(React.Fragment, null\n , React.createElement(DialogContentText, null, \"This action will unregister the following entities:\"\n\n )\n , React.createElement(DialogContentText, { component: \"ul\",}\n , state.colocatedEntities.map(e => (\n React.createElement('li', { key: `${e.kind}:${e.namespace}/${e.name}`,}\n , React.createElement(EntityRefLink, { entityRef: e,} )\n )\n ))\n )\n , React.createElement(DialogContentText, null, \"Located at the following location:\"\n\n )\n , React.createElement(DialogContentText, { component: \"ul\",}\n , React.createElement('li', null, state.location)\n )\n , React.createElement(DialogContentText, null, \"To undo, just re-register the entity in \"\n , appTitle, \".\"\n )\n , React.createElement(Box, { marginTop: 2,}\n , React.createElement(Button, {\n variant: \"contained\",\n color: \"secondary\",\n disabled: busy,\n onClick: onUnregister,}\n , \"Unregister Location\"\n\n )\n , !showDelete && (\n React.createElement(Box, { component: \"span\", marginLeft: 2,}\n , React.createElement(Button, {\n variant: \"text\",\n size: \"small\",\n color: \"primary\",\n className: classes.advancedButton,\n onClick: () => setShowDelete(true),}\n , \"Advanced Options\"\n\n )\n )\n )\n )\n\n , showDelete && (\n React.createElement(React.Fragment, null\n , React.createElement(Box, { paddingTop: 4, paddingBottom: 4,}\n , React.createElement(Divider, null )\n )\n , React.createElement(DialogContentText, null, \"You also have the option to delete the entity itself from the catalog. Note that this should only be done if you know that the catalog file has been deleted at, or moved from, its origin location. If that is not the case, the entity will reappear shortly as the next refresh round is performed by the catalog.\"\n\n\n\n\n\n )\n , React.createElement(Button, {\n variant: \"contained\",\n color: \"secondary\",\n disabled: busy,\n onClick: onDelete,}\n , \"Delete Entity\"\n\n )\n )\n )\n )\n );\n }\n\n return React.createElement(Alert, { severity: \"error\",}, \"Internal error: Unknown state\" );\n};\n\nexport const UnregisterEntityDialog = ({\n open,\n onConfirm,\n onClose,\n entity,\n}) => (\n React.createElement(Dialog, { open: open, onClose: onClose,}\n , React.createElement(DialogTitle, { id: \"responsive-dialog-title\",}, \"Are you sure you want to unregister this entity?\"\n\n )\n , React.createElement(DialogContent, null\n , React.createElement(Contents, { entity: entity, onConfirm: onConfirm,} )\n )\n , React.createElement(DialogActions, null\n , React.createElement(Button, { onClick: onClose, color: \"primary\",}, \"Cancel\"\n\n )\n )\n )\n);\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n configApiRef,\n\n useApi,\n} from '@backstage/core-plugin-api';\nimport {\n Card,\n List,\n ListItemIcon,\n ListItemSecondaryAction,\n ListItemText,\n makeStyles,\n MenuItem,\n\n Typography,\n} from '@material-ui/core';\nimport SettingsIcon from '@material-ui/icons/Settings';\nimport StarIcon from '@material-ui/icons/Star';\nimport { compact } from 'lodash';\nimport React, { Fragment, useEffect, useMemo, useState } from 'react';\nimport { UserListFilter } from '../../filters';\nimport {\n useEntityListProvider,\n useStarredEntities,\n useEntityOwnership,\n} from '../../hooks';\n\nimport { reduceEntityFilters } from '../../utils';\n\n/** @public */\n\n\n\n\n\n\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n backgroundColor: 'rgba(0, 0, 0, .11)',\n boxShadow: 'none',\n margin: theme.spacing(1, 0, 1, 0),\n },\n title: {\n margin: theme.spacing(1, 0, 0, 1),\n textTransform: 'uppercase',\n fontSize: 12,\n fontWeight: 'bold',\n },\n listIcon: {\n minWidth: 30,\n color: theme.palette.text.primary,\n },\n menuItem: {\n minHeight: theme.spacing(6),\n },\n groupWrapper: {\n margin: theme.spacing(1, 1, 2, 1),\n },\n }),\n {\n name: 'CatalogReactUserListPicker',\n },\n);\n\n\n\n\n\n\n\n\n\n\nfunction getFilterGroups(orgName) {\n return [\n {\n name: 'Personal',\n items: [\n {\n id: 'owned',\n label: 'Owned',\n icon: SettingsIcon,\n },\n {\n id: 'starred',\n label: 'Starred',\n icon: StarIcon,\n },\n ],\n },\n {\n name: orgName ?? 'Company',\n items: [\n {\n id: 'all',\n label: 'All',\n },\n ],\n },\n ];\n}\n\n\n\n\n\n\nexport const UserListPicker = ({\n initialFilter,\n availableFilters,\n}) => {\n const classes = useStyles();\n const configApi = useApi(configApiRef);\n const orgName = configApi.getOptionalString('organization.name') ?? 'Company';\n const { filters, updateFilters, backendEntities, queryParameters, loading } =\n useEntityListProvider();\n\n // Remove group items that aren't in availableFilters and exclude\n // any now-empty groups.\n const userAndGroupFilterIds = ['starred', 'all'];\n const filterGroups = getFilterGroups(orgName)\n .map(filterGroup => ({\n ...filterGroup,\n items: filterGroup.items.filter(({ id }) =>\n // TODO: avoid hardcoding kinds here\n ['group', 'user'].some(kind => kind === queryParameters.kind)\n ? userAndGroupFilterIds.includes(id)\n : !availableFilters || availableFilters.includes(id),\n ),\n }))\n .filter(({ items }) => !!items.length);\n\n const { isStarredEntity } = useStarredEntities();\n const { isOwnedEntity } = useEntityOwnership();\n\n // Static filters; used for generating counts of potentially unselected kinds\n const ownedFilter = useMemo(\n () => new UserListFilter('owned', isOwnedEntity, isStarredEntity),\n [isOwnedEntity, isStarredEntity],\n );\n const starredFilter = useMemo(\n () => new UserListFilter('starred', isOwnedEntity, isStarredEntity),\n [isOwnedEntity, isStarredEntity],\n );\n\n const queryParamUserFilter = useMemo(\n () => [queryParameters.user].flat()[0],\n [queryParameters],\n );\n\n const [selectedUserFilter, setSelectedUserFilter] = useState(\n queryParamUserFilter ?? initialFilter,\n );\n\n // To show proper counts for each section, apply all other frontend filters _except_ the user\n // filter that's controlled by this picker.\n const entitiesWithoutUserFilter = useMemo(\n () =>\n backendEntities.filter(\n reduceEntityFilters(\n compact(Object.values({ ...filters, user: undefined })),\n ),\n ),\n [filters, backendEntities],\n );\n\n const filterCounts = useMemo(\n () => ({\n all: entitiesWithoutUserFilter.length,\n starred: entitiesWithoutUserFilter.filter(entity =>\n starredFilter.filterEntity(entity),\n ).length,\n owned: entitiesWithoutUserFilter.filter(entity =>\n ownedFilter.filterEntity(entity),\n ).length,\n }),\n [entitiesWithoutUserFilter, starredFilter, ownedFilter],\n );\n\n // Set selected user filter on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (queryParamUserFilter) {\n setSelectedUserFilter(queryParamUserFilter );\n }\n }, [queryParamUserFilter]);\n\n useEffect(() => {\n if (\n !loading &&\n !!selectedUserFilter &&\n selectedUserFilter !== 'all' &&\n filterCounts[selectedUserFilter] === 0\n ) {\n setSelectedUserFilter('all');\n }\n }, [loading, filterCounts, selectedUserFilter, setSelectedUserFilter]);\n\n useEffect(() => {\n updateFilters({\n user: selectedUserFilter\n ? new UserListFilter(\n selectedUserFilter ,\n isOwnedEntity,\n isStarredEntity,\n )\n : undefined,\n });\n }, [selectedUserFilter, isOwnedEntity, isStarredEntity, updateFilters]);\n\n return (\n React.createElement(Card, { className: classes.root,}\n , filterGroups.map(group => (\n React.createElement(Fragment, { key: group.name,}\n , React.createElement(Typography, { variant: \"subtitle2\", className: classes.title,}\n , group.name\n )\n , React.createElement(Card, { className: classes.groupWrapper,}\n , React.createElement(List, { disablePadding: true, dense: true,}\n , group.items.map(item => (\n React.createElement(MenuItem, {\n key: item.id,\n button: true,\n divider: true,\n onClick: () => setSelectedUserFilter(item.id),\n selected: item.id === filters.user?.value,\n className: classes.menuItem,\n disabled: filterCounts[item.id] === 0,\n 'data-testid': `user-picker-${item.id}`,}\n \n , item.icon && (\n React.createElement(ListItemIcon, { className: classes.listIcon,}\n , React.createElement(item.icon, { fontSize: \"small\",} )\n )\n )\n , React.createElement(ListItemText, null\n , React.createElement(Typography, { variant: \"body1\",}, item.label)\n )\n , React.createElement(ListItemSecondaryAction, null\n , filterCounts[item.id] ?? '-'\n )\n )\n ))\n )\n )\n )\n ))\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, {\n\n useCallback,\n useMemo,\n useState,\n} from 'react';\nimport {\n\n EntityListContext,\n\n} from '../hooks/useEntityListProvider';\n\nexport const MockEntityListContextProvider = ({\n children,\n value,\n}\n\n) => {\n // Provides a default implementation that stores filter state, for testing components that\n // reflect filter state.\n const [filters, setFilters] = useState(\n value?.filters ?? {},\n );\n\n const updateFilters = useCallback(\n (\n update\n\n\n\n,\n ) => {\n setFilters(prevFilters => {\n const newFilters =\n typeof update === 'function' ? update(prevFilters) : update;\n return { ...prevFilters, ...newFilters };\n });\n },\n [],\n );\n\n // Memoize the default values since pickers have useEffect triggers on these; naively defaulting\n // below with `?? <X>` breaks referential equality on subsequent updates.\n const defaultValues = useMemo(\n () => ({\n entities: [],\n backendEntities: [],\n queryParameters: {},\n }),\n [],\n );\n\n const resolvedValue = useMemo(\n () => ({\n entities: value?.entities ?? defaultValues.entities,\n backendEntities: value?.backendEntities ?? defaultValues.backendEntities,\n updateFilters: value?.updateFilters ?? updateFilters,\n filters,\n loading: value?.loading ?? false,\n queryParameters: value?.queryParameters ?? defaultValues.queryParameters,\n error: value?.error,\n }),\n [value, defaultValues, filters, updateFilters],\n );\n\n return (\n React.createElement(EntityListContext.Provider, { value: resolvedValue,}\n , children\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useElementFilter } from '@backstage/core-plugin-api';\nimport { Grid, makeStyles, Typography } from '@material-ui/core';\nimport React from 'react';\n\nconst useStyles = makeStyles(theme => ({\n value: {\n fontWeight: 'bold',\n overflow: 'hidden',\n lineHeight: '24px',\n wordBreak: 'break-word',\n },\n label: {\n color: theme.palette.text.secondary,\n textTransform: 'uppercase',\n fontSize: '10px',\n fontWeight: 'bold',\n letterSpacing: 0.5,\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n },\n}));\n\n\n\n\n\n\n\n\nexport const AboutField = ({ label, value, gridSizes, children }) => {\n const classes = useStyles();\n\n const childElements = useElementFilter(children, c => c.getElements());\n\n // Content is either children or a string prop `value`\n const content =\n childElements.length > 0 ? (\n childElements\n ) : (\n React.createElement(Typography, { variant: \"body2\", className: classes.value,}\n , value || `unknown`\n )\n );\n return (\n React.createElement(Grid, { item: true, ...gridSizes,}\n , React.createElement(Typography, { variant: \"subtitle2\", className: classes.label,}\n , label\n )\n , content\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n RELATION_OWNED_BY,\n RELATION_PART_OF,\n} from '@backstage/catalog-model';\nimport {\n EntityRefLinks,\n getEntityRelations,\n} from '@backstage/plugin-catalog-react';\nimport { Chip, Grid, makeStyles, Typography } from '@material-ui/core';\nimport React from 'react';\nimport { AboutField } from './AboutField';\n\nconst useStyles = makeStyles({\n description: {\n wordBreak: 'break-word',\n },\n});\n\n\n\n\n\nexport const AboutContent = ({ entity }) => {\n const classes = useStyles();\n const isSystem = entity.kind.toLocaleLowerCase('en-US') === 'system';\n const isResource = entity.kind.toLocaleLowerCase('en-US') === 'resource';\n const isComponent = entity.kind.toLocaleLowerCase('en-US') === 'component';\n const isAPI = entity.kind.toLocaleLowerCase('en-US') === 'api';\n const isTemplate = entity.kind.toLocaleLowerCase('en-US') === 'template';\n const isLocation = entity.kind.toLocaleLowerCase('en-US') === 'location';\n const isGroup = entity.kind.toLocaleLowerCase('en-US') === 'group';\n\n const partOfSystemRelations = getEntityRelations(entity, RELATION_PART_OF, {\n kind: 'system',\n });\n const partOfComponentRelations = getEntityRelations(\n entity,\n RELATION_PART_OF,\n {\n kind: 'component',\n },\n );\n const partOfDomainRelations = getEntityRelations(entity, RELATION_PART_OF, {\n kind: 'domain',\n });\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n\n return (\n React.createElement(Grid, { container: true,}\n , React.createElement(AboutField, { label: \"Description\", gridSizes: { xs: 12 },}\n , React.createElement(Typography, { variant: \"body2\", paragraph: true, className: classes.description,}\n , entity?.metadata?.description || 'No description'\n )\n )\n , React.createElement(AboutField, {\n label: \"Owner\",\n value: \"No Owner\" ,\n gridSizes: { xs: 12, sm: 6, lg: 4 },}\n \n , ownedByRelations.length > 0 && (\n React.createElement(EntityRefLinks, { entityRefs: ownedByRelations, defaultKind: \"group\",} )\n )\n )\n , (isSystem || partOfDomainRelations.length > 0) && (\n React.createElement(AboutField, {\n label: \"Domain\",\n value: \"No Domain\" ,\n gridSizes: { xs: 12, sm: 6, lg: 4 },}\n \n , partOfDomainRelations.length > 0 && (\n React.createElement(EntityRefLinks, {\n entityRefs: partOfDomainRelations,\n defaultKind: \"domain\",}\n )\n )\n )\n )\n , (isAPI ||\n isComponent ||\n isResource ||\n partOfSystemRelations.length > 0) && (\n React.createElement(AboutField, {\n label: \"System\",\n value: \"No System\" ,\n gridSizes: { xs: 12, sm: 6, lg: 4 },}\n \n , partOfSystemRelations.length > 0 && (\n React.createElement(EntityRefLinks, {\n entityRefs: partOfSystemRelations,\n defaultKind: \"system\",}\n )\n )\n )\n )\n , isComponent && partOfComponentRelations.length > 0 && (\n React.createElement(AboutField, {\n label: \"Parent Component\" ,\n value: \"No Parent Component\" ,\n gridSizes: { xs: 12, sm: 6, lg: 4 },}\n \n , React.createElement(EntityRefLinks, {\n entityRefs: partOfComponentRelations,\n defaultKind: \"component\",}\n )\n )\n )\n , (isAPI ||\n isComponent ||\n isResource ||\n isTemplate ||\n isGroup ||\n isLocation ||\n typeof entity?.spec?.type === 'string') && (\n React.createElement(AboutField, {\n label: \"Type\",\n value: entity?.spec?.type ,\n gridSizes: { xs: 12, sm: 6, lg: 4 },}\n )\n )\n , (isAPI ||\n isComponent ||\n typeof entity?.spec?.lifecycle === 'string') && (\n React.createElement(AboutField, {\n label: \"Lifecycle\",\n value: entity?.spec?.lifecycle ,\n gridSizes: { xs: 12, sm: 6, lg: 4 },}\n )\n )\n , React.createElement(AboutField, {\n label: \"Tags\",\n value: \"No Tags\" ,\n gridSizes: { xs: 12, sm: 6, lg: 4 },}\n \n , (entity?.metadata?.tags || []).map(t => (\n React.createElement(Chip, { key: t, size: \"small\", label: t,} )\n ))\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\n ENTITY_DEFAULT_NAMESPACE,\n LOCATION_ANNOTATION,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport {\n HeaderIconLinkRow,\n\n\n Link,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport {\n ScmIntegrationIcon,\n scmIntegrationsApiRef,\n} from '@backstage/integration-react';\nimport {\n catalogApiRef,\n getEntityMetadataEditUrl,\n getEntitySourceLocation,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport {\n Card,\n CardContent,\n CardHeader,\n Divider,\n IconButton,\n makeStyles,\n} from '@material-ui/core';\nimport CachedIcon from '@material-ui/icons/Cached';\nimport DocsIcon from '@material-ui/icons/Description';\nimport EditIcon from '@material-ui/icons/Edit';\nimport React, { useCallback } from 'react';\nimport { viewTechDocRouteRef } from '../../routes';\nimport { AboutContent } from './AboutContent';\n\nconst useStyles = makeStyles({\n gridItemCard: {\n display: 'flex',\n flexDirection: 'column',\n height: 'calc(100% - 10px)', // for pages without content header\n marginBottom: '10px',\n },\n fullHeightCard: {\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n },\n gridItemCardContent: {\n flex: 1,\n },\n fullHeightCardContent: {\n flex: 1,\n },\n});\n\n\n\n\n\n\n\nexport function AboutCard({ variant }) {\n const classes = useStyles();\n const { entity } = useEntity();\n const scmIntegrationsApi = useApi(scmIntegrationsApiRef);\n const catalogApi = useApi(catalogApiRef);\n const alertApi = useApi(alertApiRef);\n const viewTechdocLink = useRouteRef(viewTechDocRouteRef);\n\n const entitySourceLocation = getEntitySourceLocation(\n entity,\n scmIntegrationsApi,\n );\n const entityMetadataEditUrl = getEntityMetadataEditUrl(entity);\n\n const viewInSource = {\n label: 'View Source',\n disabled: !entitySourceLocation,\n icon: React.createElement(ScmIntegrationIcon, { type: entitySourceLocation?.integrationType,} ),\n href: entitySourceLocation?.locationTargetUrl,\n };\n const viewInTechDocs = {\n label: 'View TechDocs',\n disabled:\n !entity.metadata.annotations?.['backstage.io/techdocs-ref'] ||\n !viewTechdocLink,\n icon: React.createElement(DocsIcon, null ),\n href:\n viewTechdocLink &&\n viewTechdocLink({\n namespace: entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE,\n kind: entity.kind,\n name: entity.metadata.name,\n }),\n };\n\n let cardClass = '';\n if (variant === 'gridItem') {\n cardClass = classes.gridItemCard;\n } else if (variant === 'fullHeight') {\n cardClass = classes.fullHeightCard;\n }\n\n let cardContentClass = '';\n if (variant === 'gridItem') {\n cardContentClass = classes.gridItemCardContent;\n } else if (variant === 'fullHeight') {\n cardContentClass = classes.fullHeightCardContent;\n }\n\n const entityLocation = entity.metadata.annotations?.[LOCATION_ANNOTATION];\n // Limiting the ability to manually refresh to the less expensive locations\n const allowRefresh =\n entityLocation?.startsWith('url:') || entityLocation?.startsWith('file:');\n const refreshEntity = useCallback(async () => {\n await catalogApi.refreshEntity(stringifyEntityRef(entity));\n alertApi.post({ message: 'Refresh scheduled', severity: 'info' });\n }, [catalogApi, alertApi, entity]);\n\n return (\n React.createElement(Card, { className: cardClass,}\n , React.createElement(CardHeader, {\n title: \"About\",\n action: \n React.createElement(React.Fragment, null\n , allowRefresh && (\n React.createElement(IconButton, {\n 'aria-label': \"Refresh\",\n title: \"Schedule entity refresh\" ,\n onClick: refreshEntity,}\n \n , React.createElement(CachedIcon, null )\n )\n )\n , React.createElement(IconButton, {\n component: Link,\n 'aria-label': \"Edit\",\n disabled: !entityMetadataEditUrl,\n title: \"Edit Metadata\" ,\n to: entityMetadataEditUrl ?? '#',}\n \n , React.createElement(EditIcon, null )\n )\n )\n ,\n subheader: React.createElement(HeaderIconLinkRow, { links: [viewInSource, viewInTechDocs],} ),}\n )\n , React.createElement(Divider, null )\n , React.createElement(CardContent, { className: cardContentClass,}\n , React.createElement(AboutContent, { entity: entity,} )\n )\n )\n );\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect, useState } from 'react';\nimport {\n capitalize,\n createStyles,\n InputBase,\n makeStyles,\n MenuItem,\n Select,\n\n} from '@material-ui/core';\nimport {\n EntityKindFilter,\n useEntityKinds,\n useEntityListProvider,\n} from '@backstage/plugin-catalog-react';\n\nconst useStyles = makeStyles((theme) =>\n createStyles({\n root: {\n ...theme.typography.h4,\n },\n }),\n);\n\n\n\n\n\nexport const CatalogKindHeader = ({\n initialFilter = 'component',\n}) => {\n const classes = useStyles();\n const { kinds: allKinds = [] } = useEntityKinds();\n const { updateFilters, queryParameters } = useEntityListProvider();\n\n const [selectedKind, setSelectedKind] = useState(\n ([queryParameters.kind].flat()[0] ?? initialFilter).toLocaleLowerCase(\n 'en-US',\n ),\n );\n\n useEffect(() => {\n updateFilters({\n kind: selectedKind ? new EntityKindFilter(selectedKind) : undefined,\n });\n }, [selectedKind, updateFilters]);\n\n // Before allKinds is loaded, or when a kind is entered manually in the URL, selectedKind may not\n // be present in allKinds. It should still be shown in the dropdown, but may not have the nice\n // enforced casing from the catalog-backend. This makes a key/value record for the Select options,\n // including selectedKind if it's unknown - but allows the selectedKind to get clobbered by the\n // more proper catalog kind if it exists.\n const options = [capitalize(selectedKind)]\n .concat(allKinds)\n .sort()\n .reduce((acc, kind) => {\n acc[kind.toLocaleLowerCase('en-US')] = kind;\n return acc;\n }, {} );\n\n return (\n React.createElement(Select, {\n input: React.createElement(InputBase, { value: selectedKind,} ),\n value: selectedKind,\n onChange: e => setSelectedKind(e.target.value ),\n classes: classes,}\n \n , Object.keys(options).map(kind => (\n React.createElement(MenuItem, { value: kind, key: kind,}\n , `${options[kind]}s`\n )\n ))\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Content,\n ContentHeader,\n CreateButton,\n PageWithHeader,\n SupportButton,\n\n\n} from '@backstage/core-components';\nimport { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport {\n EntityLifecyclePicker,\n EntityListProvider,\n EntityOwnerPicker,\n EntityTagPicker,\n EntityTypePicker,\n\n UserListPicker,\n} from '@backstage/plugin-catalog-react';\nimport React from 'react';\nimport { createComponentRouteRef } from '../../routes';\nimport { CatalogTable } from '../CatalogTable';\n\nimport {\n FilteredEntityLayout,\n EntityListContainer,\n FilterContainer,\n} from '../FilteredEntityLayout';\nimport { CatalogKindHeader } from '../CatalogKindHeader';\n\n/**\n * DefaultCatalogPageProps\n * @public\n */\n\n\n\n\n\n\nexport const DefaultCatalogPage = ({\n columns,\n actions,\n initiallySelectedFilter = 'owned',\n}) => {\n const orgName =\n useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage';\n const createComponentLink = useRouteRef(createComponentRouteRef);\n\n return (\n React.createElement(PageWithHeader, { title: `${orgName} Catalog`, themeId: \"home\",}\n , React.createElement(EntityListProvider, null\n , React.createElement(Content, null\n , React.createElement(ContentHeader, { titleComponent: React.createElement(CatalogKindHeader, null ),}\n , React.createElement(CreateButton, {\n title: \"Create Component\" ,\n to: createComponentLink && createComponentLink(),}\n )\n , React.createElement(SupportButton, null, \"All your software catalog entities\" )\n )\n , React.createElement(FilteredEntityLayout, null\n , React.createElement(FilterContainer, null\n , React.createElement(EntityTypePicker, null )\n , React.createElement(UserListPicker, { initialFilter: initiallySelectedFilter,} )\n , React.createElement(EntityOwnerPicker, null )\n , React.createElement(EntityLifecyclePicker, null )\n , React.createElement(EntityTagPicker, null )\n )\n , React.createElement(EntityListContainer, null\n , React.createElement(CatalogTable, { columns: columns, actions: actions,} )\n )\n )\n )\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { useOutlet } from 'react-router';\nimport {\n DefaultCatalogPage,\n\n} from './DefaultCatalogPage';\n\nexport const CatalogPage = (props) => {\n const outlet = useOutlet();\n\n return outlet || React.createElement(DefaultCatalogPage, { ...props,} );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport {\n formatEntityRefTitle,\n EntityRefLink,\n EntityRefLinks,\n} from '@backstage/plugin-catalog-react';\nimport { Chip } from '@material-ui/core';\n\nimport { OverflowTooltip, } from '@backstage/core-components';\n\n\n\n\n\n\nexport function createNameColumn(\n props,\n) {\n function formatContent(entity) {\n return (\n entity.metadata?.title ||\n formatEntityRefTitle(entity, {\n defaultKind: props?.defaultKind,\n })\n );\n }\n\n return {\n title: 'Name',\n field: 'resolved.name',\n highlight: true,\n customSort({ entity: entity1 }, { entity: entity2 }) {\n // TODO: We could implement this more efficiently by comparing field by field.\n // This has similar issues as above.\n return formatContent(entity1).localeCompare(formatContent(entity2));\n },\n render: ({ entity }) => (\n React.createElement(EntityRefLink, {\n entityRef: entity,\n defaultKind: props?.defaultKind || 'Component',\n title: entity.metadata?.title,}\n )\n ),\n };\n}\n\nexport function createSystemColumn() {\n return {\n title: 'System',\n field: 'resolved.partOfSystemRelationTitle',\n render: ({ resolved }) => (\n React.createElement(EntityRefLinks, {\n entityRefs: resolved.partOfSystemRelations,\n defaultKind: \"system\",}\n )\n ),\n };\n}\n\nexport function createOwnerColumn() {\n return {\n title: 'Owner',\n field: 'resolved.ownedByRelationsTitle',\n render: ({ resolved }) => (\n React.createElement(EntityRefLinks, {\n entityRefs: resolved.ownedByRelations,\n defaultKind: \"group\",}\n )\n ),\n };\n}\n\nexport function createSpecTypeColumn() {\n return {\n title: 'Type',\n field: 'entity.spec.type',\n hidden: true,\n };\n}\n\nexport function createSpecLifecycleColumn() {\n return {\n title: 'Lifecycle',\n field: 'entity.spec.lifecycle',\n };\n}\n\nexport function createMetadataDescriptionColumn() {\n return {\n title: 'Description',\n field: 'entity.metadata.description',\n render: ({ entity }) => (\n React.createElement(OverflowTooltip, {\n text: entity.metadata.description,\n placement: \"bottom-start\",}\n )\n ),\n width: 'auto',\n };\n}\n\nexport function createTagsColumn() {\n return {\n title: 'Tags',\n field: 'entity.metadata.tags',\n cellStyle: {\n padding: '0px 16px 0px 20px',\n },\n render: ({ entity }) => (\n React.createElement(React.Fragment, null\n , entity.metadata.tags &&\n entity.metadata.tags.map(t => (\n React.createElement(Chip, {\n key: t,\n label: t,\n size: \"small\",\n variant: \"outlined\",\n style: { marginBottom: '0px' },}\n )\n ))\n )\n ),\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { RELATION_OWNED_BY, RELATION_PART_OF } from '@backstage/catalog-model';\nimport {\n favoriteEntityIcon,\n favoriteEntityTooltip,\n formatEntityRefTitle,\n getEntityMetadataEditUrl,\n getEntityMetadataViewUrl,\n getEntityRelations,\n useEntityListProvider,\n useStarredEntities,\n} from '@backstage/plugin-catalog-react';\nimport Edit from '@material-ui/icons/Edit';\nimport OpenInNew from '@material-ui/icons/OpenInNew';\nimport { capitalize } from 'lodash';\nimport React, { useMemo } from 'react';\nimport * as columnFactories from './columns';\n\nimport {\n CodeSnippet,\n Table,\n\n\n WarningPanel,\n} from '@backstage/core-components';\n\n\n\n\n\n\nexport const CatalogTable = ({ columns, actions }) => {\n const { isStarredEntity, toggleStarredEntity } = useStarredEntities();\n const { loading, error, entities, filters } = useEntityListProvider();\n\n const defaultColumns = useMemo(\n () => [\n columnFactories.createNameColumn({ defaultKind: filters.kind?.value }),\n columnFactories.createSystemColumn(),\n columnFactories.createOwnerColumn(),\n columnFactories.createSpecTypeColumn(),\n columnFactories.createSpecLifecycleColumn(),\n columnFactories.createMetadataDescriptionColumn(),\n columnFactories.createTagsColumn(),\n ],\n [filters.kind?.value],\n );\n\n const showTypeColumn = filters.type === undefined;\n // TODO(timbonicus): remove the title from the CatalogTable once using EntitySearchBar\n const titlePreamble = capitalize(filters.user?.value ?? 'all');\n\n if (error) {\n return (\n React.createElement('div', null\n , React.createElement(WarningPanel, {\n severity: \"error\",\n title: \"Could not fetch catalog entities.\" ,}\n \n , React.createElement(CodeSnippet, { language: \"text\", text: error.toString(),} )\n )\n )\n );\n }\n\n const defaultActions = [\n ({ entity }) => {\n const url = getEntityMetadataViewUrl(entity);\n return {\n icon: () => React.createElement(OpenInNew, { 'aria-label': \"View\", fontSize: \"small\",} ),\n tooltip: 'View',\n disabled: !url,\n onClick: () => {\n if (!url) return;\n window.open(url, '_blank');\n },\n };\n },\n ({ entity }) => {\n const url = getEntityMetadataEditUrl(entity);\n return {\n icon: () => React.createElement(Edit, { 'aria-label': \"Edit\", fontSize: \"small\",} ),\n tooltip: 'Edit',\n disabled: !url,\n onClick: () => {\n if (!url) return;\n window.open(url, '_blank');\n },\n };\n },\n ({ entity }) => {\n const isStarred = isStarredEntity(entity);\n return {\n cellStyle: { paddingLeft: '1em' },\n icon: () => favoriteEntityIcon(isStarred),\n tooltip: favoriteEntityTooltip(isStarred),\n onClick: () => toggleStarredEntity(entity),\n };\n },\n ];\n\n const rows = entities.map(entity => {\n const partOfSystemRelations = getEntityRelations(entity, RELATION_PART_OF, {\n kind: 'system',\n });\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n\n return {\n entity,\n resolved: {\n name: formatEntityRefTitle(entity, {\n defaultKind: 'Component',\n }),\n ownedByRelationsTitle: ownedByRelations\n .map(r => formatEntityRefTitle(r, { defaultKind: 'group' }))\n .join(', '),\n ownedByRelations,\n partOfSystemRelationTitle: partOfSystemRelations\n .map(r =>\n formatEntityRefTitle(r, {\n defaultKind: 'system',\n }),\n )\n .join(', '),\n partOfSystemRelations,\n },\n };\n });\n\n const typeColumn = (columns || defaultColumns).find(c => c.title === 'Type');\n if (typeColumn) {\n typeColumn.hidden = !showTypeColumn;\n }\n const showPagination = rows.length > 20;\n\n return (\n React.createElement(Table, {\n isLoading: loading,\n columns: columns || defaultColumns,\n options: {\n paging: showPagination,\n pageSize: 20,\n actionsColumnIndex: -1,\n loadingType: 'linear',\n showEmptyDataSourceMessage: !loading,\n padding: 'dense',\n pageSizeOptions: [20, 50, 100],\n },\n title: `${titlePreamble} (${entities.length})`,\n data: rows,\n actions: actions || defaultActions,}\n )\n );\n};\n\nCatalogTable.columns = columnFactories;\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Grid } from '@material-ui/core';\nimport React, { } from 'react';\n\nexport const FilteredEntityLayout = ({ children }) => (\n React.createElement(Grid, { container: true, style: { position: 'relative' },}\n , children\n )\n);\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport {\n Box,\n Button,\n Drawer,\n Grid,\n Typography,\n useMediaQuery,\n useTheme,\n} from '@material-ui/core';\nimport FilterListIcon from '@material-ui/icons/FilterList';\nimport React, { useState, } from 'react';\n\nexport const FilterContainer = ({ children }) => {\n const isMidSizeScreen = useMediaQuery(theme =>\n theme.breakpoints.down('md'),\n );\n const theme = useTheme();\n const [filterDrawerOpen, setFilterDrawerOpen] = useState(false);\n\n return isMidSizeScreen ? (\n React.createElement(React.Fragment, null\n , React.createElement(Button, {\n style: { marginTop: theme.spacing(1), marginLeft: theme.spacing(1) },\n onClick: () => setFilterDrawerOpen(true),\n startIcon: React.createElement(FilterListIcon, null ),}\n , \"Filters\"\n\n )\n , React.createElement(Drawer, {\n open: filterDrawerOpen,\n onClose: () => setFilterDrawerOpen(false),\n anchor: \"left\",\n disableAutoFocus: true,\n keepMounted: true,\n variant: \"temporary\",}\n \n , React.createElement(Box, { m: 2,}\n , React.createElement(Typography, {\n variant: \"h6\",\n component: \"h2\",\n style: { marginBottom: theme.spacing(1) },}\n , \"Filters\"\n\n )\n , children\n )\n )\n )\n ) : (\n React.createElement(Grid, { item: true, lg: 2,}\n , children\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Grid } from '@material-ui/core';\nimport React, { } from 'react';\n\nexport const EntityListContainer = ({ children }) => (\n React.createElement(Grid, { item: true, xs: 12, lg: 10,}\n , children\n )\n);\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createExternalRouteRef } from '@backstage/core-plugin-api';\n\nexport const createComponentRouteRef = createExternalRouteRef({\n id: 'create-component',\n optional: true,\n});\n\nexport const viewTechDocRouteRef = createExternalRouteRef({\n id: 'view-techdoc',\n optional: true,\n params: ['namespace', 'kind', 'name'],\n});\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { createApiRef } from '@backstage/core-plugin-api';\n\n/**\n * This API is used by various frontend utilities that allow developers to implement authorization wihtin their frontend\n * plugins. A plugin developer will likely not have to interact with this API or its implementations directly, but\n * rather with the aforementioned utility components/hooks.\n * @public\n */\n\n\n\n\n/**\n * A Backstage ApiRef for the Permission API. See https://backstage.io/docs/api/utility-apis for more information on\n * Backstage ApiRefs.\n * @public\n */\nexport const permissionApiRef = createApiRef({\n id: 'plugin.permission.api',\n});\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * A request with a UUID identifier, so that batched responses can be matched up with the original\n * requests.\n * @public\n */\n\n\n/**\n * The result of an authorization request.\n * @public\n */\nexport var AuthorizeResult; (function (AuthorizeResult) {\n /**\n * The authorization request is denied.\n */\n const DENY = 'DENY'; AuthorizeResult[\"DENY\"] = DENY;\n /**\n * The authorization request is allowed.\n */\n const ALLOW = 'ALLOW'; AuthorizeResult[\"ALLOW\"] = ALLOW;\n /**\n * The authorization request is allowed if the provided conditions are met.\n */\n const CONDITIONAL = 'CONDITIONAL'; AuthorizeResult[\"CONDITIONAL\"] = CONDITIONAL;\n})(AuthorizeResult || (AuthorizeResult = {}));\n\n/**\n * An individual authorization request for {@link PermissionClient#authorize}.\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { ResponseError } from '@backstage/errors';\nimport fetch from 'cross-fetch';\nimport * as uuid from 'uuid';\nimport { z } from 'zod';\nimport {\n AuthorizeResult,\n\n\n\n\n\n\n\n} from './types/api';\n\n\n\n\n\n\nconst permissionCriteriaSchema\n\n = z.lazy(() =>\n z\n .object({\n rule: z.string(),\n params: z.array(z.unknown()),\n })\n .or(z.object({ anyOf: z.array(permissionCriteriaSchema) }))\n .or(z.object({ allOf: z.array(permissionCriteriaSchema) }))\n .or(z.object({ not: permissionCriteriaSchema })),\n);\n\nconst responseSchema = z.object({\n items: z.array(\n z\n .object({\n id: z.string(),\n result: z\n .literal(AuthorizeResult.ALLOW)\n .or(z.literal(AuthorizeResult.DENY)),\n })\n .or(\n z.object({\n id: z.string(),\n result: z.literal(AuthorizeResult.CONDITIONAL),\n conditions: permissionCriteriaSchema,\n }),\n ),\n ),\n});\n\n/**\n * An isomorphic client for requesting authorization for Backstage permissions.\n * @public\n */\nexport class PermissionClient {\n enabled;\n discovery;\n\n constructor(options) {\n this.discovery = options.discovery;\n this.enabled =\n options.config.getOptionalBoolean('permission.enabled') ?? false;\n }\n\n /**\n * Request authorization from the permission-backend for the given set of permissions.\n *\n * Authorization requests check that a given Backstage user can perform a protected operation,\n * potentially for a specific resource (such as a catalog entity). The Backstage identity token\n * should be included in the `options` if available.\n *\n * Permissions can be imported from plugins exposing them, such as `catalogEntityReadPermission`.\n *\n * The response will be either ALLOW or DENY when either the permission has no resourceType, or a\n * resourceRef is provided in the request. For permissions with a resourceType, CONDITIONAL may be\n * returned if no resourceRef is provided in the request. Conditional responses are intended only\n * for backends which have access to the data source for permissioned resources, so that filters\n * can be applied when loading collections of resources.\n * @public\n */\n async authorize(\n queries,\n options,\n ) {\n // TODO(permissions): it would be great to provide some kind of typing guarantee that\n // conditional responses will only ever be returned for requests containing a resourceType\n // but no resourceRef. That way clients who aren't prepared to handle filtering according\n // to conditions can be guaranteed that they won't unexpectedly get a CONDITIONAL response.\n\n if (!this.enabled) {\n return queries.map(_ => ({ result: AuthorizeResult.ALLOW }));\n }\n\n const request = {\n items: queries.map(query => ({\n id: uuid.v4(),\n ...query,\n })),\n };\n\n const permissionApi = await this.discovery.getBaseUrl('permission');\n const response = await fetch(`${permissionApi}/authorize`, {\n method: 'POST',\n body: JSON.stringify(request),\n headers: {\n ...this.getAuthorizationHeader(options?.token),\n 'content-type': 'application/json',\n },\n });\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n const responseBody = await response.json();\n this.assertValidResponse(request, responseBody);\n\n const responsesById = responseBody.items.reduce((acc, r) => {\n acc[r.id] = r;\n return acc;\n }, {} );\n\n return request.items.map(query => responsesById[query.id]);\n }\n\n getAuthorizationHeader(token) {\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n\n assertValidResponse(\n request,\n json,\n ) {\n const authorizedResponses = responseSchema.parse(json);\n const responseIds = authorizedResponses.items.map(r => r.id);\n const hasAllRequestIds = request.items.every(r =>\n responseIds.includes(r.id),\n );\n if (!hasAllRequestIds) {\n throw new Error(\n 'Unexpected authorization response from permission-backend',\n );\n }\n }\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport {\n\n\n PermissionClient,\n} from '@backstage/plugin-permission-common';\n\n\n/**\n * The default implementation of the PermissionApi, which simply calls the authorize method of the given\n * {@link @backstage/plugin-permission-common#PermissionClient}.\n * @public\n */\nexport class IdentityPermissionApi {\n constructor(\n permissionClient,\n identityApi,\n ) {;this.permissionClient = permissionClient;this.identityApi = identityApi;}\n\n static create(options\n\n\n\n) {\n const { config, discovery, identity } = options;\n const permissionClient = new PermissionClient({ discovery, config });\n return new IdentityPermissionApi(permissionClient, identity);\n }\n\n async authorize(request) {\n const response = await this.permissionClient.authorize(\n [request],\n await this.identityApi.getCredentials(),\n );\n return response[0];\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useApi } from '@backstage/core-plugin-api';\nimport { permissionApiRef } from '../apis';\nimport {\n AuthorizeResult,\n\n} from '@backstage/plugin-permission-common';\nimport useSWR from 'swr';\n\n/** @public */\n\n\n\n\n\n\n/**\n * React hook utility for authorization. Given a\n * {@link @backstage/plugin-permission-common#Permission} and an optional\n * resourceRef, it will return whether or not access is allowed (for the given\n * resource, if resourceRef is provided). See\n * {@link @backstage/plugin-permission-common/PermissionClient#authorize} for\n * more details.\n *\n * Note: This hook uses stale-while-revalidate to help avoid flicker in UI\n * elements that would be conditionally rendered based on the `allowed` result\n * of this hook.\n * @public\n */\nexport const usePermission = (\n permission,\n resourceRef,\n) => {\n const permissionApi = useApi(permissionApiRef);\n const { data, error } = useSWR({ permission, resourceRef }, async args => {\n const { result } = await permissionApi.authorize(args);\n return result;\n });\n\n if (error) {\n return { error, loading: false, allowed: false };\n }\n if (data === undefined) {\n return { loading: true, allowed: false };\n }\n return { loading: false, allowed: data === AuthorizeResult.ALLOW };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\nimport { Route } from 'react-router';\nimport { useApp } from '@backstage/core-plugin-api';\nimport { usePermission } from '../hooks';\n\n\n/**\n * Returns a React Router Route which only renders the element when authorized. If unauthorized, the Route will render a\n * NotFoundErrorPage (see {@link @backstage/core-app-api#AppComponents}).\n *\n * @public\n */\nexport const PermissionedRoute = (\n props\n\n\n\n,\n) => {\n const { permission, resourceRef, errorComponent, ...otherProps } = props;\n const permissionResult = usePermission(permission, resourceRef);\n const app = useApp();\n const { NotFoundErrorPage } = app.getComponents();\n\n let shownElement =\n errorComponent === undefined ? React.createElement(NotFoundErrorPage, null ) : errorComponent;\n\n if (permissionResult.loading) {\n shownElement = null;\n } else if (permissionResult.allowed) {\n shownElement = props.element;\n }\n\n return React.createElement(Route, { ...otherProps, element: shownElement,} );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createApiRef,\n\n\n} from '@backstage/core-plugin-api';\nimport { ResponseError } from '@backstage/errors';\n\nimport qs from 'qs';\n\nexport const searchApiRef = createApiRef({\n id: 'plugin.search.queryservice',\n});\n\n\n\n\n\nexport class SearchClient {\n discoveryApi;\n identityApi;\n\n constructor(options\n\n\n) {\n this.discoveryApi = options.discoveryApi;\n this.identityApi = options.identityApi;\n }\n\n async query(query) {\n const { token } = await this.identityApi.getCredentials();\n const queryString = qs.stringify(query);\n const url = `${await this.discoveryApi.getBaseUrl(\n 'search/query',\n )}?${queryString}`;\n const response = await fetch(url, {\n headers: token ? { Authorization: `Bearer ${token}` } : {},\n });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return response.json();\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\n\nimport {\n ListItem,\n ListItemIcon,\n ListItemText,\n Box,\n Divider,\n} from '@material-ui/core';\nimport { Link } from '@backstage/core-components';\nimport TextTruncate from 'react-text-truncate';\n\n\n\n\n\n\n\n\nexport const DefaultResultListItem = ({\n result,\n icon,\n secondaryAction,\n lineClamp = 5,\n}) => {\n return (\n React.createElement(Link, { to: result.location,}\n , React.createElement(ListItem, { alignItems: \"center\",}\n , icon && React.createElement(ListItemIcon, null, icon)\n , React.createElement(ListItemText, {\n primaryTypographyProps: { variant: 'h6' },\n primary: result.title,\n secondary: \n React.createElement(TextTruncate, {\n line: lineClamp,\n truncateText: \"…\",\n text: result.text,\n element: \"span\",}\n )\n ,}\n )\n , secondaryAction && React.createElement(Box, { alignItems: \"flex-end\",}, secondaryAction)\n )\n , React.createElement(Divider, null )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect } from 'react';\nimport { useAnalytics } from '@backstage/core-plugin-api';\nimport { useSearch } from '../SearchContext';\n\n/**\n * Capture search event on term change.\n */\nexport const TrackSearch = ({ children }) => {\n const analytics = useAnalytics();\n const { term } = useSearch();\n\n useEffect(() => {\n if (term) {\n // Capture analytics search event with search term provided as value\n analytics.captureEvent('search', term);\n }\n }, [analytics, term]);\n\n return React.createElement(React.Fragment, null, children);\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, {\n\n\n useState,\n useEffect,\n useCallback,\n useContext,\n} from 'react';\nimport useDebounce from 'react-use/lib/useDebounce';\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n InputBase,\n\n InputAdornment,\n IconButton,\n} from '@material-ui/core';\nimport SearchIcon from '@material-ui/icons/Search';\nimport ClearButton from '@material-ui/icons/Clear';\n\nimport {\n SearchContext,\n SearchContextProvider,\n useSearch,\n} from '../SearchContext';\nimport { TrackSearch } from '../SearchTracker';\n\n/**\n * Props for {@link SearchBarBase}.\n *\n * @public\n */\n\n\n\n\n\n\n\n\nconst useSearchContextCheck = () => {\n const context = useContext(SearchContext);\n return context !== undefined;\n};\n\n/**\n * All search boxes exported by the search plugin are based on the <SearchBarBase />,\n * and this one is based on the <InputBase /> component from Material UI.\n * Recommended if you don't use Search Provider or Search Context.\n *\n * @public\n */\nexport const SearchBarBase = ({\n onChange,\n onKeyDown,\n onSubmit,\n debounceTime = 200,\n clearButton = true,\n fullWidth = true,\n value: defaultValue,\n inputProps: defaultInputProps = {},\n endAdornment: defaultEndAdornment,\n ...props\n}) => {\n const configApi = useApi(configApiRef);\n const [value, setValue] = useState(defaultValue );\n const hasSearchContext = useSearchContextCheck();\n\n useEffect(() => {\n setValue(prevValue =>\n prevValue !== defaultValue ? (defaultValue ) : prevValue,\n );\n }, [defaultValue]);\n\n useDebounce(() => onChange(value), debounceTime, [value]);\n\n const handleChange = useCallback(\n (e) => {\n setValue(e.target.value);\n },\n [setValue],\n );\n\n const handleKeyDown = useCallback(\n (e) => {\n if (onKeyDown) onKeyDown(e);\n if (onSubmit && e.key === 'Enter') {\n onSubmit();\n }\n },\n [onKeyDown, onSubmit],\n );\n\n const handleClear = useCallback(() => {\n onChange('');\n }, [onChange]);\n\n const placeholder = `Search in ${\n configApi.getOptionalString('app.title') || 'Backstage'\n }`;\n\n const startAdornment = (\n React.createElement(InputAdornment, { position: \"start\",}\n , React.createElement(IconButton, { 'aria-label': \"Query\", disabled: true,}\n , React.createElement(SearchIcon, null )\n )\n )\n );\n\n const endAdornment = (\n React.createElement(InputAdornment, { position: \"end\",}\n , React.createElement(IconButton, { 'aria-label': \"Clear\", onClick: handleClear,}\n , React.createElement(ClearButton, null )\n )\n )\n );\n\n const searchBar = (\n React.createElement(TrackSearch, null\n , React.createElement(InputBase, {\n 'data-testid': \"search-bar-next\",\n value: value,\n placeholder: placeholder,\n startAdornment: startAdornment,\n endAdornment: clearButton ? endAdornment : defaultEndAdornment,\n inputProps: { 'aria-label': 'Search', ...defaultInputProps },\n fullWidth: fullWidth,\n onChange: handleChange,\n onKeyDown: handleKeyDown,\n ...props,}\n )\n )\n );\n\n return hasSearchContext ? (\n searchBar\n ) : (\n React.createElement(SearchContextProvider, null, searchBar)\n );\n};\n\n/**\n * Props for {@link SearchBar}.\n *\n * @public\n */\n\n\n/**\n * Recommended search bar when you use the Search Provider or Search Context.\n *\n * @public\n */\nexport const SearchBar = ({ onChange, ...props }) => {\n const { term, setTerm } = useSearch();\n\n const handleChange = (newValue) => {\n if (onChange) {\n onChange(newValue);\n } else {\n setTerm(newValue);\n }\n };\n\n return React.createElement(SearchBarBase, { value: term, onChange: handleChange, ...props,} );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { useApi, AnalyticsContext } from '@backstage/core-plugin-api';\n\nimport React, {\n createContext,\n\n useCallback,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport useAsync, { } from 'react-use/lib/useAsync';\nimport usePrevious from 'react-use/lib/usePrevious';\nimport { searchApiRef } from '../../apis';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const SearchContext = createContext(\n undefined,\n);\n\nexport const SearchContextProvider = ({\n initialState = {\n term: '',\n pageCursor: undefined,\n filters: {},\n types: [],\n },\n children,\n}) => {\n const searchApi = useApi(searchApiRef);\n const [pageCursor, setPageCursor] = useState(\n initialState.pageCursor,\n );\n const [filters, setFilters] = useState(initialState.filters);\n const [term, setTerm] = useState(initialState.term);\n const [types, setTypes] = useState(initialState.types);\n const [open, setOpen] = useState(false);\n const toggleModal = useCallback(\n () => setOpen(prevState => !prevState),\n [],\n );\n\n const prevTerm = usePrevious(term);\n\n const result = useAsync(\n () =>\n searchApi.query({\n term,\n filters,\n pageCursor: pageCursor,\n types,\n }),\n [term, filters, types, pageCursor],\n );\n\n const hasNextPage =\n !result.loading && !result.error && result.value?.nextPageCursor;\n const hasPreviousPage =\n !result.loading && !result.error && result.value?.previousPageCursor;\n const fetchNextPage = useCallback(() => {\n setPageCursor(result.value?.nextPageCursor);\n }, [result.value?.nextPageCursor]);\n const fetchPreviousPage = useCallback(() => {\n setPageCursor(result.value?.previousPageCursor);\n }, [result.value?.previousPageCursor]);\n\n useEffect(() => {\n // Any time a term is reset, we want to start from page 0.\n if (term && prevTerm && term !== prevTerm) {\n setPageCursor(undefined);\n }\n }, [term, prevTerm, initialState.pageCursor]);\n\n const value = {\n result,\n filters,\n setFilters,\n open,\n toggleModal,\n term,\n setTerm,\n types,\n setTypes,\n pageCursor,\n setPageCursor,\n fetchNextPage: hasNextPage ? fetchNextPage : undefined,\n fetchPreviousPage: hasPreviousPage ? fetchPreviousPage : undefined,\n };\n\n return (\n React.createElement(AnalyticsContext, { attributes: { searchTypes: types.sort().join(',') },}\n , React.createElement(SearchContext.Provider, { value: value, children: children,} )\n )\n );\n};\n\nexport const useSearch = () => {\n const context = useContext(SearchContext);\n if (context === undefined) {\n throw new Error('useSearch must be used within a SearchContextProvider');\n }\n return context;\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport {\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Divider,\n Grid,\n List,\n Paper,\n useTheme,\n} from '@material-ui/core';\nimport LaunchIcon from '@material-ui/icons/Launch';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { SearchBar } from '../SearchBar';\nimport { DefaultResultListItem } from '../DefaultResultListItem';\nimport { SearchResult } from '../SearchResult';\nimport { SearchContextProvider, useSearch } from '../SearchContext';\nimport { SearchResultPager } from '../SearchResultPager';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport { Link, useContent } from '@backstage/core-components';\nimport { rootRouteRef } from '../../plugin';\n\n\n\n\n\n\nconst useStyles = makeStyles(theme => ({\n container: {\n borderRadius: 30,\n display: 'flex',\n height: '2.4em',\n },\n input: {\n flex: 1,\n },\n // Reduces default height of the modal, keeping a gap of 128px between the top and bottom of the page.\n paperFullWidth: { height: 'calc(100% - 128px)' },\n dialogActionsContainer: { padding: theme.spacing(1, 3) },\n viewResultsLink: { verticalAlign: '0.5em' },\n}));\n\nexport const Modal = ({ open = true, toggleModal }) => {\n const getSearchLink = useRouteRef(rootRouteRef);\n const classes = useStyles();\n\n const { term } = useSearch();\n const { focusContent } = useContent();\n const { transitions } = useTheme();\n\n const handleResultClick = () => {\n toggleModal();\n setTimeout(focusContent, transitions.duration.leavingScreen);\n };\n\n const handleKeyPress = () => {\n handleResultClick();\n };\n\n return (\n React.createElement(Dialog, {\n classes: {\n paperFullWidth: classes.paperFullWidth,\n },\n onClose: toggleModal,\n 'aria-labelledby': \"search-modal-title\",\n open: open,\n fullWidth: true,\n maxWidth: \"lg\",}\n \n , React.createElement(DialogTitle, null\n , React.createElement(Paper, { className: classes.container,}\n , React.createElement(SearchBar, { className: classes.input,} )\n )\n )\n , React.createElement(DialogContent, null\n , React.createElement(Grid, {\n container: true,\n direction: \"row-reverse\",\n justifyContent: \"flex-start\",\n alignItems: \"center\",}\n \n , React.createElement(Grid, { item: true,}\n , React.createElement(Link, {\n onClick: () => {\n toggleModal();\n setTimeout(focusContent, transitions.duration.leavingScreen);\n },\n to: `${getSearchLink()}?query=${term}`,}\n \n , React.createElement('span', { className: classes.viewResultsLink,}, \"View Full Results\" )\n , React.createElement(LaunchIcon, { color: \"primary\",} )\n )\n )\n )\n , React.createElement(Divider, null )\n , React.createElement(SearchResult, null\n , ({ results }) => (\n React.createElement(List, null\n , results.map(({ document }) => (\n React.createElement('div', {\n role: \"button\",\n tabIndex: 0,\n key: `${document.location}-btn`,\n onClick: handleResultClick,\n onKeyPress: handleKeyPress,}\n \n , React.createElement(DefaultResultListItem, {\n key: document.location,\n result: document,}\n )\n )\n ))\n )\n )\n )\n )\n , React.createElement(DialogActions, { className: classes.dialogActionsContainer,}\n , React.createElement(Grid, { container: true, direction: \"row\",}\n , React.createElement(Grid, { item: true, xs: 12,}\n , React.createElement(SearchResultPager, null )\n )\n )\n )\n )\n );\n};\n\nexport const SearchModal = ({ open = true, toggleModal }) => {\n return (\n React.createElement(SearchContextProvider, null\n , React.createElement(Modal, { open: open, toggleModal: toggleModal,} )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { Paper } from '@material-ui/core';\nimport InputBase from '@material-ui/core/InputBase';\nimport IconButton from '@material-ui/core/IconButton';\nimport SearchIcon from '@material-ui/icons/Search';\nimport ClearButton from '@material-ui/icons/Clear';\n\nconst useStyles = makeStyles(() => ({\n root: {\n display: 'flex',\n alignItems: 'center',\n },\n input: {\n flex: 1,\n },\n}));\n\n\n\n\n\n\n\nexport const SearchBar = ({\n searchQuery,\n handleSearch,\n handleClearSearchBar,\n}) => {\n const classes = useStyles();\n\n return (\n React.createElement(Paper, {\n component: \"form\",\n onSubmit: e => handleSearch(e),\n className: classes.root,}\n \n , React.createElement(IconButton, { disabled: true, type: \"submit\", 'aria-label': \"search\",}\n , React.createElement(SearchIcon, null )\n )\n , React.createElement(InputBase, {\n className: classes.input,\n placeholder: \"Search in Backstage\" ,\n value: searchQuery,\n onChange: e => handleSearch(e),\n inputProps: { 'aria-label': 'search backstage' },}\n )\n , React.createElement(IconButton, { 'aria-label': \"search\", onClick: () => handleClearSearchBar(),}\n , React.createElement(ClearButton, null )\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport FilterListIcon from '@material-ui/icons/FilterList';\nimport { makeStyles, IconButton, Typography } from '@material-ui/core';\n\nconst useStyles = makeStyles(theme => ({\n filters: {\n width: '250px',\n display: 'flex',\n },\n icon: {\n margin: theme.spacing(-1, 0, 0, 0),\n },\n}));\n\n\n\n\n\n\nexport const FiltersButton = ({\n numberOfSelectedFilters,\n handleToggleFilters,\n}) => {\n const classes = useStyles();\n\n return (\n React.createElement('div', { className: classes.filters,}\n , React.createElement(IconButton, {\n className: classes.icon,\n 'aria-label': \"settings\",\n onClick: handleToggleFilters,}\n \n , React.createElement(FilterListIcon, null )\n )\n , React.createElement(Typography, { variant: \"h6\",}, \"Filters (\"\n , numberOfSelectedFilters ? numberOfSelectedFilters : 0, \")\"\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport {\n makeStyles,\n Typography,\n Divider,\n Card,\n CardHeader,\n Button,\n CardContent,\n Select,\n Checkbox,\n List,\n ListItem,\n ListItemText,\n MenuItem,\n} from '@material-ui/core';\n\nconst useStyles = makeStyles(theme => ({\n filters: {\n background: 'transparent',\n boxShadow: '0px 0px 0px 0px',\n },\n checkbox: {\n padding: theme.spacing(0, 1, 0, 1),\n },\n dropdown: {\n width: '100%',\n },\n}));\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const Filters = ({\n filters,\n filterOptions,\n resetFilters,\n updateSelected,\n updateChecked,\n}) => {\n const classes = useStyles();\n\n return (\n React.createElement(Card, { className: classes.filters,}\n , React.createElement(CardHeader, {\n title: React.createElement(Typography, { variant: \"h6\",}, \"Filters\"),\n action: \n React.createElement(Button, { color: \"primary\", onClick: () => resetFilters(),}, \"CLEAR ALL\"\n\n )\n ,}\n )\n , React.createElement(Divider, null )\n , filterOptions.kind.length === 0 && filterOptions.lifecycle.length === 0 && (\n React.createElement(CardContent, null\n , React.createElement(Typography, { variant: \"subtitle2\",}, \"Filters cannot be applied to available results\"\n\n )\n )\n )\n , filterOptions.kind.length > 0 && (\n React.createElement(CardContent, null\n , React.createElement(Typography, { variant: \"subtitle2\",}, \"Kind\")\n , React.createElement(Select, {\n id: \"outlined-select\",\n onChange: (e) =>\n updateSelected(e?.target?.value)\n ,\n variant: \"outlined\",\n className: classes.dropdown,\n value: filters.selected,}\n \n , filterOptions.kind.map(filter => (\n React.createElement(MenuItem, {\n selected: filter === '',\n dense: true,\n key: filter,\n value: filter,}\n \n , filter\n )\n ))\n )\n )\n )\n , filterOptions.lifecycle.length > 0 && (\n React.createElement(CardContent, null\n , React.createElement(Typography, { variant: \"subtitle2\",}, \"Lifecycle\")\n , React.createElement(List, { disablePadding: true, dense: true,}\n , filterOptions.lifecycle.map(filter => (\n React.createElement(ListItem, {\n key: filter,\n dense: true,\n button: true,\n onClick: () => updateChecked(filter),}\n \n , React.createElement(Checkbox, {\n edge: \"start\",\n disableRipple: true,\n className: classes.checkbox,\n color: \"primary\",\n checked: filters.checked.includes(filter),\n tabIndex: -1,\n value: filter,\n name: filter,}\n )\n , React.createElement(ListItemText, { id: filter, primary: filter,} )\n )\n ))\n )\n )\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Divider, Grid, makeStyles, Typography } from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\nimport React, { useEffect, useState } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\n\nimport { Filters, FiltersButton, } from './Filters';\nimport { ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model';\n\nimport {\n EmptyState,\n Link,\n Progress,\n Table,\n\n} from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\n\n\n\n\n\n\n\n\n\n\n\nconst useStyles = makeStyles(theme => ({\n searchQuery: {\n color: theme.palette.text.primary,\n background: theme.palette.background.default,\n borderRadius: '10%',\n },\n tableHeader: {\n margin: theme.spacing(1, 0, 0, 0),\n display: 'flex',\n },\n divider: {\n width: '1px',\n margin: theme.spacing(0, 2),\n padding: theme.spacing(2, 0),\n },\n}));\n\n\n\n\n\n\n\n\n\n\n\n\n// TODO: move out column to make the search result component more generic\nconst columns = [\n {\n title: 'Name',\n field: 'name',\n highlight: true,\n render: (result) => (\n React.createElement(Link, { to: result.url || '',}, result.name)\n ),\n },\n {\n title: 'Description',\n field: 'description',\n },\n {\n title: 'Owner',\n field: 'owner',\n },\n {\n title: 'Kind',\n field: 'kind',\n },\n {\n title: 'LifeCycle',\n field: 'lifecycle',\n },\n];\n\nconst TableHeader = ({\n searchQuery,\n numberOfSelectedFilters,\n numberOfResults,\n handleToggleFilters,\n}) => {\n const classes = useStyles();\n\n return (\n React.createElement('div', { className: classes.tableHeader,}\n , React.createElement(FiltersButton, {\n numberOfSelectedFilters: numberOfSelectedFilters,\n handleToggleFilters: handleToggleFilters,}\n )\n , React.createElement(Divider, { className: classes.divider, orientation: \"vertical\",} )\n , React.createElement(Grid, { item: true, xs: 12,}\n , searchQuery ? (\n React.createElement(Typography, { variant: \"h6\",}\n , `${numberOfResults} `\n , numberOfResults > 1 ? `results for ` : `result for `\n , React.createElement('span', { className: classes.searchQuery,}, \"\\\"\", searchQuery, \"\\\"\"), ' '\n )\n ) : (\n React.createElement(Typography, { variant: \"h6\",}, `${numberOfResults} results`)\n )\n )\n )\n );\n};\n\nexport const SearchResult = ({ searchQuery }) => {\n const catalogApi = useApi(catalogApiRef);\n\n const [showFilters, toggleFilters] = useState(false);\n const [selectedFilters, setSelectedFilters] = useState({\n selected: '',\n checked: [],\n });\n\n const [filteredResults, setFilteredResults] = useState([]);\n\n const {\n loading,\n error,\n value: results,\n } = useAsync(async () => {\n const entities = await catalogApi.getEntities();\n return entities.items.map((entity) => ({\n name: entity.metadata.name,\n description: entity.metadata.description,\n owner:\n typeof entity.spec?.owner === 'string' ? entity.spec?.owner : undefined,\n kind: entity.kind,\n lifecycle:\n typeof entity.spec?.lifecycle === 'string'\n ? entity.spec?.lifecycle\n : undefined,\n url: `/catalog/${\n entity.metadata.namespace?.toLocaleLowerCase('en-US') ||\n ENTITY_DEFAULT_NAMESPACE\n }/${entity.kind.toLocaleLowerCase('en-US')}/${entity.metadata.name}`,\n }));\n }, []);\n\n useEffect(() => {\n if (results) {\n let withFilters = results;\n\n // apply filters\n\n // filter on selected\n if (selectedFilters.selected !== '') {\n withFilters = results.filter((result) =>\n selectedFilters.selected.includes(result.kind),\n );\n }\n\n // filter on checked\n if (selectedFilters.checked.length > 0) {\n withFilters = withFilters.filter(\n (result) =>\n result.lifecycle &&\n selectedFilters.checked.includes(result.lifecycle),\n );\n }\n\n // filter on searchQuery\n if (searchQuery) {\n withFilters = withFilters.filter(\n (result) =>\n result.name?.toLocaleLowerCase('en-US').includes(searchQuery) ||\n result.name\n ?.toLocaleLowerCase('en-US')\n .includes(searchQuery.split(' ').join('-')) ||\n result.description\n ?.toLocaleLowerCase('en-US')\n .includes(searchQuery),\n );\n }\n\n setFilteredResults(withFilters);\n }\n }, [selectedFilters, searchQuery, results]);\n if (loading) {\n return React.createElement(Progress, null );\n }\n if (error) {\n return (\n React.createElement(Alert, { severity: \"error\",}, \"Error encountered while fetching search results. \"\n , error.toString()\n )\n );\n }\n if (!results || results.length === 0) {\n return React.createElement(EmptyState, { missing: \"data\", title: \"Sorry, no results were found\" ,} );\n }\n\n const resetFilters = () => {\n setSelectedFilters({\n selected: '',\n checked: [],\n });\n };\n\n const updateSelected = (filter) => {\n setSelectedFilters(prevState => ({\n ...prevState,\n selected: filter,\n }));\n };\n\n const updateChecked = (filter) => {\n if (selectedFilters.checked.includes(filter)) {\n setSelectedFilters(prevState => ({\n ...prevState,\n checked: prevState.checked.filter(item => item !== filter),\n }));\n return;\n }\n\n setSelectedFilters(prevState => ({\n ...prevState,\n checked: [...prevState.checked, filter],\n }));\n };\n\n const filterOptions = results.reduce(\n (acc, curr) => {\n if (curr.kind && acc.kind.indexOf(curr.kind) < 0) {\n acc.kind.push(curr.kind);\n }\n if (curr.lifecycle && acc.lifecycle.indexOf(curr.lifecycle) < 0) {\n acc.lifecycle.push(curr.lifecycle);\n }\n return acc;\n },\n {\n kind: [] ,\n lifecycle: [] ,\n },\n );\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(Grid, { container: true,}\n , showFilters && (\n React.createElement(Grid, { item: true, xs: 3,}\n , React.createElement(Filters, {\n filters: selectedFilters,\n filterOptions: filterOptions,\n resetFilters: resetFilters,\n updateSelected: updateSelected,\n updateChecked: updateChecked,}\n )\n )\n )\n , React.createElement(Grid, { item: true, xs: showFilters ? 9 : 12,}\n , React.createElement(Table, {\n options: { paging: true, pageSize: 20, search: false },\n data: filteredResults,\n columns: columns,\n title: \n React.createElement(TableHeader, {\n searchQuery: searchQuery,\n numberOfResults: filteredResults.length,\n numberOfSelectedFilters: \n (selectedFilters.selected !== '' ? 1 : 0) +\n selectedFilters.checked.length\n ,\n handleToggleFilters: () => toggleFilters(!showFilters),}\n )\n ,}\n )\n )\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Grid } from '@material-ui/core';\nimport React, { useEffect, useState } from 'react';\nimport useDebounce from 'react-use/lib/useDebounce';\nimport { SearchBar } from './LegacySearchBar';\nimport { SearchResult } from './LegacySearchResult';\nimport {\n Content,\n Header,\n Page,\n useQueryParamState,\n} from '@backstage/core-components';\n\n/**\n * @deprecated This SearchPage, powered directly by the Catalog API, will be\n * removed from a future release of this plugin.\n */\nexport const LegacySearchPage = () => {\n const [queryString, setQueryString] = useQueryParamState('query');\n const [searchQuery, setSearchQuery] = useState(queryString ?? '');\n\n const handleSearch = (event) => {\n event.preventDefault();\n setSearchQuery(event.target.value);\n };\n\n useEffect(() => setSearchQuery(queryString ?? ''), [queryString]);\n\n useDebounce(\n () => {\n setQueryString(searchQuery);\n },\n 200,\n [searchQuery],\n );\n\n const handleClearSearchBar = () => {\n setSearchQuery('');\n };\n\n return (\n React.createElement(Page, { themeId: \"home\",}\n , React.createElement(Header, { title: \"Search\",} )\n , React.createElement(Content, null\n , React.createElement(Grid, { container: true, direction: \"row\",}\n , React.createElement(Grid, { item: true, xs: 12,}\n , React.createElement(SearchBar, {\n handleSearch: handleSearch,\n handleClearSearchBar: handleClearSearchBar,\n searchQuery: searchQuery,}\n )\n )\n , React.createElement(Grid, { item: true, xs: 12,}\n , React.createElement(SearchResult, {\n searchQuery: (queryString ?? '').toLocaleLowerCase('en-US'),}\n )\n )\n )\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect } from 'react';\nimport usePrevious from 'react-use/lib/usePrevious';\nimport qs from 'qs';\nimport { useLocation, useOutlet } from 'react-router';\nimport { SearchContextProvider, useSearch } from '../SearchContext';\n\nimport { LegacySearchPage } from '../LegacySearchPage';\n\nexport const UrlUpdater = () => {\n const location = useLocation();\n const {\n term,\n setTerm,\n types,\n setTypes,\n pageCursor,\n setPageCursor,\n filters,\n setFilters,\n } = useSearch();\n\n const prevQueryParams = usePrevious(location.search);\n useEffect(() => {\n // Only respond to changes to url query params\n if (location.search === prevQueryParams) {\n return;\n }\n\n const query =\n qs.parse(location.search.substring(1), { arrayLimit: 0 }) || {};\n\n if (query.filters) {\n setFilters(query.filters );\n }\n\n if (query.query) {\n setTerm(query.query );\n }\n\n if (query.pageCursor) {\n setPageCursor(query.pageCursor );\n }\n\n if (query.types) {\n setTypes(query.types );\n }\n }, [prevQueryParams, location, setTerm, setTypes, setPageCursor, setFilters]);\n\n useEffect(() => {\n const newParams = qs.stringify(\n {\n query: term,\n types,\n pageCursor,\n filters,\n },\n { arrayFormat: 'brackets' },\n );\n const newUrl = `${window.location.pathname}?${newParams}`;\n\n // We directly manipulate window history here in order to not re-render\n // infinitely (state => location => state => etc). The intention of this\n // code is just to ensure the right query/filters are loaded when a user\n // clicks the \"back\" button after clicking a result.\n window.history.replaceState(null, document.title, newUrl);\n }, [term, types, pageCursor, filters]);\n\n return null;\n};\n\nexport const SearchPage = () => {\n const outlet = useOutlet();\n\n return (\n React.createElement(SearchContextProvider, null\n , React.createElement(UrlUpdater, null )\n , outlet || React.createElement(LegacySearchPage, null )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n EmptyState,\n Progress,\n ResponseErrorPanel,\n} from '@backstage/core-components';\n\nimport React from 'react';\nimport { useSearch } from '../SearchContext';\n\n\n\n\n\nexport const SearchResultComponent = ({ children }) => {\n const {\n result: { loading, error, value },\n } = useSearch();\n\n if (loading) {\n return React.createElement(Progress, null );\n }\n if (error) {\n return (\n React.createElement(ResponseErrorPanel, {\n title: \"Error encountered while fetching search results\" ,\n error: error,}\n )\n );\n }\n\n if (!value?.results.length) {\n return React.createElement(EmptyState, { missing: \"data\", title: \"Sorry, no results were found\" ,} );\n }\n\n return React.createElement(React.Fragment, null, children({ results: value.results }));\n};\n\nexport { SearchResultComponent as SearchResult };\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Button, makeStyles } from '@material-ui/core';\nimport ArrowBackIosIcon from '@material-ui/icons/ArrowBackIos';\nimport ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';\nimport React from 'react';\nimport { useSearch } from '../SearchContext';\n\nconst useStyles = makeStyles(theme => ({\n root: {\n display: 'flex',\n justifyContent: 'space-between',\n gap: theme.spacing(2),\n margin: theme.spacing(2, 0),\n },\n}));\n\nexport const SearchResultPager = () => {\n const { fetchNextPage, fetchPreviousPage } = useSearch();\n const classes = useStyles();\n\n if (!fetchNextPage && !fetchPreviousPage) {\n return React.createElement(React.Fragment, null);\n }\n\n return (\n React.createElement('nav', { 'arial-label': \"pagination navigation\" , className: classes.root,}\n , React.createElement(Button, {\n 'aria-label': \"previous page\" ,\n disabled: !fetchPreviousPage,\n onClick: fetchPreviousPage,\n startIcon: React.createElement(ArrowBackIosIcon, null ),}\n , \"Previous\"\n\n )\n\n , React.createElement(Button, {\n 'aria-label': \"next page\" ,\n disabled: !fetchNextPage,\n onClick: fetchNextPage,\n endIcon: React.createElement(ArrowForwardIosIcon, null ),}\n , \"Next\"\n\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SearchClient, searchApiRef } from './apis';\nimport {\n createApiFactory,\n createPlugin,\n createRouteRef,\n createRoutableExtension,\n discoveryApiRef,\n createComponentExtension,\n identityApiRef,\n} from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'search',\n});\n\nexport const rootNextRouteRef = createRouteRef({\n id: 'search:next',\n});\n\nexport const searchPlugin = createPlugin({\n id: 'search',\n apis: [\n createApiFactory({\n api: searchApiRef,\n deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef },\n factory: ({ discoveryApi, identityApi }) => {\n return new SearchClient({ discoveryApi, identityApi });\n },\n }),\n ],\n routes: {\n root: rootRouteRef,\n nextRoot: rootNextRouteRef,\n },\n});\n\nexport const SearchPage = searchPlugin.provide(\n createRoutableExtension({\n name: 'SearchPage',\n component: () => import('./components/SearchPage').then(m => m.SearchPage),\n mountPoint: rootRouteRef,\n }),\n);\n\n/**\n * @deprecated This component was used for rapid prototyping of the Backstage\n * Search platform. Now that the API has stabilized, you should use the\n * <SearchPage /> component instead. This component will be removed in an\n * upcoming release.\n */\nexport const SearchPageNext = searchPlugin.provide(\n createRoutableExtension({\n name: 'SearchPageNext',\n component: () => import('./components/SearchPage').then(m => m.SearchPage),\n mountPoint: rootNextRouteRef,\n }),\n);\n\nexport const SearchBar = searchPlugin.provide(\n createComponentExtension({\n name: 'SearchBar',\n component: {\n lazy: () => import('./components/SearchBar').then(m => m.SearchBar),\n },\n }),\n);\n\n/**\n * @deprecated This component was used for rapid prototyping of the Backstage\n * Search platform. Now that the API has stabilized, you should use the\n * <SearchBar /> component instead. This component will be removed in an\n * upcoming release.\n */\nexport const SearchBarNext = searchPlugin.provide(\n createComponentExtension({\n name: 'SearchBarNext',\n component: {\n lazy: () => import('./components/SearchBar').then(m => m.SearchBar),\n },\n }),\n);\n\nexport const SearchResult = searchPlugin.provide(\n createComponentExtension({\n name: 'SearchResult',\n component: {\n lazy: () => import('./components/SearchResult').then(m => m.SearchResult),\n },\n }),\n);\n\n/**\n * @deprecated This component was used for rapid prototyping of the Backstage\n * Search platform. Now that the API has stabilized, you should use the\n * <SearchResult /> component instead. This component will be removed in an\n * upcoming release.\n */\nexport const SearchResultNext = searchPlugin.provide(\n createComponentExtension({\n name: 'SearchResultNext',\n component: {\n lazy: () => import('./components/SearchResult').then(m => m.SearchResult),\n },\n }),\n);\n\nexport const SidebarSearchModal = searchPlugin.provide(\n createComponentExtension({\n name: 'SidebarSearchModal',\n component: {\n lazy: () =>\n import('./components/SidebarSearchModal').then(\n m => m.SidebarSearchModal,\n ),\n },\n }),\n);\n\nexport const DefaultResultListItem = searchPlugin.provide(\n createComponentExtension({\n name: 'DefaultResultListItem',\n component: {\n lazy: () =>\n import('./components/DefaultResultListItem').then(\n m => m.DefaultResultListItem,\n ),\n },\n }),\n);\n\nexport const HomePageSearchBar = searchPlugin.provide(\n createComponentExtension({\n name: 'HomePageSearchBar',\n component: {\n lazy: () =>\n import('./components/HomePageComponent').then(m => m.HomePageSearchBar),\n },\n }),\n);\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport { Reader } from './reader';\nimport { toLowerMaybe } from './helpers';\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\n\nexport const EntityPageDocs = ({ entity }) => {\n const config = useApi(configApiRef);\n return (\n React.createElement(Reader, {\n withSearch: false,\n entityRef: {\n namespace: toLowerMaybe(entity.metadata.namespace ?? 'default', config),\n kind: toLowerMaybe(entity.kind, config),\n name: toLowerMaybe(entity.metadata.name, config),\n },}\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { Route, Routes } from 'react-router-dom';\nimport { TechDocsIndexPage } from './home/components/TechDocsIndexPage';\nimport { TechDocsPage as TechDocsReaderPage } from './reader/components/TechDocsPage';\nimport { EntityPageDocs } from './EntityPageDocs';\nimport { MissingAnnotationEmptyState } from '@backstage/core-components';\n\nconst TECHDOCS_ANNOTATION = 'backstage.io/techdocs-ref';\n\nexport const isTechDocsAvailable = (entity) =>\n Boolean(entity?.metadata?.annotations?.[TECHDOCS_ANNOTATION]);\n\nexport const Router = () => {\n return (\n React.createElement(Routes, null\n , React.createElement(Route, { path: \"/\", element: React.createElement(TechDocsIndexPage, null ),} )\n , React.createElement(Route, {\n path: \"/:namespace/:kind/:name/*\",\n element: React.createElement(TechDocsReaderPage, null ),}\n )\n )\n );\n};\n\n\n\n\n\n\nexport const EmbeddedDocsRouter = (_props) => {\n const { entity } = useEntity();\n\n const projectId = entity.metadata.annotations?.[TECHDOCS_ANNOTATION];\n\n if (!projectId) {\n return React.createElement(MissingAnnotationEmptyState, { annotation: TECHDOCS_ANNOTATION,} );\n }\n\n return (\n React.createElement(Routes, null\n , React.createElement(Route, { path: \"/*\", element: React.createElement(EntityPageDocs, { entity: entity,} ),} )\n )\n );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { createApiRef } from '@backstage/core-plugin-api';\n\n/**\n * Utility API reference for the {@link TechDocsStorageApi}.\n *\n * @public\n */\nexport const techdocsStorageApiRef = createApiRef({\n id: 'plugin.techdocs.storageservice',\n});\n\n/**\n * Utility API reference for the {@link TechDocsApi}.\n *\n * @public\n */\nexport const techdocsApiRef = createApiRef({\n id: 'plugin.techdocs.service',\n});\n\n/**\n * The outcome of a docs sync operation.\n *\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\nimport { Divider, ListItem, ListItemText, makeStyles } from '@material-ui/core';\nimport { Link } from '@backstage/core-components';\nimport TextTruncate from 'react-text-truncate';\n\nconst useStyles = makeStyles({\n flexContainer: {\n flexWrap: 'wrap',\n },\n itemText: {\n width: '100%',\n marginBottom: '1rem',\n },\n});\n\nexport const DocsResultListItem = ({\n result,\n lineClamp = 5,\n asListItem = true,\n asLink = true,\n title,\n}\n\n\n\n\n\n) => {\n const classes = useStyles();\n const TextItem = () => (\n React.createElement(ListItemText, {\n className: classes.itemText,\n primaryTypographyProps: { variant: 'h6' },\n primary: \n title\n ? title\n : `${result.title} | ${result.entityTitle ?? result.name} docs`\n ,\n secondary: \n React.createElement(TextTruncate, {\n line: lineClamp,\n truncateText: \"…\",\n text: result.text,\n element: \"span\",}\n )\n ,}\n )\n );\n\n const LinkWrapper = ({ children }) =>\n asLink ? React.createElement(Link, { to: result.location,}, children) : React.createElement(React.Fragment, null, children);\n\n const ListItemWrapper = ({ children }) =>\n asListItem ? (\n React.createElement(React.Fragment, null\n , React.createElement(ListItem, { alignItems: \"flex-start\", className: classes.flexContainer,}\n , children\n )\n , React.createElement(Divider, { component: \"li\",} )\n )\n ) : (\n React.createElement(React.Fragment, null, children)\n );\n\n return (\n React.createElement(LinkWrapper, null\n , React.createElement(ListItemWrapper, null\n , React.createElement(TextItem, null )\n )\n )\n );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n// Lower-case entity triplets by default, but allow override.\nexport function toLowerMaybe(str, config) {\n return config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n )\n ? str\n : str.toLocaleLowerCase('en-US');\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\n\nimport { useApi, useRouteRef, configApiRef } from '@backstage/core-plugin-api';\nimport { Card, CardActions, CardContent, CardMedia } from '@material-ui/core';\nimport { rootDocsRouteRef } from '../../routes';\n\nimport {\n Button,\n ItemCardGrid,\n ItemCardHeader,\n} from '@backstage/core-components';\nimport { toLowerMaybe } from '../../helpers';\n\nexport const DocsCardGrid = ({\n entities,\n}\n\n) => {\n const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef);\n const config = useApi(configApiRef);\n if (!entities) return null;\n return (\n React.createElement(ItemCardGrid, { 'data-testid': \"docs-explore\",}\n , !entities?.length\n ? null\n : entities.map((entity, index) => (\n React.createElement(Card, { key: index,}\n , React.createElement(CardMedia, null\n , React.createElement(ItemCardHeader, {\n title: entity.metadata.title ?? entity.metadata.name,}\n )\n )\n , React.createElement(CardContent, null, entity.metadata.description)\n , React.createElement(CardActions, null\n , React.createElement(Button, {\n to: getRouteToReaderPageFor({\n namespace: toLowerMaybe(\n entity.metadata.namespace ?? 'default',\n config,\n ),\n kind: toLowerMaybe(entity.kind, config),\n name: toLowerMaybe(entity.metadata.name, config),\n }),\n color: \"primary\",\n 'data-testid': \"read_docs\",}\n , \"Read Docs\"\n\n )\n )\n )\n ))\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport useCopyToClipboard from 'react-use/lib/useCopyToClipboard';\n\nimport { useRouteRef, useApi, configApiRef } from '@backstage/core-plugin-api';\nimport { RELATION_OWNED_BY } from '@backstage/catalog-model';\nimport {\n formatEntityRefTitle,\n getEntityRelations,\n} from '@backstage/plugin-catalog-react';\nimport { rootDocsRouteRef } from '../../routes';\nimport {\n Button,\n EmptyState,\n Table,\n\n\n} from '@backstage/core-components';\nimport * as actionFactories from './actions';\nimport * as columnFactories from './columns';\n\nimport { toLowerMaybe } from '../../helpers';\n\nexport const DocsTable = ({\n entities,\n title,\n loading,\n columns,\n actions,\n}\n\n\n\n\n\n) => {\n const [, copyToClipboard] = useCopyToClipboard();\n const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef);\n const config = useApi(configApiRef);\n if (!entities) return null;\n\n const documents = entities.map(entity => {\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n return {\n entity,\n resolved: {\n docsUrl: getRouteToReaderPageFor({\n namespace: toLowerMaybe(\n entity.metadata.namespace ?? 'default',\n config,\n ),\n kind: toLowerMaybe(entity.kind, config),\n name: toLowerMaybe(entity.metadata.name, config),\n }),\n ownedByRelations,\n ownedByRelationsTitle: ownedByRelations\n .map(r => formatEntityRefTitle(r, { defaultKind: 'group' }))\n .join(', '),\n },\n };\n });\n\n const defaultColumns = [\n columnFactories.createNameColumn(),\n columnFactories.createOwnerColumn(),\n columnFactories.createTypeColumn(),\n ];\n\n const defaultActions = [\n actionFactories.createCopyDocsUrlAction(copyToClipboard),\n ];\n\n return (\n React.createElement(React.Fragment, null\n , loading || (documents && documents.length > 0) ? (\n React.createElement(Table, {\n isLoading: loading,\n options: {\n paging: true,\n pageSize: 20,\n search: true,\n actionsColumnIndex: -1,\n },\n data: documents,\n columns: columns || defaultColumns,\n actions: actions || defaultActions,\n title: \n title\n ? `${title} (${documents.length})`\n : `All (${documents.length})`\n ,}\n )\n ) : (\n React.createElement(EmptyState, {\n missing: \"data\",\n title: \"No documents to show\" ,\n description: \"Create your own document. Check out our Getting Started Information\" ,\n action: \n React.createElement(Button, {\n color: \"primary\",\n to: \"https://backstage.io/docs/features/techdocs/getting-started\",\n variant: \"contained\",}\n , \"DOCS\"\n\n )\n ,}\n )\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useState } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport { makeStyles } from '@material-ui/core';\n\nimport {\n CATALOG_FILTER_EXISTS,\n catalogApiRef,\n\n isOwnerOf,\n useOwnUser,\n} from '@backstage/plugin-catalog-react';\n\nimport { DocsTable } from './DocsTable';\nimport { DocsCardGrid } from './DocsCardGrid';\nimport { TechDocsPageWrapper } from './TechDocsPageWrapper';\n\nimport {\n CodeSnippet,\n Content,\n HeaderTabs,\n Progress,\n WarningPanel,\n SupportButton,\n ContentHeader,\n} from '@backstage/core-components';\n\nimport { useApi } from '@backstage/core-plugin-api';\n\nconst panels = {\n DocsTable: DocsTable,\n DocsCardGrid: DocsCardGrid,\n};\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst CustomPanel = ({\n config,\n entities,\n index,\n}\n\n\n\n) => {\n const useStyles = makeStyles({\n panelContainer: {\n marginBottom: '2rem',\n ...(config.panelCSS ? config.panelCSS : {}),\n },\n });\n const classes = useStyles();\n const { value: user } = useOwnUser();\n\n const Panel = panels[config.panelType];\n\n const shownEntities = entities.filter(entity => {\n if (config.filterPredicate === 'ownedByUser') {\n if (!user) {\n return false;\n }\n return isOwnerOf(user, entity);\n }\n\n return (\n typeof config.filterPredicate === 'function' &&\n config.filterPredicate(entity)\n );\n });\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(ContentHeader, { title: config.title, description: config.description,}\n , index === 0 ? (\n React.createElement(SupportButton, null, \"Discover documentation in your ecosystem.\"\n\n )\n ) : null\n )\n , React.createElement('div', { className: classes.panelContainer,}\n , React.createElement(Panel, { 'data-testid': \"techdocs-custom-panel\", entities: shownEntities,} )\n )\n )\n );\n};\n\nexport const TechDocsCustomHome = ({\n tabsConfig,\n}\n\n) => {\n const [selectedTab, setSelectedTab] = useState(0);\n const catalogApi = useApi(catalogApiRef);\n\n const {\n value: entities,\n loading,\n error,\n } = useAsync(async () => {\n const response = await catalogApi.getEntities({\n filter: {\n 'metadata.annotations.backstage.io/techdocs-ref': CATALOG_FILTER_EXISTS,\n },\n fields: [\n 'apiVersion',\n 'kind',\n 'metadata',\n 'relations',\n 'spec.owner',\n 'spec.type',\n ],\n });\n return response.items.filter((entity) => {\n return !!entity.metadata.annotations?.['backstage.io/techdocs-ref'];\n });\n });\n\n const currentTabConfig = tabsConfig[selectedTab];\n\n if (loading) {\n return (\n React.createElement(TechDocsPageWrapper, null\n , React.createElement(Content, null\n , React.createElement(Progress, null )\n )\n )\n );\n }\n\n if (error) {\n return (\n React.createElement(TechDocsPageWrapper, null\n , React.createElement(Content, null\n , React.createElement(WarningPanel, {\n severity: \"error\",\n title: \"Could not load available documentation.\" ,}\n \n , React.createElement(CodeSnippet, { language: \"text\", text: error.toString(),} )\n )\n )\n )\n );\n }\n\n return (\n React.createElement(TechDocsPageWrapper, null\n , React.createElement(HeaderTabs, {\n selectedIndex: selectedTab,\n onChange: index => setSelectedTab(index),\n tabs: tabsConfig.map(({ label }, index) => ({\n id: index.toString(),\n label,\n })),}\n )\n , React.createElement(Content, { 'data-testid': \"techdocs-content\",}\n , currentTabConfig.panels.map((config, index) => (\n React.createElement(CustomPanel, {\n key: index,\n config: config,\n entities: !!entities ? entities : [],\n index: index,}\n )\n ))\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { TechDocsCustomHome } from './TechDocsCustomHome';\n\nexport const LegacyTechDocsHome = () => {\n const tabsConfig = [\n {\n label: 'Overview',\n panels: [\n {\n title: 'Overview',\n description:\n 'Explore your internal technical ecosystem through documentation.',\n panelType: 'DocsCardGrid' ,\n filterPredicate: () => true,\n },\n // uncomment this if you would like to have a secondary panel with owned documents\n // {\n // title: 'Owned',\n // description: 'Explore your owned internal documentation.',\n // panelType: 'DocsCardGrid' as PanelType,\n // filterPredicate: 'ownedByUser',\n // },\n ],\n },\n {\n label: 'Owned Documents',\n panels: [\n {\n title: 'Owned documents',\n description: 'Access your documentation.',\n panelType: 'DocsTable' ,\n // ownedByUser filters out entities owned by signed in user\n filterPredicate: 'ownedByUser',\n },\n ],\n },\n ];\n return React.createElement(TechDocsCustomHome, { tabsConfig: tabsConfig,} );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { useOutlet } from 'react-router';\nimport { LegacyTechDocsHome } from './LegacyTechDocsHome';\n\nexport const TechDocsIndexPage = () => {\n const outlet = useOutlet();\n\n return outlet || React.createElement(LegacyTechDocsHome, null );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport { PageWithHeader } from '@backstage/core-components';\nimport { useApi, configApiRef } from '@backstage/core-plugin-api';\n\n\n\n\n\nexport const TechDocsPageWrapper = ({ children }) => {\n const configApi = useApi(configApiRef);\n const generatedSubtitle = `Documentation available in ${\n configApi.getOptionalString('organization.name') ?? 'Backstage'\n }`;\n\n return (\n React.createElement(PageWithHeader, {\n title: \"Documentation\",\n subtitle: generatedSubtitle,\n themeId: \"documentation\",}\n \n , children\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport ShareIcon from '@material-ui/icons/Share';\nimport {\n favoriteEntityIcon,\n favoriteEntityTooltip,\n} from '@backstage/plugin-catalog-react';\n\n\nexport function createCopyDocsUrlAction(copyToClipboard) {\n return (row) => {\n return {\n icon: () => React.createElement(ShareIcon, { fontSize: \"small\",} ),\n tooltip: 'Click to copy documentation link to clipboard',\n onClick: () =>\n copyToClipboard(`${window.location.origin}${row.resolved.docsUrl}`),\n };\n };\n}\n\nexport function createStarEntityAction(\n isStarredEntity,\n toggleStarredEntity,\n) {\n return ({ entity }) => {\n const isStarred = isStarredEntity(entity);\n return {\n cellStyle: { paddingLeft: '1em' },\n icon: () => favoriteEntityIcon(isStarred),\n tooltip: favoriteEntityTooltip(isStarred),\n onClick: () => toggleStarredEntity(entity),\n };\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { Link, SubvalueCell, } from '@backstage/core-components';\nimport { EntityRefLinks } from '@backstage/plugin-catalog-react';\n\n\n\nfunction customTitle(entity) {\n return entity.metadata.title || entity.metadata.name;\n}\n\nexport function createNameColumn() {\n return {\n title: 'Document',\n field: 'entity.metadata.name',\n highlight: true,\n render: (row) => (\n React.createElement(SubvalueCell, {\n value: React.createElement(Link, { to: row.resolved.docsUrl,}, customTitle(row.entity)),\n subvalue: row.entity.metadata.description,}\n )\n ),\n };\n}\n\nexport function createOwnerColumn() {\n return {\n title: 'Owner',\n field: 'resolved.ownedByRelationsTitle',\n render: ({ resolved }) => (\n React.createElement(EntityRefLinks, {\n entityRefs: resolved.ownedByRelations,\n defaultKind: \"group\",}\n )\n ),\n };\n}\n\nexport function createTypeColumn() {\n return {\n title: 'Type',\n field: 'entity.spec.type',\n };\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * TechDocs backend serves SVGs with text/plain content-type for security. This\n * helper determines if an SVG is being loaded from the backend, and thus needs\n * inlining to be displayed properly.\n */\nconst isSvgNeedingInlining = (\n attrName,\n attrVal,\n apiOrigin,\n) => {\n const isSrcToSvg = attrName === 'src' && attrVal.endsWith('.svg');\n const isRelativeUrl = !attrVal.match(/^([a-z]*:)?\\/\\//i);\n const pointsToOurBackend = attrVal.startsWith(apiOrigin);\n return isSrcToSvg && (isRelativeUrl || pointsToOurBackend);\n};\n\nexport const addBaseUrl = ({\n techdocsStorageApi,\n entityId,\n path,\n}) => {\n return async dom => {\n const apiOrigin = await techdocsStorageApi.getApiOrigin();\n\n const updateDom = async ( \n list,\n attributeName,\n ) => {\n for (const elem of list) {\n if (elem.hasAttribute(attributeName)) {\n const elemAttribute = elem.getAttribute(attributeName);\n if (!elemAttribute) return;\n\n // Special handling for SVG images.\n const newValue = await techdocsStorageApi.getBaseUrl(\n elemAttribute,\n entityId,\n path,\n );\n\n if (isSvgNeedingInlining(attributeName, elemAttribute, apiOrigin)) {\n try {\n const svg = await fetch(newValue, { credentials: 'include' });\n const svgContent = await svg.text();\n elem.setAttribute(\n attributeName,\n `data:image/svg+xml;base64,${btoa(svgContent)}`,\n );\n } catch (e) {\n elem.setAttribute('alt', `Error: ${elemAttribute}`);\n }\n } else {\n elem.setAttribute(attributeName, newValue);\n }\n }\n }\n };\n\n await Promise.all([\n updateDom(dom.querySelectorAll('img'), 'src'),\n updateDom(dom.querySelectorAll('script'), 'src'),\n updateDom(dom.querySelectorAll('source'), 'src'),\n updateDom(dom.querySelectorAll('link'), 'href'),\n updateDom(dom.querySelectorAll('a[download]'), 'href'),\n ]);\n\n return dom;\n };\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport {\n replaceGitHubUrlType,\n\n} from '@backstage/integration';\nimport FeedbackOutlinedIcon from '@material-ui/icons/FeedbackOutlined';\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport parseGitUrl from 'git-url-parse';\n\n// requires repo\nexport const addGitFeedbackLink = (\n scmIntegrationsApi,\n) => {\n return dom => {\n // attempting to use selectors that are more likely to be static as MkDocs updates over time\n const sourceAnchor = dom.querySelector(\n '[title=\"Edit this page\"]',\n ) ;\n\n // don't show if edit link not available in raw page\n if (!sourceAnchor || !sourceAnchor.href) {\n return dom;\n }\n\n const sourceURL = new URL(sourceAnchor.href);\n const integration = scmIntegrationsApi.byUrl(sourceURL);\n\n // don't show if can't identify edit link hostname as a gitlab/github hosting\n if (integration?.type !== 'github' && integration?.type !== 'gitlab') {\n return dom;\n }\n\n // topmost h1 only contains title for whole page\n const title = (dom.querySelector('article>h1') ).childNodes[0]\n .textContent;\n const issueTitle = encodeURIComponent(`Documentation Feedback: ${title}`);\n const issueDesc = encodeURIComponent(\n `Page source:\\n${sourceAnchor.href}\\n\\nFeedback:`,\n );\n\n // Convert GitHub edit url to blob type so it can be parsed by git-url-parse correctly\n const gitUrl =\n integration?.type === 'github'\n ? replaceGitHubUrlType(sourceURL.href, 'blob')\n : sourceURL.href;\n const gitInfo = parseGitUrl(gitUrl);\n const repoPath = `/${gitInfo.organization}/${gitInfo.name}`;\n\n const feedbackLink = sourceAnchor.cloneNode() ;\n switch (integration?.type) {\n case 'gitlab':\n feedbackLink.href = `${sourceURL.origin}${repoPath}/issues/new?issue[title]=${issueTitle}&issue[description]=${issueDesc}`;\n break;\n case 'github':\n feedbackLink.href = `${sourceURL.origin}${repoPath}/issues/new?title=${issueTitle}&body=${issueDesc}`;\n break;\n default:\n return dom;\n }\n ReactDOM.render(React.createElement(FeedbackOutlinedIcon), feedbackLink);\n feedbackLink.style.paddingLeft = '5px';\n feedbackLink.title = 'Leave feedback for this page';\n feedbackLink.id = 'git-feedback-link';\n sourceAnchor?.insertAdjacentElement('beforebegin', feedbackLink);\n return dom;\n };\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const rewriteDocLinks = () => {\n return dom => {\n const updateDom = (\n list,\n attributeName,\n ) => {\n Array.from(list)\n .filter(elem => elem.hasAttribute(attributeName))\n .forEach((elem) => {\n const elemAttribute = elem.getAttribute(attributeName);\n if (elemAttribute) {\n // if link is external, add target to open in a new window or tab\n if (elemAttribute.match(/^https?:\\/\\//i)) {\n elem.setAttribute('target', '_blank');\n }\n\n try {\n const normalizedWindowLocation = normalizeUrl(\n window.location.href,\n );\n elem.setAttribute(\n attributeName,\n new URL(elemAttribute, normalizedWindowLocation).toString(),\n );\n } catch (_e) {\n // Non-parseable links should be re-written as plain text.\n elem.replaceWith(elem.textContent || elemAttribute);\n }\n }\n });\n };\n\n updateDom(Array.from(dom.getElementsByTagName('a')), 'href');\n\n return dom;\n };\n};\n\n/** Make sure that the input url always ends with a '/' */\nexport function normalizeUrl(input) {\n const url = new URL(input);\n\n if (!url.pathname.endsWith('/') && !url.pathname.endsWith('.html')) {\n url.pathname += '/';\n }\n\n return url.toString();\n}\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const addLinkClickListener = ({\n baseUrl,\n onClick,\n}) => {\n return dom => {\n Array.from(dom.getElementsByTagName('a')).forEach(elem => {\n elem.addEventListener('click', (e) => {\n const target = elem ;\n const href = target.getAttribute('href');\n\n if (!href) return;\n if (href.startsWith(baseUrl) && !elem.hasAttribute('download')) {\n e.preventDefault();\n onClick(e, href);\n }\n });\n });\n\n return dom;\n };\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Recreates copy-to-clipboard functionality attached to <code> snippets that\n * is native to mkdocs-material theme.\n */\nexport const copyToClipboard = () => {\n return dom => {\n Array.from(dom.querySelectorAll('pre > code')).forEach(codeElem => {\n const button = document.createElement('button');\n const toBeCopied = codeElem.textContent || '';\n button.className = 'md-clipboard md-icon';\n button.title = 'Copy to clipboard';\n button.innerHTML =\n '<svg viewBox=\"0 0 24 24\"><path d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg>';\n button.addEventListener('click', () =>\n navigator.clipboard.writeText(toBeCopied),\n );\n codeElem?.parentElement?.prepend(button);\n });\n return dom;\n };\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const removeMkdocsHeader = () => {\n return dom => {\n // Remove the header\n dom.querySelector('.md-header')?.remove();\n\n return dom;\n };\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const simplifyMkdocsFooter = () => {\n return dom => {\n // Remove mkdocs copyright\n dom.querySelector('.md-footer-copyright')?.remove();\n\n return dom;\n };\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const onCssReady = ({\n docStorageUrl,\n onLoading,\n onLoaded,\n}) => {\n return dom => {\n const cssPages = Array.from(\n dom.querySelectorAll('head > link[rel=\"stylesheet\"]'),\n ).filter(elem => elem.getAttribute('href')?.startsWith(docStorageUrl));\n\n let count = cssPages.length;\n\n if (count > 0) {\n onLoading(dom);\n }\n\n cssPages.forEach(cssPage =>\n cssPage.addEventListener('load', () => {\n count -= 1;\n\n if (count === 0) {\n onLoaded(dom);\n }\n }),\n );\n\n return dom;\n };\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst TECHDOCS_CSS = /main\\.[A-Fa-f0-9]{8}\\.min\\.css$/;\nconst GOOGLE_FONTS = /^https:\\/\\/fonts\\.googleapis\\.com/;\nconst GSTATIC_FONTS = /^https:\\/\\/fonts\\.gstatic\\.com/;\n\nexport const safeLinksHook = (node) => {\n if (node.nodeName && node.nodeName === 'LINK') {\n const href = node.getAttribute('href') || '';\n if (href.match(TECHDOCS_CSS)) {\n node.setAttribute('rel', 'stylesheet');\n }\n if (href.match(GOOGLE_FONTS)) {\n node.setAttribute('rel', 'stylesheet');\n }\n if (href.match(GSTATIC_FONTS)) {\n node.setAttribute('rel', 'preconnect');\n }\n }\n return node;\n};\n\nconst filterIframeHook = (allowedIframeHosts) => (node) => {\n if (node.nodeName === 'IFRAME') {\n const src = node.getAttribute('src');\n if (!src) {\n node.remove();\n return node;\n }\n\n try {\n const srcUrl = new URL(src);\n const isMatch = allowedIframeHosts.some(host => srcUrl.host === host);\n if (!isMatch) {\n node.remove();\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Invalid iframe src, ${error}`);\n node.remove();\n }\n }\n return node;\n};\n\n\nimport DOMPurify from 'dompurify';\n\n\nexport const sanitizeDOM = (config) => {\n const allowedIframeHosts =\n config?.getOptionalStringArray('allowedIframeHosts') || [];\n\n return dom => {\n DOMPurify.addHook('afterSanitizeAttributes', safeLinksHook);\n const addTags = ['link'];\n\n if (allowedIframeHosts.length > 0) {\n DOMPurify.addHook(\n 'beforeSanitizeElements',\n filterIframeHook(allowedIframeHosts),\n );\n addTags.push('iframe');\n }\n\n return DOMPurify.sanitize(dom.innerHTML, {\n ADD_TAGS: addTags,\n FORBID_TAGS: ['style'],\n WHOLE_DOCUMENT: true,\n RETURN_DOM: true,\n });\n };\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const injectCss = ({ css }) => {\n return dom => {\n dom\n .getElementsByTagName('head')[0]\n .insertAdjacentHTML('beforeend', `<style>${css}</style>`);\n\n return dom;\n };\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const scrollIntoAnchor = () => {\n return dom => {\n setTimeout(() => {\n // Scroll to the desired anchor on initial navigation\n if (window.location.hash) {\n const hash = window.location.hash.slice(1);\n dom?.querySelector(`#${hash}`)?.scrollIntoView();\n }\n }, 200);\n return dom;\n };\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\nexport const transform = async (\n html,\n transformers,\n) => {\n let dom;\n\n if (typeof html === 'string') {\n dom = new DOMParser().parseFromString(html, 'text/html').documentElement;\n } else if (html instanceof Element) {\n dom = html;\n } else {\n throw new Error('dom is not a recognized type');\n }\n\n for (const transformer of transformers) {\n dom = await transformer(dom);\n }\n\n return dom;\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useMemo, useReducer, useRef } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport useAsyncRetry from 'react-use/lib/useAsyncRetry';\nimport { techdocsStorageApiRef } from '../../api';\n\n/**\n * A state representation that is used to configure the UI of <Reader />\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Calculate the state that should be reported to the display component.\n */\nexport function calculateDisplayState({\n contentLoading,\n content,\n activeSyncState,\n}\n\n\n) {\n // we have nothing to display yet\n if (contentLoading) {\n return 'CHECKING';\n }\n\n // the build is ready, but it triggered a content reload and the content variable is not trusted\n if (activeSyncState === 'BUILD_READY_RELOAD') {\n return 'CHECKING';\n }\n\n // there is no content, but the sync process is still evaluating\n if (!content && activeSyncState === 'CHECKING') {\n return 'CHECKING';\n }\n\n // there is no content yet so we assume that we are building it for the first time\n if (!content && activeSyncState === 'BUILDING') {\n return 'INITIAL_BUILD';\n }\n\n // if there is still no content after building, it might just not exist\n if (!content) {\n return 'CONTENT_NOT_FOUND';\n }\n\n // we are still building, but we already show stale content\n if (activeSyncState === 'BUILDING') {\n return 'CONTENT_STALE_REFRESHING';\n }\n\n // the build is ready, but the content is still stale\n if (activeSyncState === 'BUILD_READY') {\n return 'CONTENT_STALE_READY';\n }\n\n // the build failed, but the content is still stale\n if (activeSyncState === 'ERROR') {\n return 'CONTENT_STALE_ERROR';\n }\n\n // seems like the content is up-to-date (or we don't know yet and the sync process is still evaluating in the background)\n return 'CONTENT_FRESH';\n}\n\n/**\n * The state of the synchronization task. It checks whether the docs are\n * up-to-date. If they aren't, it triggers a build.\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport function reducer(\n oldState,\n action,\n) {\n const newState = { ...oldState };\n\n switch (action.type) {\n case 'sync':\n // reset the build log when a new check starts\n if (action.state === 'CHECKING') {\n newState.buildLog = [];\n }\n\n newState.activeSyncState = action.state;\n newState.syncError = action.syncError;\n break;\n\n case 'contentLoading':\n newState.contentLoading = true;\n\n // only reset errors but keep the old content until it is replaced by the 'content' action\n newState.contentError = undefined;\n break;\n\n case 'content':\n // only override the path if it is part of the action\n if (typeof action.path === 'string') {\n newState.path = action.path;\n }\n\n newState.contentLoading = false;\n newState.content = action.content;\n newState.contentError = action.contentError;\n break;\n\n case 'buildLog':\n newState.buildLog = newState.buildLog.concat(action.log);\n break;\n\n default:\n throw new Error();\n }\n\n // a content update loads fresh content so the build is updated to being up-to-date\n if (\n ['BUILD_READY', 'BUILD_READY_RELOAD'].includes(newState.activeSyncState) &&\n ['contentLoading', 'content'].includes(action.type)\n ) {\n newState.activeSyncState = 'UP_TO_DATE';\n newState.buildLog = [];\n }\n\n return newState;\n}\n\nexport function useReaderState(\n kind,\n namespace,\n name,\n path,\n)\n\n\n\n\n\n\n\n {\n const [state, dispatch] = useReducer(reducer, {\n activeSyncState: 'CHECKING',\n path,\n contentLoading: true,\n buildLog: [],\n });\n\n const techdocsStorageApi = useApi(techdocsStorageApiRef);\n\n // try to load the content. the function will fire events and we don't care for the return values\n const { retry: contentReload } = useAsyncRetry(async () => {\n dispatch({ type: 'contentLoading' });\n\n try {\n const entityDocs = await techdocsStorageApi.getEntityDocs(\n { kind, namespace, name },\n path,\n );\n\n // update content and path at the same time\n dispatch({ type: 'content', content: entityDocs, path });\n\n return entityDocs;\n } catch (e) {\n dispatch({ type: 'content', contentError: e, path });\n }\n\n return undefined;\n }, [techdocsStorageApi, kind, namespace, name, path]);\n\n // create a ref that holds the latest content. This provides a useAsync hook\n // with the latest content without restarting the useAsync hook.\n const contentRef = useRef({\n content: undefined,\n reload: () => {},\n });\n contentRef.current = { content: state.content, reload: contentReload };\n\n // try to derive the state. the function will fire events and we don't care for the return values\n useAsync(async () => {\n dispatch({ type: 'sync', state: 'CHECKING' });\n\n // should only switch to BUILDING if the request takes more than 1 seconds\n const buildingTimeout = setTimeout(() => {\n dispatch({ type: 'sync', state: 'BUILDING' });\n }, 1000);\n\n try {\n const result = await techdocsStorageApi.syncEntityDocs(\n {\n kind,\n namespace,\n name,\n },\n log => {\n dispatch({ type: 'buildLog', log });\n },\n );\n\n switch (result) {\n case 'updated':\n // if there was no content prior to building, retry the loading\n if (!contentRef.current.content) {\n contentRef.current.reload();\n dispatch({ type: 'sync', state: 'BUILD_READY_RELOAD' });\n } else {\n dispatch({ type: 'sync', state: 'BUILD_READY' });\n }\n break;\n case 'cached':\n dispatch({ type: 'sync', state: 'UP_TO_DATE' });\n break;\n\n default:\n dispatch({\n type: 'sync',\n state: 'ERROR',\n syncError: new Error('Unexpected return state'),\n });\n break;\n }\n } catch (e) {\n dispatch({ type: 'sync', state: 'ERROR', syncError: e });\n } finally {\n // Cancel the timer that sets the state \"BUILDING\"\n clearTimeout(buildingTimeout);\n }\n }, [kind, name, namespace, techdocsStorageApi, dispatch, contentRef]);\n\n const displayState = useMemo(\n () =>\n calculateDisplayState({\n activeSyncState: state.activeSyncState,\n contentLoading: state.contentLoading,\n content: state.content,\n }),\n [state.activeSyncState, state.content, state.contentLoading],\n );\n\n return {\n state: displayState,\n contentReload,\n path: state.path,\n content: state.content,\n contentErrorMessage: state.contentError?.toString(),\n syncErrorMessage: state.syncError?.toString(),\n buildLog: state.buildLog,\n };\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, {\n\n\n createContext,\n useContext,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { Grid, makeStyles, useTheme } from '@material-ui/core';\n\n\nimport { useApi, configApiRef } from '@backstage/core-plugin-api';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\n\nimport { SidebarPinStateContext } from '@backstage/core-components';\n\nimport { techdocsStorageApiRef } from '../../api';\n\nimport {\n addBaseUrl,\n addGitFeedbackLink,\n addLinkClickListener,\n injectCss,\n onCssReady,\n removeMkdocsHeader,\n rewriteDocLinks,\n sanitizeDOM,\n simplifyMkdocsFooter,\n scrollIntoAnchor,\n transform as transformer,\n copyToClipboard,\n} from '../transformers';\n\nimport { TechDocsSearch } from './TechDocsSearch';\nimport { TechDocsStateIndicator } from './TechDocsStateIndicator';\nimport { useReaderState } from './useReaderState';\n\n\n\n\n\n\n\nconst useStyles = makeStyles(theme => ({\n searchBar: {\n marginLeft: '20rem',\n maxWidth: 'calc(100% - 20rem * 2 - 3rem)',\n marginTop: theme.spacing(1),\n '@media screen and (max-width: 76.1875em)': {\n marginLeft: '10rem',\n maxWidth: 'calc(100% - 10rem)',\n },\n },\n}));\n\n\n\nconst TechDocsReaderContext = createContext(\n {} ,\n);\n\nconst TechDocsReaderProvider = ({\n children,\n entityRef,\n}) => {\n const { '*': path } = useParams();\n const { kind, namespace, name } = entityRef;\n const value = useReaderState(kind, namespace, name, path);\n return (\n React.createElement(TechDocsReaderContext.Provider, { value: value,}\n , children\n )\n );\n};\n\n/**\n * Note: this HOC is currently being exported so that we can rapidly\n * iterate on alternative <Reader /> implementations that extend core\n * functionality. There is no guarantee that this HOC will continue to be\n * exported by the package in the future!\n *\n * todo: Make public or stop exporting (ctrl+f \"altReaderExperiments\")\n * @internal\n */\nexport const withTechDocsReaderProvider =\n (Component, entityRef) =>\n (props) =>\n (\n React.createElement(TechDocsReaderProvider, { entityRef: entityRef,}\n , React.createElement(Component, { ...props,} )\n )\n );\n\n/**\n * Note: this hook is currently being exported so that we can rapidly\n * iterate on alternative <Reader /> implementations that extend core\n * functionality. There is no guarantee that this hook will continue to be\n * exported by the package in the future!\n *\n * todo: Make public or stop exporting (ctrl+f \"altReaderExperiments\")\n * @internal\n */\nexport const useTechDocsReader = () => useContext(TechDocsReaderContext);\n\n/**\n * Hook that encapsulates the behavior of getting raw HTML and applying\n * transforms to it in order to make it function at a basic level in the\n * Backstage UI.\n *\n * Note: this hook is currently being exported so that we can rapidly iterate\n * on alternative <Reader /> implementations that extend core functionality.\n * There is no guarantee that this hook will continue to be exported by the\n * package in the future!\n *\n * todo: Make public or stop exporting (see others: \"altReaderExperiments\")\n * @internal\n */\nexport const useTechDocsReaderDom = (entityRef) => {\n const navigate = useNavigate();\n const theme = useTheme();\n const techdocsStorageApi = useApi(techdocsStorageApiRef);\n const scmIntegrationsApi = useApi(scmIntegrationsApiRef);\n const techdocsSanitizer = useApi(configApiRef);\n const { namespace = '', kind = '', name = '' } = entityRef;\n const { state, path, content: rawPage } = useTechDocsReader();\n\n const [sidebars, setSidebars] = useState();\n const [dom, setDom] = useState(null);\n\n // sidebar pinned status to be used in computing CSS style injections\n const { isPinned } = useContext(SidebarPinStateContext);\n\n const updateSidebarPosition = useCallback(() => {\n if (!dom || !sidebars) return;\n // set sidebar height so they don't initially render in wrong position\n const mdTabs = dom.querySelector('.md-container > .md-tabs');\n sidebars.forEach(sidebar => {\n const newTop = Math.max(dom.getBoundingClientRect().top, 0);\n sidebar.style.top = mdTabs\n ? `${newTop + mdTabs.getBoundingClientRect().height}px`\n : `${newTop}px`;\n });\n }, [dom, sidebars]);\n\n useEffect(() => {\n updateSidebarPosition();\n window.addEventListener('scroll', updateSidebarPosition, true);\n window.addEventListener('resize', updateSidebarPosition);\n return () => {\n window.removeEventListener('scroll', updateSidebarPosition, true);\n window.removeEventListener('resize', updateSidebarPosition);\n };\n // an update to \"state\" might lead to an updated UI so we include it as a trigger\n }, [updateSidebarPosition, state]);\n\n // dynamically set width of footer to accommodate for pinning of the sidebar\n const updateFooterWidth = useCallback(() => {\n if (!dom) return;\n const footer = dom.querySelector('.md-footer') ;\n if (footer) {\n footer.style.width = `${dom.getBoundingClientRect().width}px`;\n }\n }, [dom]);\n\n useEffect(() => {\n updateFooterWidth();\n window.addEventListener('resize', updateFooterWidth);\n return () => {\n window.removeEventListener('resize', updateFooterWidth);\n };\n });\n\n // a function that performs transformations that are executed prior to adding it to the DOM\n const preRender = useCallback(\n (rawContent, contentPath) =>\n transformer(rawContent, [\n sanitizeDOM(techdocsSanitizer.getOptionalConfig('techdocs.sanitizer')),\n addBaseUrl({\n techdocsStorageApi,\n entityId: {\n kind,\n name,\n namespace,\n },\n path: contentPath,\n }),\n rewriteDocLinks(),\n removeMkdocsHeader(),\n simplifyMkdocsFooter(),\n addGitFeedbackLink(scmIntegrationsApi),\n injectCss({\n css: `\n body {\n font-family: ${theme.typography.fontFamily};\n --md-text-color: ${theme.palette.text.primary};\n --md-text-link-color: ${theme.palette.primary.main};\n\n --md-code-fg-color: ${theme.palette.text.primary};\n --md-code-bg-color: ${theme.palette.background.paper};\n --md-accent-fg-color: ${theme.palette.primary.main};\n --md-default-fg-color--lightest: ${theme.palette.textVerySubtle};\n }\n .md-main__inner { margin-top: 0; }\n .md-sidebar { position: fixed; bottom: 100px; width: 20rem; }\n .md-sidebar--secondary { right: 2rem; }\n .md-content { margin-bottom: 50px }\n .md-footer { position: fixed; bottom: 0px; }\n .md-footer-nav__link { width: 20rem;}\n .md-content { margin-left: 20rem; max-width: calc(100% - 20rem * 2 - 3rem); }\n .md-typeset { font-size: 1rem; }\n .md-typeset h1, .md-typeset h2, .md-typeset h3 { font-weight: bold; }\n .md-nav { font-size: 1rem; }\n .md-grid { max-width: 90vw; margin: 0 }\n .md-typeset blockquote {\n color: ${theme.palette.textSubtle};\n border-left: 0.2rem solid ${theme.palette.textVerySubtle};\n }\n .md-typeset hr {\n border-bottom: 0.05rem dotted ${theme.palette.textVerySubtle};\n }\n .md-typeset table:not([class]) {\n font-size: 1rem;\n border: 1px solid ${theme.palette.text.primary};\n border-bottom: none;\n border-collapse: collapse;\n }\n .md-typeset table:not([class]) td, .md-typeset table:not([class]) th {\n border-bottom: 1px solid ${theme.palette.text.primary};\n }\n .md-typeset table:not([class]) th { font-weight: bold; }\n .md-typeset .admonition, .md-typeset details {\n font-size: 1rem;\n }\n \n /* style the checkmarks of the task list */\n .md-typeset .task-list-control .task-list-indicator::before {\n background-color: ${theme.palette.action.disabledBackground};\n }\n .md-typeset .task-list-control [type=\"checkbox\"]:checked + .task-list-indicator:before {\n background-color: ${theme.palette.success.main};\n }\n /**/\n\n @media screen and (max-width: 76.1875em) {\n .md-nav {\n background-color: ${theme.palette.background.default};\n transition: none !important\n }\n .md-sidebar--secondary { display: none; }\n .md-sidebar--primary { left: ${\n isPinned ? '242px' : '72px'\n }; width: 10rem }\n .md-content { margin-left: 10rem; max-width: calc(100% - 10rem); }\n .md-content__inner { font-size: 0.9rem }\n .md-footer {\n position: static;\n padding-left: 10rem;\n }\n .md-footer-nav__link {\n /* footer links begin to overlap at small sizes without setting width */\n width: 50%;\n }\n .md-nav--primary .md-nav__title {\n white-space: normal;\n height: auto;\n line-height: 1rem;\n cursor: auto;\n }\n .md-nav--primary > .md-nav__title [for=\"none\"] {\n padding-top: 0;\n }\n }\n `,\n }),\n injectCss({\n // Disable CSS animations on link colors as they lead to issues in dark\n // mode. The dark mode color theme is applied later and theirfore there\n // is always an animation from light to dark mode when navigation\n // between pages.\n css: `\n .md-nav__link, .md-typeset a, .md-typeset a::before, .md-typeset .headerlink {\n transition: none;\n }\n `,\n }),\n injectCss({\n // Properly style code blocks.\n css: `\n .md-typeset pre > code::-webkit-scrollbar-thumb {\n background-color: hsla(0, 0%, 0%, 0.32);\n }\n .md-typeset pre > code::-webkit-scrollbar-thumb:hover {\n background-color: hsla(0, 0%, 0%, 0.87);\n }\n `,\n }),\n injectCss({\n // Admonitions and others are using SVG masks to define icons. These\n // masks are defined as CSS variables.\n // As the MkDocs output is rendered in shadow DOM, the CSS variable\n // definitions on the root selector are not applied. Instead, the have\n // to be applied on :host.\n // As there is no way to transform the served main*.css yet (for\n // example in the backend), we have to copy from main*.css and modify\n // them.\n css: `\n :host {\n --md-admonition-icon--note: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z\"/></svg>');\n --md-admonition-icon--abstract: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M4 5h16v2H4V5m0 4h16v2H4V9m0 4h16v2H4v-2m0 4h10v2H4v-2z\"/></svg>');\n --md-admonition-icon--info: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 002 12a10 10 0 0010 10 10 10 0 0010-10A10 10 0 0012 2z\"/></svg>');\n --md-admonition-icon--tip: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M17.55 11.2c-.23-.3-.5-.56-.76-.82-.65-.6-1.4-1.03-2.03-1.66C13.3 7.26 13 4.85 13.91 3c-.91.23-1.75.75-2.45 1.32-2.54 2.08-3.54 5.75-2.34 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.22.1-.46.04-.64-.12a.83.83 0 01-.15-.17c-1.1-1.43-1.28-3.48-.53-5.12C5.89 10 5 12.3 5.14 14.47c.04.5.1 1 .27 1.5.14.6.4 1.2.72 1.73 1.04 1.73 2.87 2.97 4.84 3.22 2.1.27 4.35-.12 5.96-1.6 1.8-1.66 2.45-4.32 1.5-6.6l-.13-.26c-.2-.46-.47-.87-.8-1.25l.05-.01m-3.1 6.3c-.28.24-.73.5-1.08.6-1.1.4-2.2-.16-2.87-.82 1.19-.28 1.89-1.16 2.09-2.05.17-.8-.14-1.46-.27-2.23-.12-.74-.1-1.37.18-2.06.17.38.37.76.6 1.06.76 1 1.95 1.44 2.2 2.8.04.14.06.28.06.43.03.82-.32 1.72-.92 2.27h.01z\"/></svg>');\n --md-admonition-icon--success: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2m-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z\"/></svg>');\n --md-admonition-icon--question: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M15.07 11.25l-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 00-2-2 2 2 0 00-2 2H8a4 4 0 014-4 4 4 0 014 4 3.2 3.2 0 01-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 002 12a10 10 0 0010 10 10 10 0 0010-10c0-5.53-4.5-10-10-10z\"/></svg>');\n --md-admonition-icon--warning: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M13 14h-2v-4h2m0 8h-2v-2h2M1 21h22L12 2 1 21z\"/></svg>');\n --md-admonition-icon--failure: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M12 2c5.53 0 10 4.47 10 10s-4.47 10-10 10S2 17.53 2 12 6.47 2 12 2m3.59 5L12 10.59 8.41 7 7 8.41 10.59 12 7 15.59 8.41 17 12 13.41 15.59 17 17 15.59 13.41 12 17 8.41 15.59 7z\"/></svg>');\n --md-admonition-icon--danger: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M11.5 20l4.86-9.73H13V4l-5 9.73h3.5V20M12 2c2.75 0 5.1 1 7.05 2.95C21 6.9 22 9.25 22 12s-1 5.1-2.95 7.05C17.1 21 14.75 22 12 22s-5.1-1-7.05-2.95C3 17.1 2 14.75 2 12s1-5.1 2.95-7.05C6.9 3 9.25 2 12 2z\"/></svg>');\n --md-admonition-icon--bug: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 00-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 00-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z\"/></svg>');\n --md-admonition-icon--example: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 01.75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z\"/></svg>');\n --md-admonition-icon--quote: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z\"/></svg>');\n }\n :host {\n --md-footnotes-icon: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.42L5.83 13H21V7h-2z\"/></svg>');\n }\n :host {\n --md-details-icon: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M8.59 16.58L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42z\"/></svg>');\n }\n :host {\n --md-tasklist-icon: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M0 0h24v24H0z\" fill=\"none\"/><path d=\"M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z\"/></svg>');\n --md-tasklist-icon--checked: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M0 0h24v24H0z\" fill=\"none\"/><path d=\"M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z\"/></svg>');\n }\n `,\n }),\n ]),\n [\n kind,\n name,\n namespace,\n scmIntegrationsApi,\n techdocsStorageApi,\n techdocsSanitizer,\n theme.palette.action.disabledBackground,\n theme.palette.background.default,\n theme.palette.background.paper,\n theme.palette.primary.main,\n theme.palette.success.main,\n theme.palette.text.primary,\n theme.palette.textSubtle,\n theme.palette.textVerySubtle,\n theme.typography.fontFamily,\n isPinned,\n ],\n );\n\n // a function that performs transformations that are executed after adding it to the DOM\n const postRender = useCallback(\n async (transformedElement) =>\n transformer(transformedElement, [\n scrollIntoAnchor(),\n copyToClipboard(),\n addLinkClickListener({\n baseUrl: window.location.origin,\n onClick: (event, url) => {\n // detect if CTRL or META keys are pressed so that links can be opened in a new tab with `window.open`\n const modifierActive = event.ctrlKey || event.metaKey;\n const parsedUrl = new URL(url);\n\n // hash exists when anchor is clicked on secondary sidebar\n if (parsedUrl.hash) {\n if (modifierActive) {\n window.open(`${parsedUrl.pathname}${parsedUrl.hash}`, '_blank');\n } else {\n navigate(`${parsedUrl.pathname}${parsedUrl.hash}`);\n // Scroll to hash if it's on the current page\n transformedElement\n ?.querySelector(`#${parsedUrl.hash.slice(1)}`)\n ?.scrollIntoView();\n }\n } else {\n if (modifierActive) {\n window.open(parsedUrl.pathname, '_blank');\n } else {\n navigate(parsedUrl.pathname);\n // Scroll to top of reader if primary sidebar link is clicked\n transformedElement\n ?.querySelector('.md-content__inner')\n ?.scrollIntoView();\n }\n }\n },\n }),\n onCssReady({\n docStorageUrl: await techdocsStorageApi.getApiOrigin(),\n onLoading: (renderedElement) => {\n (renderedElement ).style.setProperty('opacity', '0');\n },\n onLoaded: (renderedElement) => {\n (renderedElement ).style.removeProperty('opacity');\n // disable MkDocs drawer toggling ('for' attribute => checkbox mechanism)\n renderedElement\n .querySelector('.md-nav__title')\n ?.removeAttribute('for');\n setSidebars(\n Array.from(renderedElement.querySelectorAll('.md-sidebar')),\n );\n },\n }),\n ]),\n [navigate, techdocsStorageApi],\n );\n\n useEffect(() => {\n if (!rawPage) return () => {};\n\n // if false, there is already a newer execution of this effect\n let shouldReplaceContent = true;\n\n // Pre-render\n preRender(rawPage, path).then(async preTransformedDomElement => {\n if (!preTransformedDomElement?.innerHTML) {\n return; // An unexpected error occurred\n }\n\n // don't manipulate the shadow dom if this isn't the latest effect execution\n if (!shouldReplaceContent) {\n return;\n }\n\n // Scroll to top after render\n window.scroll({ top: 0 });\n\n // Post-render\n const postTransformedDomElement = await postRender(\n preTransformedDomElement,\n );\n setDom(postTransformedDomElement );\n });\n\n // cancel this execution\n return () => {\n shouldReplaceContent = false;\n };\n }, [rawPage, path, preRender, postRender]);\n\n return dom;\n};\n\nconst TheReader = ({\n entityRef,\n onReady = () => {},\n withSearch = true,\n}) => {\n const classes = useStyles();\n const dom = useTechDocsReaderDom(entityRef);\n const shadowDomRef = useRef(null);\n\n const onReadyRef = useRef(onReady);\n useEffect(() => {\n onReadyRef.current = onReady;\n }, [onReady]);\n\n useEffect(() => {\n if (!dom || !shadowDomRef.current) return;\n const shadowDiv = shadowDomRef.current;\n const shadowRoot =\n shadowDiv.shadowRoot || shadowDiv.attachShadow({ mode: 'open' });\n Array.from(shadowRoot.children).forEach(child =>\n shadowRoot.removeChild(child),\n );\n shadowRoot.appendChild(dom);\n onReadyRef.current();\n\n // this hook must ONLY be triggered by a changed dom\n }, [dom]);\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(TechDocsStateIndicator, null )\n , withSearch && shadowDomRef?.current?.shadowRoot?.innerHTML && (\n React.createElement(Grid, { container: true, className: classes.searchBar,}\n , React.createElement(TechDocsSearch, { entityId: entityRef,} )\n )\n )\n , React.createElement('div', { 'data-testid': \"techdocs-content-shadowroot\", ref: shadowDomRef,} )\n )\n );\n};\n\nexport const Reader = ({\n entityRef,\n onReady = () => {},\n withSearch = true,\n}) => (\n React.createElement(TechDocsReaderProvider, { entityRef: entityRef,}\n , React.createElement(TheReader, {\n entityRef: entityRef,\n onReady: onReady,\n withSearch: withSearch,}\n )\n )\n);\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { useApi, configApiRef } from '@backstage/core-plugin-api';\nimport { ErrorPage } from '@backstage/core-components';\n\n\n\n\n\nexport const TechDocsNotFound = ({ errorMessage }) => {\n const techdocsBuilder =\n useApi(configApiRef).getOptionalString('techdocs.builder');\n\n let additionalInfo = '';\n if (techdocsBuilder !== 'local') {\n additionalInfo =\n \"Note that techdocs.builder is not set to 'local' in your config, which means this Backstage app will not \" +\n \"generate docs if they are not found. Make sure the project's docs are generated and published by some external \" +\n \"process (e.g. CI/CD pipeline). Or change techdocs.builder to 'local' to generate docs from this Backstage \" +\n 'instance.';\n }\n\n return (\n React.createElement(ErrorPage, {\n status: \"404\",\n statusMessage: errorMessage || 'Documentation not found',\n additionalInfo: additionalInfo,}\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useCallback, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport useAsync from 'react-use/lib/useAsync';\nimport { techdocsApiRef } from '../../api';\nimport { TechDocsNotFound } from './TechDocsNotFound';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Page, Content } from '@backstage/core-components';\nimport { Reader } from './Reader';\nimport { TechDocsPageHeader } from './TechDocsPageHeader';\n\nexport const LegacyTechDocsPage = () => {\n const [documentReady, setDocumentReady] = useState(false);\n const { namespace, kind, name } = useParams();\n\n const techdocsApi = useApi(techdocsApiRef);\n\n const { value: techdocsMetadataValue } = useAsync(() => {\n if (documentReady) {\n return techdocsApi.getTechDocsMetadata({ kind, namespace, name });\n }\n\n return Promise.resolve(undefined);\n }, [kind, namespace, name, techdocsApi, documentReady]);\n\n const { value: entityMetadataValue, error: entityMetadataError } =\n useAsync(() => {\n return techdocsApi.getEntityMetadata({ kind, namespace, name });\n }, [kind, namespace, name, techdocsApi]);\n\n const onReady = useCallback(() => {\n setDocumentReady(true);\n }, [setDocumentReady]);\n\n if (entityMetadataError) {\n return React.createElement(TechDocsNotFound, { errorMessage: entityMetadataError.message,} );\n }\n\n return (\n React.createElement(Page, { themeId: \"documentation\",}\n , React.createElement(TechDocsPageHeader, {\n techDocsMetadata: techdocsMetadataValue,\n entityMetadata: entityMetadataValue,\n entityRef: {\n kind,\n namespace,\n name,\n },}\n )\n , React.createElement(Content, { 'data-testid': \"techdocs-content\",}\n , React.createElement(Reader, {\n onReady: onReady,\n entityRef: {\n kind,\n namespace,\n name,\n },}\n )\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useCallback, useState } from 'react';\nimport { useOutlet } from 'react-router';\nimport { useParams } from 'react-router-dom';\nimport useAsync from 'react-use/lib/useAsync';\nimport { techdocsApiRef } from '../../api';\nimport { TechDocsNotFound } from './TechDocsNotFound';\nimport { LegacyTechDocsPage } from './LegacyTechDocsPage';\n\n\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Page } from '@backstage/core-components';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const TechDocsPage = ({ children }) => {\n const outlet = useOutlet();\n\n const [documentReady, setDocumentReady] = useState(false);\n const { namespace, kind, name } = useParams();\n\n const techdocsApi = useApi(techdocsApiRef);\n\n const { value: techdocsMetadataValue } = useAsync(() => {\n if (documentReady) {\n return techdocsApi.getTechDocsMetadata({ kind, namespace, name });\n }\n\n return Promise.resolve(undefined);\n }, [kind, namespace, name, techdocsApi, documentReady]);\n\n const { value: entityMetadataValue, error: entityMetadataError } =\n useAsync(() => {\n return techdocsApi.getEntityMetadata({ kind, namespace, name });\n }, [kind, namespace, name, techdocsApi]);\n\n const onReady = useCallback(() => {\n setDocumentReady(true);\n }, [setDocumentReady]);\n\n if (entityMetadataError) {\n return React.createElement(TechDocsNotFound, { errorMessage: entityMetadataError.message,} );\n }\n\n if (!children) return outlet || React.createElement(LegacyTechDocsPage, null );\n\n return (\n React.createElement(Page, { themeId: \"documentation\",}\n , children instanceof Function\n ? children({\n techdocsMetadataValue,\n entityMetadataValue,\n entityRef: { kind, namespace, name },\n onReady,\n })\n : children\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RELATION_OWNED_BY } from '@backstage/catalog-model';\nimport { Header, HeaderLabel } from '@backstage/core-components';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport {\n EntityRefLink,\n EntityRefLinks,\n getEntityRelations,\n} from '@backstage/plugin-catalog-react';\nimport CodeIcon from '@material-ui/icons/Code';\nimport React from 'react';\nimport { rootRouteRef } from '../../routes';\n\n\n\n\n\n\n\n\nexport const TechDocsPageHeader = ({\n entityRef,\n entityMetadata,\n techDocsMetadata,\n}) => {\n const { name } = entityRef;\n\n const { site_name: siteName, site_description: siteDescription } =\n techDocsMetadata || {};\n\n const { locationMetadata, spec } = entityMetadata || {};\n const lifecycle = spec?.lifecycle;\n\n const ownedByRelations = entityMetadata\n ? getEntityRelations(entityMetadata, RELATION_OWNED_BY)\n : [];\n\n const docsRootLink = useRouteRef(rootRouteRef)();\n\n const labels = (\n React.createElement(React.Fragment, null\n , React.createElement(HeaderLabel, {\n label: \"Component\",\n value: \n React.createElement(EntityRefLink, {\n color: \"inherit\",\n entityRef: entityRef,\n defaultKind: \"Component\",}\n )\n ,}\n )\n , ownedByRelations.length > 0 && (\n React.createElement(HeaderLabel, {\n label: \"Owner\",\n value: \n React.createElement(EntityRefLinks, {\n color: \"inherit\",\n entityRefs: ownedByRelations,\n defaultKind: \"group\",}\n )\n ,}\n )\n )\n , lifecycle ? React.createElement(HeaderLabel, { label: \"Lifecycle\", value: lifecycle,} ) : null\n , locationMetadata &&\n locationMetadata.type !== 'dir' &&\n locationMetadata.type !== 'file' ? (\n React.createElement(HeaderLabel, {\n label: \"\",\n value: \n React.createElement('a', {\n href: locationMetadata.target,\n target: \"_blank\",\n rel: \"noopener noreferrer\" ,}\n \n , React.createElement(CodeIcon, { style: { marginTop: '-25px', fill: '#fff' },} )\n )\n ,}\n )\n ) : null\n )\n );\n\n return (\n React.createElement(Header, {\n title: siteName ? siteName : '.',\n pageTitleOverride: siteName || name,\n subtitle: \n siteDescription && siteDescription !== 'None' ? siteDescription : ''\n ,\n type: \"Docs\",\n typeLink: docsRootLink,}\n \n , labels\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport FilterListIcon from '@material-ui/icons/FilterList';\nimport { makeStyles, IconButton, Typography } from '@material-ui/core';\n\nconst useStyles = makeStyles(theme => ({\n filters: {\n width: '250px',\n display: 'flex',\n },\n icon: {\n margin: theme.spacing(-1, 0, 0, 0),\n },\n}));\n\n\n\n\n\n\nexport const FiltersButton = ({\n numberOfSelectedFilters,\n handleToggleFilters,\n}) => {\n const classes = useStyles();\n\n return (\n React.createElement('div', { className: classes.filters,}\n , React.createElement(IconButton, {\n className: classes.icon,\n 'aria-label': \"settings\",\n onClick: handleToggleFilters,}\n \n , React.createElement(FilterListIcon, null )\n )\n , React.createElement(Typography, { variant: \"h6\",}, \"Filters (\"\n , numberOfSelectedFilters ? numberOfSelectedFilters : 0, \")\"\n )\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport {\n makeStyles,\n Typography,\n Divider,\n Card,\n CardHeader,\n Button,\n CardContent,\n Select,\n Checkbox,\n List,\n ListItem,\n ListItemText,\n MenuItem,\n} from '@material-ui/core';\n\nconst useStyles = makeStyles(theme => ({\n filters: {\n background: 'transparent',\n boxShadow: '0px 0px 0px 0px',\n },\n checkbox: {\n padding: theme.spacing(0, 1, 0, 1),\n },\n dropdown: {\n width: '100%',\n },\n}));\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nexport const Filters = ({\n filters,\n filterOptions,\n resetFilters,\n updateSelected,\n updateChecked,\n}) => {\n const classes = useStyles();\n\n return (\n React.createElement(Card, { className: classes.filters,}\n , React.createElement(CardHeader, {\n title: React.createElement(Typography, { variant: \"h6\",}, \"Filters\"),\n action: \n React.createElement(Button, { color: \"primary\", onClick: () => resetFilters(),}, \"CLEAR ALL\"\n\n )\n ,}\n )\n , React.createElement(Divider, null )\n , filterOptions.kind.length === 0 && filterOptions.lifecycle.length === 0 && (\n React.createElement(CardContent, null\n , React.createElement(Typography, { variant: \"subtitle2\",}, \"Filters cannot be applied to available results\"\n\n )\n )\n )\n , filterOptions.kind.length > 0 && (\n React.createElement(CardContent, null\n , React.createElement(Typography, { variant: \"subtitle2\",}, \"Kind\")\n , React.createElement(Select, {\n id: \"outlined-select\",\n onChange: (e) =>\n updateSelected(e?.target?.value)\n ,\n variant: \"outlined\",\n className: classes.dropdown,\n value: filters.selected,}\n \n , filterOptions.kind.map(filter => (\n React.createElement(MenuItem, {\n selected: filter === '',\n dense: true,\n key: filter,\n value: filter,}\n \n , filter\n )\n ))\n )\n )\n )\n , filterOptions.lifecycle.length > 0 && (\n React.createElement(CardContent, null\n , React.createElement(Typography, { variant: \"subtitle2\",}, \"Lifecycle\")\n , React.createElement(List, { disablePadding: true, dense: true,}\n , filterOptions.lifecycle.map(filter => (\n React.createElement(ListItem, {\n key: filter,\n dense: true,\n button: true,\n onClick: () => updateChecked(filter),}\n \n , React.createElement(Checkbox, {\n edge: \"start\",\n disableRipple: true,\n className: classes.checkbox,\n color: \"primary\",\n checked: filters.checked.includes(filter),\n tabIndex: -1,\n value: filter,\n name: filter,}\n )\n , React.createElement(ListItemText, { id: filter, primary: filter,} )\n )\n ))\n )\n )\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect, useRef } from 'react';\nimport useAsyncFn from 'react-use/lib/useAsyncFn';\nimport useDebounce from 'react-use/lib/useDebounce';\nimport { useSearch } from '../SearchContext';\n\n/**\n * Utility hook for either asynchronously loading filter values from a given\n * function or synchronously providing a given list of default values.\n */\nexport const useAsyncFilterValues = (\n fn,\n inputValue,\n defaultValues = [],\n debounce = 250,\n) => {\n const valuesMemo = useRef({});\n const definiteFn = fn || (() => Promise.resolve([]));\n\n const [state, callback] = useAsyncFn(definiteFn, [inputValue], {\n loading: true,\n });\n\n // Do not invoke the given function more than necessary.\n useDebounce(\n () => {\n // Performance optimization: only invoke the callback once per inputValue\n // for the lifetime of the hook/component.\n if (valuesMemo.current[inputValue] === undefined) {\n valuesMemo.current[inputValue] = callback(inputValue).then(values => {\n // Overrite the value for future immediate returns.\n valuesMemo.current[inputValue] = values;\n return values;\n });\n }\n },\n debounce,\n [callback, inputValue],\n );\n\n // Immediately return the default values if they are provided.\n if (defaultValues.length) {\n return {\n loading: false,\n value: defaultValues,\n };\n }\n\n // Immediately return a memoized value if it is set (and not a promise).\n const possibleValue = valuesMemo.current[inputValue];\n if (Array.isArray(possibleValue)) {\n return {\n loading: false,\n value: possibleValue,\n };\n }\n\n return state;\n};\n\n/**\n * Utility hook for applying a given default value to the search context.\n */\nexport const useDefaultFilterValue = (\n name,\n defaultValue,\n) => {\n const { setFilters } = useSearch();\n\n useEffect(() => {\n if (defaultValue && [defaultValue].flat().length > 0) {\n setFilters(prevFilters => ({\n ...prevFilters,\n [name]: defaultValue,\n }));\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useState } from 'react';\nimport { Chip, TextField } from '@material-ui/core';\nimport {\n Autocomplete,\n\n\n} from '@material-ui/lab';\nimport { useSearch } from '../SearchContext';\nimport { useAsyncFilterValues, useDefaultFilterValue } from './hooks';\n\n\n/**\n * @public\n */\n\n\n\n\n\n\nexport const AutocompleteFilter = (props) => {\n const {\n className,\n defaultValue,\n name,\n values: givenValues,\n valuesDebounceMs,\n label,\n filterSelectedOptions,\n limitTags,\n multiple,\n } = props;\n const [inputValue, setInputValue] = useState('');\n useDefaultFilterValue(name, defaultValue);\n const asyncValues =\n typeof givenValues === 'function' ? givenValues : undefined;\n const defaultValues =\n typeof givenValues === 'function' ? undefined : givenValues;\n const { value: values, loading } = useAsyncFilterValues(\n asyncValues,\n inputValue,\n defaultValues,\n valuesDebounceMs,\n );\n const { filters, setFilters } = useSearch();\n const filterValue =\n (filters[name] ) || (multiple ? [] : null);\n\n // Set new filter values on input change.\n const handleChange = (\n _,\n newValue,\n ) => {\n setFilters(prevState => {\n const { [name]: filter, ...others } = prevState;\n\n if (newValue) {\n return { ...others, [name]: newValue };\n }\n return { ...others };\n });\n };\n\n // Provide the input field.\n const renderInput = (params) => (\n React.createElement(TextField, {\n ...params,\n name: \"search\",\n variant: \"outlined\",\n label: label,\n fullWidth: true,}\n )\n );\n\n // Render tags as primary-colored chips.\n const renderTags = (\n tagValue,\n getTagProps,\n ) =>\n tagValue.map((option, index) => (\n React.createElement(Chip, { label: option, color: \"primary\", ...getTagProps({ index }),} )\n ));\n\n return (\n React.createElement(Autocomplete, {\n filterSelectedOptions: filterSelectedOptions,\n limitTags: limitTags,\n multiple: multiple,\n className: className,\n id: `${multiple ? 'multi-' : ''}select-filter-${name}--select`,\n options: values || [],\n loading: loading,\n value: filterValue,\n onChange: handleChange,\n onInputChange: (_, newValue) => setInputValue(newValue),\n renderInput: renderInput,\n renderTags: renderTags,}\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { } from 'react';\nimport {\n makeStyles,\n FormControl,\n FormControlLabel,\n InputLabel,\n Checkbox,\n Select,\n MenuItem,\n FormLabel,\n} from '@material-ui/core';\n\nimport {\n AutocompleteFilter,\n\n} from './SearchFilter.Autocomplete';\nimport { useSearch } from '../SearchContext';\nimport { useAsyncFilterValues, useDefaultFilterValue } from './hooks';\n\nconst useStyles = makeStyles({\n label: {\n textTransform: 'capitalize',\n },\n});\n\n/**\n * @public\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst CheckboxFilter = (props) => {\n const {\n className,\n defaultValue,\n label,\n name,\n values: givenValues = [],\n valuesDebounceMs,\n } = props;\n const classes = useStyles();\n const { filters, setFilters } = useSearch();\n useDefaultFilterValue(name, defaultValue);\n const asyncValues =\n typeof givenValues === 'function' ? givenValues : undefined;\n const defaultValues =\n typeof givenValues === 'function' ? undefined : givenValues;\n const { value: values = [], loading } = useAsyncFilterValues(\n asyncValues,\n '',\n defaultValues,\n valuesDebounceMs,\n );\n\n const handleChange = (e) => {\n const {\n target: { value, checked },\n } = e;\n\n setFilters(prevFilters => {\n const { [name]: filter, ...others } = prevFilters;\n const rest = ((filter ) || []).filter(i => i !== value);\n const items = checked ? [...rest, value] : rest;\n return items.length ? { ...others, [name]: items } : others;\n });\n };\n\n return (\n React.createElement(FormControl, {\n className: className,\n disabled: loading,\n fullWidth: true,\n 'data-testid': \"search-checkboxfilter-next\",}\n \n , label ? React.createElement(FormLabel, { className: classes.label,}, label) : null\n , values.map((value) => (\n React.createElement(FormControlLabel, {\n key: value,\n control: \n React.createElement(Checkbox, {\n color: \"primary\",\n tabIndex: -1,\n inputProps: { 'aria-labelledby': value },\n value: value,\n name: value,\n onChange: handleChange,\n checked: ((filters[name] ) ?? []).includes(value),}\n )\n ,\n label: value,}\n )\n ))\n )\n );\n};\n\nconst SelectFilter = (props) => {\n const {\n className,\n defaultValue,\n label,\n name,\n values: givenValues,\n valuesDebounceMs,\n } = props;\n const classes = useStyles();\n useDefaultFilterValue(name, defaultValue);\n const asyncValues =\n typeof givenValues === 'function' ? givenValues : undefined;\n const defaultValues =\n typeof givenValues === 'function' ? undefined : givenValues;\n const { value: values = [], loading } = useAsyncFilterValues(\n asyncValues,\n '',\n defaultValues,\n valuesDebounceMs,\n );\n const { filters, setFilters } = useSearch();\n\n const handleChange = (e) => {\n const {\n target: { value },\n } = e;\n\n setFilters(prevFilters => {\n const { [name]: filter, ...others } = prevFilters;\n return value ? { ...others, [name]: value } : others;\n });\n };\n\n return (\n React.createElement(FormControl, {\n disabled: loading,\n className: className,\n variant: \"filled\",\n fullWidth: true,\n 'data-testid': \"search-selectfilter-next\",}\n \n , label ? (\n React.createElement(InputLabel, { className: classes.label, margin: \"dense\",}\n , label\n )\n ) : null\n , React.createElement(Select, {\n variant: \"outlined\",\n value: filters[name] || '',\n onChange: handleChange,}\n \n , React.createElement(MenuItem, { value: \"\",}\n , React.createElement('em', null, \"All\")\n )\n , values.map((value) => (\n React.createElement(MenuItem, { key: value, value: value,}\n , value\n )\n ))\n )\n )\n );\n};\n\nconst SearchFilter = ({\n component: Element,\n ...props\n}) => React.createElement(Element, { ...props,} );\n\nSearchFilter.Checkbox = (\n props\n,\n) => React.createElement(SearchFilter, { ...props, component: CheckboxFilter,} );\n\nSearchFilter.Select = (\n props\n,\n) => React.createElement(SearchFilter, { ...props, component: SelectFilter,} );\n\n/**\n * A control surface for a given filter field name, rendered as an autocomplete\n * textfield. A hard-coded list of values may be provided, or an async function\n * which returns values may be provided instead.\n * @public\n */\nSearchFilter.Autocomplete = (props) => (\n React.createElement(SearchFilter, { ...props, component: AutocompleteFilter,} )\n);\n\n/**\n * @deprecated This component was used for rapid prototyping of the Backstage\n * Search platform. Now that the API has stabilized, you should use the\n * <SearchFilter /> component instead. This component will be removed in an\n * upcoming release.\n */\nconst SearchFilterNext = SearchFilter;\n\nexport { SearchFilter, SearchFilterNext };\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { cloneElement, Fragment, useEffect, useState } from 'react';\nimport { useSearch } from '../SearchContext';\nimport {\n Accordion,\n AccordionSummary,\n AccordionDetails,\n Card,\n CardContent,\n CardHeader,\n Divider,\n List,\n ListItem,\n ListItemIcon,\n ListItemText,\n makeStyles,\n} from '@material-ui/core';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport AllIcon from '@material-ui/icons/FontDownload';\n\nconst useStyles = makeStyles(theme => ({\n card: {\n backgroundColor: 'rgba(0, 0, 0, .11)',\n },\n cardContent: {\n paddingTop: theme.spacing(1),\n },\n icon: {\n color: theme.palette.common.black,\n },\n list: {\n width: '100%',\n },\n listItemIcon: {\n width: '24px',\n height: '24px',\n },\n accordion: {\n backgroundColor: theme.palette.background.paper,\n },\n accordionSummary: {\n minHeight: 'auto',\n '&.Mui-expanded': {\n minHeight: 'auto',\n },\n },\n accordionSummaryContent: {\n margin: theme.spacing(2, 0),\n '&.Mui-expanded': {\n margin: theme.spacing(2, 0),\n },\n },\n accordionDetails: {\n padding: theme.spacing(0, 0, 1),\n },\n}));\n\n/**\n * @public\n */\n\n\n\n\n\n\n\n\n\n\nexport const SearchTypeAccordion = (props) => {\n const classes = useStyles();\n const { setPageCursor, setTypes, types } = useSearch();\n const [expanded, setExpanded] = useState(true);\n const { defaultValue, name, types: givenTypes } = props;\n\n const toggleExpanded = () => setExpanded(prevState => !prevState);\n const handleClick = (type) => {\n return () => {\n setTypes(type !== '' ? [type] : []);\n setPageCursor(undefined);\n setExpanded(false);\n };\n };\n\n // Handle any provided defaultValue\n useEffect(() => {\n if (defaultValue) {\n setTypes([defaultValue]);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const definedTypes = [\n {\n value: '',\n name: 'All',\n icon: React.createElement(AllIcon, null ),\n },\n ...givenTypes,\n ];\n const selected = types[0] || '';\n\n return (\n React.createElement(Card, { className: classes.card,}\n , React.createElement(CardHeader, { title: name, titleTypographyProps: { variant: 'overline' },} )\n , React.createElement(CardContent, { className: classes.cardContent,}\n , React.createElement(Accordion, {\n className: classes.accordion,\n expanded: expanded,\n onChange: toggleExpanded,}\n \n , React.createElement(AccordionSummary, {\n classes: {\n root: classes.accordionSummary,\n content: classes.accordionSummaryContent,\n },\n expandIcon: React.createElement(ExpandMoreIcon, { className: classes.icon,} ),\n IconButtonProps: { size: 'small' },}\n \n , expanded\n ? 'Collapse'\n : definedTypes.filter(t => t.value === selected)[0].name\n )\n , React.createElement(AccordionDetails, { classes: { root: classes.accordionDetails },}\n , React.createElement(List, {\n className: classes.list,\n component: \"nav\",\n 'aria-label': \"filter by type\" ,\n disablePadding: true,\n dense: true,}\n \n , definedTypes.map(type => (\n React.createElement(Fragment, { key: type.value,}\n , React.createElement(Divider, null )\n , React.createElement(ListItem, {\n selected: \n types[0] === type.value ||\n (types.length === 0 && type.value === '')\n ,\n onClick: handleClick(type.value),\n button: true,}\n \n , React.createElement(ListItemIcon, null\n , cloneElement(type.icon, {\n className: classes.listItemIcon,\n })\n )\n , React.createElement(ListItemText, { primary: type.name,} )\n )\n )\n ))\n )\n )\n )\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect } from 'react';\nimport { useSearch } from '../SearchContext';\n\nimport { makeStyles, Tab, Tabs } from '@material-ui/core';\n\nconst useStyles = makeStyles((theme) => ({\n tabs: {\n borderBottom: `1px solid ${theme.palette.textVerySubtle}`,\n padding: theme.spacing(0, 4),\n },\n tab: {\n height: '50px',\n fontWeight: theme.typography.fontWeightBold,\n fontSize: theme.typography.pxToRem(13),\n color: theme.palette.textSubtle,\n minWidth: '130px',\n },\n}));\n\n/**\n * @public\n */\n\n\n\n\n\n\n\n\nexport const SearchTypeTabs = (props) => {\n const classes = useStyles();\n const { setPageCursor, setTypes, types } = useSearch();\n const { defaultValue, types: givenTypes } = props;\n\n const changeTab = (_, newType) => {\n setTypes(newType !== '' ? [newType] : []);\n setPageCursor(undefined);\n };\n\n // Handle any provided defaultValue\n useEffect(() => {\n if (defaultValue) {\n setTypes([defaultValue]);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const definedTypes = [\n {\n value: '',\n name: 'All',\n },\n ...givenTypes,\n ];\n\n return (\n React.createElement(Tabs, {\n className: classes.tabs,\n indicatorColor: \"primary\",\n value: types.length === 0 ? '' : types[0],\n onChange: changeTab,}\n \n , definedTypes.map(type => (\n React.createElement(Tab, {\n className: classes.tab,\n disableRipple: true,\n label: type.name,\n value: type.value,}\n )\n ))\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n Checkbox,\n Chip,\n FormControl,\n InputLabel,\n ListItemText,\n makeStyles,\n MenuItem,\n Select,\n} from '@material-ui/core';\nimport React, { } from 'react';\nimport useEffectOnce from 'react-use/lib/useEffectOnce';\nimport {\n SearchTypeAccordion,\n SearchTypeAccordionProps,\n} from './SearchType.Accordion';\nimport { SearchTypeTabs, SearchTypeTabsProps } from './SearchType.Tabs';\nimport { useSearch } from '../SearchContext';\n\nconst useStyles = makeStyles(theme => ({\n label: {\n textTransform: 'capitalize',\n },\n chips: {\n display: 'flex',\n flexWrap: 'wrap',\n marginTop: theme.spacing(1),\n },\n chip: {\n margin: 2,\n },\n}));\n\n/**\n * @public\n */\n\n\n\n\n\n\n\nconst SearchType = (props) => {\n const { className, defaultValue, name, values = [] } = props;\n const classes = useStyles();\n const { types, setTypes } = useSearch();\n\n useEffectOnce(() => {\n if (!types.length) {\n if (defaultValue && Array.isArray(defaultValue)) {\n setTypes(defaultValue);\n } else if (defaultValue) {\n setTypes([defaultValue]);\n }\n }\n });\n\n const handleChange = (e) => {\n const value = e.target.value ;\n setTypes(value );\n };\n\n return (\n React.createElement(FormControl, {\n className: className,\n variant: \"filled\",\n fullWidth: true,\n 'data-testid': \"search-typefilter-next\",}\n \n , React.createElement(InputLabel, { className: classes.label, margin: \"dense\",}\n , name\n )\n , React.createElement(Select, {\n multiple: true,\n variant: \"outlined\",\n value: types,\n onChange: handleChange,\n placeholder: \"All Results\" ,\n renderValue: selected => (\n React.createElement('div', { className: classes.chips,}\n , (selected ).map(value => (\n React.createElement(Chip, {\n key: value,\n label: value,\n className: classes.chip,\n size: \"small\",}\n )\n ))\n )\n ),}\n \n , values.map((value) => (\n React.createElement(MenuItem, { key: value, value: value,}\n , React.createElement(Checkbox, { checked: types.indexOf(value) > -1,} )\n , React.createElement(ListItemText, { primary: value,} )\n )\n ))\n )\n )\n );\n};\n\n/**\n * A control surface for the search query's \"types\" property, displayed as a\n * single-select collapsible accordion suitable for use in faceted search UIs.\n * @public\n */\nSearchType.Accordion = (props) => {\n return React.createElement(SearchTypeAccordion, { ...props,} );\n};\n\n/**\n * A control surface for the search query's \"types\" property, displayed as a\n * tabs suitable for use in faceted search UIs.\n * @public\n */\nSearchType.Tabs = (props) => {\n return React.createElement(SearchTypeTabs, { ...props,} );\n};\n\nexport { SearchType };\n;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport qs from 'qs';\nimport React, { useCallback } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { rootRouteRef } from '../../plugin';\n\nimport { useRouteRef, } from '@backstage/core-plugin-api';\nimport { SidebarSearchField, useContent } from '@backstage/core-components';\n\n\n\n\n\nexport const SidebarSearch = (props) => {\n const searchRoute = useRouteRef(rootRouteRef);\n const { focusContent } = useContent();\n const navigate = useNavigate();\n const handleSearch = useCallback(\n (query) => {\n const queryString = qs.stringify({ query }, { addQueryPrefix: true });\n focusContent();\n navigate(`${searchRoute()}${queryString}`);\n },\n [focusContent, navigate, searchRoute],\n );\n\n return (\n React.createElement(SidebarSearchField, {\n icon: props.icon,\n onSearch: handleSearch,\n to: \"/search\",}\n )\n );\n};\n","\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { SearchContextProvider, useSearch } from '@backstage/plugin-search';\nimport {\n CircularProgress,\n Grid,\n IconButton,\n InputAdornment,\n TextField,\n} from '@material-ui/core';\nimport SearchIcon from '@material-ui/icons/Search';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport React, { useEffect, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport useDebounce from 'react-use/lib/useDebounce';\nimport { DocsResultListItem } from '../../components/DocsResultListItem';\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst TechDocsSearchBar = ({\n entityId,\n debounceTime = 150,\n}) => {\n const [open, setOpen] = useState(false);\n const navigate = useNavigate();\n const {\n term,\n setTerm,\n result: { loading, value: searchVal },\n } = useSearch();\n const [options, setOptions] = useState([]);\n useEffect(() => {\n let mounted = true;\n\n if (mounted && searchVal) {\n // TODO: Change this into getting only subset of search results from the BE in the first place\n // once pagination is implemented for search engines\n // See: https://github.com/backstage/backstage/issues/6062\n const searchResults = searchVal.results.slice(0, 10);\n setOptions(searchResults);\n }\n return () => {\n mounted = false;\n };\n }, [loading, searchVal]);\n\n const [value, setValue] = useState(term);\n\n useDebounce(() => setTerm(value), debounceTime, [value]);\n\n const handleQuery = (e) => {\n if (!open) {\n setOpen(true);\n }\n setValue(e.target.value);\n };\n\n const handleSelection = (_, selection) => {\n if (selection?.document) {\n const { location } = selection.document;\n navigate(location);\n }\n };\n\n return (\n React.createElement(Grid, { item: true, xs: 12,}\n , React.createElement(Autocomplete, {\n 'data-testid': \"techdocs-search-bar\",\n size: \"small\",\n open: open,\n getOptionLabel: () => '',\n filterOptions: x => {\n return x; // This is needed to get renderOption to be called after options change. Bug in material-ui?\n },\n onClose: () => {\n setOpen(false);\n },\n onFocus: () => {\n setOpen(true);\n },\n onChange: handleSelection,\n blurOnSelect: true,\n noOptionsText: \"No results found\" ,\n value: null,\n options: options,\n renderOption: ({ document }) => (\n React.createElement(DocsResultListItem, {\n result: document,\n lineClamp: 3,\n asListItem: false,\n asLink: false,\n title: document.title,}\n )\n ),\n loading: loading,\n renderInput: params => (\n React.createElement(TextField, {\n ...params,\n 'data-testid': \"techdocs-search-bar-input\",\n variant: \"outlined\",\n fullWidth: true,\n placeholder: `Search ${entityId.name} docs`,\n value: value,\n onChange: handleQuery,\n InputProps: {\n ...params.InputProps,\n startAdornment: (\n React.createElement(InputAdornment, { position: \"start\",}\n , React.createElement(IconButton, { 'aria-label': \"Query\", disabled: true,}\n , React.createElement(SearchIcon, null )\n )\n )\n ),\n endAdornment: (\n React.createElement(React.Fragment, null\n , loading ? (\n React.createElement(CircularProgress, { color: \"inherit\", size: 20,} )\n ) : null\n , params.InputProps.endAdornment\n )\n ),\n },}\n )\n ),}\n )\n )\n );\n};\n\nexport const TechDocsSearch = (props) => {\n const initialState = {\n term: '',\n types: ['techdocs'],\n pageCursor: '',\n filters: props.entityId,\n };\n return (\n React.createElement(SearchContextProvider, { initialState: initialState,}\n , React.createElement(TechDocsSearchBar, { ...props,} )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LogViewer } from '@backstage/core-components';\nimport {\n Button,\n createStyles,\n Drawer,\n Grid,\n IconButton,\n makeStyles,\n\n Typography,\n} from '@material-ui/core';\nimport Close from '@material-ui/icons/Close';\nimport React, { useState } from 'react';\n\nconst useDrawerStyles = makeStyles((theme) =>\n createStyles({\n paper: {\n width: '100%',\n [theme.breakpoints.up('sm')]: {\n width: '75%',\n },\n [theme.breakpoints.up('md')]: {\n width: '50%',\n },\n padding: theme.spacing(2.5),\n },\n root: {\n height: '100%',\n overflow: 'hidden',\n },\n logs: {\n background: theme.palette.background.default,\n },\n }),\n);\n\nexport const TechDocsBuildLogsDrawerContent = ({\n buildLog,\n onClose,\n}\n\n\n) => {\n const classes = useDrawerStyles();\n const logText =\n buildLog.length === 0 ? 'Waiting for logs...' : buildLog.join('\\n');\n return (\n React.createElement(Grid, {\n container: true,\n direction: \"column\",\n className: classes.root,\n spacing: 0,\n wrap: \"nowrap\",}\n \n , React.createElement(Grid, {\n item: true,\n container: true,\n justifyContent: \"space-between\",\n alignItems: \"center\",\n spacing: 0,\n wrap: \"nowrap\",}\n \n , React.createElement(Typography, { variant: \"h5\",}, \"Build Details\" )\n , React.createElement(IconButton, {\n key: \"dismiss\",\n title: \"Close the drawer\" ,\n onClick: onClose,\n color: \"inherit\",}\n \n , React.createElement(Close, null )\n )\n )\n , React.createElement(LogViewer, { text: logText, classes: { root: classes.logs },} )\n )\n );\n};\n\nexport const TechDocsBuildLogs = ({ buildLog }) => {\n const classes = useDrawerStyles();\n const [open, setOpen] = useState(false);\n\n return (\n React.createElement(React.Fragment, null\n , React.createElement(Button, { color: \"inherit\", onClick: () => setOpen(true),}, \"Show Build Logs\"\n\n )\n , React.createElement(Drawer, {\n classes: { paper: classes.paper },\n anchor: \"right\",\n open: open,\n onClose: () => setOpen(false),}\n \n , React.createElement(TechDocsBuildLogsDrawerContent, {\n buildLog: buildLog,\n onClose: () => setOpen(false),}\n )\n )\n )\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { Progress } from '@backstage/core-components';\nimport { CircularProgress, Button, makeStyles } from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\n\nimport { TechDocsBuildLogs } from './TechDocsBuildLogs';\nimport { TechDocsNotFound } from './TechDocsNotFound';\nimport { useTechDocsReader } from './Reader';\n\nconst useStyles = makeStyles(() => ({\n message: {\n // `word-break: break-word` is deprecated, but gives legacy support to browsers not supporting `overflow-wrap` yet\n // https://developer.mozilla.org/en-US/docs/Web/CSS/word-break\n wordBreak: 'break-word',\n overflowWrap: 'anywhere',\n },\n}));\n\n/**\n * Note: this component is currently being exported so that we can rapidly\n * iterate on alternative <Reader /> implementations that extend core\n * functionality. There is no guarantee that this component will continue to be\n * exported by the package in the future!\n *\n * todo: Make public or stop exporting (ctrl+f \"altReaderExperiments\")\n * @internal\n */\nexport const TechDocsStateIndicator = () => {\n let StateAlert = null;\n const classes = useStyles();\n\n const {\n state,\n contentReload,\n contentErrorMessage,\n syncErrorMessage,\n buildLog,\n } = useTechDocsReader();\n\n const ReaderProgress = state === 'CHECKING' ? React.createElement(Progress, null ) : null;\n\n if (state === 'INITIAL_BUILD') {\n StateAlert = (\n React.createElement(Alert, {\n variant: \"outlined\",\n severity: \"info\",\n icon: React.createElement(CircularProgress, { size: \"24px\",} ),\n action: React.createElement(TechDocsBuildLogs, { buildLog: buildLog,} ),}\n , \"Documentation is accessed for the first time and is being prepared. The subsequent loads are much faster.\"\n\n\n )\n );\n }\n\n if (state === 'CONTENT_STALE_REFRESHING') {\n StateAlert = (\n React.createElement(Alert, {\n variant: \"outlined\",\n severity: \"info\",\n icon: React.createElement(CircularProgress, { size: \"24px\",} ),\n action: React.createElement(TechDocsBuildLogs, { buildLog: buildLog,} ),}\n , \"A newer version of this documentation is being prepared and will be available shortly.\"\n\n\n )\n );\n }\n\n if (state === 'CONTENT_STALE_READY') {\n StateAlert = (\n React.createElement(Alert, {\n variant: \"outlined\",\n severity: \"success\",\n action: \n React.createElement(Button, { color: \"inherit\", onClick: () => contentReload(),}, \"Refresh\"\n\n )\n ,}\n , \"A newer version of this documentation is now available, please refresh to view.\"\n\n\n )\n );\n }\n\n if (state === 'CONTENT_STALE_ERROR') {\n StateAlert = (\n React.createElement(Alert, {\n variant: \"outlined\",\n severity: \"error\",\n action: React.createElement(TechDocsBuildLogs, { buildLog: buildLog,} ),\n classes: { message: classes.message },}\n , \"Building a newer version of this documentation failed.\"\n , ' '\n , syncErrorMessage\n )\n );\n }\n\n if (state === 'CONTENT_NOT_FOUND') {\n StateAlert = (\n React.createElement(React.Fragment, null\n , syncErrorMessage && (\n React.createElement(Alert, {\n variant: \"outlined\",\n severity: \"error\",\n action: React.createElement(TechDocsBuildLogs, { buildLog: buildLog,} ),\n classes: { message: classes.message },}\n , \"Building a newer version of this documentation failed.\"\n , ' '\n , syncErrorMessage\n )\n )\n , React.createElement(TechDocsNotFound, { errorMessage: contentErrorMessage,} )\n )\n );\n }\n\n return (\n React.createElement(React.Fragment, null\n , ReaderProgress\n , StateAlert\n )\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'techdocs:index-page',\n});\n\nexport const rootDocsRouteRef = createRouteRef({\n id: 'techdocs:reader-page',\n params: ['namespace', 'kind', 'name'],\n});\n\nexport const rootCatalogDocsRouteRef = createRouteRef({\n id: 'techdocs:catalog-reader-view',\n});\n"],"sourceRoot":""}