@trismegisto/spine 3.3.1 → 3.3.3

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 (31) hide show
  1. package/fesm2022/trismegisto-spine-auto-service-auto-service-suggestions-page.component-mMjE3JOL.mjs +2179 -0
  2. package/fesm2022/trismegisto-spine-auto-service-auto-service-suggestions-page.component-mMjE3JOL.mjs.map +1 -0
  3. package/fesm2022/{trismegisto-spine-auto-service-home.component-rQ3dIGIE.mjs → trismegisto-spine-auto-service-home.component-9WvXOH3l.mjs} +7 -4
  4. package/fesm2022/trismegisto-spine-auto-service-home.component-9WvXOH3l.mjs.map +1 -0
  5. package/fesm2022/trismegisto-spine-auto-service.mjs +2 -2
  6. package/fesm2022/trismegisto-spine-graphql.mjs +3 -1
  7. package/fesm2022/trismegisto-spine-graphql.mjs.map +1 -1
  8. package/fesm2022/trismegisto-spine-layout-suggestions-page.component-xI2gDMok.mjs +532 -0
  9. package/fesm2022/trismegisto-spine-layout-suggestions-page.component-xI2gDMok.mjs.map +1 -0
  10. package/fesm2022/trismegisto-spine-layout-trismegisto-spine-layout-Clphrsgc.mjs +8429 -0
  11. package/fesm2022/trismegisto-spine-layout-trismegisto-spine-layout-Clphrsgc.mjs.map +1 -0
  12. package/fesm2022/trismegisto-spine-layout.mjs +1 -7651
  13. package/fesm2022/trismegisto-spine-layout.mjs.map +1 -1
  14. package/fesm2022/trismegisto-spine-notification.mjs +1 -1
  15. package/fesm2022/trismegisto-spine-notification.mjs.map +1 -1
  16. package/fesm2022/trismegisto-spine-routing.mjs +16 -3
  17. package/fesm2022/trismegisto-spine-routing.mjs.map +1 -1
  18. package/fesm2022/trismegisto-spine-shell.mjs +4 -2
  19. package/fesm2022/trismegisto-spine-shell.mjs.map +1 -1
  20. package/fesm2022/trismegisto-spine.mjs +286 -29
  21. package/fesm2022/trismegisto-spine.mjs.map +1 -1
  22. package/package.json +6 -6
  23. package/types/trismegisto-spine-layout.d.ts +879 -20
  24. package/types/trismegisto-spine-layout.d.ts.map +1 -1
  25. package/types/trismegisto-spine-routing.d.ts.map +1 -1
  26. package/types/trismegisto-spine-shell.d.ts.map +1 -1
  27. package/types/trismegisto-spine.d.ts +130 -12
  28. package/types/trismegisto-spine.d.ts.map +1 -1
  29. package/fesm2022/trismegisto-spine-auto-service-auto-service-suggestions-page.component-DIeunpQ9.mjs +0 -2123
  30. package/fesm2022/trismegisto-spine-auto-service-auto-service-suggestions-page.component-DIeunpQ9.mjs.map +0 -1
  31. package/fesm2022/trismegisto-spine-auto-service-home.component-rQ3dIGIE.mjs.map +0 -1
@@ -7,7 +7,7 @@ import { ViewService, AuthorizationService } from '@orfeu/angular/core';
7
7
  import { IconButtonComponent, IconComponent, MenuButtonComponent, StatePageComponent } from '@trismegisto/angular';
8
8
  import { pluralMessage, formatMessage } from '@trismegisto/primitives';
9
9
  import { spineRoutesOf, SpineQuickAccessService, SPINE_MESSAGES } from '@trismegisto/spine';
10
- import { SpineDocsService, SpineSettingsService, SpineNewsService, ShortcutService, SpineInitialSetupService } from '@trismegisto/spine/layout';
10
+ import { SpineDocsService, SpineSettingsService, SpineNewsService, spineSuggestionsEnabled, SPINE_SUGGESTIONS_PAGE_PATH, ShortcutService, SpineInitialSetupService } from '@trismegisto/spine/layout';
11
11
  import { map } from 'rxjs';
12
12
  import { AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID, AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID, AUTO_SERVICE_LOGIN_ATTEMPTS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_NEWS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_SUGGESTIONS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_RATINGS_TEMPLATE_ROUTER_ID, AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID } from './trismegisto-spine-auto-service.mjs';
13
13
 
