@grimoire-rs/indexer 0.4.0 → 0.4.2
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.
- package/README.md +85 -9
- package/dist/cli/enrich.d.ts +1 -0
- package/dist/cli/enrich.d.ts.map +1 -1
- package/dist/cli/enrich.js +38 -0
- package/dist/cli/enrich.js.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +1 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +13 -0
- package/dist/data/index.js.map +1 -1
- package/dist/enrich/checkpoint.d.ts +53 -0
- package/dist/enrich/checkpoint.d.ts.map +1 -0
- package/dist/enrich/checkpoint.js +296 -0
- package/dist/enrich/checkpoint.js.map +1 -0
- package/dist/enrich/index.d.ts +14 -0
- package/dist/enrich/index.d.ts.map +1 -1
- package/dist/enrich/index.js +3 -3
- package/dist/enrich/index.js.map +1 -1
- package/dist/ratings/paging.d.ts +16 -0
- package/dist/ratings/paging.d.ts.map +1 -0
- package/dist/ratings/paging.js +36 -0
- package/dist/ratings/paging.js.map +1 -0
- package/dist/ratings/provider.d.ts +1 -9
- package/dist/ratings/provider.d.ts.map +1 -1
- package/dist/ratings/provider.js +11 -10
- package/dist/ratings/provider.js.map +1 -1
- package/dist/ratings/provider_github.d.ts.map +1 -1
- package/dist/ratings/provider_github.js +2 -1
- package/dist/ratings/provider_github.js.map +1 -1
- package/dist/ratings/provider_gitlab.d.ts.map +1 -1
- package/dist/ratings/provider_gitlab.js +2 -1
- package/dist/ratings/provider_gitlab.js.map +1 -1
- package/dist/ratings/reconcile.d.ts.map +1 -1
- package/dist/ratings/reconcile.js +14 -4
- package/dist/ratings/reconcile.js.map +1 -1
- package/dist/renderer/astro/components/Catalog.js +3 -3
- package/dist/renderer/astro/components/Catalog.tsx +15 -9
- package/dist/renderer/astro/components/CommandField.astro +1 -0
- package/dist/renderer/astro/components/VersionMenu.astro +31 -23
- package/dist/renderer/astro/layouts/Base.astro +212 -264
- package/dist/renderer/astro/pages/p/[...slug].astro +99 -89
- package/dist/renderer/astro/styles/tokens.css +157 -0
- package/dist/validate/adapters/http.d.ts +23 -0
- package/dist/validate/adapters/http.d.ts.map +1 -1
- package/dist/validate/adapters/http.js +12 -1
- package/dist/validate/adapters/http.js.map +1 -1
- package/package.json +1 -1
- package/templates/ci/github-enrich.yml +9 -1
- package/templates/ci/gitlab-enrich.sh +10 -1
|
@@ -166,7 +166,7 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
166
166
|
|
|
167
167
|
<Base title={`${title} — ${config.brand}`} description={description} image={pkg.logo}>
|
|
168
168
|
<div class="detail">
|
|
169
|
-
<header class="detail-head">
|
|
169
|
+
<header class="detail-head" data-slot="detail-header">
|
|
170
170
|
{
|
|
171
171
|
pkg.logo ? (
|
|
172
172
|
// The placeholder ships in the markup and the image fades in over
|
|
@@ -182,7 +182,7 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
182
182
|
<img src={withBase(pkg.logo)} alt="" />
|
|
183
183
|
</span>
|
|
184
184
|
) : (
|
|
185
|
-
<div class="tile letter" style={`background: var(--kind-${pkg.kind}, var(--muted))`}>
|
|
185
|
+
<div class="tile letter" style={`background: var(--grim-color-kind-${pkg.kind}, var(--grim-color-muted))`}>
|
|
186
186
|
{pkg.name[0]?.toUpperCase()}
|
|
187
187
|
</div>
|
|
188
188
|
)
|
|
@@ -202,7 +202,7 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
202
202
|
|
|
203
203
|
{
|
|
204
204
|
pkg.deprecated && (
|
|
205
|
-
<p class="deprecated-banner">
|
|
205
|
+
<p class="deprecated-banner" data-slot="deprecated-banner">
|
|
206
206
|
⚠️ deprecated{pkg.replacedBy ? ` — replaced by ${pkg.replacedBy}` : ""}
|
|
207
207
|
</p>
|
|
208
208
|
)
|
|
@@ -229,7 +229,7 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
229
229
|
}
|
|
230
230
|
</div>
|
|
231
231
|
|
|
232
|
-
<div class="detail-body">
|
|
232
|
+
<div class="detail-body" data-slot="detail-body">
|
|
233
233
|
<main class="detail-main">
|
|
234
234
|
{/* Radio tabs, not a scripted tablist: the ribbon works on a page
|
|
235
235
|
whose JS never ran, and a radio group already has the keyboard
|
|
@@ -324,7 +324,7 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
324
324
|
{openTab === null && <p class="panel-empty">No content available.</p>}
|
|
325
325
|
</main>
|
|
326
326
|
|
|
327
|
-
<aside class="detail-rail">
|
|
327
|
+
<aside class="detail-rail" data-slot="detail-rail">
|
|
328
328
|
{tags.length > 0 && (
|
|
329
329
|
<section>
|
|
330
330
|
<h2>Versions</h2>
|
|
@@ -509,33 +509,39 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
509
509
|
</script>
|
|
510
510
|
|
|
511
511
|
<style>
|
|
512
|
+
@layer grimoire {
|
|
513
|
+
/* Layered so a user CSS file (unlayered) outranks these rules. Astro
|
|
514
|
+
scopes a component style to `.foo[data-astro-cid-…]` — specificity
|
|
515
|
+
(0,2,0) — which beats a consumer's `.foo` in EITHER source order, so
|
|
516
|
+
source order alone does not make this overridable. Not reindented:
|
|
517
|
+
the wrapper stays a two-line diff. */
|
|
512
518
|
.detail {
|
|
513
519
|
display: flex;
|
|
514
520
|
flex-direction: column;
|
|
515
|
-
gap:
|
|
521
|
+
gap: var(--grim-space-7);
|
|
516
522
|
}
|
|
517
523
|
.detail-head {
|
|
518
524
|
display: flex;
|
|
519
525
|
align-items: center;
|
|
520
|
-
gap:
|
|
521
|
-
background: var(--card);
|
|
522
|
-
border:
|
|
523
|
-
border-radius:
|
|
524
|
-
padding:
|
|
526
|
+
gap: var(--grim-space-6);
|
|
527
|
+
background: var(--grim-color-card);
|
|
528
|
+
border: var(--grim-border-width) solid var(--grim-color-border);
|
|
529
|
+
border-radius: var(--grim-radius-xl);
|
|
530
|
+
padding: var(--grim-space-6) var(--grim-space-7);
|
|
525
531
|
}
|
|
526
532
|
.tile {
|
|
527
533
|
flex-shrink: 0;
|
|
528
534
|
width: 3.5rem;
|
|
529
535
|
height: 3.5rem;
|
|
530
|
-
border-radius:
|
|
536
|
+
border-radius: var(--grim-radius-xl);
|
|
531
537
|
object-fit: cover;
|
|
532
538
|
}
|
|
533
539
|
.tile.letter {
|
|
534
540
|
display: flex;
|
|
535
541
|
align-items: center;
|
|
536
542
|
justify-content: center;
|
|
537
|
-
color: var(--on-accent);
|
|
538
|
-
font-size:
|
|
543
|
+
color: var(--grim-color-on-accent);
|
|
544
|
+
font-size: var(--grim-text-xl);
|
|
539
545
|
font-weight: 700;
|
|
540
546
|
font-family: ui-monospace, "SFMono-Regular", monospace;
|
|
541
547
|
}
|
|
@@ -543,18 +549,18 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
543
549
|
margin: 0;
|
|
544
550
|
display: flex;
|
|
545
551
|
align-items: center;
|
|
546
|
-
gap:
|
|
547
|
-
font-size:
|
|
552
|
+
gap: var(--grim-space-4);
|
|
553
|
+
font-size: var(--grim-text-xl);
|
|
548
554
|
font-family: ui-monospace, "SFMono-Regular", monospace;
|
|
549
555
|
}
|
|
550
556
|
.summary {
|
|
551
|
-
margin:
|
|
552
|
-
color: var(--muted);
|
|
557
|
+
margin: var(--grim-space-2) 0 0;
|
|
558
|
+
color: var(--grim-color-muted);
|
|
553
559
|
}
|
|
554
560
|
.byline {
|
|
555
|
-
margin:
|
|
556
|
-
color: var(--muted);
|
|
557
|
-
font-size:
|
|
561
|
+
margin: var(--grim-space-3) 0 0;
|
|
562
|
+
color: var(--grim-color-muted);
|
|
563
|
+
font-size: var(--grim-text-sm);
|
|
558
564
|
}
|
|
559
565
|
/* The kind badge names a closed set of five and shouts accordingly. A
|
|
560
566
|
compatibility hint is a free string off the registry — upper-casing it
|
|
@@ -570,31 +576,31 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
570
576
|
padding: 0;
|
|
571
577
|
display: flex;
|
|
572
578
|
flex-direction: column;
|
|
573
|
-
gap:
|
|
579
|
+
gap: var(--grim-space-4);
|
|
574
580
|
}
|
|
575
581
|
.support li {
|
|
576
582
|
display: flex;
|
|
577
583
|
align-items: center;
|
|
578
|
-
gap:
|
|
579
|
-
font-size:
|
|
584
|
+
gap: var(--grim-space-3);
|
|
585
|
+
font-size: var(--grim-text-md);
|
|
580
586
|
}
|
|
581
587
|
.support li :global(svg) {
|
|
582
588
|
flex-shrink: 0;
|
|
583
|
-
color: var(--muted);
|
|
589
|
+
color: var(--grim-color-muted);
|
|
584
590
|
}
|
|
585
591
|
.deprecated-banner {
|
|
586
592
|
margin: 0;
|
|
587
|
-
background: var(--banner-bg);
|
|
588
|
-
color: var(--banner-fg);
|
|
589
|
-
border:
|
|
590
|
-
border-radius:
|
|
591
|
-
padding:
|
|
593
|
+
background: var(--grim-color-banner-bg);
|
|
594
|
+
color: var(--grim-color-banner-fg);
|
|
595
|
+
border: var(--grim-border-width) solid var(--grim-color-banner-border);
|
|
596
|
+
border-radius: var(--grim-radius-lg);
|
|
597
|
+
padding: var(--grim-space-4) var(--grim-space-6);
|
|
592
598
|
font-weight: 600;
|
|
593
599
|
}
|
|
594
600
|
.detail-body {
|
|
595
601
|
display: grid;
|
|
596
602
|
grid-template-columns: 1fr 18rem;
|
|
597
|
-
gap:
|
|
603
|
+
gap: var(--grim-space-8);
|
|
598
604
|
align-items: start;
|
|
599
605
|
}
|
|
600
606
|
@media (max-width: 55rem) {
|
|
@@ -604,10 +610,10 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
604
610
|
}
|
|
605
611
|
.detail-main {
|
|
606
612
|
min-width: 0;
|
|
607
|
-
background: var(--card);
|
|
608
|
-
border:
|
|
609
|
-
border-radius:
|
|
610
|
-
padding:
|
|
613
|
+
background: var(--grim-color-card);
|
|
614
|
+
border: var(--grim-border-width) solid var(--grim-color-border);
|
|
615
|
+
border-radius: var(--grim-radius-xl);
|
|
616
|
+
padding: var(--grim-space-7) var(--grim-space-7);
|
|
611
617
|
}
|
|
612
618
|
/* Markdown opens with its own heading, whose margin lands on top of the
|
|
613
619
|
panel padding and reads as a hole. Every panel sets its own top edge. */
|
|
@@ -624,23 +630,26 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
624
630
|
panel's own top edge rather than a line floating in the content. */
|
|
625
631
|
.ribbon {
|
|
626
632
|
display: flex;
|
|
627
|
-
gap:
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
633
|
+
gap: var(--grim-space-7);
|
|
634
|
+
/* The negation of `.detail-main`'s own padding, written as that token so
|
|
635
|
+
the two cannot drift apart into a bleed that no longer reaches the edge. */
|
|
636
|
+
margin: calc(-1 * var(--grim-space-7)) calc(-1 * var(--grim-space-7))
|
|
637
|
+
var(--grim-space-7);
|
|
638
|
+
padding: 0 var(--grim-space-7);
|
|
639
|
+
border-bottom: var(--grim-border-width) solid var(--grim-color-border);
|
|
631
640
|
}
|
|
632
641
|
.ribbon label {
|
|
633
|
-
padding:
|
|
634
|
-
margin-bottom: -
|
|
642
|
+
padding: var(--grim-space-5) 0;
|
|
643
|
+
margin-bottom: calc(-1 * var(--grim-border-width)); /* the active underline sits on the panel rule */
|
|
635
644
|
border-bottom: 2px solid transparent;
|
|
636
|
-
font-size:
|
|
645
|
+
font-size: var(--grim-text-sm);
|
|
637
646
|
text-transform: uppercase;
|
|
638
647
|
letter-spacing: 0.04em;
|
|
639
|
-
color: var(--muted);
|
|
648
|
+
color: var(--grim-color-muted);
|
|
640
649
|
cursor: pointer;
|
|
641
650
|
}
|
|
642
651
|
.ribbon label:hover {
|
|
643
|
-
color: var(--fg);
|
|
652
|
+
color: var(--grim-color-fg);
|
|
644
653
|
}
|
|
645
654
|
/* Nothing behind it. Still shown, so the ribbon is the same shape on every
|
|
646
655
|
package page, but visibly not a thing to click. */
|
|
@@ -653,7 +662,7 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
653
662
|
#panel-readme:disabled ~ .ribbon label[for="panel-readme"]:hover,
|
|
654
663
|
#panel-contents:disabled ~ .ribbon label[for="panel-contents"]:hover,
|
|
655
664
|
#panel-changelog:disabled ~ .ribbon label[for="panel-changelog"]:hover {
|
|
656
|
-
color: var(--muted);
|
|
665
|
+
color: var(--grim-color-muted);
|
|
657
666
|
}
|
|
658
667
|
/* Every tab empty: say it once, in the middle. */
|
|
659
668
|
.panel-empty {
|
|
@@ -661,7 +670,7 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
661
670
|
place-items: center;
|
|
662
671
|
min-height: 11rem;
|
|
663
672
|
margin: 0;
|
|
664
|
-
color: var(--muted);
|
|
673
|
+
color: var(--grim-color-muted);
|
|
665
674
|
}
|
|
666
675
|
.tab-panel {
|
|
667
676
|
display: none;
|
|
@@ -674,16 +683,16 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
674
683
|
#panel-readme:checked ~ .ribbon label[for="panel-readme"],
|
|
675
684
|
#panel-contents:checked ~ .ribbon label[for="panel-contents"],
|
|
676
685
|
#panel-changelog:checked ~ .ribbon label[for="panel-changelog"] {
|
|
677
|
-
color: var(--fg);
|
|
678
|
-
border-bottom-color: var(--accent);
|
|
686
|
+
color: var(--grim-color-fg);
|
|
687
|
+
border-bottom-color: var(--grim-color-accent);
|
|
679
688
|
}
|
|
680
689
|
/* The input carries the focus, the label shows it. */
|
|
681
690
|
#panel-readme:focus-visible ~ .ribbon label[for="panel-readme"],
|
|
682
691
|
#panel-contents:focus-visible ~ .ribbon label[for="panel-contents"],
|
|
683
692
|
#panel-changelog:focus-visible ~ .ribbon label[for="panel-changelog"] {
|
|
684
|
-
outline: 2px solid var(--accent);
|
|
693
|
+
outline: 2px solid var(--grim-color-accent);
|
|
685
694
|
outline-offset: 2px;
|
|
686
|
-
border-radius:
|
|
695
|
+
border-radius: var(--grim-radius-sm);
|
|
687
696
|
}
|
|
688
697
|
|
|
689
698
|
/* A bundle's member list: what it installs, one row each. A grid, not a
|
|
@@ -696,7 +705,7 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
696
705
|
padding: 0;
|
|
697
706
|
display: grid;
|
|
698
707
|
grid-template-columns: auto auto 1fr;
|
|
699
|
-
gap:
|
|
708
|
+
gap: var(--grim-space-4) var(--grim-space-5);
|
|
700
709
|
align-items: center;
|
|
701
710
|
}
|
|
702
711
|
.members li {
|
|
@@ -711,8 +720,8 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
711
720
|
justify-self: start;
|
|
712
721
|
}
|
|
713
722
|
.members code {
|
|
714
|
-
color: var(--muted);
|
|
715
|
-
font-size:
|
|
723
|
+
color: var(--grim-color-muted);
|
|
724
|
+
font-size: var(--grim-text-sm);
|
|
716
725
|
overflow-wrap: anywhere;
|
|
717
726
|
}
|
|
718
727
|
/* Narrow: three columns of a long ref do not fit, so each member becomes
|
|
@@ -729,32 +738,32 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
729
738
|
.detail-rail {
|
|
730
739
|
display: flex;
|
|
731
740
|
flex-direction: column;
|
|
732
|
-
gap:
|
|
741
|
+
gap: var(--grim-space-7);
|
|
733
742
|
}
|
|
734
743
|
.detail-rail section {
|
|
735
|
-
background: var(--card);
|
|
736
|
-
border:
|
|
737
|
-
border-radius:
|
|
738
|
-
padding:
|
|
744
|
+
background: var(--grim-color-card);
|
|
745
|
+
border: var(--grim-border-width) solid var(--grim-color-border);
|
|
746
|
+
border-radius: var(--grim-radius-xl);
|
|
747
|
+
padding: var(--grim-space-6);
|
|
739
748
|
}
|
|
740
749
|
/* Panel label. The main panel's ribbon labels match this by hand — they
|
|
741
750
|
are <label>s, not headings, so they cannot join the selector. */
|
|
742
751
|
.detail-rail h2 {
|
|
743
|
-
margin: 0 0
|
|
744
|
-
font-size:
|
|
752
|
+
margin: 0 0 var(--grim-space-4);
|
|
753
|
+
font-size: var(--grim-text-sm);
|
|
745
754
|
text-transform: uppercase;
|
|
746
755
|
letter-spacing: 0.04em;
|
|
747
|
-
color: var(--muted);
|
|
756
|
+
color: var(--grim-color-muted);
|
|
748
757
|
}
|
|
749
758
|
/* Loose badges, both for the cascade and the older tags — VersionMenu owns
|
|
750
759
|
the pill itself, this only lays them out. */
|
|
751
760
|
.cascade {
|
|
752
761
|
display: flex;
|
|
753
762
|
flex-wrap: wrap;
|
|
754
|
-
gap:
|
|
763
|
+
gap: var(--grim-space-2);
|
|
755
764
|
}
|
|
756
765
|
.older {
|
|
757
|
-
margin-top:
|
|
766
|
+
margin-top: var(--grim-space-5);
|
|
758
767
|
}
|
|
759
768
|
/* The UA marker is a glyph that flips between two characters with no
|
|
760
769
|
in-between; a real chevron can turn. `list-style` kills it everywhere
|
|
@@ -764,22 +773,22 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
764
773
|
.older > summary {
|
|
765
774
|
display: flex;
|
|
766
775
|
align-items: center;
|
|
767
|
-
gap:
|
|
776
|
+
gap: var(--grim-space-3);
|
|
768
777
|
list-style: none;
|
|
769
|
-
padding-block:
|
|
778
|
+
padding-block: var(--grim-space-1);
|
|
770
779
|
cursor: pointer;
|
|
771
|
-
font-size:
|
|
772
|
-
color: var(--muted);
|
|
780
|
+
font-size: var(--grim-text-sm);
|
|
781
|
+
color: var(--grim-color-muted);
|
|
773
782
|
}
|
|
774
783
|
.older > summary::-webkit-details-marker {
|
|
775
784
|
display: none;
|
|
776
785
|
}
|
|
777
786
|
.older > summary:hover {
|
|
778
|
-
color: var(--fg);
|
|
787
|
+
color: var(--grim-color-fg);
|
|
779
788
|
}
|
|
780
789
|
.older > summary :global(svg) {
|
|
781
790
|
flex-shrink: 0;
|
|
782
|
-
transition: transform
|
|
791
|
+
transition: transform var(--grim-duration-base) ease;
|
|
783
792
|
}
|
|
784
793
|
.older[open] > summary :global(svg) {
|
|
785
794
|
transform: rotate(90deg);
|
|
@@ -790,7 +799,7 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
790
799
|
}
|
|
791
800
|
}
|
|
792
801
|
.older[open] > summary {
|
|
793
|
-
margin-bottom:
|
|
802
|
+
margin-bottom: var(--grim-space-4);
|
|
794
803
|
}
|
|
795
804
|
dl {
|
|
796
805
|
margin: 0;
|
|
@@ -800,14 +809,14 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
800
809
|
`stretch` sits each at the top of its own box, so the size difference
|
|
801
810
|
reads as two lines that never quite line up. */
|
|
802
811
|
align-items: center;
|
|
803
|
-
gap:
|
|
812
|
+
gap: var(--grim-space-4) var(--grim-space-5);
|
|
804
813
|
}
|
|
805
814
|
dt {
|
|
806
815
|
display: flex;
|
|
807
816
|
align-items: center;
|
|
808
|
-
gap:
|
|
809
|
-
color: var(--muted);
|
|
810
|
-
font-size:
|
|
817
|
+
gap: var(--grim-space-3);
|
|
818
|
+
color: var(--grim-color-muted);
|
|
819
|
+
font-size: var(--grim-text-sm);
|
|
811
820
|
}
|
|
812
821
|
/* Every icon is the same box, so the label text lands on one x without an
|
|
813
822
|
icon column of its own. */
|
|
@@ -816,15 +825,15 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
816
825
|
}
|
|
817
826
|
dd {
|
|
818
827
|
margin: 0;
|
|
819
|
-
font-size:
|
|
828
|
+
font-size: var(--grim-text-md);
|
|
820
829
|
}
|
|
821
830
|
.keywords {
|
|
822
831
|
list-style: none;
|
|
823
|
-
margin:
|
|
832
|
+
margin: var(--grim-space-5) 0 0;
|
|
824
833
|
padding: 0;
|
|
825
834
|
display: flex;
|
|
826
835
|
flex-wrap: wrap;
|
|
827
|
-
gap:
|
|
836
|
+
gap: var(--grim-space-3);
|
|
828
837
|
}
|
|
829
838
|
/* The chip is the link, not a box around it — otherwise the padding is
|
|
830
839
|
dead space the pointer falls through. Bordered and hovering to accent
|
|
@@ -833,27 +842,28 @@ const updatedTitle = pkg.revision ? `${updated} · revision ${pkg.revision}` : u
|
|
|
833
842
|
that answers differently reads as a different kind of thing. */
|
|
834
843
|
.keywords a {
|
|
835
844
|
display: inline-block;
|
|
836
|
-
border:
|
|
837
|
-
border-radius:
|
|
838
|
-
background: var(--chip-bg);
|
|
839
|
-
padding:
|
|
840
|
-
font-size:
|
|
841
|
-
color: var(--muted);
|
|
845
|
+
border: var(--grim-border-width) solid var(--grim-color-border);
|
|
846
|
+
border-radius: var(--grim-radius-pill);
|
|
847
|
+
background: var(--grim-color-chip-bg);
|
|
848
|
+
padding: var(--grim-space-1) var(--grim-space-4);
|
|
849
|
+
font-size: var(--grim-text-xs);
|
|
850
|
+
color: var(--grim-color-muted);
|
|
842
851
|
text-decoration: none;
|
|
843
852
|
transition:
|
|
844
|
-
color
|
|
845
|
-
border-color
|
|
846
|
-
background-color
|
|
853
|
+
color var(--grim-duration-fast) ease,
|
|
854
|
+
border-color var(--grim-duration-fast) ease,
|
|
855
|
+
background-color var(--grim-duration-fast) ease;
|
|
847
856
|
}
|
|
848
857
|
.keywords a:hover,
|
|
849
858
|
.keywords a:focus-visible {
|
|
850
|
-
color: var(--accent);
|
|
851
|
-
border-color: var(--accent);
|
|
852
|
-
background: var(--accent-soft);
|
|
859
|
+
color: var(--grim-color-accent);
|
|
860
|
+
border-color: var(--grim-color-accent);
|
|
861
|
+
background: var(--grim-color-accent-soft);
|
|
853
862
|
}
|
|
854
863
|
@media (prefers-reduced-motion: reduce) {
|
|
855
864
|
.keywords a {
|
|
856
865
|
transition: none;
|
|
857
866
|
}
|
|
858
867
|
}
|
|
868
|
+
}
|
|
859
869
|
</style>
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/* SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
Copyright 2026 The Grimoire Authors
|
|
3
|
+
|
|
4
|
+
THE THEMING CONTRACT — these custom properties are the whole customization
|
|
5
|
+
surface. There is no component-override API; see `data-slot` below for the
|
|
6
|
+
other half of the contract.
|
|
7
|
+
|
|
8
|
+
Everything the renderer ships is layered. Unlayered CSS — i.e. any user
|
|
9
|
+
override file — beats a layered declaration outright, at any specificity,
|
|
10
|
+
so a single `:root { --grim-color-accent: … }` wins in light AND dark
|
|
11
|
+
without !important and without knowing where Astro injects its bundle.
|
|
12
|
+
|
|
13
|
+
Names are `--grim-<category>-<role>`. The category segment is not
|
|
14
|
+
decoration: it is what stops a colour named `--grim-text` from colliding
|
|
15
|
+
with the type-scale tokens below.
|
|
16
|
+
|
|
17
|
+
COLOUR is the one family that differs per scheme, so it is the one family
|
|
18
|
+
declared twice — `:root` and `[data-theme="dark"]`. Redeclare BOTH when you
|
|
19
|
+
override one: `:root` is scheme-agnostic, so a `:root`-only override
|
|
20
|
+
silently takes dark mode with it. Every other family is a measurement, not
|
|
21
|
+
an appearance, and is declared once.
|
|
22
|
+
|
|
23
|
+
Adding a token is additive. Removing or renaming one is a breaking change.
|
|
24
|
+
|
|
25
|
+
`test/renderer/style_contract.test.ts` holds this file to it, and
|
|
26
|
+
`test/renderer/build.test.ts` proves the layer survives a real build. */
|
|
27
|
+
|
|
28
|
+
@layer grimoire {
|
|
29
|
+
:root {
|
|
30
|
+
/* ---- Colour: surface ------------------------------------------- */
|
|
31
|
+
--grim-color-bg: #f7f6f3;
|
|
32
|
+
--grim-color-fg: #1d1c1a;
|
|
33
|
+
--grim-color-muted: #6d6a63;
|
|
34
|
+
--grim-color-card: #ffffff;
|
|
35
|
+
--grim-color-border: #dedbd3;
|
|
36
|
+
--grim-color-chip-bg: #edebe5;
|
|
37
|
+
|
|
38
|
+
/* ---- Colour: accent -------------------------------------------- */
|
|
39
|
+
--grim-color-accent: #6d4fc4;
|
|
40
|
+
--grim-color-accent-soft: #efeafd;
|
|
41
|
+
--grim-color-on-accent: #ffffff;
|
|
42
|
+
|
|
43
|
+
/* ---- Colour: package kind --------------------------------------
|
|
44
|
+
Read through a name composed at runtime — `Catalog.tsx` and the detail
|
|
45
|
+
page build `var(--grim-color-kind-${pkg.kind})`. Grepping for one of
|
|
46
|
+
these finds the declaration and no use site; all five are used. */
|
|
47
|
+
--grim-color-kind-skill: #6d4fc4;
|
|
48
|
+
--grim-color-kind-rule: #1a7f6b;
|
|
49
|
+
--grim-color-kind-agent: #b0641a;
|
|
50
|
+
--grim-color-kind-mcp: #2565c7;
|
|
51
|
+
--grim-color-kind-bundle: #a63d68;
|
|
52
|
+
|
|
53
|
+
/* ---- Colour: state --------------------------------------------- */
|
|
54
|
+
/* ~5.7:1 on --grim-color-card (white) */
|
|
55
|
+
--grim-color-deprecated: #9c5400;
|
|
56
|
+
--grim-color-banner-bg: #fff3cd;
|
|
57
|
+
--grim-color-banner-fg: #6b4c00;
|
|
58
|
+
--grim-color-banner-border: #e0b84c;
|
|
59
|
+
|
|
60
|
+
color-scheme: light;
|
|
61
|
+
|
|
62
|
+
/* ---- Space -----------------------------------------------------
|
|
63
|
+
Numbered, not role-named, because a spacing step is pure ordinal
|
|
64
|
+
magnitude: bigger number, more room. The steps are sparse and the
|
|
65
|
+
distance between them GROWS — 2, 2, 2, 4, 4, 8, 8, 16px — so the
|
|
66
|
+
scale stays usable at the top without minting a step per pixel.
|
|
67
|
+
A bare number is only honest with a published role, so here it is:
|
|
68
|
+
|
|
69
|
+
1 hairline inset — badge and pill padding
|
|
70
|
+
2 tight — an icon and its label
|
|
71
|
+
3 chip padding, keyword gaps
|
|
72
|
+
4 default gap inside one control
|
|
73
|
+
5 between related controls
|
|
74
|
+
6 card padding, row gap
|
|
75
|
+
7 between sections
|
|
76
|
+
8 page block separation
|
|
77
|
+
9 page bottom */
|
|
78
|
+
--grim-space-1: 0.125rem;
|
|
79
|
+
--grim-space-2: 0.25rem;
|
|
80
|
+
--grim-space-3: 0.375rem;
|
|
81
|
+
--grim-space-4: 0.5rem;
|
|
82
|
+
--grim-space-5: 0.75rem;
|
|
83
|
+
--grim-space-6: 1rem;
|
|
84
|
+
--grim-space-7: 1.5rem;
|
|
85
|
+
--grim-space-8: 2rem;
|
|
86
|
+
--grim-space-9: 3rem;
|
|
87
|
+
|
|
88
|
+
/* ---- Type ------------------------------------------------------
|
|
89
|
+
Role-named, unlike space: a type step is "metadata vs body vs
|
|
90
|
+
heading", which is a job, not a magnitude. `xl` is a detail-page
|
|
91
|
+
heading and `2xl` the landing hero — two sizes because those are two
|
|
92
|
+
deliberately different headings, not drift. */
|
|
93
|
+
--grim-text-2xs: 0.72rem;
|
|
94
|
+
--grim-text-xs: 0.78rem;
|
|
95
|
+
--grim-text-sm: 0.85rem;
|
|
96
|
+
--grim-text-md: 0.95rem;
|
|
97
|
+
--grim-text-lg: 1.05rem;
|
|
98
|
+
--grim-text-xl: 1.5rem;
|
|
99
|
+
--grim-text-2xl: 1.6rem;
|
|
100
|
+
|
|
101
|
+
/* ---- Radius ---------------------------------------------------- */
|
|
102
|
+
--grim-radius-sm: 4px;
|
|
103
|
+
--grim-radius-md: 6px;
|
|
104
|
+
--grim-radius-lg: 8px;
|
|
105
|
+
--grim-radius-xl: 10px;
|
|
106
|
+
--grim-radius-pill: 999px;
|
|
107
|
+
|
|
108
|
+
/* ---- Border ----------------------------------------------------
|
|
109
|
+
One width carries every rule in the UI. It is a token so a consumer
|
|
110
|
+
can thicken every seam at once, and so the two places that pull a
|
|
111
|
+
border into its neighbour can say `calc(-1 * …)` instead of
|
|
112
|
+
hardcoding the negation of a number declared elsewhere. */
|
|
113
|
+
--grim-border-width: 1px;
|
|
114
|
+
|
|
115
|
+
/* ---- Motion ---------------------------------------------------- */
|
|
116
|
+
--grim-duration-fast: 120ms;
|
|
117
|
+
--grim-duration-base: 160ms;
|
|
118
|
+
--grim-duration-slow: 200ms;
|
|
119
|
+
|
|
120
|
+
/* ---- Elevation -------------------------------------------------
|
|
121
|
+
A drop shadow is a black scrim rather than a palette colour: it reads
|
|
122
|
+
correctly over either scheme, which is why these are not declared
|
|
123
|
+
twice. Overriding one is how a consumer changes elevation. */
|
|
124
|
+
--grim-shadow-raised: 0 6px 20px rgb(0 0 0 / 18%);
|
|
125
|
+
--grim-shadow-overlay: 0 8px 24px rgb(0 0 0 / 18%);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* Colour only. Every other family above is a measurement that does not
|
|
129
|
+
change with the scheme, and redeclaring one here would be a second
|
|
130
|
+
source of truth for the same value. */
|
|
131
|
+
[data-theme="dark"] {
|
|
132
|
+
--grim-color-bg: #16151a;
|
|
133
|
+
--grim-color-fg: #e8e6e1;
|
|
134
|
+
--grim-color-muted: #98948b;
|
|
135
|
+
--grim-color-card: #201f26;
|
|
136
|
+
--grim-color-border: #35333d;
|
|
137
|
+
--grim-color-chip-bg: #2a2931;
|
|
138
|
+
|
|
139
|
+
--grim-color-accent: #a58cf0;
|
|
140
|
+
--grim-color-accent-soft: #2c2540;
|
|
141
|
+
--grim-color-on-accent: #ffffff;
|
|
142
|
+
|
|
143
|
+
--grim-color-kind-skill: #a58cf0;
|
|
144
|
+
--grim-color-kind-rule: #4cc2a9;
|
|
145
|
+
--grim-color-kind-agent: #e0a35c;
|
|
146
|
+
--grim-color-kind-mcp: #6fa8f5;
|
|
147
|
+
--grim-color-kind-bundle: #e07ba6;
|
|
148
|
+
|
|
149
|
+
/* ~7.6:1 on --grim-color-card (#201f26) */
|
|
150
|
+
--grim-color-deprecated: #e3a640;
|
|
151
|
+
--grim-color-banner-bg: #4a3b0a;
|
|
152
|
+
--grim-color-banner-fg: #f0d78c;
|
|
153
|
+
--grim-color-banner-border: #8a6d1a;
|
|
154
|
+
|
|
155
|
+
color-scheme: dark;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
@@ -9,6 +9,17 @@
|
|
|
9
9
|
export declare const USER_AGENT = "grim-indexer-bot";
|
|
10
10
|
export declare const TIMEOUT_MS = 30000;
|
|
11
11
|
export declare const MAX_RESPONSE_BYTES: number;
|
|
12
|
+
/**
|
|
13
|
+
* The cap for the two calls that legitimately read more than a small JSON
|
|
14
|
+
* document: the enrichment checkpoint, which is the whole sidecar tree, and a
|
|
15
|
+
* ratings page, which carries every thread's full body — including bodies this
|
|
16
|
+
* bot did not write.
|
|
17
|
+
*
|
|
18
|
+
* The same ceiling `enrich` already accepts from one `grim` subprocess
|
|
19
|
+
* (`MAX_OUTPUT_BYTES`), so the largest thing this toolchain holds in memory is
|
|
20
|
+
* one number rather than three.
|
|
21
|
+
*/
|
|
22
|
+
export declare const LARGE_RESPONSE_BYTES: number;
|
|
12
23
|
export interface HttpResponse {
|
|
13
24
|
/** HTTP status, or 0 when the request never completed. */
|
|
14
25
|
status: number;
|
|
@@ -19,6 +30,18 @@ export interface HttpResponse {
|
|
|
19
30
|
export interface RequestOptions {
|
|
20
31
|
method?: string;
|
|
21
32
|
body?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Response-size cap for this call, in bytes. Defaults to
|
|
35
|
+
* [`MAX_RESPONSE_BYTES`], so every call site that does not ask keeps the
|
|
36
|
+
* reply it already got, byte for byte.
|
|
37
|
+
*
|
|
38
|
+
* Per-call because the default is sized for a small JSON document, and two
|
|
39
|
+
* callers legitimately read more: the enrichment checkpoint is the whole
|
|
40
|
+
* sidecar tree, and a ratings page carries every thread's full body. Both
|
|
41
|
+
* used to surface as `{status: 0}` — indistinguishable from a transport
|
|
42
|
+
* failure, which is how an oversized page got reported as one.
|
|
43
|
+
*/
|
|
44
|
+
maxBytes?: number;
|
|
22
45
|
}
|
|
23
46
|
export declare function request(url: string, headers?: Record<string, string>, options?: RequestOptions): Promise<HttpResponse>;
|
|
24
47
|
/** `request` plus a `JSON.parse` that yields `null` instead of throwing. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/validate/adapters/http.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,eAAO,MAAM,UAAU,qBAAqB,CAAC;AAC7C,eAAO,MAAM,UAAU,QAAS,CAAC;AACjC,eAAO,MAAM,kBAAkB,QAAc,CAAC;AAE9C,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AA4BD,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/validate/adapters/http.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,eAAO,MAAM,UAAU,qBAAqB,CAAC;AAC7C,eAAO,MAAM,UAAU,QAAS,CAAC;AACjC,eAAO,MAAM,kBAAkB,QAAc,CAAC;AAE9C;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,QAAmB,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AA4BD,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,OAAO,CAC3B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACpC,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAwBvB;AAED,4EAA4E;AAC5E,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACnC,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAQ5C"}
|
|
@@ -11,6 +11,17 @@
|
|
|
11
11
|
export const USER_AGENT = "grim-indexer-bot";
|
|
12
12
|
export const TIMEOUT_MS = 30_000;
|
|
13
13
|
export const MAX_RESPONSE_BYTES = 1024 * 1024;
|
|
14
|
+
/**
|
|
15
|
+
* The cap for the two calls that legitimately read more than a small JSON
|
|
16
|
+
* document: the enrichment checkpoint, which is the whole sidecar tree, and a
|
|
17
|
+
* ratings page, which carries every thread's full body — including bodies this
|
|
18
|
+
* bot did not write.
|
|
19
|
+
*
|
|
20
|
+
* The same ceiling `enrich` already accepts from one `grim` subprocess
|
|
21
|
+
* (`MAX_OUTPUT_BYTES`), so the largest thing this toolchain holds in memory is
|
|
22
|
+
* one number rather than three.
|
|
23
|
+
*/
|
|
24
|
+
export const LARGE_RESPONSE_BYTES = 16 * 1024 * 1024;
|
|
14
25
|
async function readCapped(response, cap) {
|
|
15
26
|
if (!response.body)
|
|
16
27
|
return "";
|
|
@@ -51,7 +62,7 @@ export async function request(url, headers = {}, options = {}) {
|
|
|
51
62
|
redirect: "manual",
|
|
52
63
|
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
53
64
|
});
|
|
54
|
-
const body = await readCapped(response, MAX_RESPONSE_BYTES);
|
|
65
|
+
const body = await readCapped(response, options.maxBytes ?? MAX_RESPONSE_BYTES);
|
|
55
66
|
if (body === null)
|
|
56
67
|
return none;
|
|
57
68
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/validate/adapters/http.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,sCAAsC;AAEtC;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,kBAAkB,CAAC;AAC7C,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;AACjC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/validate/adapters/http.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,sCAAsC;AAEtC;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,kBAAkB,CAAC;AAC7C,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;AACjC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,GAAG,IAAI,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AASrD,KAAK,UAAU,UAAU,CACvB,QAAkB,EAClB,GAAW;IAEX,IAAI,CAAC,QAAQ,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;IACzC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,CAAC;QACH,SAAS,CAAC;YACR,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAChB,IAAI,CAAC,KAAK;gBAAE,SAAS;YACrB,IAAI,IAAI,KAAK,CAAC,UAAU,CAAC;YACzB,IAAI,IAAI,GAAG,GAAG,EAAE,CAAC;gBACf,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC;AAoBD,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAW,EACX,UAAkC,EAAE,EACpC,UAA0B,EAAE;IAE5B,MAAM,IAAI,GAAiB,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;IACrE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,OAAO,EAAE,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE;YACjD,uEAAuE;YACvE,sEAAsE;YACtE,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,yEAAyE;YACzE,wEAAwE;YACxE,QAAQ,EAAE,QAAQ;YAClB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC;SACxC,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,kBAAkB,CAAC,CAAC;QAChF,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC/B,OAAO;YACL,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,IAAI;YACJ,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;SACnD,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAW,EACX,UAAkC,EAAE;IAEpC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC7C,IAAI,QAAQ,CAAC,IAAI,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACzE,IAAI,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACjD,CAAC;AACH,CAAC"}
|