@@ -159,6 +159,9 @@ class HomeComponent {
159
159
  this.autoRedirect = inject(HomeAutoRedirect);
160
160
  this.messages = inject(SPINE_MESSAGES);
161
161
  this.t = this.messages.home;
162
+ /** "Sugestões do app" em Ajuda e recursos, só com o recurso ligado (o mesmo nome da página). */
163
+ this.suggestions = spineSuggestionsEnabled() ? this.messages.suggestions.page.title : null;
164
+ this.suggestionsPath = SPINE_SUGGESTIONS_PAGE_PATH;
162
165
  this.uid = `home-${++instances}`;
163
166
  this.view = inject(ViewService);
164
167
  this.tree = toSignal(this.view.currentView$.pipe(map(cleanTree)), {
@@ -304,12 +307,12 @@ class HomeComponent {
304
307
  return text.charAt(0).toLocaleUpperCase(locale) + text.slice(1);
305
308
  }
306
309
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HomeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
307
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: HomeComponent, isStandalone: true, selector: "home", ngImport: i0, template: "@if (noAccess()) {\n <hm-state-page kind=\"no-rights\" [heading]=\"t.noAccessTitle\" [description]=\"t.noAccessText\" action=\"\" />\n} @else {\n <div class=\"home\">\n <!-- Sauda\u00E7\u00E3o \u00E0 esquerda; as novidades, quando houver, ocupam o espa\u00E7o \u00E0 direita dela. -->\n <div class=\"hero\">\n <div class=\"hero__text\">\n <p class=\"hero__greeting\">{{ greeting }}</p>\n <p class=\"hero__intro\">{{ t.intro }}</p>\n </div>\n @if (newsRows().length) {\n <!-- Compacto: cabe\u00E7alho numa linha e cada novidade numa linha s\u00F3 (t\u00EDtulo e o come\u00E7o do texto). -->\n <section class=\"card card--compact hero__news\" [attr.aria-labelledby]=\"uid + '-news'\">\n <div class=\"card__head\">\n <span class=\"card__heading\">\n <h2 class=\"card__title\" [id]=\"uid + '-news'\">{{ t.news }}</h2>\n <span class=\"badge\">{{ t.newsBadge }}</span>\n </span>\n <button type=\"button\" class=\"more\" (click)=\"openNews()\">{{ t.newsAll }}</button>\n </div>\n <ul class=\"list\">\n @for (entry of newsRows(); track entry.id) {\n <li>\n <button type=\"button\" class=\"news\" [title]=\"entry.title + ' \u2014 ' + entry.text\" (click)=\"openNews(entry.id)\">\n <span class=\"news__dot\" [class.news__dot--seen]=\"!entry.unseen\" aria-hidden=\"true\"></span>\n <span class=\"news__title\">{{ entry.title }}</span>\n <span class=\"news__body\">{{ entry.text }}</span>\n </button>\n </li>\n }\n </ul>\n </section>\n }\n </div>\n\n <!-- Atalhos de trabalho e privilegiados dividem a mesma linha (cada grupo na propor\u00E7\u00E3o dos seus atalhos). -->\n @if (workTiles().length || adminTiles().length) {\n <div class=\"shortcuts\">\n @if (workTiles().length) {\n <section class=\"block shortcuts__group\" [style.--tiles]=\"workTiles().length\" [attr.aria-labelledby]=\"uid + '-work'\">\n <h2 class=\"block__title\" [id]=\"uid + '-work'\">{{ descended() ? t.yourScreens : t.modules }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: workTiles(), admin: false }\" />\n </section>\n }\n @if (adminTiles().length) {\n <section class=\"block shortcuts__group\" [style.--tiles]=\"adminTiles().length\" [attr.aria-labelledby]=\"uid + '-admin'\">\n <h2 class=\"block__title\" [id]=\"uid + '-admin'\">{{ t.privileged }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: adminTiles(), admin: true }\" />\n </section>\n }\n </div>\n }\n\n <!-- Linha 1: o que a pessoa usa (recentes | favoritos). Linha 2: o resto do sistema (m\u00F3dulos | ajuda).\n Sem um dos lados, o outro ocupa a linha inteira. -->\n <div class=\"pair\">\n @if (recentRows().length) {\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-recent'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-recent'\">{{ t.recent }}</h2>\n @if (moreRecents()) {\n <button type=\"button\" class=\"more\" [attr.aria-expanded]=\"showAllRecents()\" (click)=\"showAllRecents.set(!showAllRecents())\">\n {{ showAllRecents() ? t.seeLess : t.seeAll }}\n </button>\n }\n </div>\n <ul class=\"list\" [attr.aria-label]=\"t.recentCaption\">\n @for (item of recentRows(); track item.id) {\n <li class=\"recent\">\n <button type=\"button\" class=\"recent__open\" (click)=\"go(item.redirect)\">\n <hm-icon class=\"recent__icon\" [shape]=\"item.icon || 'grid-layout'\" />\n <span class=\"recent__name\">{{ item.displayName }}</span>\n <span class=\"recent__where\">{{ item.where }}</span>\n @if (item.when) {\n <span class=\"recent__when\">{{ item.when }}</span>\n }\n </button>\n <hm-icon-button\n emphasis=\"subtle\"\n size=\"small\"\n icon=\"heart\"\n [solid]=\"isFavorite(item.id)\"\n [class.heart--on]=\"isFavorite(item.id)\"\n [label]=\"favoriteLabel(item)\"\n (clicked)=\"toggleFavorite(item)\"\n />\n <hm-menu-button\n class=\"recent__menu\"\n icon=\"ellipsis-vertical\"\n shape=\"circle\"\n size=\"small\"\n align=\"end\"\n [showArrow]=\"false\"\n [label]=\"recentMenuLabel(item)\"\n [items]=\"recentMenu\"\n (chosen)=\"onRecentMenu(item, $event)\"\n />\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-fav'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-fav'\">{{ t.favorites }}</h2>\n @if (moreFavorites()) {\n <button type=\"button\" class=\"more\" [attr.aria-expanded]=\"showAllFavorites()\" (click)=\"showAllFavorites.set(!showAllFavorites())\">\n {{ showAllFavorites() ? t.seeLess : t.seeAll }}\n </button>\n }\n </div>\n @if (visibleFavorites().length) {\n <ul class=\"list\">\n @for (fav of visibleFavorites(); track fav.id) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(fav.redirect)\">\n <hm-icon class=\"row__icon\" [shape]=\"fav.icon || 'grid-layout'\" />\n <span class=\"row__name\">{{ fav.displayName }}</span>\n <span class=\"row__meta\">{{ whereOf(fav) }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n </ul>\n } @else {\n <p class=\"card__empty\">{{ t.favoritesEmpty }}</p>\n }\n </section>\n </div>\n\n <div class=\"pair\">\n @if (systems().length) {\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-systems'\">\n <div class=\"card__head card__head--stacked\">\n <h2 class=\"card__title\" [id]=\"uid + '-systems'\">{{ t.explore }}</h2>\n <p class=\"card__intro\">{{ t.exploreIntro }}</p>\n </div>\n <ul class=\"systems\">\n @for (system of systems(); track system.id) {\n <!-- O card inteiro abre o m\u00F3dulo (como os atalhos): uma seta no canto, sem link pr\u00F3prio. -->\n <li class=\"systems__cell\">\n <button type=\"button\" class=\"system\" (click)=\"go(system.redirect)\">\n <span class=\"system__head\">\n <hm-icon class=\"system__icon\" [shape]=\"system.icon\" size=\"lg\" />\n <span class=\"system__name\" [title]=\"system.label\">{{ system.label }}</span>\n <span class=\"badge badge--neutral\">{{ system.count }}</span>\n <hm-icon class=\"system__chevron\" shape=\"angle-right\" size=\"sm\" />\n </span>\n @if (system.description) {\n <span class=\"system__description\">{{ system.description }}</span>\n }\n @if (system.chips.length) {\n <span class=\"system__chips\">\n @for (chip of system.chips; track chip) {\n <span class=\"system__chip\">{{ chip }}</span>\n }\n </span>\n }\n </button>\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-help'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-help'\">{{ t.help }}</h2>\n </div>\n <ul class=\"list\">\n @for (area of areas(); track area.routed_id) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(area.route_redirect)\">\n <hm-icon class=\"row__icon\" [shape]=\"area.route_icon || 'home'\" />\n <span class=\"row__name\">{{ area.route_display_name }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openDocs()\">\n <hm-icon class=\"row__icon\" shape=\"book\" />\n <span class=\"row__name\">{{ t.systemDocs }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openShortcuts()\">\n <hm-icon class=\"row__icon\" shape=\"keyboard\" />\n <span class=\"row__name\">{{ t.shortcuts }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openEssentials()\">\n <hm-icon class=\"row__icon\" shape=\"help\" />\n <span class=\"row__name\">{{ t.essentials }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openSettings()\">\n <hm-icon class=\"row__icon\" shape=\"cog\" />\n <span class=\"row__name\">{{ t.settings }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n </ul>\n </section>\n </div>\n </div>\n}\n\n<ng-template #tileGrid let-tiles let-admin=\"admin\">\n <ul class=\"tiles\" [class.tiles--admin]=\"admin\">\n @for (tile of tiles; track tile.id; let i = $index) {\n <li class=\"tiles__cell\" [style.--tile-order]=\"i\">\n <button type=\"button\" class=\"tile\" (click)=\"go(tile.redirect)\">\n <hm-icon class=\"tile__icon\" [shape]=\"tile.icon ?? 'grid-layout'\" size=\"lg\" />\n <span class=\"tile__text\">\n <span class=\"tile__label\">{{ tile.label }}</span>\n @if (caption(tile); as meta) {\n <span class=\"tile__meta\">{{ meta }}</span>\n }\n </span>\n <hm-icon class=\"tile__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n </ul>\n</ng-template>\n", styles: [":host{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:100%;min-inline-size:0}hm-state-page{flex:1 1 auto}ul{margin:0;padding:0;list-style:none}p{margin:0}.home{container-type:inline-size;display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.hero{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--hm-space-md)}.hero__text{display:flex;flex:1 1 20rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.hero__news{flex:0 1 32rem;min-inline-size:min(100%,20rem)}.hero__greeting{color:var(--hm-text);font-size:var(--hm-font-size-xxl);font-weight:var(--hm-font-weight-bold);line-height:var(--hm-line-height-tight)}.hero__intro{color:var(--hm-muted);font-size:var(--hm-font-size-md)}.block{display:flex;flex-direction:column;gap:var(--hm-space-sm);min-inline-size:0}.block__title{margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.news,.row,.system,.recent__open,.more,.tile{display:flex;align-items:center;gap:var(--hm-space-sm);border:var(--hm-border-hairline) solid transparent;border-radius:var(--hm-radius-control);background:transparent;color:var(--hm-text);font:inherit;text-align:start;cursor:pointer;transition:background-color var(--hm-duration-quick) var(--hm-ease-standard),border-color var(--hm-duration-quick) var(--hm-ease-standard)}.news:hover,.row:hover,.system:hover,.recent__open:hover,.more:hover,.tile:hover{background:var(--hm-hover)}.news:focus-visible,.row:focus-visible,.system:focus-visible,.recent__open:focus-visible,.more:focus-visible,.tile:focus-visible{outline:var(--hm-border-thin) solid var(--hm-accent);outline-offset:2px}@media(forced-colors:active){.news,.row,.system,.recent__open,.more,.tile{border-color:ButtonText}.news:focus-visible,.row:focus-visible,.system:focus-visible,.recent__open:focus-visible,.more:focus-visible,.tile:focus-visible{outline-color:Highlight}}.shortcuts{display:flex;flex-wrap:wrap;gap:var(--hm-space-md)}.shortcuts__group{flex:var(--tiles, 1) 1 calc(var(--tiles, 1) * 13rem + (var(--tiles, 1) - 1) * var(--hm-space-sm))}.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,13rem),1fr));gap:var(--hm-space-sm)}.tiles__cell{display:flex}.tile{flex:1 1 auto;gap:var(--hm-space-md);padding:var(--hm-space-md);border-color:var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.tile:hover{border-color:var(--hm-accent);background:var(--hm-surface-raised)}.tile__icon{flex:none;color:var(--hm-accent)}.tiles--admin .tile__icon{color:var(--hm-warning)}.tile__text{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--hm-space-nano);min-inline-size:0}.tile__label{font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold);overflow-wrap:anywhere}.tile__meta{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.tile__chevron,.row__chevron{flex:none;color:var(--hm-muted)}@media(prefers-reduced-motion:no-preference){.tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}}:host-context([data-motion=full]) .tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}:host-context([data-motion=reduce]) .tiles__cell{animation:none}@keyframes tile-in{0%{opacity:0;transform:translateY(var(--hm-space-xs))}}.pair{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:var(--hm-space-md);align-items:stretch}.pair>:only-child{grid-column:1/-1}.stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.stack>.card:last-child{flex:1 1 auto}@container (max-width: 56rem){.pair{grid-template-columns:minmax(0,1fr)}}.card{display:flex;flex-direction:column;gap:var(--hm-space-sm);min-inline-size:0;padding:var(--hm-space-md);border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.card__head{display:flex;align-items:center;justify-content:space-between;gap:var(--hm-space-sm)}.card__head--stacked{flex-direction:column;align-items:flex-start;gap:var(--hm-space-micro)}.card__heading{display:flex;align-items:center;gap:var(--hm-space-xs)}.card__title{margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.card__intro,.card__empty{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.more{flex:none;padding:var(--hm-space-nano) var(--hm-space-xs);color:var(--hm-accent);font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-medium)}.badge{flex:none;padding:var(--hm-space-nano) var(--hm-space-xs);border-radius:var(--hm-radius-micro);background:var(--hm-accent-subtle);color:var(--hm-accent);font-size:var(--hm-font-size-3xs);font-weight:var(--hm-font-weight-semibold);letter-spacing:.04em;text-transform:uppercase}.badge--neutral{background:var(--hm-surface-muted);color:var(--hm-muted);letter-spacing:normal;text-transform:none}.card--compact{gap:var(--hm-space-micro);padding:var(--hm-space-sm) var(--hm-space-md)}.recent{display:flex;align-items:center;gap:var(--hm-space-micro)}.recent__open{flex:1 1 auto;min-inline-size:0;padding:var(--hm-space-nano) var(--hm-space-xs)}.recent__icon{flex:none;color:var(--hm-accent)}.recent__name{flex:none;max-inline-size:50%;overflow:hidden;font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.recent__where{flex:1 1 auto;min-inline-size:0;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}.recent__when{flex:none;color:var(--hm-muted);font-size:var(--hm-font-size-xs);white-space:nowrap}.heart--on{color:var(--hm-danger)}.systems{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,14rem),1fr));gap:var(--hm-space-sm)}.systems__cell{display:flex}.system{flex:1 1 auto;flex-direction:column;align-items:stretch;gap:var(--hm-space-xs);padding:var(--hm-space-sm) var(--hm-space-md);border-color:var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.system:hover{border-color:var(--hm-accent);background:var(--hm-surface-raised)}.system__head{display:flex;align-items:center;gap:var(--hm-space-sm);min-inline-size:0}.system__icon{flex:none;color:var(--hm-accent)}.system__name{min-inline-size:0;overflow:hidden;font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.system__chevron{flex:none;margin-inline-start:auto;color:var(--hm-muted)}.system__description{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.system__chips{display:flex;flex-wrap:wrap;gap:var(--hm-space-micro)}.system__chip{padding:var(--hm-space-nano) var(--hm-space-xs);border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-pill);background:var(--hm-surface-muted);color:var(--hm-text);font-size:var(--hm-font-size-xs)}.list{display:flex;flex-direction:column}.list>li+li{border-block-start:var(--hm-border-hairline) solid var(--hm-divider)}.row{inline-size:100%;padding:var(--hm-space-nano) var(--hm-space-xs)}.row__icon{flex:none;color:var(--hm-muted)}.row__name{flex:1 1 auto;min-inline-size:0;overflow:hidden;font-size:var(--hm-font-size-sm);text-overflow:ellipsis;white-space:nowrap}.row__meta{flex:0 1 auto;min-inline-size:0;max-inline-size:45%;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}.news{inline-size:100%;gap:var(--hm-space-xs);padding:var(--hm-space-nano) var(--hm-space-xs)}.news__dot{flex:none;inline-size:var(--hm-space-xs);block-size:var(--hm-space-xs);border-radius:var(--hm-radius-pill);background:var(--hm-accent)}.news__dot--seen{background:var(--hm-divider)}.news__title{flex:none;max-inline-size:50%;overflow:hidden;font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.news__body{flex:1 1 auto;min-inline-size:0;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconButtonComponent, selector: "hm-icon-button", inputs: ["label", "icon", "solid", "iconDirection", "emphasis", "intent", "size", "disabled", "toggle", "pressed", "keyShortcuts"], outputs: ["pressedChange", "clicked"] }, { kind: "component", type: IconComponent, selector: "hm-icon", inputs: ["shape", "direction", "size", "solid", "badge", "status", "flip", "inverse", "label"] }, { kind: "component", type: MenuButtonComponent, selector: "hm-menu-button", inputs: ["label", "icon", "items", "showArrow", "align", "side", "size", "shape", "layer", "closeOnCheck", "disabled"], outputs: ["chosen", "checkedChange"] }, { kind: "component", type: StatePageComponent, selector: "hm-state-page", inputs: ["kind", "heading", "description", "action", "actionIcon"], outputs: ["actionTriggered"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
310
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: HomeComponent, isStandalone: true, selector: "home", ngImport: i0, template: "@if (noAccess()) {\n <hm-state-page kind=\"no-rights\" [heading]=\"t.noAccessTitle\" [description]=\"t.noAccessText\" action=\"\" />\n} @else {\n <div class=\"home\">\n <!-- Sauda\u00E7\u00E3o \u00E0 esquerda; as novidades, quando houver, ocupam o espa\u00E7o \u00E0 direita dela. -->\n <div class=\"hero\">\n <div class=\"hero__text\">\n <p class=\"hero__greeting\">{{ greeting }}</p>\n <p class=\"hero__intro\">{{ t.intro }}</p>\n </div>\n @if (newsRows().length) {\n <!-- Compacto: cabe\u00E7alho numa linha e cada novidade numa linha s\u00F3 (t\u00EDtulo e o come\u00E7o do texto). -->\n <section class=\"card card--compact hero__news\" [attr.aria-labelledby]=\"uid + '-news'\">\n <div class=\"card__head\">\n <span class=\"card__heading\">\n <h2 class=\"card__title\" [id]=\"uid + '-news'\">{{ t.news }}</h2>\n <span class=\"badge\">{{ t.newsBadge }}</span>\n </span>\n <button type=\"button\" class=\"more\" (click)=\"openNews()\">{{ t.newsAll }}</button>\n </div>\n <ul class=\"list\">\n @for (entry of newsRows(); track entry.id) {\n <li>\n <button type=\"button\" class=\"news\" [title]=\"entry.title + ' \u2014 ' + entry.text\" (click)=\"openNews(entry.id)\">\n <span class=\"news__dot\" [class.news__dot--seen]=\"!entry.unseen\" aria-hidden=\"true\"></span>\n <span class=\"news__title\">{{ entry.title }}</span>\n <span class=\"news__body\">{{ entry.text }}</span>\n </button>\n </li>\n }\n </ul>\n </section>\n }\n </div>\n\n <!-- Atalhos de trabalho e privilegiados dividem a mesma linha (cada grupo na propor\u00E7\u00E3o dos seus atalhos). -->\n @if (workTiles().length || adminTiles().length) {\n <div class=\"shortcuts\">\n @if (workTiles().length) {\n <section class=\"block shortcuts__group\" [style.--tiles]=\"workTiles().length\" [attr.aria-labelledby]=\"uid + '-work'\">\n <h2 class=\"block__title\" [id]=\"uid + '-work'\">{{ descended() ? t.yourScreens : t.modules }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: workTiles(), admin: false }\" />\n </section>\n }\n @if (adminTiles().length) {\n <section class=\"block shortcuts__group\" [style.--tiles]=\"adminTiles().length\" [attr.aria-labelledby]=\"uid + '-admin'\">\n <h2 class=\"block__title\" [id]=\"uid + '-admin'\">{{ t.privileged }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: adminTiles(), admin: true }\" />\n </section>\n }\n </div>\n }\n\n <!-- Linha 1: o que a pessoa usa (recentes | favoritos). Linha 2: o resto do sistema (m\u00F3dulos | ajuda).\n Sem um dos lados, o outro ocupa a linha inteira. -->\n <div class=\"pair\">\n @if (recentRows().length) {\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-recent'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-recent'\">{{ t.recent }}</h2>\n @if (moreRecents()) {\n <button type=\"button\" class=\"more\" [attr.aria-expanded]=\"showAllRecents()\" (click)=\"showAllRecents.set(!showAllRecents())\">\n {{ showAllRecents() ? t.seeLess : t.seeAll }}\n </button>\n }\n </div>\n <ul class=\"list\" [attr.aria-label]=\"t.recentCaption\">\n @for (item of recentRows(); track item.id) {\n <li class=\"recent\">\n <button type=\"button\" class=\"recent__open\" (click)=\"go(item.redirect)\">\n <hm-icon class=\"recent__icon\" [shape]=\"item.icon || 'grid-layout'\" />\n <span class=\"recent__name\">{{ item.displayName }}</span>\n <span class=\"recent__where\">{{ item.where }}</span>\n @if (item.when) {\n <span class=\"recent__when\">{{ item.when }}</span>\n }\n </button>\n <hm-icon-button\n emphasis=\"subtle\"\n size=\"small\"\n icon=\"heart\"\n [solid]=\"isFavorite(item.id)\"\n [class.heart--on]=\"isFavorite(item.id)\"\n [label]=\"favoriteLabel(item)\"\n (clicked)=\"toggleFavorite(item)\"\n />\n <hm-menu-button\n class=\"recent__menu\"\n icon=\"ellipsis-vertical\"\n shape=\"circle\"\n size=\"small\"\n align=\"end\"\n [showArrow]=\"false\"\n [label]=\"recentMenuLabel(item)\"\n [items]=\"recentMenu\"\n (chosen)=\"onRecentMenu(item, $event)\"\n />\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-fav'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-fav'\">{{ t.favorites }}</h2>\n @if (moreFavorites()) {\n <button type=\"button\" class=\"more\" [attr.aria-expanded]=\"showAllFavorites()\" (click)=\"showAllFavorites.set(!showAllFavorites())\">\n {{ showAllFavorites() ? t.seeLess : t.seeAll }}\n </button>\n }\n </div>\n @if (visibleFavorites().length) {\n <ul class=\"list\">\n @for (fav of visibleFavorites(); track fav.id) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(fav.redirect)\">\n <hm-icon class=\"row__icon\" [shape]=\"fav.icon || 'grid-layout'\" />\n <span class=\"row__name\">{{ fav.displayName }}</span>\n <span class=\"row__meta\">{{ whereOf(fav) }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n </ul>\n } @else {\n <p class=\"card__empty\">{{ t.favoritesEmpty }}</p>\n }\n </section>\n </div>\n\n <div class=\"pair\">\n @if (systems().length) {\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-systems'\">\n <div class=\"card__head card__head--stacked\">\n <h2 class=\"card__title\" [id]=\"uid + '-systems'\">{{ t.explore }}</h2>\n <p class=\"card__intro\">{{ t.exploreIntro }}</p>\n </div>\n <ul class=\"systems\">\n @for (system of systems(); track system.id) {\n <!-- O card inteiro abre o m\u00F3dulo (como os atalhos): uma seta no canto, sem link pr\u00F3prio. -->\n <li class=\"systems__cell\">\n <button type=\"button\" class=\"system\" (click)=\"go(system.redirect)\">\n <span class=\"system__head\">\n <hm-icon class=\"system__icon\" [shape]=\"system.icon\" size=\"lg\" />\n <span class=\"system__name\" [title]=\"system.label\">{{ system.label }}</span>\n <span class=\"badge badge--neutral\">{{ system.count }}</span>\n <hm-icon class=\"system__chevron\" shape=\"angle-right\" size=\"sm\" />\n </span>\n @if (system.description) {\n <span class=\"system__description\">{{ system.description }}</span>\n }\n @if (system.chips.length) {\n <span class=\"system__chips\">\n @for (chip of system.chips; track chip) {\n <span class=\"system__chip\">{{ chip }}</span>\n }\n </span>\n }\n </button>\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-help'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-help'\">{{ t.help }}</h2>\n </div>\n <ul class=\"list\">\n @for (area of areas(); track area.routed_id) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(area.route_redirect)\">\n <hm-icon class=\"row__icon\" [shape]=\"area.route_icon || 'home'\" />\n <span class=\"row__name\">{{ area.route_display_name }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openDocs()\">\n <hm-icon class=\"row__icon\" shape=\"book\" />\n <span class=\"row__name\">{{ t.systemDocs }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n @if (suggestions) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(suggestionsPath)\">\n <hm-icon class=\"row__icon\" shape=\"lightbulb\" />\n <span class=\"row__name\">{{ suggestions }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openShortcuts()\">\n <hm-icon class=\"row__icon\" shape=\"keyboard\" />\n <span class=\"row__name\">{{ t.shortcuts }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openEssentials()\">\n <hm-icon class=\"row__icon\" shape=\"help\" />\n <span class=\"row__name\">{{ t.essentials }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openSettings()\">\n <hm-icon class=\"row__icon\" shape=\"cog\" />\n <span class=\"row__name\">{{ t.settings }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n </ul>\n </section>\n </div>\n </div>\n}\n\n<ng-template #tileGrid let-tiles let-admin=\"admin\">\n <ul class=\"tiles\" [class.tiles--admin]=\"admin\">\n @for (tile of tiles; track tile.id; let i = $index) {\n <li class=\"tiles__cell\" [style.--tile-order]=\"i\">\n <button type=\"button\" class=\"tile\" (click)=\"go(tile.redirect)\">\n <hm-icon class=\"tile__icon\" [shape]=\"tile.icon ?? 'grid-layout'\" size=\"lg\" />\n <span class=\"tile__text\">\n <span class=\"tile__label\">{{ tile.label }}</span>\n @if (caption(tile); as meta) {\n <span class=\"tile__meta\">{{ meta }}</span>\n }\n </span>\n <hm-icon class=\"tile__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n </ul>\n</ng-template>\n", styles: [":host{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:100%;min-inline-size:0}hm-state-page{flex:1 1 auto}ul{margin:0;padding:0;list-style:none}p{margin:0}.home{container-type:inline-size;display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.hero{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--hm-space-md)}.hero__text{display:flex;flex:1 1 20rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.hero__news{flex:0 1 32rem;min-inline-size:min(100%,20rem)}.hero__greeting{color:var(--hm-text);font-size:var(--hm-font-size-xxl);font-weight:var(--hm-font-weight-bold);line-height:var(--hm-line-height-tight)}.hero__intro{color:var(--hm-muted);font-size:var(--hm-font-size-md)}.block{display:flex;flex-direction:column;gap:var(--hm-space-sm);min-inline-size:0}.block__title{margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.news,.row,.system,.recent__open,.more,.tile{display:flex;align-items:center;gap:var(--hm-space-sm);border:var(--hm-border-hairline) solid transparent;border-radius:var(--hm-radius-control);background:transparent;color:var(--hm-text);font:inherit;text-align:start;cursor:pointer;transition:background-color var(--hm-duration-quick) var(--hm-ease-standard),border-color var(--hm-duration-quick) var(--hm-ease-standard)}.news:hover,.row:hover,.system:hover,.recent__open:hover,.more:hover,.tile:hover{background:var(--hm-hover)}.news:focus-visible,.row:focus-visible,.system:focus-visible,.recent__open:focus-visible,.more:focus-visible,.tile:focus-visible{outline:var(--hm-border-thin) solid var(--hm-accent);outline-offset:2px}@media(forced-colors:active){.news,.row,.system,.recent__open,.more,.tile{border-color:ButtonText}.news:focus-visible,.row:focus-visible,.system:focus-visible,.recent__open:focus-visible,.more:focus-visible,.tile:focus-visible{outline-color:Highlight}}.shortcuts{display:flex;flex-wrap:wrap;gap:var(--hm-space-md)}.shortcuts__group{flex:var(--tiles, 1) 1 calc(var(--tiles, 1) * 13rem + (var(--tiles, 1) - 1) * var(--hm-space-sm))}.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,13rem),1fr));gap:var(--hm-space-sm)}.tiles__cell{display:flex}.tile{flex:1 1 auto;gap:var(--hm-space-md);padding:var(--hm-space-md);border-color:var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.tile:hover{border-color:var(--hm-accent);background:var(--hm-surface-raised)}.tile__icon{flex:none;color:var(--hm-accent)}.tiles--admin .tile__icon{color:var(--hm-warning)}.tile__text{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--hm-space-nano);min-inline-size:0}.tile__label{font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold);overflow-wrap:anywhere}.tile__meta{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.tile__chevron,.row__chevron{flex:none;color:var(--hm-muted)}@media(prefers-reduced-motion:no-preference){.tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}}:host-context([data-motion=full]) .tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}:host-context([data-motion=reduce]) .tiles__cell{animation:none}@keyframes tile-in{0%{opacity:0;transform:translateY(var(--hm-space-xs))}}.pair{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:var(--hm-space-md);align-items:stretch}.pair>:only-child{grid-column:1/-1}.stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.stack>.card:last-child{flex:1 1 auto}@container (max-width: 56rem){.pair{grid-template-columns:minmax(0,1fr)}}.card{display:flex;flex-direction:column;gap:var(--hm-space-sm);min-inline-size:0;padding:var(--hm-space-md);border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.card__head{display:flex;align-items:center;justify-content:space-between;gap:var(--hm-space-sm)}.card__head--stacked{flex-direction:column;align-items:flex-start;gap:var(--hm-space-micro)}.card__heading{display:flex;align-items:center;gap:var(--hm-space-xs)}.card__title{margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.card__intro,.card__empty{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.more{flex:none;padding:var(--hm-space-nano) var(--hm-space-xs);color:var(--hm-accent);font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-medium)}.badge{flex:none;padding:var(--hm-space-nano) var(--hm-space-xs);border-radius:var(--hm-radius-micro);background:var(--hm-accent-subtle);color:var(--hm-accent);font-size:var(--hm-font-size-3xs);font-weight:var(--hm-font-weight-semibold);letter-spacing:.04em;text-transform:uppercase}.badge--neutral{background:var(--hm-surface-muted);color:var(--hm-muted);letter-spacing:normal;text-transform:none}.card--compact{gap:var(--hm-space-micro);padding:var(--hm-space-sm) var(--hm-space-md)}.recent{display:flex;align-items:center;gap:var(--hm-space-micro)}.recent__open{flex:1 1 auto;min-inline-size:0;padding:var(--hm-space-nano) var(--hm-space-xs)}.recent__icon{flex:none;color:var(--hm-accent)}.recent__name{flex:none;max-inline-size:50%;overflow:hidden;font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.recent__where{flex:1 1 auto;min-inline-size:0;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}.recent__when{flex:none;color:var(--hm-muted);font-size:var(--hm-font-size-xs);white-space:nowrap}.heart--on{color:var(--hm-danger)}.systems{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,14rem),1fr));gap:var(--hm-space-sm)}.systems__cell{display:flex}.system{flex:1 1 auto;flex-direction:column;align-items:stretch;gap:var(--hm-space-xs);padding:var(--hm-space-sm) var(--hm-space-md);border-color:var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.system:hover{border-color:var(--hm-accent);background:var(--hm-surface-raised)}.system__head{display:flex;align-items:center;gap:var(--hm-space-sm);min-inline-size:0}.system__icon{flex:none;color:var(--hm-accent)}.system__name{min-inline-size:0;overflow:hidden;font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.system__chevron{flex:none;margin-inline-start:auto;color:var(--hm-muted)}.system__description{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.system__chips{display:flex;flex-wrap:wrap;gap:var(--hm-space-micro)}.system__chip{padding:var(--hm-space-nano) var(--hm-space-xs);border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-pill);background:var(--hm-surface-muted);color:var(--hm-text);font-size:var(--hm-font-size-xs)}.list{display:flex;flex-direction:column}.list>li+li{border-block-start:var(--hm-border-hairline) solid var(--hm-divider)}.row{inline-size:100%;padding:var(--hm-space-nano) var(--hm-space-xs)}.row__icon{flex:none;color:var(--hm-muted)}.row__name{flex:1 1 auto;min-inline-size:0;overflow:hidden;font-size:var(--hm-font-size-sm);text-overflow:ellipsis;white-space:nowrap}.row__meta{flex:0 1 auto;min-inline-size:0;max-inline-size:45%;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}.news{inline-size:100%;gap:var(--hm-space-xs);padding:var(--hm-space-nano) var(--hm-space-xs)}.news__dot{flex:none;inline-size:var(--hm-space-xs);block-size:var(--hm-space-xs);border-radius:var(--hm-radius-pill);background:var(--hm-accent)}.news__dot--seen{background:var(--hm-divider)}.news__title{flex:none;max-inline-size:50%;overflow:hidden;font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.news__body{flex:1 1 auto;min-inline-size:0;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconButtonComponent, selector: "hm-icon-button", inputs: ["label", "icon", "solid", "iconDirection", "emphasis", "intent", "size", "disabled", "toggle", "pressed", "keyShortcuts"], outputs: ["pressedChange", "clicked"] }, { kind: "component", type: IconComponent, selector: "hm-icon", inputs: ["shape", "direction", "size", "solid", "badge", "status", "flip", "inverse", "label"] }, { kind: "component", type: MenuButtonComponent, selector: "hm-menu-button", inputs: ["label", "icon", "items", "showArrow", "align", "side", "size", "shape", "layer", "closeOnCheck", "disabled"], outputs: ["chosen", "checkedChange"] }, { kind: "component", type: StatePageComponent, selector: "hm-state-page", inputs: ["kind", "heading", "description", "action", "actionIcon"], outputs: ["actionTriggered"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
308
311
  }
309
312
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HomeComponent, decorators: [{
310
313
  type: Component,
311
- args: [{ selector: 'home', imports: [NgTemplateOutlet, IconButtonComponent, IconComponent, MenuButtonComponent, StatePageComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (noAccess()) {\n <hm-state-page kind=\"no-rights\" [heading]=\"t.noAccessTitle\" [description]=\"t.noAccessText\" action=\"\" />\n} @else {\n <div class=\"home\">\n <!-- Sauda\u00E7\u00E3o \u00E0 esquerda; as novidades, quando houver, ocupam o espa\u00E7o \u00E0 direita dela. -->\n <div class=\"hero\">\n <div class=\"hero__text\">\n <p class=\"hero__greeting\">{{ greeting }}</p>\n <p class=\"hero__intro\">{{ t.intro }}</p>\n </div>\n @if (newsRows().length) {\n <!-- Compacto: cabe\u00E7alho numa linha e cada novidade numa linha s\u00F3 (t\u00EDtulo e o come\u00E7o do texto). -->\n <section class=\"card card--compact hero__news\" [attr.aria-labelledby]=\"uid + '-news'\">\n <div class=\"card__head\">\n <span class=\"card__heading\">\n <h2 class=\"card__title\" [id]=\"uid + '-news'\">{{ t.news }}</h2>\n <span class=\"badge\">{{ t.newsBadge }}</span>\n </span>\n <button type=\"button\" class=\"more\" (click)=\"openNews()\">{{ t.newsAll }}</button>\n </div>\n <ul class=\"list\">\n @for (entry of newsRows(); track entry.id) {\n <li>\n <button type=\"button\" class=\"news\" [title]=\"entry.title + ' \u2014 ' + entry.text\" (click)=\"openNews(entry.id)\">\n <span class=\"news__dot\" [class.news__dot--seen]=\"!entry.unseen\" aria-hidden=\"true\"></span>\n <span class=\"news__title\">{{ entry.title }}</span>\n <span class=\"news__body\">{{ entry.text }}</span>\n </button>\n </li>\n }\n </ul>\n </section>\n }\n </div>\n\n <!-- Atalhos de trabalho e privilegiados dividem a mesma linha (cada grupo na propor\u00E7\u00E3o dos seus atalhos). -->\n @if (workTiles().length || adminTiles().length) {\n <div class=\"shortcuts\">\n @if (workTiles().length) {\n <section class=\"block shortcuts__group\" [style.--tiles]=\"workTiles().length\" [attr.aria-labelledby]=\"uid + '-work'\">\n <h2 class=\"block__title\" [id]=\"uid + '-work'\">{{ descended() ? t.yourScreens : t.modules }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: workTiles(), admin: false }\" />\n </section>\n }\n @if (adminTiles().length) {\n <section class=\"block shortcuts__group\" [style.--tiles]=\"adminTiles().length\" [attr.aria-labelledby]=\"uid + '-admin'\">\n <h2 class=\"block__title\" [id]=\"uid + '-admin'\">{{ t.privileged }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: adminTiles(), admin: true }\" />\n </section>\n }\n </div>\n }\n\n <!-- Linha 1: o que a pessoa usa (recentes | favoritos). Linha 2: o resto do sistema (m\u00F3dulos | ajuda).\n Sem um dos lados, o outro ocupa a linha inteira. -->\n <div class=\"pair\">\n @if (recentRows().length) {\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-recent'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-recent'\">{{ t.recent }}</h2>\n @if (moreRecents()) {\n <button type=\"button\" class=\"more\" [attr.aria-expanded]=\"showAllRecents()\" (click)=\"showAllRecents.set(!showAllRecents())\">\n {{ showAllRecents() ? t.seeLess : t.seeAll }}\n </button>\n }\n </div>\n <ul class=\"list\" [attr.aria-label]=\"t.recentCaption\">\n @for (item of recentRows(); track item.id) {\n <li class=\"recent\">\n <button type=\"button\" class=\"recent__open\" (click)=\"go(item.redirect)\">\n <hm-icon class=\"recent__icon\" [shape]=\"item.icon || 'grid-layout'\" />\n <span class=\"recent__name\">{{ item.displayName }}</span>\n <span class=\"recent__where\">{{ item.where }}</span>\n @if (item.when) {\n <span class=\"recent__when\">{{ item.when }}</span>\n }\n </button>\n <hm-icon-button\n emphasis=\"subtle\"\n size=\"small\"\n icon=\"heart\"\n [solid]=\"isFavorite(item.id)\"\n [class.heart--on]=\"isFavorite(item.id)\"\n [label]=\"favoriteLabel(item)\"\n (clicked)=\"toggleFavorite(item)\"\n />\n <hm-menu-button\n class=\"recent__menu\"\n icon=\"ellipsis-vertical\"\n shape=\"circle\"\n size=\"small\"\n align=\"end\"\n [showArrow]=\"false\"\n [label]=\"recentMenuLabel(item)\"\n [items]=\"recentMenu\"\n (chosen)=\"onRecentMenu(item, $event)\"\n />\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-fav'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-fav'\">{{ t.favorites }}</h2>\n @if (moreFavorites()) {\n <button type=\"button\" class=\"more\" [attr.aria-expanded]=\"showAllFavorites()\" (click)=\"showAllFavorites.set(!showAllFavorites())\">\n {{ showAllFavorites() ? t.seeLess : t.seeAll }}\n </button>\n }\n </div>\n @if (visibleFavorites().length) {\n <ul class=\"list\">\n @for (fav of visibleFavorites(); track fav.id) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(fav.redirect)\">\n <hm-icon class=\"row__icon\" [shape]=\"fav.icon || 'grid-layout'\" />\n <span class=\"row__name\">{{ fav.displayName }}</span>\n <span class=\"row__meta\">{{ whereOf(fav) }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n </ul>\n } @else {\n <p class=\"card__empty\">{{ t.favoritesEmpty }}</p>\n }\n </section>\n </div>\n\n <div class=\"pair\">\n @if (systems().length) {\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-systems'\">\n <div class=\"card__head card__head--stacked\">\n <h2 class=\"card__title\" [id]=\"uid + '-systems'\">{{ t.explore }}</h2>\n <p class=\"card__intro\">{{ t.exploreIntro }}</p>\n </div>\n <ul class=\"systems\">\n @for (system of systems(); track system.id) {\n <!-- O card inteiro abre o m\u00F3dulo (como os atalhos): uma seta no canto, sem link pr\u00F3prio. -->\n <li class=\"systems__cell\">\n <button type=\"button\" class=\"system\" (click)=\"go(system.redirect)\">\n <span class=\"system__head\">\n <hm-icon class=\"system__icon\" [shape]=\"system.icon\" size=\"lg\" />\n <span class=\"system__name\" [title]=\"system.label\">{{ system.label }}</span>\n <span class=\"badge badge--neutral\">{{ system.count }}</span>\n <hm-icon class=\"system__chevron\" shape=\"angle-right\" size=\"sm\" />\n </span>\n @if (system.description) {\n <span class=\"system__description\">{{ system.description }}</span>\n }\n @if (system.chips.length) {\n <span class=\"system__chips\">\n @for (chip of system.chips; track chip) {\n <span class=\"system__chip\">{{ chip }}</span>\n }\n </span>\n }\n </button>\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-help'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-help'\">{{ t.help }}</h2>\n </div>\n <ul class=\"list\">\n @for (area of areas(); track area.routed_id) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(area.route_redirect)\">\n <hm-icon class=\"row__icon\" [shape]=\"area.route_icon || 'home'\" />\n <span class=\"row__name\">{{ area.route_display_name }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openDocs()\">\n <hm-icon class=\"row__icon\" shape=\"book\" />\n <span class=\"row__name\">{{ t.systemDocs }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openShortcuts()\">\n <hm-icon class=\"row__icon\" shape=\"keyboard\" />\n <span class=\"row__name\">{{ t.shortcuts }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openEssentials()\">\n <hm-icon class=\"row__icon\" shape=\"help\" />\n <span class=\"row__name\">{{ t.essentials }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openSettings()\">\n <hm-icon class=\"row__icon\" shape=\"cog\" />\n <span class=\"row__name\">{{ t.settings }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n </ul>\n </section>\n </div>\n </div>\n}\n\n<ng-template #tileGrid let-tiles let-admin=\"admin\">\n <ul class=\"tiles\" [class.tiles--admin]=\"admin\">\n @for (tile of tiles; track tile.id; let i = $index) {\n <li class=\"tiles__cell\" [style.--tile-order]=\"i\">\n <button type=\"button\" class=\"tile\" (click)=\"go(tile.redirect)\">\n <hm-icon class=\"tile__icon\" [shape]=\"tile.icon ?? 'grid-layout'\" size=\"lg\" />\n <span class=\"tile__text\">\n <span class=\"tile__label\">{{ tile.label }}</span>\n @if (caption(tile); as meta) {\n <span class=\"tile__meta\">{{ meta }}</span>\n }\n </span>\n <hm-icon class=\"tile__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n </ul>\n</ng-template>\n", styles: [":host{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:100%;min-inline-size:0}hm-state-page{flex:1 1 auto}ul{margin:0;padding:0;list-style:none}p{margin:0}.home{container-type:inline-size;display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.hero{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--hm-space-md)}.hero__text{display:flex;flex:1 1 20rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.hero__news{flex:0 1 32rem;min-inline-size:min(100%,20rem)}.hero__greeting{color:var(--hm-text);font-size:var(--hm-font-size-xxl);font-weight:var(--hm-font-weight-bold);line-height:var(--hm-line-height-tight)}.hero__intro{color:var(--hm-muted);font-size:var(--hm-font-size-md)}.block{display:flex;flex-direction:column;gap:var(--hm-space-sm);min-inline-size:0}.block__title{margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.news,.row,.system,.recent__open,.more,.tile{display:flex;align-items:center;gap:var(--hm-space-sm);border:var(--hm-border-hairline) solid transparent;border-radius:var(--hm-radius-control);background:transparent;color:var(--hm-text);font:inherit;text-align:start;cursor:pointer;transition:background-color var(--hm-duration-quick) var(--hm-ease-standard),border-color var(--hm-duration-quick) var(--hm-ease-standard)}.news:hover,.row:hover,.system:hover,.recent__open:hover,.more:hover,.tile:hover{background:var(--hm-hover)}.news:focus-visible,.row:focus-visible,.system:focus-visible,.recent__open:focus-visible,.more:focus-visible,.tile:focus-visible{outline:var(--hm-border-thin) solid var(--hm-accent);outline-offset:2px}@media(forced-colors:active){.news,.row,.system,.recent__open,.more,.tile{border-color:ButtonText}.news:focus-visible,.row:focus-visible,.system:focus-visible,.recent__open:focus-visible,.more:focus-visible,.tile:focus-visible{outline-color:Highlight}}.shortcuts{display:flex;flex-wrap:wrap;gap:var(--hm-space-md)}.shortcuts__group{flex:var(--tiles, 1) 1 calc(var(--tiles, 1) * 13rem + (var(--tiles, 1) - 1) * var(--hm-space-sm))}.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,13rem),1fr));gap:var(--hm-space-sm)}.tiles__cell{display:flex}.tile{flex:1 1 auto;gap:var(--hm-space-md);padding:var(--hm-space-md);border-color:var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.tile:hover{border-color:var(--hm-accent);background:var(--hm-surface-raised)}.tile__icon{flex:none;color:var(--hm-accent)}.tiles--admin .tile__icon{color:var(--hm-warning)}.tile__text{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--hm-space-nano);min-inline-size:0}.tile__label{font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold);overflow-wrap:anywhere}.tile__meta{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.tile__chevron,.row__chevron{flex:none;color:var(--hm-muted)}@media(prefers-reduced-motion:no-preference){.tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}}:host-context([data-motion=full]) .tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}:host-context([data-motion=reduce]) .tiles__cell{animation:none}@keyframes tile-in{0%{opacity:0;transform:translateY(var(--hm-space-xs))}}.pair{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:var(--hm-space-md);align-items:stretch}.pair>:only-child{grid-column:1/-1}.stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.stack>.card:last-child{flex:1 1 auto}@container (max-width: 56rem){.pair{grid-template-columns:minmax(0,1fr)}}.card{display:flex;flex-direction:column;gap:var(--hm-space-sm);min-inline-size:0;padding:var(--hm-space-md);border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.card__head{display:flex;align-items:center;justify-content:space-between;gap:var(--hm-space-sm)}.card__head--stacked{flex-direction:column;align-items:flex-start;gap:var(--hm-space-micro)}.card__heading{display:flex;align-items:center;gap:var(--hm-space-xs)}.card__title{margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.card__intro,.card__empty{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.more{flex:none;padding:var(--hm-space-nano) var(--hm-space-xs);color:var(--hm-accent);font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-medium)}.badge{flex:none;padding:var(--hm-space-nano) var(--hm-space-xs);border-radius:var(--hm-radius-micro);background:var(--hm-accent-subtle);color:var(--hm-accent);font-size:var(--hm-font-size-3xs);font-weight:var(--hm-font-weight-semibold);letter-spacing:.04em;text-transform:uppercase}.badge--neutral{background:var(--hm-surface-muted);color:var(--hm-muted);letter-spacing:normal;text-transform:none}.card--compact{gap:var(--hm-space-micro);padding:var(--hm-space-sm) var(--hm-space-md)}.recent{display:flex;align-items:center;gap:var(--hm-space-micro)}.recent__open{flex:1 1 auto;min-inline-size:0;padding:var(--hm-space-nano) var(--hm-space-xs)}.recent__icon{flex:none;color:var(--hm-accent)}.recent__name{flex:none;max-inline-size:50%;overflow:hidden;font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.recent__where{flex:1 1 auto;min-inline-size:0;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}.recent__when{flex:none;color:var(--hm-muted);font-size:var(--hm-font-size-xs);white-space:nowrap}.heart--on{color:var(--hm-danger)}.systems{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,14rem),1fr));gap:var(--hm-space-sm)}.systems__cell{display:flex}.system{flex:1 1 auto;flex-direction:column;align-items:stretch;gap:var(--hm-space-xs);padding:var(--hm-space-sm) var(--hm-space-md);border-color:var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.system:hover{border-color:var(--hm-accent);background:var(--hm-surface-raised)}.system__head{display:flex;align-items:center;gap:var(--hm-space-sm);min-inline-size:0}.system__icon{flex:none;color:var(--hm-accent)}.system__name{min-inline-size:0;overflow:hidden;font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.system__chevron{flex:none;margin-inline-start:auto;color:var(--hm-muted)}.system__description{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.system__chips{display:flex;flex-wrap:wrap;gap:var(--hm-space-micro)}.system__chip{padding:var(--hm-space-nano) var(--hm-space-xs);border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-pill);background:var(--hm-surface-muted);color:var(--hm-text);font-size:var(--hm-font-size-xs)}.list{display:flex;flex-direction:column}.list>li+li{border-block-start:var(--hm-border-hairline) solid var(--hm-divider)}.row{inline-size:100%;padding:var(--hm-space-nano) var(--hm-space-xs)}.row__icon{flex:none;color:var(--hm-muted)}.row__name{flex:1 1 auto;min-inline-size:0;overflow:hidden;font-size:var(--hm-font-size-sm);text-overflow:ellipsis;white-space:nowrap}.row__meta{flex:0 1 auto;min-inline-size:0;max-inline-size:45%;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}.news{inline-size:100%;gap:var(--hm-space-xs);padding:var(--hm-space-nano) var(--hm-space-xs)}.news__dot{flex:none;inline-size:var(--hm-space-xs);block-size:var(--hm-space-xs);border-radius:var(--hm-radius-pill);background:var(--hm-accent)}.news__dot--seen{background:var(--hm-divider)}.news__title{flex:none;max-inline-size:50%;overflow:hidden;font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.news__body{flex:1 1 auto;min-inline-size:0;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}\n"] }]
314
+ args: [{ selector: 'home', imports: [NgTemplateOutlet, IconButtonComponent, IconComponent, MenuButtonComponent, StatePageComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (noAccess()) {\n <hm-state-page kind=\"no-rights\" [heading]=\"t.noAccessTitle\" [description]=\"t.noAccessText\" action=\"\" />\n} @else {\n <div class=\"home\">\n <!-- Sauda\u00E7\u00E3o \u00E0 esquerda; as novidades, quando houver, ocupam o espa\u00E7o \u00E0 direita dela. -->\n <div class=\"hero\">\n <div class=\"hero__text\">\n <p class=\"hero__greeting\">{{ greeting }}</p>\n <p class=\"hero__intro\">{{ t.intro }}</p>\n </div>\n @if (newsRows().length) {\n <!-- Compacto: cabe\u00E7alho numa linha e cada novidade numa linha s\u00F3 (t\u00EDtulo e o come\u00E7o do texto). -->\n <section class=\"card card--compact hero__news\" [attr.aria-labelledby]=\"uid + '-news'\">\n <div class=\"card__head\">\n <span class=\"card__heading\">\n <h2 class=\"card__title\" [id]=\"uid + '-news'\">{{ t.news }}</h2>\n <span class=\"badge\">{{ t.newsBadge }}</span>\n </span>\n <button type=\"button\" class=\"more\" (click)=\"openNews()\">{{ t.newsAll }}</button>\n </div>\n <ul class=\"list\">\n @for (entry of newsRows(); track entry.id) {\n <li>\n <button type=\"button\" class=\"news\" [title]=\"entry.title + ' \u2014 ' + entry.text\" (click)=\"openNews(entry.id)\">\n <span class=\"news__dot\" [class.news__dot--seen]=\"!entry.unseen\" aria-hidden=\"true\"></span>\n <span class=\"news__title\">{{ entry.title }}</span>\n <span class=\"news__body\">{{ entry.text }}</span>\n </button>\n </li>\n }\n </ul>\n </section>\n }\n </div>\n\n <!-- Atalhos de trabalho e privilegiados dividem a mesma linha (cada grupo na propor\u00E7\u00E3o dos seus atalhos). -->\n @if (workTiles().length || adminTiles().length) {\n <div class=\"shortcuts\">\n @if (workTiles().length) {\n <section class=\"block shortcuts__group\" [style.--tiles]=\"workTiles().length\" [attr.aria-labelledby]=\"uid + '-work'\">\n <h2 class=\"block__title\" [id]=\"uid + '-work'\">{{ descended() ? t.yourScreens : t.modules }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: workTiles(), admin: false }\" />\n </section>\n }\n @if (adminTiles().length) {\n <section class=\"block shortcuts__group\" [style.--tiles]=\"adminTiles().length\" [attr.aria-labelledby]=\"uid + '-admin'\">\n <h2 class=\"block__title\" [id]=\"uid + '-admin'\">{{ t.privileged }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: adminTiles(), admin: true }\" />\n </section>\n }\n </div>\n }\n\n <!-- Linha 1: o que a pessoa usa (recentes | favoritos). Linha 2: o resto do sistema (m\u00F3dulos | ajuda).\n Sem um dos lados, o outro ocupa a linha inteira. -->\n <div class=\"pair\">\n @if (recentRows().length) {\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-recent'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-recent'\">{{ t.recent }}</h2>\n @if (moreRecents()) {\n <button type=\"button\" class=\"more\" [attr.aria-expanded]=\"showAllRecents()\" (click)=\"showAllRecents.set(!showAllRecents())\">\n {{ showAllRecents() ? t.seeLess : t.seeAll }}\n </button>\n }\n </div>\n <ul class=\"list\" [attr.aria-label]=\"t.recentCaption\">\n @for (item of recentRows(); track item.id) {\n <li class=\"recent\">\n <button type=\"button\" class=\"recent__open\" (click)=\"go(item.redirect)\">\n <hm-icon class=\"recent__icon\" [shape]=\"item.icon || 'grid-layout'\" />\n <span class=\"recent__name\">{{ item.displayName }}</span>\n <span class=\"recent__where\">{{ item.where }}</span>\n @if (item.when) {\n <span class=\"recent__when\">{{ item.when }}</span>\n }\n </button>\n <hm-icon-button\n emphasis=\"subtle\"\n size=\"small\"\n icon=\"heart\"\n [solid]=\"isFavorite(item.id)\"\n [class.heart--on]=\"isFavorite(item.id)\"\n [label]=\"favoriteLabel(item)\"\n (clicked)=\"toggleFavorite(item)\"\n />\n <hm-menu-button\n class=\"recent__menu\"\n icon=\"ellipsis-vertical\"\n shape=\"circle\"\n size=\"small\"\n align=\"end\"\n [showArrow]=\"false\"\n [label]=\"recentMenuLabel(item)\"\n [items]=\"recentMenu\"\n (chosen)=\"onRecentMenu(item, $event)\"\n />\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-fav'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-fav'\">{{ t.favorites }}</h2>\n @if (moreFavorites()) {\n <button type=\"button\" class=\"more\" [attr.aria-expanded]=\"showAllFavorites()\" (click)=\"showAllFavorites.set(!showAllFavorites())\">\n {{ showAllFavorites() ? t.seeLess : t.seeAll }}\n </button>\n }\n </div>\n @if (visibleFavorites().length) {\n <ul class=\"list\">\n @for (fav of visibleFavorites(); track fav.id) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(fav.redirect)\">\n <hm-icon class=\"row__icon\" [shape]=\"fav.icon || 'grid-layout'\" />\n <span class=\"row__name\">{{ fav.displayName }}</span>\n <span class=\"row__meta\">{{ whereOf(fav) }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n </ul>\n } @else {\n <p class=\"card__empty\">{{ t.favoritesEmpty }}</p>\n }\n </section>\n </div>\n\n <div class=\"pair\">\n @if (systems().length) {\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-systems'\">\n <div class=\"card__head card__head--stacked\">\n <h2 class=\"card__title\" [id]=\"uid + '-systems'\">{{ t.explore }}</h2>\n <p class=\"card__intro\">{{ t.exploreIntro }}</p>\n </div>\n <ul class=\"systems\">\n @for (system of systems(); track system.id) {\n <!-- O card inteiro abre o m\u00F3dulo (como os atalhos): uma seta no canto, sem link pr\u00F3prio. -->\n <li class=\"systems__cell\">\n <button type=\"button\" class=\"system\" (click)=\"go(system.redirect)\">\n <span class=\"system__head\">\n <hm-icon class=\"system__icon\" [shape]=\"system.icon\" size=\"lg\" />\n <span class=\"system__name\" [title]=\"system.label\">{{ system.label }}</span>\n <span class=\"badge badge--neutral\">{{ system.count }}</span>\n <hm-icon class=\"system__chevron\" shape=\"angle-right\" size=\"sm\" />\n </span>\n @if (system.description) {\n <span class=\"system__description\">{{ system.description }}</span>\n }\n @if (system.chips.length) {\n <span class=\"system__chips\">\n @for (chip of system.chips; track chip) {\n <span class=\"system__chip\">{{ chip }}</span>\n }\n </span>\n }\n </button>\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-help'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-help'\">{{ t.help }}</h2>\n </div>\n <ul class=\"list\">\n @for (area of areas(); track area.routed_id) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(area.route_redirect)\">\n <hm-icon class=\"row__icon\" [shape]=\"area.route_icon || 'home'\" />\n <span class=\"row__name\">{{ area.route_display_name }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openDocs()\">\n <hm-icon class=\"row__icon\" shape=\"book\" />\n <span class=\"row__name\">{{ t.systemDocs }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n @if (suggestions) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(suggestionsPath)\">\n <hm-icon class=\"row__icon\" shape=\"lightbulb\" />\n <span class=\"row__name\">{{ suggestions }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openShortcuts()\">\n <hm-icon class=\"row__icon\" shape=\"keyboard\" />\n <span class=\"row__name\">{{ t.shortcuts }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openEssentials()\">\n <hm-icon class=\"row__icon\" shape=\"help\" />\n <span class=\"row__name\">{{ t.essentials }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openSettings()\">\n <hm-icon class=\"row__icon\" shape=\"cog\" />\n <span class=\"row__name\">{{ t.settings }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n </ul>\n </section>\n </div>\n </div>\n}\n\n<ng-template #tileGrid let-tiles let-admin=\"admin\">\n <ul class=\"tiles\" [class.tiles--admin]=\"admin\">\n @for (tile of tiles; track tile.id; let i = $index) {\n <li class=\"tiles__cell\" [style.--tile-order]=\"i\">\n <button type=\"button\" class=\"tile\" (click)=\"go(tile.redirect)\">\n <hm-icon class=\"tile__icon\" [shape]=\"tile.icon ?? 'grid-layout'\" size=\"lg\" />\n <span class=\"tile__text\">\n <span class=\"tile__label\">{{ tile.label }}</span>\n @if (caption(tile); as meta) {\n <span class=\"tile__meta\">{{ meta }}</span>\n }\n </span>\n <hm-icon class=\"tile__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n </ul>\n</ng-template>\n", styles: [":host{display:flex;flex:1 1 auto;flex-direction:column;min-block-size:100%;min-inline-size:0}hm-state-page{flex:1 1 auto}ul{margin:0;padding:0;list-style:none}p{margin:0}.home{container-type:inline-size;display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.hero{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--hm-space-md)}.hero__text{display:flex;flex:1 1 20rem;flex-direction:column;gap:var(--hm-space-micro);min-inline-size:0}.hero__news{flex:0 1 32rem;min-inline-size:min(100%,20rem)}.hero__greeting{color:var(--hm-text);font-size:var(--hm-font-size-xxl);font-weight:var(--hm-font-weight-bold);line-height:var(--hm-line-height-tight)}.hero__intro{color:var(--hm-muted);font-size:var(--hm-font-size-md)}.block{display:flex;flex-direction:column;gap:var(--hm-space-sm);min-inline-size:0}.block__title{margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.news,.row,.system,.recent__open,.more,.tile{display:flex;align-items:center;gap:var(--hm-space-sm);border:var(--hm-border-hairline) solid transparent;border-radius:var(--hm-radius-control);background:transparent;color:var(--hm-text);font:inherit;text-align:start;cursor:pointer;transition:background-color var(--hm-duration-quick) var(--hm-ease-standard),border-color var(--hm-duration-quick) var(--hm-ease-standard)}.news:hover,.row:hover,.system:hover,.recent__open:hover,.more:hover,.tile:hover{background:var(--hm-hover)}.news:focus-visible,.row:focus-visible,.system:focus-visible,.recent__open:focus-visible,.more:focus-visible,.tile:focus-visible{outline:var(--hm-border-thin) solid var(--hm-accent);outline-offset:2px}@media(forced-colors:active){.news,.row,.system,.recent__open,.more,.tile{border-color:ButtonText}.news:focus-visible,.row:focus-visible,.system:focus-visible,.recent__open:focus-visible,.more:focus-visible,.tile:focus-visible{outline-color:Highlight}}.shortcuts{display:flex;flex-wrap:wrap;gap:var(--hm-space-md)}.shortcuts__group{flex:var(--tiles, 1) 1 calc(var(--tiles, 1) * 13rem + (var(--tiles, 1) - 1) * var(--hm-space-sm))}.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,13rem),1fr));gap:var(--hm-space-sm)}.tiles__cell{display:flex}.tile{flex:1 1 auto;gap:var(--hm-space-md);padding:var(--hm-space-md);border-color:var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.tile:hover{border-color:var(--hm-accent);background:var(--hm-surface-raised)}.tile__icon{flex:none;color:var(--hm-accent)}.tiles--admin .tile__icon{color:var(--hm-warning)}.tile__text{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--hm-space-nano);min-inline-size:0}.tile__label{font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold);overflow-wrap:anywhere}.tile__meta{color:var(--hm-muted);font-size:var(--hm-font-size-xs)}.tile__chevron,.row__chevron{flex:none;color:var(--hm-muted)}@media(prefers-reduced-motion:no-preference){.tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}}:host-context([data-motion=full]) .tiles__cell{animation:tile-in var(--hm-duration-standard) var(--hm-ease-decelerate) both;animation-delay:calc(min(var(--tile-order, 0),10)*35ms)}:host-context([data-motion=reduce]) .tiles__cell{animation:none}@keyframes tile-in{0%{opacity:0;transform:translateY(var(--hm-space-xs))}}.pair{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:var(--hm-space-md);align-items:stretch}.pair>:only-child{grid-column:1/-1}.stack{display:flex;flex-direction:column;gap:var(--hm-space-md);min-inline-size:0}.stack>.card:last-child{flex:1 1 auto}@container (max-width: 56rem){.pair{grid-template-columns:minmax(0,1fr)}}.card{display:flex;flex-direction:column;gap:var(--hm-space-sm);min-inline-size:0;padding:var(--hm-space-md);border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.card__head{display:flex;align-items:center;justify-content:space-between;gap:var(--hm-space-sm)}.card__head--stacked{flex-direction:column;align-items:flex-start;gap:var(--hm-space-micro)}.card__heading{display:flex;align-items:center;gap:var(--hm-space-xs)}.card__title{margin:0;color:var(--hm-text);font-size:var(--hm-font-size-md);font-weight:var(--hm-font-weight-semibold)}.card__intro,.card__empty{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.more{flex:none;padding:var(--hm-space-nano) var(--hm-space-xs);color:var(--hm-accent);font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-medium)}.badge{flex:none;padding:var(--hm-space-nano) var(--hm-space-xs);border-radius:var(--hm-radius-micro);background:var(--hm-accent-subtle);color:var(--hm-accent);font-size:var(--hm-font-size-3xs);font-weight:var(--hm-font-weight-semibold);letter-spacing:.04em;text-transform:uppercase}.badge--neutral{background:var(--hm-surface-muted);color:var(--hm-muted);letter-spacing:normal;text-transform:none}.card--compact{gap:var(--hm-space-micro);padding:var(--hm-space-sm) var(--hm-space-md)}.recent{display:flex;align-items:center;gap:var(--hm-space-micro)}.recent__open{flex:1 1 auto;min-inline-size:0;padding:var(--hm-space-nano) var(--hm-space-xs)}.recent__icon{flex:none;color:var(--hm-accent)}.recent__name{flex:none;max-inline-size:50%;overflow:hidden;font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.recent__where{flex:1 1 auto;min-inline-size:0;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}.recent__when{flex:none;color:var(--hm-muted);font-size:var(--hm-font-size-xs);white-space:nowrap}.heart--on{color:var(--hm-danger)}.systems{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,14rem),1fr));gap:var(--hm-space-sm)}.systems__cell{display:flex}.system{flex:1 1 auto;flex-direction:column;align-items:stretch;gap:var(--hm-space-xs);padding:var(--hm-space-sm) var(--hm-space-md);border-color:var(--hm-divider);border-radius:var(--hm-radius);background:var(--hm-surface-raised)}.system:hover{border-color:var(--hm-accent);background:var(--hm-surface-raised)}.system__head{display:flex;align-items:center;gap:var(--hm-space-sm);min-inline-size:0}.system__icon{flex:none;color:var(--hm-accent)}.system__name{min-inline-size:0;overflow:hidden;font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.system__chevron{flex:none;margin-inline-start:auto;color:var(--hm-muted)}.system__description{color:var(--hm-muted);font-size:var(--hm-font-size-sm)}.system__chips{display:flex;flex-wrap:wrap;gap:var(--hm-space-micro)}.system__chip{padding:var(--hm-space-nano) var(--hm-space-xs);border:var(--hm-border-hairline) solid var(--hm-divider);border-radius:var(--hm-radius-pill);background:var(--hm-surface-muted);color:var(--hm-text);font-size:var(--hm-font-size-xs)}.list{display:flex;flex-direction:column}.list>li+li{border-block-start:var(--hm-border-hairline) solid var(--hm-divider)}.row{inline-size:100%;padding:var(--hm-space-nano) var(--hm-space-xs)}.row__icon{flex:none;color:var(--hm-muted)}.row__name{flex:1 1 auto;min-inline-size:0;overflow:hidden;font-size:var(--hm-font-size-sm);text-overflow:ellipsis;white-space:nowrap}.row__meta{flex:0 1 auto;min-inline-size:0;max-inline-size:45%;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}.news{inline-size:100%;gap:var(--hm-space-xs);padding:var(--hm-space-nano) var(--hm-space-xs)}.news__dot{flex:none;inline-size:var(--hm-space-xs);block-size:var(--hm-space-xs);border-radius:var(--hm-radius-pill);background:var(--hm-accent)}.news__dot--seen{background:var(--hm-divider)}.news__title{flex:none;max-inline-size:50%;overflow:hidden;font-size:var(--hm-font-size-sm);font-weight:var(--hm-font-weight-semibold);text-overflow:ellipsis;white-space:nowrap}.news__body{flex:1 1 auto;min-inline-size:0;overflow:hidden;color:var(--hm-muted);font-size:var(--hm-font-size-xs);text-overflow:ellipsis;white-space:nowrap}\n"] }]
312
315
  }], ctorParameters: () => [] });
313
316
 
314
317
  export { HomeAutoRedirect, HomeComponent };
315
- //# sourceMappingURL=trismegisto-spine-auto-service-home.component-rQ3dIGIE.mjs.map
318
+ //# sourceMappingURL=trismegisto-spine-auto-service-home.component-9WvXOH3l.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trismegisto-spine-auto-service-home.component-9WvXOH3l.mjs","sources":["../../../projects/ui/auto-service/src/home/home-shortcuts.ts","../../../projects/ui/auto-service/src/home/home.component.ts","../../../projects/ui/auto-service/src/home/home.component.html"],"sourcesContent":["import { Route } from '@trismegisto/spine';\nimport {\n AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_LOGIN_ATTEMPTS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_NEWS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_RATINGS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_SUGGESTIONS_TEMPLATE_ROUTER_ID,\n} from '../auto-service.tokens';\n\n/** A page the person can open, with the labels of the menus above it. */\nexport interface HomeDestination {\n readonly id: string;\n readonly label: string;\n readonly icon: string | null;\n readonly redirect: string;\n readonly trail: readonly string[];\n}\n\n/** A large entry tile on the home screen. */\nexport interface HomeShortcut extends HomeDestination {\n readonly screens: number;\n readonly privileged: boolean;\n}\n\n// Above this many tiles a grid stops being scannable at a glance.\nconst MAX_TILES = 12;\n\nconst ADMIN_TEMPLATES = new Set(\n [\n AUTO_SERVICE_GROUPS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_APPS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_CLIENT_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_LOGIN_ATTEMPTS_TEMPLATE_ROUTER_ID,\n // Novidades, Sugestões e Avaliações também são de quem administra o client (migration 0036 do argos).\n AUTO_SERVICE_NEWS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_SUGGESTIONS_TEMPLATE_ROUTER_ID,\n AUTO_SERVICE_RATINGS_TEMPLATE_ROUTER_ID,\n ].map((id) => id.toLowerCase()),\n);\nconst HOME_TEMPLATE = AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID.toLowerCase();\n\nfunction childrenOf(node: Route): Route[] {\n return (node.routes ?? []).filter((child): child is Route => child != null);\n}\n\nfunction labelOf(node: Route): string {\n return (node.route_display_name ?? node.route_name ?? '').trim();\n}\n\nfunction identityOf(node: Route): string {\n return node.route_redirect || `${node.route_type ?? 'node'}:${node.routed_id}`;\n}\n\nfunction templateOf(node: Route): string {\n return (node.source_template_router_id ?? '').toLowerCase();\n}\n\nexport function isPage(node: Route): boolean {\n return !!node.route_redirect && (node.route_type === 'page' || childrenOf(node).length === 0);\n}\n\nexport function isHome(node: Route): boolean {\n return templateOf(node) === HOME_TEMPLATE || (isPage(node) && node.route_path === 'home');\n}\n\nexport function modules(tree: readonly Route[]): readonly Route[] {\n return tree.filter((node) => node != null && !isHome(node));\n}\n\nexport function systemAreas(tree: readonly Route[]): readonly Route[] {\n return tree.filter((node) => node != null && isHome(node));\n}\n\nexport function destinations(tree: readonly Route[], trail: readonly string[] = []): readonly HomeDestination[] {\n const found: HomeDestination[] = [];\n const walk = (nodes: readonly Route[], path: readonly string[]) => {\n for (const node of nodes) {\n if (node == null) continue;\n if (isPage(node)) {\n found.push({ id: identityOf(node), label: labelOf(node), icon: node.route_icon ?? null, redirect: node.route_redirect!, trail: path });\n }\n const kids = childrenOf(node);\n if (kids.length) walk(kids, [...path, labelOf(node)]);\n }\n };\n walk(tree, trail);\n return found;\n}\n\nexport function trailFor(tree: readonly Route[], redirect: string): readonly string[] | null {\n return destinations(tree).find((d) => d.redirect === redirect)?.trail ?? null;\n}\n\nfunction isPrivileged(node: Route): boolean {\n return ADMIN_TEMPLATES.has(templateOf(node)) || childrenOf(node).some(isPrivileged);\n}\n\ninterface Candidate {\n readonly node: Route;\n readonly trail: readonly string[];\n readonly privileged: boolean;\n}\n\nfunction navigableChildren(node: Route): Route[] {\n return childrenOf(node).filter((child) => isPage(child) || destinations([child]).length > 0);\n}\n\n/** Replaces each candidate by its navigable children; `null` when nobody has any. */\nfunction descend(level: readonly Candidate[]): Candidate[] | null {\n let changed = false;\n const next = level.flatMap((item) => {\n const kids = navigableChildren(item.node);\n if (!kids.length) return [item];\n changed = true;\n const trail = [...item.trail, labelOf(item.node)];\n return kids.map((node) => ({ node, trail, privileged: item.privileged }));\n });\n return changed ? next : null;\n}\n\nfunction toShortcut({ node, trail, privileged }: Candidate): HomeShortcut {\n const below = destinations([node]);\n return {\n id: identityOf(node),\n label: labelOf(node),\n icon: node.route_icon ?? null,\n redirect: node.route_redirect || below[0]?.redirect || '',\n trail,\n screens: below.length - (isPage(node) ? 1 : 0),\n privileged,\n };\n}\n\n/**\n * Picks the shallowest level of the tree where there is a real choice to make: a single item is\n * skipped over, a pair is opened up while the result still fits the grid, three or more stay put.\n */\nexport function entryShortcuts(tree: readonly Route[]): readonly HomeShortcut[] {\n let level: readonly Candidate[] = modules(tree).map((node) => ({ node, trail: [], privileged: isPrivileged(node) }));\n while (level.length > 0 && level.length < 3) {\n const next = descend(level);\n if (!next) break;\n if (level.length === 2 && next.length > MAX_TILES) break;\n level = next;\n }\n return level.map(toShortcut);\n}\n","import { ChangeDetectionStrategy, Component, Injectable, Injector, computed, effect, inject, signal } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { Router } from '@angular/router';\nimport { AuthorizationService, ViewService } from '@orfeu/angular/core';\nimport { IconButtonComponent, IconComponent, MenuButtonComponent, MenuItem, StatePageComponent } from '@trismegisto/angular';\nimport { formatMessage, pluralMessage } from '@trismegisto/primitives';\nimport { QuickAccessItem, Route, SPINE_MESSAGES, SpineQuickAccessService, spineRoutesOf } from '@trismegisto/spine';\nimport {\n SPINE_SUGGESTIONS_PAGE_PATH,\n ShortcutService,\n SpineDocsService,\n SpineInitialSetupService,\n SpineNewsService,\n SpineSettingsService,\n spineSuggestionsEnabled,\n} from '@trismegisto/spine/layout';\nimport { map } from 'rxjs';\nimport { HomeShortcut, destinations, entryShortcuts, modules, systemAreas, trailFor } from './home-shortcuts';\n\n/** Remembers, for the whole app load, that the home screen already jumped to the only screen. */\n@Injectable({ providedIn: 'root' })\nexport class HomeAutoRedirect {\n done = false;\n}\n\ninterface RecentRow extends QuickAccessItem {\n readonly where: string;\n readonly when: string;\n}\n\n/** A top-level module in \"Explore systems\": what is inside it and where it starts. */\ninterface SystemCard {\n readonly id: string;\n readonly label: string;\n readonly icon: string;\n /** Descrição do nó no menu (vazia = sem linha). */\n readonly description: string;\n /** \"13 telas\", na etiqueta ao lado do nome. */\n readonly count: string;\n readonly chips: readonly string[];\n readonly redirect: string;\n}\n\nconst TRAIL_SEPARATOR = ' › ';\n// Recentes e favoritos lado a lado mostram o mesmo número de linhas; o resto fica no \"Ver tudo\".\nconst RECENT_ROWS = 5;\nconst FAVORITE_ROWS = 5;\nconst NEWS_ROWS = 2;\nconst SYSTEM_CHIPS = 3;\nconst MINUTE = 60_000;\nconst HOUR = 60 * MINUTE;\nconst DAY = 24 * HOUR;\n\nlet instances = 0;\n\nfunction cleanTree(view: Parameters<typeof spineRoutesOf>[0]): Route[] {\n return spineRoutesOf(view).filter((node): node is Route => node != null);\n}\n\nfunction pathOf(redirect: string | null | undefined): string {\n return (redirect ?? '').split(/[?#]/)[0];\n}\n\nfunction labelOf(node: Route): string {\n return (node.route_display_name ?? node.route_name ?? '').trim();\n}\n\n@Component({\n selector: 'home',\n imports: [NgTemplateOutlet, IconButtonComponent, IconComponent, MenuButtonComponent, StatePageComponent],\n templateUrl: './home.component.html',\n styleUrl: './home.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class HomeComponent {\n private readonly router = inject(Router);\n private readonly injector = inject(Injector);\n private readonly quickAccess = inject(SpineQuickAccessService);\n private readonly docs = inject(SpineDocsService);\n private readonly settings = inject(SpineSettingsService);\n private readonly news = inject(SpineNewsService);\n private readonly autoRedirect = inject(HomeAutoRedirect);\n private readonly messages = inject(SPINE_MESSAGES);\n protected readonly t = this.messages.home;\n /** \"Sugestões do app\" em Ajuda e recursos, só com o recurso ligado (o mesmo nome da página). */\n protected readonly suggestions = spineSuggestionsEnabled() ? this.messages.suggestions.page.title : null;\n protected readonly suggestionsPath = SPINE_SUGGESTIONS_PAGE_PATH;\n protected readonly uid = `home-${++instances}`;\n\n private readonly view = inject(ViewService);\n private readonly tree = toSignal(this.view.currentView$.pipe(map(cleanTree)), {\n initialValue: cleanTree(this.view.currentView),\n });\n\n /** \"Bom dia, Lucas\": the first name from the session, the salutation from the hour the page was opened. */\n protected readonly greeting = this.greet(inject(AuthorizationService, { optional: true })?.profile?.name);\n\n private readonly workDestinations = computed(() => destinations(modules(this.tree())));\n protected readonly noAccess = computed(() => this.tree().length > 0 && modules(this.tree()).length === 0);\n protected readonly areas = computed(() => systemAreas(this.tree()));\n\n private readonly shortcuts = computed(() => entryShortcuts(this.tree()));\n protected readonly workTiles = computed(() => this.shortcuts().filter((s) => !s.privileged));\n protected readonly adminTiles = computed(() => this.shortcuts().filter((s) => s.privileged));\n protected readonly descended = computed(() => this.shortcuts().some((s) => s.trail.length > 0));\n\n /**\n * Screens the current badge can open (every page in the tree, the start pages included). Recents and favorites\n * are filtered by it: switching badges hides what the new one cannot reach, without forgetting it.\n */\n private readonly reachable = computed(() => {\n const tree = this.tree();\n return new Set([...destinations(tree).map((d) => pathOf(d.redirect)), ...systemAreas(tree).map((a) => pathOf(a.route_redirect))]);\n });\n private readonly canOpen = (item: QuickAccessItem) => this.reachable().has(pathOf(item.redirect));\n\n /** Top-level modules with something inside: their first sub-items as chips and the first screen to open. */\n protected readonly systems = computed<readonly SystemCard[]>(() =>\n modules(this.tree()).flatMap((node) => {\n const children = (node.routes ?? []).filter((child): child is Route => child != null);\n const screens = destinations([node]);\n if (children.length < 2 || screens.length === 0) return [];\n return [\n {\n id: node.routed_id,\n label: labelOf(node),\n icon: node.route_icon || 'grid-layout',\n description: (node.description ?? '').trim(),\n count: pluralMessage(this.t.screenCount, screens.length, this.messages.meta.locale),\n chips: children.slice(0, SYSTEM_CHIPS).map(labelOf).filter(Boolean),\n redirect: node.route_redirect || screens[0].redirect,\n },\n ];\n }),\n );\n\n protected readonly showAllRecents = signal(false);\n protected readonly showAllFavorites = signal(false);\n\n protected readonly favorites = computed(() => this.quickAccess.favorites().filter(this.canOpen));\n protected readonly visibleFavorites = computed(() =>\n this.showAllFavorites() ? this.favorites() : this.favorites().slice(0, FAVORITE_ROWS),\n );\n protected readonly moreFavorites = computed(() => this.favorites().length > FAVORITE_ROWS);\n\n private readonly allRecents = computed<readonly RecentRow[]>(() => {\n const now = Date.now();\n return this.quickAccess\n .recents()\n .filter(this.canOpen)\n .map((item) => ({ ...item, where: this.whereOf(item), when: this.whenOf(item, now) }));\n });\n protected readonly recentRows = computed(() =>\n this.showAllRecents() ? this.allRecents() : this.allRecents().slice(0, RECENT_ROWS),\n );\n protected readonly moreRecents = computed(() => this.allRecents().length > RECENT_ROWS);\n\n protected readonly newsRows = computed(() => this.news.highlights().slice(0, NEWS_ROWS));\n protected readonly recentMenu: readonly MenuItem[] = [{ id: 'forget', label: this.t.forgetRecent, icon: 'times' }];\n\n constructor() {\n effect(() => {\n const only = this.workDestinations();\n if (only.length !== 1 || this.autoRedirect.done) return;\n this.autoRedirect.done = true;\n void this.router.navigateByUrl(only[0].redirect, { replaceUrl: true });\n });\n }\n\n protected caption(tile: HomeShortcut): string {\n if (tile.screens > 0) return pluralMessage(this.t.screenCount, tile.screens, this.messages.meta.locale);\n return tile.trail.join(TRAIL_SEPARATOR);\n }\n\n /** Where the screen sits in the menu; empty for a top-level screen (nothing above it to show). */\n protected whereOf(item: QuickAccessItem): string {\n const trail = item.trail ?? trailFor(this.tree(), item.redirect);\n return trail?.join(TRAIL_SEPARATOR) ?? '';\n }\n\n protected isFavorite(id: string): boolean {\n return this.quickAccess.isFavorite(id);\n }\n\n protected favoriteLabel(row: RecentRow): string {\n const template = this.isFavorite(row.id) ? this.t.unfavorite : this.t.favorite;\n return formatMessage(template, { name: row.displayName });\n }\n\n protected toggleFavorite(row: RecentRow): void {\n this.quickAccess.toggleFavorite({\n id: row.id,\n icon: row.icon,\n displayName: row.displayName,\n redirect: row.redirect,\n trail: row.trail ?? trailFor(this.tree(), row.redirect) ?? [],\n });\n }\n\n protected recentMenuLabel(row: RecentRow): string {\n return formatMessage(this.t.recentActions, { name: row.displayName });\n }\n\n protected onRecentMenu(row: RecentRow, action: string): void {\n if (action === 'forget') this.quickAccess.forgetRecent(row.id);\n }\n\n protected go(redirect: string | null | undefined): void {\n if (redirect) void this.router.navigateByUrl(redirect);\n }\n\n protected openSettings(): void {\n this.settings.open();\n }\n\n protected openDocs(): void {\n this.docs.openIndex();\n }\n\n // Lidos na hora do clique: a home não precisa montar o painel de atalhos nem a configuração inicial para aparecer.\n protected openShortcuts(): void {\n this.injector.get(ShortcutService).help$.next();\n }\n\n protected openEssentials(): void {\n this.injector.get(SpineInitialSetupService).openEssentials();\n }\n\n /** Com `id`: abre o painel já com a novidade aberta; sem, a lista. */\n protected openNews(id?: string): void {\n if (id) this.news.showItem(id);\n else this.news.showAll();\n }\n\n private greet(fullName: string | null | undefined): string {\n const hour = new Date().getHours();\n const greeting = hour < 12 ? this.t.morning : hour < 18 ? this.t.afternoon : this.t.evening;\n const name = (fullName ?? '').trim().split(/\\s+/)[0];\n return name ? formatMessage(this.t.greetingName, { greeting, name }) : greeting;\n }\n\n /** \"Há 12 min\", \"Ontem\", \"Há 2 dias\" (Intl, no idioma do catálogo); vazio para item gravado sem horário. */\n private whenOf(item: QuickAccessItem, now: number): string {\n if (!item.visitedAt) return '';\n const locale = this.messages.meta.locale;\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto', style: 'short' });\n const ago = Math.max(0, now - item.visitedAt);\n const text =\n ago < MINUTE\n ? rtf.format(0, 'second')\n : ago < HOUR\n ? rtf.format(-Math.floor(ago / MINUTE), 'minute')\n : ago < DAY\n ? rtf.format(-Math.floor(ago / HOUR), 'hour')\n : rtf.format(-Math.floor(ago / DAY), 'day');\n return text.charAt(0).toLocaleUpperCase(locale) + text.slice(1);\n }\n}\n","@if (noAccess()) {\n <hm-state-page kind=\"no-rights\" [heading]=\"t.noAccessTitle\" [description]=\"t.noAccessText\" action=\"\" />\n} @else {\n <div class=\"home\">\n <!-- Saudação à esquerda; as novidades, quando houver, ocupam o espaço à direita dela. -->\n <div class=\"hero\">\n <div class=\"hero__text\">\n <p class=\"hero__greeting\">{{ greeting }}</p>\n <p class=\"hero__intro\">{{ t.intro }}</p>\n </div>\n @if (newsRows().length) {\n <!-- Compacto: cabeçalho numa linha e cada novidade numa linha só (título e o começo do texto). -->\n <section class=\"card card--compact hero__news\" [attr.aria-labelledby]=\"uid + '-news'\">\n <div class=\"card__head\">\n <span class=\"card__heading\">\n <h2 class=\"card__title\" [id]=\"uid + '-news'\">{{ t.news }}</h2>\n <span class=\"badge\">{{ t.newsBadge }}</span>\n </span>\n <button type=\"button\" class=\"more\" (click)=\"openNews()\">{{ t.newsAll }}</button>\n </div>\n <ul class=\"list\">\n @for (entry of newsRows(); track entry.id) {\n <li>\n <button type=\"button\" class=\"news\" [title]=\"entry.title + ' — ' + entry.text\" (click)=\"openNews(entry.id)\">\n <span class=\"news__dot\" [class.news__dot--seen]=\"!entry.unseen\" aria-hidden=\"true\"></span>\n <span class=\"news__title\">{{ entry.title }}</span>\n <span class=\"news__body\">{{ entry.text }}</span>\n </button>\n </li>\n }\n </ul>\n </section>\n }\n </div>\n\n <!-- Atalhos de trabalho e privilegiados dividem a mesma linha (cada grupo na proporção dos seus atalhos). -->\n @if (workTiles().length || adminTiles().length) {\n <div class=\"shortcuts\">\n @if (workTiles().length) {\n <section class=\"block shortcuts__group\" [style.--tiles]=\"workTiles().length\" [attr.aria-labelledby]=\"uid + '-work'\">\n <h2 class=\"block__title\" [id]=\"uid + '-work'\">{{ descended() ? t.yourScreens : t.modules }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: workTiles(), admin: false }\" />\n </section>\n }\n @if (adminTiles().length) {\n <section class=\"block shortcuts__group\" [style.--tiles]=\"adminTiles().length\" [attr.aria-labelledby]=\"uid + '-admin'\">\n <h2 class=\"block__title\" [id]=\"uid + '-admin'\">{{ t.privileged }}</h2>\n <ng-container *ngTemplateOutlet=\"tileGrid; context: { $implicit: adminTiles(), admin: true }\" />\n </section>\n }\n </div>\n }\n\n <!-- Linha 1: o que a pessoa usa (recentes | favoritos). Linha 2: o resto do sistema (módulos | ajuda).\n Sem um dos lados, o outro ocupa a linha inteira. -->\n <div class=\"pair\">\n @if (recentRows().length) {\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-recent'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-recent'\">{{ t.recent }}</h2>\n @if (moreRecents()) {\n <button type=\"button\" class=\"more\" [attr.aria-expanded]=\"showAllRecents()\" (click)=\"showAllRecents.set(!showAllRecents())\">\n {{ showAllRecents() ? t.seeLess : t.seeAll }}\n </button>\n }\n </div>\n <ul class=\"list\" [attr.aria-label]=\"t.recentCaption\">\n @for (item of recentRows(); track item.id) {\n <li class=\"recent\">\n <button type=\"button\" class=\"recent__open\" (click)=\"go(item.redirect)\">\n <hm-icon class=\"recent__icon\" [shape]=\"item.icon || 'grid-layout'\" />\n <span class=\"recent__name\">{{ item.displayName }}</span>\n <span class=\"recent__where\">{{ item.where }}</span>\n @if (item.when) {\n <span class=\"recent__when\">{{ item.when }}</span>\n }\n </button>\n <hm-icon-button\n emphasis=\"subtle\"\n size=\"small\"\n icon=\"heart\"\n [solid]=\"isFavorite(item.id)\"\n [class.heart--on]=\"isFavorite(item.id)\"\n [label]=\"favoriteLabel(item)\"\n (clicked)=\"toggleFavorite(item)\"\n />\n <hm-menu-button\n class=\"recent__menu\"\n icon=\"ellipsis-vertical\"\n shape=\"circle\"\n size=\"small\"\n align=\"end\"\n [showArrow]=\"false\"\n [label]=\"recentMenuLabel(item)\"\n [items]=\"recentMenu\"\n (chosen)=\"onRecentMenu(item, $event)\"\n />\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-fav'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-fav'\">{{ t.favorites }}</h2>\n @if (moreFavorites()) {\n <button type=\"button\" class=\"more\" [attr.aria-expanded]=\"showAllFavorites()\" (click)=\"showAllFavorites.set(!showAllFavorites())\">\n {{ showAllFavorites() ? t.seeLess : t.seeAll }}\n </button>\n }\n </div>\n @if (visibleFavorites().length) {\n <ul class=\"list\">\n @for (fav of visibleFavorites(); track fav.id) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(fav.redirect)\">\n <hm-icon class=\"row__icon\" [shape]=\"fav.icon || 'grid-layout'\" />\n <span class=\"row__name\">{{ fav.displayName }}</span>\n <span class=\"row__meta\">{{ whereOf(fav) }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n </ul>\n } @else {\n <p class=\"card__empty\">{{ t.favoritesEmpty }}</p>\n }\n </section>\n </div>\n\n <div class=\"pair\">\n @if (systems().length) {\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-systems'\">\n <div class=\"card__head card__head--stacked\">\n <h2 class=\"card__title\" [id]=\"uid + '-systems'\">{{ t.explore }}</h2>\n <p class=\"card__intro\">{{ t.exploreIntro }}</p>\n </div>\n <ul class=\"systems\">\n @for (system of systems(); track system.id) {\n <!-- O card inteiro abre o módulo (como os atalhos): uma seta no canto, sem link próprio. -->\n <li class=\"systems__cell\">\n <button type=\"button\" class=\"system\" (click)=\"go(system.redirect)\">\n <span class=\"system__head\">\n <hm-icon class=\"system__icon\" [shape]=\"system.icon\" size=\"lg\" />\n <span class=\"system__name\" [title]=\"system.label\">{{ system.label }}</span>\n <span class=\"badge badge--neutral\">{{ system.count }}</span>\n <hm-icon class=\"system__chevron\" shape=\"angle-right\" size=\"sm\" />\n </span>\n @if (system.description) {\n <span class=\"system__description\">{{ system.description }}</span>\n }\n @if (system.chips.length) {\n <span class=\"system__chips\">\n @for (chip of system.chips; track chip) {\n <span class=\"system__chip\">{{ chip }}</span>\n }\n </span>\n }\n </button>\n </li>\n }\n </ul>\n </section>\n }\n\n <section class=\"card\" [attr.aria-labelledby]=\"uid + '-help'\">\n <div class=\"card__head\">\n <h2 class=\"card__title\" [id]=\"uid + '-help'\">{{ t.help }}</h2>\n </div>\n <ul class=\"list\">\n @for (area of areas(); track area.routed_id) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(area.route_redirect)\">\n <hm-icon class=\"row__icon\" [shape]=\"area.route_icon || 'home'\" />\n <span class=\"row__name\">{{ area.route_display_name }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openDocs()\">\n <hm-icon class=\"row__icon\" shape=\"book\" />\n <span class=\"row__name\">{{ t.systemDocs }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n @if (suggestions) {\n <li>\n <button type=\"button\" class=\"row\" (click)=\"go(suggestionsPath)\">\n <hm-icon class=\"row__icon\" shape=\"lightbulb\" />\n <span class=\"row__name\">{{ suggestions }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openShortcuts()\">\n <hm-icon class=\"row__icon\" shape=\"keyboard\" />\n <span class=\"row__name\">{{ t.shortcuts }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openEssentials()\">\n <hm-icon class=\"row__icon\" shape=\"help\" />\n <span class=\"row__name\">{{ t.essentials }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n <li>\n <button type=\"button\" class=\"row\" (click)=\"openSettings()\">\n <hm-icon class=\"row__icon\" shape=\"cog\" />\n <span class=\"row__name\">{{ t.settings }}</span>\n <hm-icon class=\"row__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n </ul>\n </section>\n </div>\n </div>\n}\n\n<ng-template #tileGrid let-tiles let-admin=\"admin\">\n <ul class=\"tiles\" [class.tiles--admin]=\"admin\">\n @for (tile of tiles; track tile.id; let i = $index) {\n <li class=\"tiles__cell\" [style.--tile-order]=\"i\">\n <button type=\"button\" class=\"tile\" (click)=\"go(tile.redirect)\">\n <hm-icon class=\"tile__icon\" [shape]=\"tile.icon ?? 'grid-layout'\" size=\"lg\" />\n <span class=\"tile__text\">\n <span class=\"tile__label\">{{ tile.label }}</span>\n @if (caption(tile); as meta) {\n <span class=\"tile__meta\">{{ meta }}</span>\n }\n </span>\n <hm-icon class=\"tile__chevron\" shape=\"angle-right\" size=\"sm\" />\n </button>\n </li>\n }\n </ul>\n</ng-template>\n"],"names":["labelOf"],"mappings":";;;;;;;;;;;;;AA4BA;AACA,MAAM,SAAS,GAAG,EAAE;AAEpB,MAAM,eAAe,GAAG,IAAI,GAAG,CAC7B;IACE,sCAAsC;IACtC,oCAAoC;IACpC,sCAAsC;IACtC,qCAAqC;IACrC,8CAA8C;;IAE9C,oCAAoC;IACpC,2CAA2C;IAC3C,uCAAuC;AACxC,CAAA,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE,CAAC,CAChC;AACD,MAAM,aAAa,GAAG,oCAAoC,CAAC,WAAW,EAAE;AAExE,SAAS,UAAU,CAAC,IAAW,EAAA;AAC7B,IAAA,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,KAAK,KAAqB,KAAK,IAAI,IAAI,CAAC;AAC7E;AAEA,SAASA,SAAO,CAAC,IAAW,EAAA;AAC1B,IAAA,OAAO,CAAC,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,IAAI,EAAE;AAClE;AAEA,SAAS,UAAU,CAAC,IAAW,EAAA;AAC7B,IAAA,OAAO,IAAI,CAAC,cAAc,IAAI,GAAG,IAAI,CAAC,UAAU,IAAI,MAAM,CAAA,CAAA,EAAI,IAAI,CAAC,SAAS,EAAE;AAChF;AAEA,SAAS,UAAU,CAAC,IAAW,EAAA;IAC7B,OAAO,CAAC,IAAI,CAAC,yBAAyB,IAAI,EAAE,EAAE,WAAW,EAAE;AAC7D;AAEM,SAAU,MAAM,CAAC,IAAW,EAAA;IAChC,OAAO,CAAC,CAAC,IAAI,CAAC,cAAc,KAAK,IAAI,CAAC,UAAU,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AAC/F;AAEM,SAAU,MAAM,CAAC,IAAW,EAAA;AAChC,IAAA,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,aAAa,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,KAAK,MAAM,CAAC;AAC3F;AAEM,SAAU,OAAO,CAAC,IAAsB,EAAA;AAC5C,IAAA,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC7D;AAEM,SAAU,WAAW,CAAC,IAAsB,EAAA;AAChD,IAAA,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;AAC5D;SAEgB,YAAY,CAAC,IAAsB,EAAE,QAA2B,EAAE,EAAA;IAChF,MAAM,KAAK,GAAsB,EAAE;AACnC,IAAA,MAAM,IAAI,GAAG,CAAC,KAAuB,EAAE,IAAuB,KAAI;AAChE,QAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;YACxB,IAAI,IAAI,IAAI,IAAI;gBAAE;AAClB,YAAA,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE;AAChB,gBAAA,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAEA,SAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,cAAe,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YACxI;AACA,YAAA,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC;YAC7B,IAAI,IAAI,CAAC,MAAM;AAAE,gBAAA,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAEA,SAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACvD;AACF,IAAA,CAAC;AACD,IAAA,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;AACjB,IAAA,OAAO,KAAK;AACd;AAEM,SAAU,QAAQ,CAAC,IAAsB,EAAE,QAAgB,EAAA;IAC/D,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,EAAE,KAAK,IAAI,IAAI;AAC/E;AAEA,SAAS,YAAY,CAAC,IAAW,EAAA;AAC/B,IAAA,OAAO,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;AACrF;AAQA,SAAS,iBAAiB,CAAC,IAAW,EAAA;AACpC,IAAA,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC9F;AAEA;AACA,SAAS,OAAO,CAAC,KAA2B,EAAA;IAC1C,IAAI,OAAO,GAAG,KAAK;IACnB,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,KAAI;QAClC,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;QACzC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,IAAI,CAAC;QAC/B,OAAO,GAAG,IAAI;AACd,QAAA,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,EAAEA,SAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;AAC3E,IAAA,CAAC,CAAC;IACF,OAAO,OAAO,GAAG,IAAI,GAAG,IAAI;AAC9B;AAEA,SAAS,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAa,EAAA;IACxD,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;IAClC,OAAO;AACL,QAAA,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC;AACpB,QAAA,KAAK,EAAEA,SAAO,CAAC,IAAI,CAAC;AACpB,QAAA,IAAI,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;AAC7B,QAAA,QAAQ,EAAE,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,IAAI,EAAE;QACzD,KAAK;AACL,QAAA,OAAO,EAAE,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9C,UAAU;KACX;AACH;AAEA;;;AAGG;AACG,SAAU,cAAc,CAAC,IAAsB,EAAA;AACnD,IAAA,IAAI,KAAK,GAAyB,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACpH,IAAA,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;AAC3C,QAAA,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;AAC3B,QAAA,IAAI,CAAC,IAAI;YAAE;QACX,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,SAAS;YAAE;QACnD,KAAK,GAAG,IAAI;IACd;AACA,IAAA,OAAO,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;AAC9B;;ACnIA;MAEa,gBAAgB,CAAA;AAD7B,IAAA,WAAA,GAAA;QAEE,IAAA,CAAA,IAAI,GAAG,KAAK;AACb,IAAA;+GAFY,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAhB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,gBAAgB,cADH,MAAM,EAAA,CAAA,CAAA;;4FACnB,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAD5B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;AAuBlC,MAAM,eAAe,GAAG,KAAK;AAC7B;AACA,MAAM,WAAW,GAAG,CAAC;AACrB,MAAM,aAAa,GAAG,CAAC;AACvB,MAAM,SAAS,GAAG,CAAC;AACnB,MAAM,YAAY,GAAG,CAAC;AACtB,MAAM,MAAM,GAAG,MAAM;AACrB,MAAM,IAAI,GAAG,EAAE,GAAG,MAAM;AACxB,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI;AAErB,IAAI,SAAS,GAAG,CAAC;AAEjB,SAAS,SAAS,CAAC,IAAyC,EAAA;AAC1D,IAAA,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,KAAoB,IAAI,IAAI,IAAI,CAAC;AAC1E;AAEA,SAAS,MAAM,CAAC,QAAmC,EAAA;AACjD,IAAA,OAAO,CAAC,QAAQ,IAAI,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAC1C;AAEA,SAAS,OAAO,CAAC,IAAW,EAAA;AAC1B,IAAA,OAAO,CAAC,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,IAAI,EAAE;AAClE;MASa,aAAa,CAAA;AAsFxB,IAAA,WAAA,GAAA;AArFiB,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,QAAA,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAC3B,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,uBAAuB,CAAC;AAC7C,QAAA,IAAA,CAAA,IAAI,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAC/B,QAAA,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAC,oBAAoB,CAAC;AACvC,QAAA,IAAA,CAAA,IAAI,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAC/B,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAC,gBAAgB,CAAC;AACvC,QAAA,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAC;AAC/B,QAAA,IAAA,CAAA,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI;;AAEtB,QAAA,IAAA,CAAA,WAAW,GAAG,uBAAuB,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI;QACrF,IAAA,CAAA,eAAe,GAAG,2BAA2B;AAC7C,QAAA,IAAA,CAAA,GAAG,GAAG,CAAA,KAAA,EAAQ,EAAE,SAAS,EAAE;AAE7B,QAAA,IAAA,CAAA,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC;AAC1B,QAAA,IAAA,CAAA,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE;YAC5E,YAAY,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;AAC/C,SAAA,CAAC;;QAGiB,IAAA,CAAA,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC;AAExF,QAAA,IAAA,CAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,uFAAC;QACnE,IAAA,CAAA,QAAQ,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,UAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAC;AACtF,QAAA,IAAA,CAAA,KAAK,GAAG,QAAQ,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,4EAAC;AAElD,QAAA,IAAA,CAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,gFAAC;QACrD,IAAA,CAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,WAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAC;QACzE,IAAA,CAAA,UAAU,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,YAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAC;QACzE,IAAA,CAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,WAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAC;AAE/F;;;AAGG;AACc,QAAA,IAAA,CAAA,SAAS,GAAG,QAAQ,CAAC,MAAK;AACzC,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE;YACxB,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACnI,QAAA,CAAC,gFAAC;QACe,IAAA,CAAA,OAAO,GAAG,CAAC,IAAqB,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;;AAG9E,QAAA,IAAA,CAAA,OAAO,GAAG,QAAQ,CAAwB,MAC3D,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,KAAI;YACpC,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,KAAK,KAAqB,KAAK,IAAI,IAAI,CAAC;YACrF,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;AAAE,gBAAA,OAAO,EAAE;YAC1D,OAAO;AACL,gBAAA;oBACE,EAAE,EAAE,IAAI,CAAC,SAAS;AAClB,oBAAA,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC;AACpB,oBAAA,IAAI,EAAE,IAAI,CAAC,UAAU,IAAI,aAAa;oBACtC,WAAW,EAAE,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,EAAE,IAAI,EAAE;oBAC5C,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;AACnF,oBAAA,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;oBACnE,QAAQ,EAAE,IAAI,CAAC,cAAc,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ;AACrD,iBAAA;aACF;QACH,CAAC,CAAC,8EACH;AAEkB,QAAA,IAAA,CAAA,cAAc,GAAG,MAAM,CAAC,KAAK,qFAAC;AAC9B,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,KAAK,uFAAC;QAEhC,IAAA,CAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,gFAAC;AAC7E,QAAA,IAAA,CAAA,gBAAgB,GAAG,QAAQ,CAAC,MAC7C,IAAI,CAAC,gBAAgB,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,uFACtF;AACkB,QAAA,IAAA,CAAA,aAAa,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,GAAG,aAAa,oFAAC;AAEzE,QAAA,IAAA,CAAA,UAAU,GAAG,QAAQ,CAAuB,MAAK;AAChE,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;YACtB,OAAO,IAAI,CAAC;AACT,iBAAA,OAAO;AACP,iBAAA,MAAM,CAAC,IAAI,CAAC,OAAO;AACnB,iBAAA,GAAG,CAAC,CAAC,IAAI,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;AAC1F,QAAA,CAAC,iFAAC;AACiB,QAAA,IAAA,CAAA,UAAU,GAAG,QAAQ,CAAC,MACvC,IAAI,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,iFACpF;AACkB,QAAA,IAAA,CAAA,WAAW,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC,MAAM,GAAG,WAAW,kFAAC;QAEpE,IAAA,CAAA,QAAQ,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,+EAAC;QACrE,IAAA,CAAA,UAAU,GAAwB,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAGhH,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,EAAE;YACpC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI;gBAAE;AACjD,YAAA,IAAI,CAAC,YAAY,CAAC,IAAI,GAAG,IAAI;AAC7B,YAAA,KAAK,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AACxE,QAAA,CAAC,CAAC;IACJ;AAEU,IAAA,OAAO,CAAC,IAAkB,EAAA;AAClC,QAAA,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC;YAAE,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;QACvG,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC;IACzC;;AAGU,IAAA,OAAO,CAAC,IAAqB,EAAA;AACrC,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC;QAChE,OAAO,KAAK,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE;IAC3C;AAEU,IAAA,UAAU,CAAC,EAAU,EAAA;QAC7B,OAAO,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;IACxC;AAEU,IAAA,aAAa,CAAC,GAAc,EAAA;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ;AAC9E,QAAA,OAAO,aAAa,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;IAC3D;AAEU,IAAA,cAAc,CAAC,GAAc,EAAA;AACrC,QAAA,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;YAC9B,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,QAAQ,EAAE,GAAG,CAAC,QAAQ;AACtB,YAAA,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE;AAC9D,SAAA,CAAC;IACJ;AAEU,IAAA,eAAe,CAAC,GAAc,EAAA;AACtC,QAAA,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;IACvE;IAEU,YAAY,CAAC,GAAc,EAAE,MAAc,EAAA;QACnD,IAAI,MAAM,KAAK,QAAQ;YAAE,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;IAChE;AAEU,IAAA,EAAE,CAAC,QAAmC,EAAA;AAC9C,QAAA,IAAI,QAAQ;YAAE,KAAK,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC;IACxD;IAEU,YAAY,GAAA;AACpB,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;IACtB;IAEU,QAAQ,GAAA;AAChB,QAAA,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;IACvB;;IAGU,aAAa,GAAA;AACrB,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE;IACjD;IAEU,cAAc,GAAA;QACtB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,cAAc,EAAE;IAC9D;;AAGU,IAAA,QAAQ,CAAC,EAAW,EAAA;AAC5B,QAAA,IAAI,EAAE;AAAE,YAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;;AACzB,YAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;IAC1B;AAEQ,IAAA,KAAK,CAAC,QAAmC,EAAA;QAC/C,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,QAAQ,EAAE;AAClC,QAAA,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO;AAC3F,QAAA,MAAM,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACpD,OAAO,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,GAAG,QAAQ;IACjF;;IAGQ,MAAM,CAAC,IAAqB,EAAE,GAAW,EAAA;QAC/C,IAAI,CAAC,IAAI,CAAC,SAAS;AAAE,YAAA,OAAO,EAAE;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM;AACxC,QAAA,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACpF,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC;AAC7C,QAAA,MAAM,IAAI,GACR,GAAG,GAAG;cACF,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ;cACtB,GAAG,GAAG;AACN,kBAAE,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,QAAQ;kBAC9C,GAAG,GAAG;AACN,sBAAE,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,EAAE,MAAM;AAC5C,sBAAE,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,KAAK,CAAC;AACnD,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACjE;+GAtLW,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;mGAAb,aAAa,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC3E1B,m1WAiPA,EAAA,MAAA,EAAA,CAAA,q+PAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,ED3KY,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,mBAAmB,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAAA,eAAA,EAAA,UAAA,EAAA,QAAA,EAAA,MAAA,EAAA,UAAA,EAAA,QAAA,EAAA,SAAA,EAAA,cAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,EAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,aAAa,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,WAAA,EAAA,MAAA,EAAA,OAAA,EAAA,OAAA,EAAA,QAAA,EAAA,MAAA,EAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,mBAAmB,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAAA,WAAA,EAAA,OAAA,EAAA,MAAA,EAAA,MAAA,EAAA,OAAA,EAAA,OAAA,EAAA,cAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,EAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,kBAAkB,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,SAAA,EAAA,aAAA,EAAA,QAAA,EAAA,YAAA,CAAA,EAAA,OAAA,EAAA,CAAA,iBAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAK5F,aAAa,EAAA,UAAA,EAAA,CAAA;kBAPzB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,MAAM,EAAA,OAAA,EACP,CAAC,gBAAgB,EAAE,mBAAmB,EAAE,aAAa,EAAE,mBAAmB,EAAE,kBAAkB,CAAC,EAAA,eAAA,EAGvF,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,m1WAAA,EAAA,MAAA,EAAA,CAAA,q+PAAA,CAAA,EAAA;;;"}
@@ -42,14 +42,14 @@ const AUTO_SERVICE_HOME_TEMPLATE_ROUTER_ID = '6a9a13db-f31b-494e-b51c-79af0ac28b
42
42
  * do carregamento inicial. Não exporte as telas no `public-api.ts` (ver o comentário lá).
43
43
  */
44
44
  const AUTO_SERVICE_SCREENS = {
45
- home: () => import('./trismegisto-spine-auto-service-home.component-rQ3dIGIE.mjs').then(m => m.HomeComponent),
45
+ home: () => import('./trismegisto-spine-auto-service-home.component-9WvXOH3l.mjs').then(m => m.HomeComponent),
46
46
  groups: () => import('./trismegisto-spine-auto-service-auto-service-groups.component-BYjIQ9ID.mjs').then(m => m.AutoServiceGroupsComponent),
47
47
  apps: () => import('./trismegisto-spine-auto-service-auto-service.component-QsIQ61w2.mjs').then(m => m.AutoServiceComponent),
48
48
  client: () => import('./trismegisto-spine-auto-service-auto-service-client.component-BAfeLyTB.mjs').then(m => m.AutoServiceClientComponent),
49
49
  audit: () => import('./trismegisto-spine-auto-service-auto-service-audit.component-D8HUpZtA.mjs').then(m => m.AutoServiceAuditComponent),
50
50
  loginAttempts: () => import('./trismegisto-spine-auto-service-auto-service-login-attempts.component-DoyhkSYc.mjs').then(m => m.AutoServiceLoginAttemptsComponent),
51
51
  news: () => import('./trismegisto-spine-auto-service-auto-service-news-page.component-CBemH4hr.mjs').then(m => m.AutoServiceNewsPageComponent),
52
- suggestions: () => import('./trismegisto-spine-auto-service-auto-service-suggestions-page.component-DIeunpQ9.mjs').then(m => m.AutoServiceSuggestionsPageComponent),
52
+ suggestions: () => import('./trismegisto-spine-auto-service-auto-service-suggestions-page.component-mMjE3JOL.mjs').then(m => m.AutoServiceSuggestionsPageComponent),
53
53
  ratings: () => import('./trismegisto-spine-auto-service-auto-service-ratings-page.component-C_THGTkw.mjs').then(m => m.AutoServiceRatingsPageComponent),
54
54
  };
55
55
  /**
@@ -93,8 +93,10 @@ function injectGraphqlClient(namedClient) {
93
93
  const result = await firstValueFrom(client().mutate({ mutation: document, variables, context: contextOf(options) }));
94
94
  return required(result.data);
95
95
  },
96
+ // `no-cache` explícito: o Apollo não aplica `defaultOptions` em subscription e, sem policy, grava cada evento no
97
+ // InMemoryCache (write + diff da árvore inteira) - com payload de MBs isso trava a aba por segundos a cada evento.
96
98
  subscribe(document, variables) {
97
- return client().subscribe({ query: document, variables }).pipe(map((result) => result.data), filter((data) => data !== null && data !== undefined));
99
+ return client().subscribe({ query: document, variables, fetchPolicy: 'no-cache' }).pipe(map((result) => result.data), filter((data) => data !== null && data !== undefined));
98
100
  },
99
101
  };
100
102
  /* eslint-enable @typescript-eslint/no-explicit-any */
@@ -1 +1 @@
1
- {"version":3,"file":"trismegisto-spine-graphql.mjs","sources":["../../../projects/ui/graphql/src/envelope.ts","../../../projects/ui/graphql/src/graphql-client.ts","../../../projects/ui/graphql/src/provide-graphql.ts","../../../projects/ui/graphql/src/trismegisto-spine-graphql.ts"],"sourcesContent":["import { currentSpineMessages } from '@trismegisto/spine';\n\n/** Shape every root query/mutation field returns on the platform: business status travels in the payload. */\nexport interface GraphqlEnvelope<T> {\n readonly status?: number | string | null;\n readonly message?: string | null;\n readonly data?: T | null;\n}\n\n/** Business failure carried by an envelope. `status` is kept exactly as the backend sent it. */\nexport class GraphqlEnvelopeError extends Error {\n readonly status: number | string | null | undefined;\n\n constructor(status: number | string | null | undefined, message: string) {\n super(message);\n this.name = 'GraphqlEnvelopeError';\n this.status = status;\n // Keeps `instanceof` working when the output is down-levelled.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nconst FAILURE_WORDS = new Set(['error', 'failed', 'failure', 'fail']);\n\nexport function isEnvelopeOk(status: GraphqlEnvelope<unknown>['status']): boolean {\n if (status === null || status === undefined) return true;\n if (typeof status === 'number') return status >= 200 && status < 300;\n if (typeof status !== 'string') return true;\n // Numeric text is deliberately not parsed: only the failure words count as failure.\n return !FAILURE_WORDS.has(status.trim().toLowerCase());\n}\n\n/** Returns `data` of an ok envelope; throws `GraphqlEnvelopeError` for a missing or failed one. */\nexport function unwrap<T>(envelope: GraphqlEnvelope<T> | null | undefined): T {\n if (envelope === null || envelope === undefined) {\n throw new GraphqlEnvelopeError(null, currentSpineMessages().graphql.noResponse);\n }\n if (!isEnvelopeOk(envelope.status)) {\n throw new GraphqlEnvelopeError(envelope.status, envelope.message || currentSpineMessages().graphql.failed);\n }\n return envelope.data as T;\n}\n\ntype Fields = [string, Record<string, unknown>][];\n\nfunction objectFields(data: unknown): Fields {\n if (!data || typeof data !== 'object') return [];\n return Object.entries(data as Record<string, unknown>).filter(\n (entry): entry is [string, Record<string, unknown>] => typeof entry[1] === 'object' && entry[1] !== null,\n );\n}\n\nconst hasStatus = (value: Record<string, unknown>): boolean =>\n 'status' in value && value['status'] !== null && value['status'] !== undefined;\n\n/** First-level envelopes found in an operation's `data` (fields that carry both `status` and `message`). */\nexport function envelopesOf(data: unknown): { field: string; status: number | string; message: string; ok: boolean }[] {\n return objectFields(data)\n .filter(([, value]) => 'message' in value && hasStatus(value))\n .map(([field, value]) => {\n const status = value['status'] as number | string;\n return { field, status, message: (value['message'] as string | null) ?? '', ok: isEnvelopeOk(status) };\n });\n}\n\n/** First-level fields whose status is a failure; `message` is optional here. */\nexport function failedEnvelopes(\n data: unknown,\n fallbackMessage: string = currentSpineMessages().graphql.serviceFailure,\n): { field: string; status: unknown; message: string }[] {\n return objectFields(data)\n .filter(([, value]) => hasStatus(value) && !isEnvelopeOk(value['status'] as GraphqlEnvelope<unknown>['status']))\n .map(([field, value]) => ({\n field,\n status: value['status'],\n message: (value['message'] as string | null | undefined) || fallbackMessage,\n }));\n}\n","import { inject } from '@angular/core';\nimport type { DefaultContext, OperationVariables, TypedDocumentNode } from '@apollo/client/core';\nimport { Apollo } from 'apollo-angular';\nimport { Observable, filter, firstValueFrom, map } from 'rxjs';\n\nimport { currentSpineMessages } from '@trismegisto/spine';\nimport { GraphqlEnvelopeError } from './envelope';\n\n/** Opções de uma chamada. `silenceEnvelope`: a tela trata a falha sozinha, sem o toast automático. */\nexport interface GraphqlCallOptions {\n readonly silenceEnvelope?: boolean;\n readonly context?: DefaultContext;\n}\n\n/**\n * Cliente GraphQL de UM backend do app, tipado pelo documento gerado no codegen\n * (`TypedDocumentNode`): o retorno é o `data` da operação, sem `<any>`. Junto com o `unwrap` do\n * envelope, é o caminho padrão dos serviços de domínio:\n *\n * private readonly gql = injectGraphqlClient('main');\n * async listTeams() { return unwrap((await this.gql.query(ListTeamsDocument)).teams); }\n *\n * Erro de transporte/GraphQL (`errors[]`) rejeita a Promise (o `errorPolicy` é o padrão `none`);\n * resposta sem `data` também. Falha de NEGÓCIO vem no envelope e quem decide é o `unwrap`.\n */\nexport interface GraphqlClient {\n query<T, V extends OperationVariables = OperationVariables>(\n document: TypedDocumentNode<T, V>, variables?: V, options?: GraphqlCallOptions): Promise<T>;\n mutate<T, V extends OperationVariables = OperationVariables>(\n document: TypedDocumentNode<T, V>, variables?: V, options?: GraphqlCallOptions): Promise<T>;\n /** Eventos da subscription (sem envelope: evento não é resposta). Mensagem sem `data` é ignorada. */\n subscribe<T, V extends OperationVariables = OperationVariables>(\n document: TypedDocumentNode<T, V>, variables?: V): Observable<T>;\n}\n\nconst contextOf = (options?: GraphqlCallOptions): DefaultContext | undefined =>\n options?.silenceEnvelope ? { ...options.context, silenceEnvelope: true } : options?.context;\n\nconst required = <T>(data: T | null | undefined): T => {\n if (data === null || data === undefined) throw new GraphqlEnvelopeError(null, currentSpineMessages().graphql.noResponse);\n return data;\n};\n\n/** O `GraphqlClient` do backend `namedClient` (`environment.graphql.<chave>.namedClient`). Chamar em contexto de injeção. */\nexport function injectGraphqlClient(namedClient: string): GraphqlClient {\n const apollo = inject(Apollo);\n const client = () => apollo.use(namedClient);\n // Os genéricos do apollo-angular não casam 1:1 com os do TypedDocumentNode (variáveis opcionais):\n // o tipo público acima é o contrato; aqui dentro o cast é deliberado.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n return {\n async query(document: any, variables?: any, options?: GraphqlCallOptions) {\n const result = await firstValueFrom(client().query<any, any>({ query: document, variables, context: contextOf(options) }));\n return required(result.data);\n },\n async mutate(document: any, variables?: any, options?: GraphqlCallOptions) {\n const result = await firstValueFrom(client().mutate<any, any>({ mutation: document, variables, context: contextOf(options) }));\n return required(result.data);\n },\n subscribe(document: any, variables?: any) {\n return client().subscribe<any, any>({ query: document, variables }).pipe(\n map((result) => result.data),\n filter((data) => data !== null && data !== undefined),\n );\n },\n } as GraphqlClient;\n /* eslint-enable @typescript-eslint/no-explicit-any */\n}\n","import { DOCUMENT, DestroyRef, PLATFORM_ID, Provider, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { HttpHeaders } from '@angular/common/http';\nimport { ApolloLink, CombinedGraphQLErrors, InMemoryCache } from '@apollo/client';\nimport { ErrorLink } from '@apollo/client/link/error';\nimport { GraphQLWsLink } from '@apollo/client/link/subscriptions';\nimport { NamedOptions, provideNamedApollo } from 'apollo-angular';\nimport { HttpBatchLink } from 'apollo-angular/http';\nimport { OperationTypeNode } from 'graphql';\nimport { Client, createClient } from 'graphql-ws';\nimport { Subject, tap } from 'rxjs';\n\nimport { AuthorizationService } from '@orfeu/angular/core';\nimport { SPINE_CONFIG, SPINE_MESSAGES, SpineMessages } from '@trismegisto/spine';\nimport { AlertType, NotificationService } from '@trismegisto/spine/notification';\nimport { LoggerService } from '@trismegisto/spine/routing';\n\nimport { envelopesOf } from './envelope';\n\nexport interface GraphqlEndpoint {\n // Mutable on purpose: the runtime environment rewrites `http`/`ws` before bootstrap.\n namedClient: string;\n http: string;\n ws?: string;\n}\n\nexport interface GraphqlOptions {\n readonly endpoints: Readonly<Record<string, GraphqlEndpoint>>;\n}\n\n/** Emits the `namedClient` whose socket came back after a drop (never on the first connection). */\nexport const wsReconnected$ = new Subject<string>();\n\nconst TOKEN_HEADER = 'x-access-token';\nconst AUTH_CODES = new Set([401, 4401, 4403]);\nconst AUTH_RESET_WINDOW_MS = 5_000;\nconst STALE_TAB_MS = 60_000;\n// Well under the ~60 s idle cut most reverse proxies apply.\nconst PING_EVERY_MS = 20_000;\nconst RETRY_BASE_MS = 1_000;\nconst RETRY_CAP_MS = 30_000;\nconst TOAST_OK_SECONDS = 4;\nconst TOAST_FAIL_SECONDS = 8;\n// graphql-ws gives up on some close codes no matter what `shouldRetry` says; reporting them as this\n// \"try again later\" code keeps the socket coming back.\nconst RETRYABLE_CLOSE = 1013;\n\ntype InitPayload = Record<string, unknown>;\n\nexport function provideGraphql(options: GraphqlOptions): Provider {\n return provideNamedApollo(() => buildClients(options));\n}\n\nfunction buildClients(options: GraphqlOptions): NamedOptions {\n const auth = inject(AuthorizationService);\n const messages = inject(SPINE_MESSAGES);\n const batchLink = inject(HttpBatchLink);\n const notifications = inject(NotificationService, { optional: true });\n const logger = inject(LoggerService, { optional: true });\n const config = inject(SPINE_CONFIG, { optional: true });\n const browser = isPlatformBrowser(inject(PLATFORM_ID));\n\n const sockets: Client[] = [];\n const dropAllSockets = () => {\n for (const socket of sockets) {\n try {\n socket.terminate();\n } catch {\n // already dead: nothing to do\n }\n }\n };\n\n let lastAuthReset = -Infinity;\n const authErrorLink = new ErrorLink(({ error }) => {\n if (!carriesAuthCode(error)) return;\n const now = Date.now();\n if (now - lastAuthReset < AUTH_RESET_WINDOW_MS) return;\n lastAuthReset = now;\n dropAllSockets();\n });\n\n const tokenLink = new ApolloLink((operation, forward) => {\n const token = auth.getToken();\n if (token) {\n operation.setContext(({ headers }: { headers?: HttpHeaders | Record<string, string> }) => ({\n headers: toHttpHeaders(headers).set(TOKEN_HEADER, token),\n }));\n }\n return forward(operation);\n });\n\n const toastLink = notifications ? envelopeToastLink(notifications, messages) : null;\n\n const socketParams = async (): Promise<InitPayload> => {\n const token = await validToken(auth);\n if (!token) return {};\n const params: InitPayload = { [TOKEN_HEADER]: token, headers: { [TOKEN_HEADER]: token } };\n const routeId = logger?.routeId;\n if (routeId) params['routeId'] = routeId;\n if (config?.clientId) params['clientId'] = config.clientId;\n return params;\n };\n\n const named: NamedOptions = {};\n for (const endpoint of Object.values(options.endpoints)) {\n const httpLink = ApolloLink.concat(tokenLink, batchLink.create({ uri: endpoint.http }));\n let transport: ApolloLink = httpLink;\n\n if (browser && endpoint.ws) {\n const socket = openSocket(endpoint, socketParams);\n sockets.push(socket);\n transport = ApolloLink.split(\n (operation) => operation.operationType === OperationTypeNode.SUBSCRIPTION,\n new GraphQLWsLink(socket),\n httpLink,\n );\n }\n\n named[endpoint.namedClient] = {\n link: ApolloLink.from(toastLink ? [authErrorLink, toastLink, transport] : [authErrorLink, transport]),\n cache: new InMemoryCache(),\n defaultOptions: {\n query: { fetchPolicy: 'no-cache' },\n watchQuery: { fetchPolicy: 'no-cache' },\n },\n };\n }\n\n const destroyRef = inject(DestroyRef);\n if (browser && sockets.length) {\n const doc = inject(DOCUMENT);\n let hiddenAt: number | null = null;\n const onVisibility = () => {\n if (doc.visibilityState === 'hidden') {\n hiddenAt = Date.now();\n return;\n }\n if (doc.visibilityState !== 'visible' || hiddenAt === null) return;\n const away = Date.now() - hiddenAt;\n hiddenAt = null;\n if (away >= STALE_TAB_MS) dropAllSockets();\n };\n doc.addEventListener('visibilitychange', onVisibility);\n destroyRef.onDestroy(() => doc.removeEventListener('visibilitychange', onVisibility));\n }\n destroyRef.onDestroy(() => {\n for (const socket of sockets) {\n Promise.resolve()\n .then(() => socket.dispose())\n .catch(() => undefined);\n }\n });\n\n return named;\n}\n\n/**\n * The socket skips HttpClient (and the @orfeu/angular token interceptor), so on (re)connect it asks for a token that\n * is not stale: `getValidToken` (@orfeu/angular 1.7+) waits for the renewal when the tab's timers were held past the\n * expiry. Older versions only have `getToken`.\n */\nfunction validToken(auth: AuthorizationService): Promise<string | null> {\n const renewing = auth as unknown as { getValidToken?: () => Promise<string | null> };\n return renewing.getValidToken ? renewing.getValidToken() : Promise.resolve(auth.getToken());\n}\n\nfunction openSocket(endpoint: GraphqlEndpoint, connectionParams: () => Promise<InitPayload>): Client {\n let everConnected = false;\n return createClient({\n url: endpoint.ws!,\n connectionParams,\n keepAlive: PING_EVERY_MS,\n retryAttempts: Infinity,\n shouldRetry: () => true,\n retryWait: backoff,\n webSocketImpl: forgivingSocket(globalThis.WebSocket),\n on: {\n connected: (_socket, _payload, wasRetry) => {\n if (wasRetry && everConnected) wsReconnected$.next(endpoint.namedClient);\n everConnected = true;\n },\n },\n });\n}\n\n/** Exponential wait with \"equal jitter\": half fixed, half random, capped. */\nfunction backoff(attempt: number): Promise<void> {\n const ceiling = Math.min(RETRY_CAP_MS, RETRY_BASE_MS * 2 ** attempt);\n const wait = ceiling / 2 + Math.random() * (ceiling / 2);\n return new Promise((resolve) => setTimeout(resolve, wait));\n}\n\n/**\n * Thin wrapper around the platform WebSocket that reports every abnormal close as retryable, so the\n * client keeps reconnecting even after closes graphql-ws would otherwise treat as final.\n */\nfunction forgivingSocket(Native: typeof WebSocket): typeof WebSocket {\n class ForgivingSocket {\n static readonly CONNECTING = 0;\n static readonly OPEN = 1;\n static readonly CLOSING = 2;\n static readonly CLOSED = 3;\n\n private readonly inner: WebSocket;\n\n constructor(url: string | URL, protocols?: string | string[]) {\n this.inner = new Native(url, protocols);\n }\n\n get readyState(): number {\n return this.inner.readyState;\n }\n\n get protocol(): string {\n return this.inner.protocol;\n }\n\n set onopen(handler: WebSocket['onopen']) {\n this.inner.onopen = handler;\n }\n\n set onmessage(handler: WebSocket['onmessage']) {\n this.inner.onmessage = handler;\n }\n\n set onerror(handler: WebSocket['onerror']) {\n this.inner.onerror = handler;\n }\n\n set onclose(handler: ((event: CloseEvent) => void) | null) {\n this.inner.onclose = handler\n ? (event: CloseEvent) =>\n handler({\n code: event.code === 1000 ? 1000 : RETRYABLE_CLOSE,\n reason: event.reason,\n wasClean: event.wasClean,\n } as CloseEvent)\n : null;\n }\n\n send(data: string): void {\n this.inner.send(data);\n }\n\n close(code?: number, reason?: string): void {\n this.inner.close(code, reason);\n }\n }\n return ForgivingSocket as unknown as typeof WebSocket;\n}\n\nfunction toHttpHeaders(headers: HttpHeaders | Record<string, string> | undefined): HttpHeaders {\n if (headers instanceof HttpHeaders) return headers;\n return new HttpHeaders(headers ?? {});\n}\n\nfunction codeOf(source: unknown): number | null {\n if (!source || typeof source !== 'object') return null;\n const record = source as Record<string, unknown>;\n for (const key of ['code', 'status', 'statusCode']) {\n const value = record[key];\n if (value !== undefined && value !== null && value !== '') {\n const code = Number(value);\n if (Number.isFinite(code)) return code;\n }\n }\n return null;\n}\n\nfunction carriesAuthCode(error: unknown): boolean {\n const codes = CombinedGraphQLErrors.is(error)\n ? error.errors.map((entry) => codeOf(entry.extensions))\n : [codeOf(error)];\n return codes.some((code) => code !== null && AUTH_CODES.has(code));\n}\n\nfunction envelopeToastLink(notifications: NotificationService, messages: SpineMessages): ApolloLink {\n return new ApolloLink((operation, forward) => {\n const kind = operation.operationType;\n if (kind === OperationTypeNode.SUBSCRIPTION || operation.getContext()['silenceEnvelope'] === true) {\n return forward(operation);\n }\n const isMutation = kind === OperationTypeNode.MUTATION;\n return forward(operation).pipe(\n tap((result) => {\n for (const envelope of envelopesOf(result.data)) {\n if (envelope.ok ? !isMutation || !envelope.message : !isMutation && String(envelope.status) === '404') {\n continue;\n }\n const numeric = Number(envelope.status);\n notifications.addNotification({\n timer: envelope.ok ? TOAST_OK_SECONDS : TOAST_FAIL_SECONDS,\n hermesAlertType: Number.isFinite(numeric)\n ? notifications.resolveAlertType(numeric)\n : envelope.ok\n ? AlertType.SUCCESS\n : AlertType.DANGER,\n message: envelope.message || (envelope.ok ? messages.graphql.done : messages.graphql.failed),\n hermesAlertClosable: true,\n });\n }\n }),\n );\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"trismegisto-spine-graphql.mjs","sources":["../../../projects/ui/graphql/src/envelope.ts","../../../projects/ui/graphql/src/graphql-client.ts","../../../projects/ui/graphql/src/provide-graphql.ts","../../../projects/ui/graphql/src/trismegisto-spine-graphql.ts"],"sourcesContent":["import { currentSpineMessages } from '@trismegisto/spine';\n\n/** Shape every root query/mutation field returns on the platform: business status travels in the payload. */\nexport interface GraphqlEnvelope<T> {\n readonly status?: number | string | null;\n readonly message?: string | null;\n readonly data?: T | null;\n}\n\n/** Business failure carried by an envelope. `status` is kept exactly as the backend sent it. */\nexport class GraphqlEnvelopeError extends Error {\n readonly status: number | string | null | undefined;\n\n constructor(status: number | string | null | undefined, message: string) {\n super(message);\n this.name = 'GraphqlEnvelopeError';\n this.status = status;\n // Keeps `instanceof` working when the output is down-levelled.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nconst FAILURE_WORDS = new Set(['error', 'failed', 'failure', 'fail']);\n\nexport function isEnvelopeOk(status: GraphqlEnvelope<unknown>['status']): boolean {\n if (status === null || status === undefined) return true;\n if (typeof status === 'number') return status >= 200 && status < 300;\n if (typeof status !== 'string') return true;\n // Numeric text is deliberately not parsed: only the failure words count as failure.\n return !FAILURE_WORDS.has(status.trim().toLowerCase());\n}\n\n/** Returns `data` of an ok envelope; throws `GraphqlEnvelopeError` for a missing or failed one. */\nexport function unwrap<T>(envelope: GraphqlEnvelope<T> | null | undefined): T {\n if (envelope === null || envelope === undefined) {\n throw new GraphqlEnvelopeError(null, currentSpineMessages().graphql.noResponse);\n }\n if (!isEnvelopeOk(envelope.status)) {\n throw new GraphqlEnvelopeError(envelope.status, envelope.message || currentSpineMessages().graphql.failed);\n }\n return envelope.data as T;\n}\n\ntype Fields = [string, Record<string, unknown>][];\n\nfunction objectFields(data: unknown): Fields {\n if (!data || typeof data !== 'object') return [];\n return Object.entries(data as Record<string, unknown>).filter(\n (entry): entry is [string, Record<string, unknown>] => typeof entry[1] === 'object' && entry[1] !== null,\n );\n}\n\nconst hasStatus = (value: Record<string, unknown>): boolean =>\n 'status' in value && value['status'] !== null && value['status'] !== undefined;\n\n/** First-level envelopes found in an operation's `data` (fields that carry both `status` and `message`). */\nexport function envelopesOf(data: unknown): { field: string; status: number | string; message: string; ok: boolean }[] {\n return objectFields(data)\n .filter(([, value]) => 'message' in value && hasStatus(value))\n .map(([field, value]) => {\n const status = value['status'] as number | string;\n return { field, status, message: (value['message'] as string | null) ?? '', ok: isEnvelopeOk(status) };\n });\n}\n\n/** First-level fields whose status is a failure; `message` is optional here. */\nexport function failedEnvelopes(\n data: unknown,\n fallbackMessage: string = currentSpineMessages().graphql.serviceFailure,\n): { field: string; status: unknown; message: string }[] {\n return objectFields(data)\n .filter(([, value]) => hasStatus(value) && !isEnvelopeOk(value['status'] as GraphqlEnvelope<unknown>['status']))\n .map(([field, value]) => ({\n field,\n status: value['status'],\n message: (value['message'] as string | null | undefined) || fallbackMessage,\n }));\n}\n","import { inject } from '@angular/core';\nimport type { DefaultContext, OperationVariables, TypedDocumentNode } from '@apollo/client/core';\nimport { Apollo } from 'apollo-angular';\nimport { Observable, filter, firstValueFrom, map } from 'rxjs';\n\nimport { currentSpineMessages } from '@trismegisto/spine';\nimport { GraphqlEnvelopeError } from './envelope';\n\n/** Opções de uma chamada. `silenceEnvelope`: a tela trata a falha sozinha, sem o toast automático. */\nexport interface GraphqlCallOptions {\n readonly silenceEnvelope?: boolean;\n readonly context?: DefaultContext;\n}\n\n/**\n * Cliente GraphQL de UM backend do app, tipado pelo documento gerado no codegen\n * (`TypedDocumentNode`): o retorno é o `data` da operação, sem `<any>`. Junto com o `unwrap` do\n * envelope, é o caminho padrão dos serviços de domínio:\n *\n * private readonly gql = injectGraphqlClient('main');\n * async listTeams() { return unwrap((await this.gql.query(ListTeamsDocument)).teams); }\n *\n * Erro de transporte/GraphQL (`errors[]`) rejeita a Promise (o `errorPolicy` é o padrão `none`);\n * resposta sem `data` também. Falha de NEGÓCIO vem no envelope e quem decide é o `unwrap`.\n */\nexport interface GraphqlClient {\n query<T, V extends OperationVariables = OperationVariables>(\n document: TypedDocumentNode<T, V>, variables?: V, options?: GraphqlCallOptions): Promise<T>;\n mutate<T, V extends OperationVariables = OperationVariables>(\n document: TypedDocumentNode<T, V>, variables?: V, options?: GraphqlCallOptions): Promise<T>;\n /** Eventos da subscription (sem envelope: evento não é resposta). Mensagem sem `data` é ignorada. */\n subscribe<T, V extends OperationVariables = OperationVariables>(\n document: TypedDocumentNode<T, V>, variables?: V): Observable<T>;\n}\n\nconst contextOf = (options?: GraphqlCallOptions): DefaultContext | undefined =>\n options?.silenceEnvelope ? { ...options.context, silenceEnvelope: true } : options?.context;\n\nconst required = <T>(data: T | null | undefined): T => {\n if (data === null || data === undefined) throw new GraphqlEnvelopeError(null, currentSpineMessages().graphql.noResponse);\n return data;\n};\n\n/** O `GraphqlClient` do backend `namedClient` (`environment.graphql.<chave>.namedClient`). Chamar em contexto de injeção. */\nexport function injectGraphqlClient(namedClient: string): GraphqlClient {\n const apollo = inject(Apollo);\n const client = () => apollo.use(namedClient);\n // Os genéricos do apollo-angular não casam 1:1 com os do TypedDocumentNode (variáveis opcionais):\n // o tipo público acima é o contrato; aqui dentro o cast é deliberado.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n return {\n async query(document: any, variables?: any, options?: GraphqlCallOptions) {\n const result = await firstValueFrom(client().query<any, any>({ query: document, variables, context: contextOf(options) }));\n return required(result.data);\n },\n async mutate(document: any, variables?: any, options?: GraphqlCallOptions) {\n const result = await firstValueFrom(client().mutate<any, any>({ mutation: document, variables, context: contextOf(options) }));\n return required(result.data);\n },\n // `no-cache` explícito: o Apollo não aplica `defaultOptions` em subscription e, sem policy, grava cada evento no\n // InMemoryCache (write + diff da árvore inteira) - com payload de MBs isso trava a aba por segundos a cada evento.\n subscribe(document: any, variables?: any) {\n return client().subscribe<any, any>({ query: document, variables, fetchPolicy: 'no-cache' }).pipe(\n map((result) => result.data),\n filter((data) => data !== null && data !== undefined),\n );\n },\n } as GraphqlClient;\n /* eslint-enable @typescript-eslint/no-explicit-any */\n}\n","import { DOCUMENT, DestroyRef, PLATFORM_ID, Provider, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { HttpHeaders } from '@angular/common/http';\nimport { ApolloLink, CombinedGraphQLErrors, InMemoryCache } from '@apollo/client';\nimport { ErrorLink } from '@apollo/client/link/error';\nimport { GraphQLWsLink } from '@apollo/client/link/subscriptions';\nimport { NamedOptions, provideNamedApollo } from 'apollo-angular';\nimport { HttpBatchLink } from 'apollo-angular/http';\nimport { OperationTypeNode } from 'graphql';\nimport { Client, createClient } from 'graphql-ws';\nimport { Subject, tap } from 'rxjs';\n\nimport { AuthorizationService } from '@orfeu/angular/core';\nimport { SPINE_CONFIG, SPINE_MESSAGES, SpineMessages } from '@trismegisto/spine';\nimport { AlertType, NotificationService } from '@trismegisto/spine/notification';\nimport { LoggerService } from '@trismegisto/spine/routing';\n\nimport { envelopesOf } from './envelope';\n\nexport interface GraphqlEndpoint {\n // Mutable on purpose: the runtime environment rewrites `http`/`ws` before bootstrap.\n namedClient: string;\n http: string;\n ws?: string;\n}\n\nexport interface GraphqlOptions {\n readonly endpoints: Readonly<Record<string, GraphqlEndpoint>>;\n}\n\n/** Emits the `namedClient` whose socket came back after a drop (never on the first connection). */\nexport const wsReconnected$ = new Subject<string>();\n\nconst TOKEN_HEADER = 'x-access-token';\nconst AUTH_CODES = new Set([401, 4401, 4403]);\nconst AUTH_RESET_WINDOW_MS = 5_000;\nconst STALE_TAB_MS = 60_000;\n// Well under the ~60 s idle cut most reverse proxies apply.\nconst PING_EVERY_MS = 20_000;\nconst RETRY_BASE_MS = 1_000;\nconst RETRY_CAP_MS = 30_000;\nconst TOAST_OK_SECONDS = 4;\nconst TOAST_FAIL_SECONDS = 8;\n// graphql-ws gives up on some close codes no matter what `shouldRetry` says; reporting them as this\n// \"try again later\" code keeps the socket coming back.\nconst RETRYABLE_CLOSE = 1013;\n\ntype InitPayload = Record<string, unknown>;\n\nexport function provideGraphql(options: GraphqlOptions): Provider {\n return provideNamedApollo(() => buildClients(options));\n}\n\nfunction buildClients(options: GraphqlOptions): NamedOptions {\n const auth = inject(AuthorizationService);\n const messages = inject(SPINE_MESSAGES);\n const batchLink = inject(HttpBatchLink);\n const notifications = inject(NotificationService, { optional: true });\n const logger = inject(LoggerService, { optional: true });\n const config = inject(SPINE_CONFIG, { optional: true });\n const browser = isPlatformBrowser(inject(PLATFORM_ID));\n\n const sockets: Client[] = [];\n const dropAllSockets = () => {\n for (const socket of sockets) {\n try {\n socket.terminate();\n } catch {\n // already dead: nothing to do\n }\n }\n };\n\n let lastAuthReset = -Infinity;\n const authErrorLink = new ErrorLink(({ error }) => {\n if (!carriesAuthCode(error)) return;\n const now = Date.now();\n if (now - lastAuthReset < AUTH_RESET_WINDOW_MS) return;\n lastAuthReset = now;\n dropAllSockets();\n });\n\n const tokenLink = new ApolloLink((operation, forward) => {\n const token = auth.getToken();\n if (token) {\n operation.setContext(({ headers }: { headers?: HttpHeaders | Record<string, string> }) => ({\n headers: toHttpHeaders(headers).set(TOKEN_HEADER, token),\n }));\n }\n return forward(operation);\n });\n\n const toastLink = notifications ? envelopeToastLink(notifications, messages) : null;\n\n const socketParams = async (): Promise<InitPayload> => {\n const token = await validToken(auth);\n if (!token) return {};\n const params: InitPayload = { [TOKEN_HEADER]: token, headers: { [TOKEN_HEADER]: token } };\n const routeId = logger?.routeId;\n if (routeId) params['routeId'] = routeId;\n if (config?.clientId) params['clientId'] = config.clientId;\n return params;\n };\n\n const named: NamedOptions = {};\n for (const endpoint of Object.values(options.endpoints)) {\n const httpLink = ApolloLink.concat(tokenLink, batchLink.create({ uri: endpoint.http }));\n let transport: ApolloLink = httpLink;\n\n if (browser && endpoint.ws) {\n const socket = openSocket(endpoint, socketParams);\n sockets.push(socket);\n transport = ApolloLink.split(\n (operation) => operation.operationType === OperationTypeNode.SUBSCRIPTION,\n new GraphQLWsLink(socket),\n httpLink,\n );\n }\n\n named[endpoint.namedClient] = {\n link: ApolloLink.from(toastLink ? [authErrorLink, toastLink, transport] : [authErrorLink, transport]),\n cache: new InMemoryCache(),\n defaultOptions: {\n query: { fetchPolicy: 'no-cache' },\n watchQuery: { fetchPolicy: 'no-cache' },\n },\n };\n }\n\n const destroyRef = inject(DestroyRef);\n if (browser && sockets.length) {\n const doc = inject(DOCUMENT);\n let hiddenAt: number | null = null;\n const onVisibility = () => {\n if (doc.visibilityState === 'hidden') {\n hiddenAt = Date.now();\n return;\n }\n if (doc.visibilityState !== 'visible' || hiddenAt === null) return;\n const away = Date.now() - hiddenAt;\n hiddenAt = null;\n if (away >= STALE_TAB_MS) dropAllSockets();\n };\n doc.addEventListener('visibilitychange', onVisibility);\n destroyRef.onDestroy(() => doc.removeEventListener('visibilitychange', onVisibility));\n }\n destroyRef.onDestroy(() => {\n for (const socket of sockets) {\n Promise.resolve()\n .then(() => socket.dispose())\n .catch(() => undefined);\n }\n });\n\n return named;\n}\n\n/**\n * The socket skips HttpClient (and the @orfeu/angular token interceptor), so on (re)connect it asks for a token that\n * is not stale: `getValidToken` (@orfeu/angular 1.7+) waits for the renewal when the tab's timers were held past the\n * expiry. Older versions only have `getToken`.\n */\nfunction validToken(auth: AuthorizationService): Promise<string | null> {\n const renewing = auth as unknown as { getValidToken?: () => Promise<string | null> };\n return renewing.getValidToken ? renewing.getValidToken() : Promise.resolve(auth.getToken());\n}\n\nfunction openSocket(endpoint: GraphqlEndpoint, connectionParams: () => Promise<InitPayload>): Client {\n let everConnected = false;\n return createClient({\n url: endpoint.ws!,\n connectionParams,\n keepAlive: PING_EVERY_MS,\n retryAttempts: Infinity,\n shouldRetry: () => true,\n retryWait: backoff,\n webSocketImpl: forgivingSocket(globalThis.WebSocket),\n on: {\n connected: (_socket, _payload, wasRetry) => {\n if (wasRetry && everConnected) wsReconnected$.next(endpoint.namedClient);\n everConnected = true;\n },\n },\n });\n}\n\n/** Exponential wait with \"equal jitter\": half fixed, half random, capped. */\nfunction backoff(attempt: number): Promise<void> {\n const ceiling = Math.min(RETRY_CAP_MS, RETRY_BASE_MS * 2 ** attempt);\n const wait = ceiling / 2 + Math.random() * (ceiling / 2);\n return new Promise((resolve) => setTimeout(resolve, wait));\n}\n\n/**\n * Thin wrapper around the platform WebSocket that reports every abnormal close as retryable, so the\n * client keeps reconnecting even after closes graphql-ws would otherwise treat as final.\n */\nfunction forgivingSocket(Native: typeof WebSocket): typeof WebSocket {\n class ForgivingSocket {\n static readonly CONNECTING = 0;\n static readonly OPEN = 1;\n static readonly CLOSING = 2;\n static readonly CLOSED = 3;\n\n private readonly inner: WebSocket;\n\n constructor(url: string | URL, protocols?: string | string[]) {\n this.inner = new Native(url, protocols);\n }\n\n get readyState(): number {\n return this.inner.readyState;\n }\n\n get protocol(): string {\n return this.inner.protocol;\n }\n\n set onopen(handler: WebSocket['onopen']) {\n this.inner.onopen = handler;\n }\n\n set onmessage(handler: WebSocket['onmessage']) {\n this.inner.onmessage = handler;\n }\n\n set onerror(handler: WebSocket['onerror']) {\n this.inner.onerror = handler;\n }\n\n set onclose(handler: ((event: CloseEvent) => void) | null) {\n this.inner.onclose = handler\n ? (event: CloseEvent) =>\n handler({\n code: event.code === 1000 ? 1000 : RETRYABLE_CLOSE,\n reason: event.reason,\n wasClean: event.wasClean,\n } as CloseEvent)\n : null;\n }\n\n send(data: string): void {\n this.inner.send(data);\n }\n\n close(code?: number, reason?: string): void {\n this.inner.close(code, reason);\n }\n }\n return ForgivingSocket as unknown as typeof WebSocket;\n}\n\nfunction toHttpHeaders(headers: HttpHeaders | Record<string, string> | undefined): HttpHeaders {\n if (headers instanceof HttpHeaders) return headers;\n return new HttpHeaders(headers ?? {});\n}\n\nfunction codeOf(source: unknown): number | null {\n if (!source || typeof source !== 'object') return null;\n const record = source as Record<string, unknown>;\n for (const key of ['code', 'status', 'statusCode']) {\n const value = record[key];\n if (value !== undefined && value !== null && value !== '') {\n const code = Number(value);\n if (Number.isFinite(code)) return code;\n }\n }\n return null;\n}\n\nfunction carriesAuthCode(error: unknown): boolean {\n const codes = CombinedGraphQLErrors.is(error)\n ? error.errors.map((entry) => codeOf(entry.extensions))\n : [codeOf(error)];\n return codes.some((code) => code !== null && AUTH_CODES.has(code));\n}\n\nfunction envelopeToastLink(notifications: NotificationService, messages: SpineMessages): ApolloLink {\n return new ApolloLink((operation, forward) => {\n const kind = operation.operationType;\n if (kind === OperationTypeNode.SUBSCRIPTION || operation.getContext()['silenceEnvelope'] === true) {\n return forward(operation);\n }\n const isMutation = kind === OperationTypeNode.MUTATION;\n return forward(operation).pipe(\n tap((result) => {\n for (const envelope of envelopesOf(result.data)) {\n if (envelope.ok ? !isMutation || !envelope.message : !isMutation && String(envelope.status) === '404') {\n continue;\n }\n const numeric = Number(envelope.status);\n notifications.addNotification({\n timer: envelope.ok ? TOAST_OK_SECONDS : TOAST_FAIL_SECONDS,\n hermesAlertType: Number.isFinite(numeric)\n ? notifications.resolveAlertType(numeric)\n : envelope.ok\n ? AlertType.SUCCESS\n : AlertType.DANGER,\n message: envelope.message || (envelope.ok ? messages.graphql.done : messages.graphql.failed),\n hermesAlertClosable: true,\n });\n }\n }),\n );\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AASA;AACM,MAAO,oBAAqB,SAAQ,KAAK,CAAA;IAG7C,WAAA,CAAY,MAA0C,EAAE,OAAe,EAAA;QACrE,KAAK,CAAC,OAAO,CAAC;AACd,QAAA,IAAI,CAAC,IAAI,GAAG,sBAAsB;AAClC,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;;QAEpB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IACnD;AACD;AAED,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;AAE/D,SAAU,YAAY,CAAC,MAA0C,EAAA;AACrE,IAAA,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS;AAAE,QAAA,OAAO,IAAI;IACxD,IAAI,OAAO,MAAM,KAAK,QAAQ;AAAE,QAAA,OAAO,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG;IACpE,IAAI,OAAO,MAAM,KAAK,QAAQ;AAAE,QAAA,OAAO,IAAI;;AAE3C,IAAA,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACxD;AAEA;AACM,SAAU,MAAM,CAAI,QAA+C,EAAA;IACvE,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS,EAAE;AAC/C,QAAA,MAAM,IAAI,oBAAoB,CAAC,IAAI,EAAE,oBAAoB,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;IACjF;IACA,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;AAClC,QAAA,MAAM,IAAI,oBAAoB,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,IAAI,oBAAoB,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IAC5G;IACA,OAAO,QAAQ,CAAC,IAAS;AAC3B;AAIA,SAAS,YAAY,CAAC,IAAa,EAAA;AACjC,IAAA,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;AAAE,QAAA,OAAO,EAAE;AAChD,IAAA,OAAO,MAAM,CAAC,OAAO,CAAC,IAA+B,CAAC,CAAC,MAAM,CAC3D,CAAC,KAAK,KAAiD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CACzG;AACH;AAEA,MAAM,SAAS,GAAG,CAAC,KAA8B,KAC/C,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,SAAS;AAEhF;AACM,SAAU,WAAW,CAAC,IAAa,EAAA;IACvC,OAAO,YAAY,CAAC,IAAI;AACrB,SAAA,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,SAAS,IAAI,KAAK,IAAI,SAAS,CAAC,KAAK,CAAC;SAC5D,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,KAAI;AACtB,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAoB;QACjD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAG,KAAK,CAAC,SAAS,CAAmB,IAAI,EAAE,EAAE,EAAE,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE;AACxG,IAAA,CAAC,CAAC;AACN;AAEA;AACM,SAAU,eAAe,CAC7B,IAAa,EACb,eAAA,GAA0B,oBAAoB,EAAE,CAAC,OAAO,CAAC,cAAc,EAAA;IAEvE,OAAO,YAAY,CAAC,IAAI;SACrB,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAuC,CAAC;SAC9G,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM;QACxB,KAAK;AACL,QAAA,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC;AACvB,QAAA,OAAO,EAAG,KAAK,CAAC,SAAS,CAA+B,IAAI,eAAe;AAC5E,KAAA,CAAC,CAAC;AACP;;AC1CA,MAAM,SAAS,GAAG,CAAC,OAA4B,KAC7C,OAAO,EAAE,eAAe,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,OAAO;AAE7F,MAAM,QAAQ,GAAG,CAAI,IAA0B,KAAO;AACpD,IAAA,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS;AAAE,QAAA,MAAM,IAAI,oBAAoB,CAAC,IAAI,EAAE,oBAAoB,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;AACxH,IAAA,OAAO,IAAI;AACb,CAAC;AAED;AACM,SAAU,mBAAmB,CAAC,WAAmB,EAAA;AACrD,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;;;;IAI5C,OAAO;AACL,QAAA,MAAM,KAAK,CAAC,QAAa,EAAE,SAAe,EAAE,OAA4B,EAAA;YACtE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,CAAC,KAAK,CAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC1H,YAAA,OAAO,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;QAC9B,CAAC;AACD,QAAA,MAAM,MAAM,CAAC,QAAa,EAAE,SAAe,EAAE,OAA4B,EAAA;YACvE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,CAAC,MAAM,CAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC9H,YAAA,OAAO,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;QAC9B,CAAC;;;QAGD,SAAS,CAAC,QAAa,EAAE,SAAe,EAAA;YACtC,OAAO,MAAM,EAAE,CAAC,SAAS,CAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC,IAAI,CAC/F,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,EAC5B,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,CAAC,CACtD;QACH,CAAC;KACe;;AAEpB;;ACvCA;AACO,MAAM,cAAc,GAAG,IAAI,OAAO;AAEzC,MAAM,YAAY,GAAG,gBAAgB;AACrC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC7C,MAAM,oBAAoB,GAAG,KAAK;AAClC,MAAM,YAAY,GAAG,MAAM;AAC3B;AACA,MAAM,aAAa,GAAG,MAAM;AAC5B,MAAM,aAAa,GAAG,KAAK;AAC3B,MAAM,YAAY,GAAG,MAAM;AAC3B,MAAM,gBAAgB,GAAG,CAAC;AAC1B,MAAM,kBAAkB,GAAG,CAAC;AAC5B;AACA;AACA,MAAM,eAAe,GAAG,IAAI;AAItB,SAAU,cAAc,CAAC,OAAuB,EAAA;IACpD,OAAO,kBAAkB,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;AACxD;AAEA,SAAS,YAAY,CAAC,OAAuB,EAAA;AAC3C,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,oBAAoB,CAAC;AACzC,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAC;AACvC,IAAA,MAAM,SAAS,GAAG,MAAM,CAAC,aAAa,CAAC;AACvC,IAAA,MAAM,aAAa,GAAG,MAAM,CAAC,mBAAmB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACrE,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACxD,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACvD,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAEtD,MAAM,OAAO,GAAa,EAAE;IAC5B,MAAM,cAAc,GAAG,MAAK;AAC1B,QAAA,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;AAC5B,YAAA,IAAI;gBACF,MAAM,CAAC,SAAS,EAAE;YACpB;AAAE,YAAA,MAAM;;YAER;QACF;AACF,IAAA,CAAC;AAED,IAAA,IAAI,aAAa,GAAG,CAAC,QAAQ;IAC7B,MAAM,aAAa,GAAG,IAAI,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,KAAI;AAChD,QAAA,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;YAAE;AAC7B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;AACtB,QAAA,IAAI,GAAG,GAAG,aAAa,GAAG,oBAAoB;YAAE;QAChD,aAAa,GAAG,GAAG;AACnB,QAAA,cAAc,EAAE;AAClB,IAAA,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,CAAC,SAAS,EAAE,OAAO,KAAI;AACtD,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;QAC7B,IAAI,KAAK,EAAE;YACT,SAAS,CAAC,UAAU,CAAC,CAAC,EAAE,OAAO,EAAsD,MAAM;gBACzF,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC;AACzD,aAAA,CAAC,CAAC;QACL;AACA,QAAA,OAAO,OAAO,CAAC,SAAS,CAAC;AAC3B,IAAA,CAAC,CAAC;AAEF,IAAA,MAAM,SAAS,GAAG,aAAa,GAAG,iBAAiB,CAAC,aAAa,EAAE,QAAQ,CAAC,GAAG,IAAI;AAEnF,IAAA,MAAM,YAAY,GAAG,YAAiC;AACpD,QAAA,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC;AACpC,QAAA,IAAI,CAAC,KAAK;AAAE,YAAA,OAAO,EAAE;AACrB,QAAA,MAAM,MAAM,GAAgB,EAAE,CAAC,YAAY,GAAG,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,GAAG,KAAK,EAAE,EAAE;AACzF,QAAA,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO;AAC/B,QAAA,IAAI,OAAO;AAAE,YAAA,MAAM,CAAC,SAAS,CAAC,GAAG,OAAO;QACxC,IAAI,MAAM,EAAE,QAAQ;AAAE,YAAA,MAAM,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,QAAQ;AAC1D,QAAA,OAAO,MAAM;AACf,IAAA,CAAC;IAED,MAAM,KAAK,GAAiB,EAAE;AAC9B,IAAA,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;QACvD,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QACvF,IAAI,SAAS,GAAe,QAAQ;AAEpC,QAAA,IAAI,OAAO,IAAI,QAAQ,CAAC,EAAE,EAAE;YAC1B,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,EAAE,YAAY,CAAC;AACjD,YAAA,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;YACpB,SAAS,GAAG,UAAU,CAAC,KAAK,CAC1B,CAAC,SAAS,KAAK,SAAS,CAAC,aAAa,KAAK,iBAAiB,CAAC,YAAY,EACzE,IAAI,aAAa,CAAC,MAAM,CAAC,EACzB,QAAQ,CACT;QACH;AAEA,QAAA,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG;YAC5B,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,aAAa,EAAE,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;YACrG,KAAK,EAAE,IAAI,aAAa,EAAE;AAC1B,YAAA,cAAc,EAAE;AACd,gBAAA,KAAK,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE;AAClC,gBAAA,UAAU,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE;AACxC,aAAA;SACF;IACH;AAEA,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AACrC,IAAA,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE;AAC7B,QAAA,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC;QAC5B,IAAI,QAAQ,GAAkB,IAAI;QAClC,MAAM,YAAY,GAAG,MAAK;AACxB,YAAA,IAAI,GAAG,CAAC,eAAe,KAAK,QAAQ,EAAE;AACpC,gBAAA,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE;gBACrB;YACF;YACA,IAAI,GAAG,CAAC,eAAe,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI;gBAAE;YAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ;YAClC,QAAQ,GAAG,IAAI;YACf,IAAI,IAAI,IAAI,YAAY;AAAE,gBAAA,cAAc,EAAE;AAC5C,QAAA,CAAC;AACD,QAAA,GAAG,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,YAAY,CAAC;AACtD,QAAA,UAAU,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;IACvF;AACA,IAAA,UAAU,CAAC,SAAS,CAAC,MAAK;AACxB,QAAA,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;YAC5B,OAAO,CAAC,OAAO;iBACZ,IAAI,CAAC,MAAM,MAAM,CAAC,OAAO,EAAE;AAC3B,iBAAA,KAAK,CAAC,MAAM,SAAS,CAAC;QAC3B;AACF,IAAA,CAAC,CAAC;AAEF,IAAA,OAAO,KAAK;AACd;AAEA;;;;AAIG;AACH,SAAS,UAAU,CAAC,IAA0B,EAAA;IAC5C,MAAM,QAAQ,GAAG,IAAmE;IACpF,OAAO,QAAQ,CAAC,aAAa,GAAG,QAAQ,CAAC,aAAa,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;AAC7F;AAEA,SAAS,UAAU,CAAC,QAAyB,EAAE,gBAA4C,EAAA;IACzF,IAAI,aAAa,GAAG,KAAK;AACzB,IAAA,OAAO,YAAY,CAAC;QAClB,GAAG,EAAE,QAAQ,CAAC,EAAG;QACjB,gBAAgB;AAChB,QAAA,SAAS,EAAE,aAAa;AACxB,QAAA,aAAa,EAAE,QAAQ;AACvB,QAAA,WAAW,EAAE,MAAM,IAAI;AACvB,QAAA,SAAS,EAAE,OAAO;AAClB,QAAA,aAAa,EAAE,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC;AACpD,QAAA,EAAE,EAAE;YACF,SAAS,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,KAAI;gBACzC,IAAI,QAAQ,IAAI,aAAa;AAAE,oBAAA,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;gBACxE,aAAa,GAAG,IAAI;YACtB,CAAC;AACF,SAAA;AACF,KAAA,CAAC;AACJ;AAEA;AACA,SAAS,OAAO,CAAC,OAAe,EAAA;AAC9B,IAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,aAAa,GAAG,CAAC,IAAI,OAAO,CAAC;AACpE,IAAA,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,OAAO,GAAG,CAAC,CAAC;AACxD,IAAA,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC5D;AAEA;;;AAGG;AACH,SAAS,eAAe,CAAC,MAAwB,EAAA;AAC/C,IAAA,MAAM,eAAe,CAAA;iBACH,IAAA,CAAA,UAAU,GAAG,CAAC,CAAC;iBACf,IAAA,CAAA,IAAI,GAAG,CAAC,CAAC;iBACT,IAAA,CAAA,OAAO,GAAG,CAAC,CAAC;iBACZ,IAAA,CAAA,MAAM,GAAG,CAAC,CAAC;QAI3B,WAAA,CAAY,GAAiB,EAAE,SAA6B,EAAA;YAC1D,IAAI,CAAC,KAAK,GAAG,IAAI,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC;QACzC;AAEA,QAAA,IAAI,UAAU,GAAA;AACZ,YAAA,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU;QAC9B;AAEA,QAAA,IAAI,QAAQ,GAAA;AACV,YAAA,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ;QAC5B;QAEA,IAAI,MAAM,CAAC,OAA4B,EAAA;AACrC,YAAA,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,OAAO;QAC7B;QAEA,IAAI,SAAS,CAAC,OAA+B,EAAA;AAC3C,YAAA,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,OAAO;QAChC;QAEA,IAAI,OAAO,CAAC,OAA6B,EAAA;AACvC,YAAA,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO;QAC9B;QAEA,IAAI,OAAO,CAAC,OAA6C,EAAA;AACvD,YAAA,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG;AACnB,kBAAE,CAAC,KAAiB,KAChB,OAAO,CAAC;AACN,oBAAA,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,IAAI,GAAG,IAAI,GAAG,eAAe;oBAClD,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;iBACX;kBACjB,IAAI;QACV;AAEA,QAAA,IAAI,CAAC,IAAY,EAAA;AACf,YAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QACvB;QAEA,KAAK,CAAC,IAAa,EAAE,MAAe,EAAA;YAClC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC;QAChC;;AAEF,IAAA,OAAO,eAA8C;AACvD;AAEA,SAAS,aAAa,CAAC,OAAyD,EAAA;IAC9E,IAAI,OAAO,YAAY,WAAW;AAAE,QAAA,OAAO,OAAO;AAClD,IAAA,OAAO,IAAI,WAAW,CAAC,OAAO,IAAI,EAAE,CAAC;AACvC;AAEA,SAAS,MAAM,CAAC,MAAe,EAAA;AAC7B,IAAA,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;AAAE,QAAA,OAAO,IAAI;IACtD,MAAM,MAAM,GAAG,MAAiC;IAChD,KAAK,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE;AAClD,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC;AACzB,QAAA,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE;AACzD,YAAA,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;AAC1B,YAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;AAAE,gBAAA,OAAO,IAAI;QACxC;IACF;AACA,IAAA,OAAO,IAAI;AACb;AAEA,SAAS,eAAe,CAAC,KAAc,EAAA;AACrC,IAAA,MAAM,KAAK,GAAG,qBAAqB,CAAC,EAAE,CAAC,KAAK;AAC1C,UAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;AACtD,UAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnB,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACpE;AAEA,SAAS,iBAAiB,CAAC,aAAkC,EAAE,QAAuB,EAAA;IACpF,OAAO,IAAI,UAAU,CAAC,CAAC,SAAS,EAAE,OAAO,KAAI;AAC3C,QAAA,MAAM,IAAI,GAAG,SAAS,CAAC,aAAa;AACpC,QAAA,IAAI,IAAI,KAAK,iBAAiB,CAAC,YAAY,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC,iBAAiB,CAAC,KAAK,IAAI,EAAE;AACjG,YAAA,OAAO,OAAO,CAAC,SAAS,CAAC;QAC3B;AACA,QAAA,MAAM,UAAU,GAAG,IAAI,KAAK,iBAAiB,CAAC,QAAQ;AACtD,QAAA,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAC5B,GAAG,CAAC,CAAC,MAAM,KAAI;YACb,KAAK,MAAM,QAAQ,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;AAC/C,gBAAA,IAAI,QAAQ,CAAC,EAAE,GAAG,CAAC,UAAU,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE;oBACrG;gBACF;gBACA,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACvC,aAAa,CAAC,eAAe,CAAC;oBAC5B,KAAK,EAAE,QAAQ,CAAC,EAAE,GAAG,gBAAgB,GAAG,kBAAkB;AAC1D,oBAAA,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO;AACtC,0BAAE,aAAa,CAAC,gBAAgB,CAAC,OAAO;0BACtC,QAAQ,CAAC;8BACP,SAAS,CAAC;8BACV,SAAS,CAAC,MAAM;oBACtB,OAAO,EAAE,QAAQ,CAAC,OAAO,KAAK,QAAQ,CAAC,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;AAC5F,oBAAA,mBAAmB,EAAE,IAAI;AAC1B,iBAAA,CAAC;YACJ;QACF,CAAC,CAAC,CACH;AACH,IAAA,CAAC,CAAC;AACJ;;ACjTA;;AAEG;;"}