@nowline/renderer 0.8.6 → 0.10.0

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 (86) hide show
  1. package/dist/image-size.d.ts +9 -0
  2. package/dist/image-size.d.ts.map +1 -0
  3. package/dist/image-size.js +104 -0
  4. package/dist/image-size.js.map +1 -0
  5. package/dist/index.d.ts +4 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +4 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/logo.d.ts +24 -0
  10. package/dist/logo.d.ts.map +1 -0
  11. package/dist/logo.js +60 -0
  12. package/dist/logo.js.map +1 -0
  13. package/dist/stage.d.ts +78 -0
  14. package/dist/stage.d.ts.map +1 -0
  15. package/dist/stage.js +88 -0
  16. package/dist/stage.js.map +1 -0
  17. package/dist/svg/edges.d.ts +3 -0
  18. package/dist/svg/edges.d.ts.map +1 -0
  19. package/dist/svg/edges.js +144 -0
  20. package/dist/svg/edges.js.map +1 -0
  21. package/dist/svg/footnotes.d.ts +4 -0
  22. package/dist/svg/footnotes.d.ts.map +1 -0
  23. package/dist/svg/footnotes.js +81 -0
  24. package/dist/svg/footnotes.js.map +1 -0
  25. package/dist/svg/header.d.ts +6 -0
  26. package/dist/svg/header.d.ts.map +1 -0
  27. package/dist/svg/header.js +215 -0
  28. package/dist/svg/header.js.map +1 -0
  29. package/dist/svg/include-region.d.ts +4 -0
  30. package/dist/svg/include-region.d.ts.map +1 -0
  31. package/dist/svg/include-region.js +157 -0
  32. package/dist/svg/include-region.js.map +1 -0
  33. package/dist/svg/item.d.ts +36 -0
  34. package/dist/svg/item.d.ts.map +1 -0
  35. package/dist/svg/item.js +549 -0
  36. package/dist/svg/item.js.map +1 -0
  37. package/dist/svg/markers.d.ts +7 -0
  38. package/dist/svg/markers.d.ts.map +1 -0
  39. package/dist/svg/markers.js +151 -0
  40. package/dist/svg/markers.js.map +1 -0
  41. package/dist/svg/nowline.d.ts +4 -0
  42. package/dist/svg/nowline.d.ts.map +1 -0
  43. package/dist/svg/nowline.js +133 -0
  44. package/dist/svg/nowline.js.map +1 -0
  45. package/dist/svg/primitives.d.ts +7 -0
  46. package/dist/svg/primitives.d.ts.map +1 -0
  47. package/dist/svg/primitives.js +70 -0
  48. package/dist/svg/primitives.js.map +1 -0
  49. package/dist/svg/render.d.ts +13 -7
  50. package/dist/svg/render.d.ts.map +1 -1
  51. package/dist/svg/render.js +64 -1701
  52. package/dist/svg/render.js.map +1 -1
  53. package/dist/svg/sanitize.d.ts +10 -0
  54. package/dist/svg/sanitize.d.ts.map +1 -1
  55. package/dist/svg/sanitize.js +264 -16
  56. package/dist/svg/sanitize.js.map +1 -1
  57. package/dist/svg/swimlanes.d.ts +5 -0
  58. package/dist/svg/swimlanes.d.ts.map +1 -0
  59. package/dist/svg/swimlanes.js +228 -0
  60. package/dist/svg/swimlanes.js.map +1 -0
  61. package/dist/svg/timeline.d.ts +24 -0
  62. package/dist/svg/timeline.d.ts.map +1 -0
  63. package/dist/svg/timeline.js +284 -0
  64. package/dist/svg/timeline.js.map +1 -0
  65. package/dist/svg/waves.d.ts +62 -0
  66. package/dist/svg/waves.d.ts.map +1 -0
  67. package/dist/svg/waves.js +397 -0
  68. package/dist/svg/waves.js.map +1 -0
  69. package/package.json +6 -6
  70. package/src/image-size.ts +113 -0
  71. package/src/index.ts +10 -1
  72. package/src/logo.ts +82 -0
  73. package/src/stage.ts +191 -0
  74. package/src/svg/edges.ts +154 -0
  75. package/src/svg/footnotes.ts +115 -0
  76. package/src/svg/header.ts +285 -0
  77. package/src/svg/include-region.ts +201 -0
  78. package/src/svg/item.ts +672 -0
  79. package/src/svg/markers.ts +178 -0
  80. package/src/svg/nowline.ts +152 -0
  81. package/src/svg/primitives.ts +86 -0
  82. package/src/svg/render.ts +94 -2110
  83. package/src/svg/sanitize.ts +286 -16
  84. package/src/svg/swimlanes.ts +317 -0
  85. package/src/svg/timeline.ts +343 -0
  86. package/src/svg/waves.ts +502 -0
@@ -0,0 +1,151 @@
1
+ // The marker layer: anchors, milestones and the cut lines they drop through the
2
+ // chart body, with the diamonds and labels that sit in the marker row.
3
+ import { ACCENT_DASH_PATTERN } from '@nowline/layout';
4
+ import { escText, num, tag, textTag } from './xml.js';
5
+ export function renderAnchor(a, palette, fonts) {
6
+ const size = a.radius;
7
+ const cx = a.center.x;
8
+ const cy = a.center.y;
9
+ const fill = palette.anchorDiamond.fill;
10
+ const stroke = palette.anchorDiamond.stroke;
11
+ const diamond = tag('path', {
12
+ d: `M${num(cx)} ${num(cy - size)} L${num(cx + size)} ${num(cy)} L${num(cx)} ${num(cy + size)} L${num(cx - size)} ${num(cy)} Z`,
13
+ fill,
14
+ stroke,
15
+ 'stroke-width': 1.25,
16
+ });
17
+ const labelColor = palette.anchorDiamond.label;
18
+ // For left-flipped labels, anchor the text at its RIGHT edge using
19
+ // `text-anchor: end`. The layout's `labelBox.width` is intentionally
20
+ // pessimistic (0.58 em/char) so positioning by the box's left edge
21
+ // would leave a visible gap between the actual text right edge and
22
+ // the diamond. End-anchoring lets the browser size the glyph run
23
+ // exactly and put the rightmost glyph 6 px from the diamond — same
24
+ // rhythm the right-side labels already get from start-anchoring at
25
+ // `diamondRight + 6`.
26
+ const labelX = a.labelSide === 'left' ? a.labelBox.x + a.labelBox.width : a.labelBox.x;
27
+ const labelAttrs = {
28
+ x: num(labelX),
29
+ y: num(cy + 4),
30
+ 'font-family': fonts.sans,
31
+ 'font-size': 10,
32
+ fill: labelColor,
33
+ };
34
+ if (a.labelSide === 'left')
35
+ labelAttrs['text-anchor'] = 'end';
36
+ const label = a.title ? textTag(labelAttrs, a.title) : '';
37
+ return tag('g', { 'data-layer': 'anchor', 'data-id': a.id ?? null }, hiddenDateTitle(a.hiddenDate) + diamond + label);
38
+ }
39
+ export function renderAnchorCutLine(a, palette) {
40
+ const stroke = palette.anchorDiamond.cutLine;
41
+ return tag('line', {
42
+ x1: num(a.center.x),
43
+ y1: num(a.center.y + a.radius + 1),
44
+ x2: num(a.center.x),
45
+ y2: num(a.cutBottomY),
46
+ stroke,
47
+ 'stroke-width': 1,
48
+ 'stroke-dasharray': '1 3',
49
+ });
50
+ }
51
+ export function renderMilestone(m, palette, fonts) {
52
+ const cx = m.center.x;
53
+ const cy = m.center.y;
54
+ const r = m.radius;
55
+ const overrun = palette.milestoneDiamond.cutLineOverrun;
56
+ const diamond = (x, fill) => tag('path', {
57
+ d: `M${num(x)} ${num(cy - r)} L${num(x + r)} ${num(cy)} L${num(x)} ${num(cy + r)} L${num(x - r)} ${num(cy)} Z`,
58
+ fill,
59
+ stroke: fill,
60
+ 'stroke-width': 1,
61
+ });
62
+ // An overrun dated milestone paints its diamond in the overrun colour
63
+ // (specs/rendering.md, Milestones). When it slipped, that diamond marks
64
+ // the missed date and a dotted span runs on to a second diamond, in the
65
+ // normal colour, where it lands; the label sits there. When it did not
66
+ // slip (the two diamonds would meet), the label is red too.
67
+ const slipX = m.slip?.x;
68
+ let flag;
69
+ if (slipX !== undefined) {
70
+ flag =
71
+ diamond(cx, overrun) +
72
+ tag('path', {
73
+ d: `M${num(cx + r)} ${num(cy)} H${num(slipX - r)}`,
74
+ fill: 'none',
75
+ stroke: overrun,
76
+ 'stroke-width': 1.1,
77
+ 'stroke-dasharray': '3 3',
78
+ 'stroke-linecap': 'round',
79
+ }) +
80
+ diamond(slipX, palette.milestoneDiamond.fill);
81
+ }
82
+ else {
83
+ flag = diamond(cx, m.isOverrun ? overrun : palette.milestoneDiamond.fill);
84
+ }
85
+ const labelColor = m.isOverrun && slipX === undefined ? overrun : palette.milestoneDiamond.label;
86
+ // See renderAnchor — left-flipped labels use `text-anchor: end` so
87
+ // the visual right edge sits at `diamondLeft - 6`, matching the
88
+ // 6 px rhythm of right-side labels.
89
+ const labelX = m.labelSide === 'left' ? m.labelBox.x + m.labelBox.width : m.labelBox.x;
90
+ const labelAttrs = {
91
+ x: num(labelX),
92
+ y: num(cy + 4),
93
+ 'font-family': fonts.sans,
94
+ 'font-size': 10,
95
+ 'font-weight': 600,
96
+ fill: labelColor,
97
+ };
98
+ if (m.labelSide === 'left')
99
+ labelAttrs['text-anchor'] = 'end';
100
+ const label = m.title ? textTag(labelAttrs, m.title) : '';
101
+ return tag('g', { 'data-layer': 'milestone', 'data-id': m.id ?? null }, hiddenDateTitle(m.hiddenDate) + flag + label);
102
+ }
103
+ /**
104
+ * A marker dated on a day the axis hides sits at the next working day's
105
+ * x, so its own date rides along as a native tooltip, the way
106
+ * `renderInlineDatePin` titles its glyph (specs/working-calendar.md
107
+ * §7.4). Empty for a working-day date.
108
+ */
109
+ function hiddenDateTitle(hiddenDate) {
110
+ return hiddenDate === undefined ? '' : `<title>${escText(hiddenDate)}</title>`;
111
+ }
112
+ export function renderMilestoneCutLine(m, idPrefix, palette) {
113
+ // A slipped milestone's cut line drops from where it lands, in the
114
+ // normal colour; one that overran without slipping keeps the red line.
115
+ const cutX = m.slip?.x ?? m.center.x;
116
+ const stroke = m.isOverrun && m.slip === undefined
117
+ ? palette.milestoneDiamond.cutLineOverrun
118
+ : palette.milestoneDiamond.cutLineNormal;
119
+ const parts = [];
120
+ // A milestone on a wave boundary draws no cut line: the boundary
121
+ // already marks that instant (specs/waves.md §9.2).
122
+ if (!m.onWaveBoundary) {
123
+ parts.push(tag('line', {
124
+ x1: num(cutX),
125
+ y1: num(m.center.y + m.radius + 1),
126
+ x2: num(cutX),
127
+ y2: num(m.cutBottomY),
128
+ stroke,
129
+ 'stroke-width': 2,
130
+ 'stroke-dasharray': ACCENT_DASH_PATTERN,
131
+ 'stroke-linecap': 'round',
132
+ }));
133
+ }
134
+ if (m.slackArrows && m.slackArrows.length > 0) {
135
+ // Only a floating milestone draws slack arrows, in ink; a dated one
136
+ // slips instead.
137
+ for (const arrow of m.slackArrows) {
138
+ parts.push(tag('path', {
139
+ d: `M${num(arrow.x)} ${num(arrow.y)} H${num(m.center.x - 6)}`,
140
+ fill: 'none',
141
+ stroke: palette.milestoneDiamond.slack,
142
+ 'stroke-width': 1.1,
143
+ 'stroke-dasharray': '3 3',
144
+ 'stroke-linecap': 'round',
145
+ 'marker-end': `url(#${idPrefix}-arrow-dark)`,
146
+ }));
147
+ }
148
+ }
149
+ return parts.join('');
150
+ }
151
+ //# sourceMappingURL=markers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markers.js","sourceRoot":"","sources":["../../src/svg/markers.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,uEAAuE;AAGvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEtD,MAAM,UAAU,YAAY,CAAC,CAAmB,EAAE,OAAc,EAAE,KAAmB;IACjF,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACtB,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACtB,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC;IACxC,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC;IAC5C,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE;QACxB,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI;QAC9H,IAAI;QACJ,MAAM;QACN,cAAc,EAAE,IAAI;KACvB,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC;IAC/C,mEAAmE;IACnE,qEAAqE;IACrE,mEAAmE;IACnE,mEAAmE;IACnE,iEAAiE;IACjE,mEAAmE;IACnE,mEAAmE;IACnE,sBAAsB;IACtB,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvF,MAAM,UAAU,GAAuD;QACnE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC;QACd,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QACd,aAAa,EAAE,KAAK,CAAC,IAAI;QACzB,WAAW,EAAE,EAAE;QACf,IAAI,EAAE,UAAU;KACnB,CAAC;IACF,IAAI,CAAC,CAAC,SAAS,KAAK,MAAM;QAAE,UAAU,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC;IAC9D,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,OAAO,GAAG,CACN,GAAG,EACH,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,EACnD,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,OAAO,GAAG,KAAK,CAClD,CAAC;AACN,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,CAAmB,EAAE,OAAc;IACnE,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC;IAC7C,OAAO,GAAG,CAAC,MAAM,EAAE;QACf,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QACnB,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QAClC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QACnB,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;QACrB,MAAM;QACN,cAAc,EAAE,CAAC;QACjB,kBAAkB,EAAE,KAAK;KAC5B,CAAC,CAAC;AACP,CAAC;AAED,MAAM,UAAU,eAAe,CAC3B,CAAsB,EACtB,OAAc,EACd,KAAmB;IAEnB,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACtB,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACtB,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACnB,MAAM,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,cAAc,CAAC;IACxD,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,IAAY,EAAU,EAAE,CAChD,GAAG,CAAC,MAAM,EAAE;QACR,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI;QAC9G,IAAI;QACJ,MAAM,EAAE,IAAI;QACZ,cAAc,EAAE,CAAC;KACpB,CAAC,CAAC;IACP,sEAAsE;IACtE,wEAAwE;IACxE,wEAAwE;IACxE,uEAAuE;IACvE,4DAA4D;IAC5D,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACxB,IAAI,IAAY,CAAC;IACjB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACtB,IAAI;YACA,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC;gBACpB,GAAG,CAAC,MAAM,EAAE;oBACR,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE;oBAClD,IAAI,EAAE,MAAM;oBACZ,MAAM,EAAE,OAAO;oBACf,cAAc,EAAE,GAAG;oBACnB,kBAAkB,EAAE,KAAK;oBACzB,gBAAgB,EAAE,OAAO;iBAC5B,CAAC;gBACF,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC;SAAM,CAAC;QACJ,IAAI,GAAG,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,UAAU,GACZ,CAAC,CAAC,SAAS,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC;IAClF,mEAAmE;IACnE,gEAAgE;IAChE,oCAAoC;IACpC,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvF,MAAM,UAAU,GAAuD;QACnE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC;QACd,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QACd,aAAa,EAAE,KAAK,CAAC,IAAI;QACzB,WAAW,EAAE,EAAE;QACf,aAAa,EAAE,GAAG;QAClB,IAAI,EAAE,UAAU;KACnB,CAAC;IACF,IAAI,CAAC,CAAC,SAAS,KAAK,MAAM;QAAE,UAAU,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC;IAC9D,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,OAAO,GAAG,CACN,GAAG,EACH,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,EACtD,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,KAAK,CAC/C,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,UAA8B;IACnD,OAAO,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,sBAAsB,CAClC,CAAsB,EACtB,QAAgB,EAChB,OAAc;IAEd,mEAAmE;IACnE,uEAAuE;IACvE,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACrC,MAAM,MAAM,GACR,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;QAC/B,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,cAAc;QACzC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,aAAa,CAAC;IACjD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,iEAAiE;IACjE,oDAAoD;IACpD,IAAI,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CACN,GAAG,CAAC,MAAM,EAAE;YACR,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC;YACb,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAClC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC;YACb,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;YACrB,MAAM;YACN,cAAc,EAAE,CAAC;YACjB,kBAAkB,EAAE,mBAAmB;YACvC,gBAAgB,EAAE,OAAO;SAC5B,CAAC,CACL,CAAC;IACN,CAAC;IACD,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,oEAAoE;QACpE,iBAAiB;QACjB,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CACN,GAAG,CAAC,MAAM,EAAE;gBACR,CAAC,EAAE,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;gBAC7D,IAAI,EAAE,MAAM;gBACZ,MAAM,EAAE,OAAO,CAAC,gBAAgB,CAAC,KAAK;gBACtC,cAAc,EAAE,GAAG;gBACnB,kBAAkB,EAAE,KAAK;gBACzB,gBAAgB,EAAE,OAAO;gBACzB,YAAY,EAAE,QAAQ,QAAQ,cAAc;aAC/C,CAAC,CACL,CAAC;QACN,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { PositionedNowline, Theme } from '@nowline/layout';
2
+ import type { FontFamilies } from './render.js';
3
+ export declare function renderNowline(n: PositionedNowline | null, palette: Theme, fonts: FontFamilies): string;
4
+ //# sourceMappingURL=nowline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nowline.d.ts","sourceRoot":"","sources":["../../src/svg/nowline.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAShE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,wBAAgB,aAAa,CACzB,CAAC,EAAE,iBAAiB,GAAG,IAAI,EAC3B,OAAO,EAAE,KAAK,EACd,KAAK,EAAE,YAAY,GACpB,MAAM,CA0BR"}
@@ -0,0 +1,133 @@
1
+ // The now-line layer: the vertical line marking the current date and the pill
2
+ // at its top that carries the date label.
3
+ import { NOW_PILL_CORNER_RADIUS_PX, NOW_PILL_HEIGHT_PX, NOW_PILL_LABEL_BASELINE_OFFSET_PX, NOW_PILL_LABEL_FONT_SIZE_PX, NOW_PILL_LABEL_INSET_X_PX, NOWLINE_STROKE_WIDTH_PX, } from '@nowline/layout';
4
+ import { num, tag, textTag } from './xml.js';
5
+ export function renderNowline(n, palette, fonts) {
6
+ if (!n)
7
+ return '';
8
+ const color = palette.nowline.stroke;
9
+ const labelTextColor = palette.nowline.labelText;
10
+ // Line drops from `topY` (just below the pill / top of date headers)
11
+ // through the headers into the chart, ending at `bottomY`.
12
+ const line = tag('line', {
13
+ x1: num(n.x),
14
+ y1: num(n.topY),
15
+ x2: num(n.x),
16
+ y2: num(n.bottomY),
17
+ stroke: color,
18
+ 'stroke-width': NOWLINE_STROKE_WIDTH_PX,
19
+ });
20
+ // Pill — sits above the date headers at `pillTopY`. Three modes
21
+ // (decided by layout in `buildNowline`):
22
+ // - center → rounded rect centered on the line, label `middle`
23
+ // - flag-right → squared LEFT, rounded RIGHT, line at left edge,
24
+ // label `start` past the line
25
+ // - flag-left → rounded LEFT, squared RIGHT, line at right edge,
26
+ // label `end` before the line
27
+ // The squared edge IS the line; the rounded edge points into the
28
+ // chart, so the pill always hugs the line and never overflows.
29
+ const pillBg = renderNowPillBg(n, color);
30
+ const label = renderNowPillLabel(n, labelTextColor, fonts);
31
+ return tag('g', { 'data-layer': 'nowline' }, line + pillBg + label);
32
+ }
33
+ /**
34
+ * X coordinate of the pill's squared edge in flag modes. SVG strokes
35
+ * are centered on their geometry, so a 2.25 px line at `n.x` actually
36
+ * paints from `n.x - 1.125` to `n.x + 1.125`. To make the pill's
37
+ * squared edge line up with the OUTER edge of the line stroke (so
38
+ * the line and the pill share a single continuous edge instead of
39
+ * the line peeking past the pill by half-stroke), we offset by
40
+ * `NOWLINE_STROKE_WIDTH_PX / 2` on the side the line is on.
41
+ *
42
+ * flag-right: line on the LEFT → squared edge at n.x - half-stroke
43
+ * flag-left: line on the RIGHT → squared edge at n.x + half-stroke
44
+ *
45
+ * Center mode doesn't apply — the line passes through the pill's
46
+ * vertical center, so a half-stroke offset would make things worse.
47
+ */
48
+ function squaredEdgeX(n) {
49
+ const halfStroke = NOWLINE_STROKE_WIDTH_PX / 2;
50
+ if (n.pillMode === 'flag-right')
51
+ return n.x - halfStroke;
52
+ if (n.pillMode === 'flag-left')
53
+ return n.x + halfStroke;
54
+ return n.x;
55
+ }
56
+ function renderNowPillBg(n, color) {
57
+ const top = n.pillTopY;
58
+ const bottom = n.pillTopY + NOW_PILL_HEIGHT_PX;
59
+ const r = NOW_PILL_CORNER_RADIUS_PX;
60
+ // Pill width comes from the layout (`n.pillWidth`) — locale-aware,
61
+ // floored at `NOW_PILL_WIDTH_PX` so en-US output stays byte-stable
62
+ // and longer locale strings (e.g. fr `'maint.'`) grow the pill
63
+ // instead of clipping. See `buildNowline` in `@nowline/layout`.
64
+ const width = n.pillWidth;
65
+ if (n.pillMode === 'center') {
66
+ return tag('rect', {
67
+ x: num(n.x - width / 2),
68
+ y: num(top),
69
+ width: num(width),
70
+ height: num(NOW_PILL_HEIGHT_PX),
71
+ rx: r,
72
+ ry: r,
73
+ fill: color,
74
+ });
75
+ }
76
+ const edgeX = squaredEdgeX(n);
77
+ if (n.pillMode === 'flag-right') {
78
+ // Squared LEFT edge aligns with line's left outer stroke edge,
79
+ // rounded corners on the RIGHT.
80
+ const right = edgeX + width;
81
+ const d = [
82
+ `M ${num(edgeX)} ${num(top)}`,
83
+ `L ${num(right - r)} ${num(top)}`,
84
+ `A ${r} ${r} 0 0 1 ${num(right)} ${num(top + r)}`,
85
+ `L ${num(right)} ${num(bottom - r)}`,
86
+ `A ${r} ${r} 0 0 1 ${num(right - r)} ${num(bottom)}`,
87
+ `L ${num(edgeX)} ${num(bottom)}`,
88
+ 'Z',
89
+ ].join(' ');
90
+ return tag('path', { d, fill: color });
91
+ }
92
+ // flag-left: squared RIGHT edge aligns with line's right outer
93
+ // stroke edge, rounded corners on the LEFT.
94
+ const left = edgeX - width;
95
+ const d = [
96
+ `M ${num(edgeX)} ${num(top)}`,
97
+ `L ${num(left + r)} ${num(top)}`,
98
+ `A ${r} ${r} 0 0 0 ${num(left)} ${num(top + r)}`,
99
+ `L ${num(left)} ${num(bottom - r)}`,
100
+ `A ${r} ${r} 0 0 0 ${num(left + r)} ${num(bottom)}`,
101
+ `L ${num(edgeX)} ${num(bottom)}`,
102
+ 'Z',
103
+ ].join(' ');
104
+ return tag('path', { d, fill: color });
105
+ }
106
+ function renderNowPillLabel(n, labelTextColor, fonts) {
107
+ const baselineY = n.pillTopY + NOW_PILL_LABEL_BASELINE_OFFSET_PX;
108
+ const edgeX = squaredEdgeX(n);
109
+ let labelX;
110
+ let textAnchor;
111
+ if (n.pillMode === 'center') {
112
+ labelX = n.x;
113
+ textAnchor = 'middle';
114
+ }
115
+ else if (n.pillMode === 'flag-right') {
116
+ labelX = edgeX + NOW_PILL_LABEL_INSET_X_PX;
117
+ textAnchor = 'start';
118
+ }
119
+ else {
120
+ labelX = edgeX - NOW_PILL_LABEL_INSET_X_PX;
121
+ textAnchor = 'end';
122
+ }
123
+ return textTag({
124
+ x: num(labelX),
125
+ y: num(baselineY),
126
+ 'font-family': fonts.sans,
127
+ 'font-size': NOW_PILL_LABEL_FONT_SIZE_PX,
128
+ 'font-weight': 700,
129
+ fill: labelTextColor,
130
+ 'text-anchor': textAnchor,
131
+ }, n.label);
132
+ }
133
+ //# sourceMappingURL=nowline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nowline.js","sourceRoot":"","sources":["../../src/svg/nowline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { BoundingBox, ResolvedStyle } from '@nowline/layout';
2
+ import type { FontFamilies } from './render.js';
3
+ export declare function fontAttrs(style: ResolvedStyle, fonts: FontFamilies, overrideSize?: number): Record<string, string | number>;
4
+ export declare function rectFrame(x: number, y: number, w: number, h: number, style: ResolvedStyle, extra?: Record<string, string | number | undefined | null | boolean>): string;
5
+ /** `a ∩ b`, or undefined when they do not overlap. */
6
+ export declare function intersectBox(a: BoundingBox, b: BoundingBox): BoundingBox | undefined;
7
+ //# sourceMappingURL=primitives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/svg/primitives.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAwBhD,wBAAgB,SAAS,CACrB,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,YAAY,EACnB,YAAY,CAAC,EAAE,MAAM,GACtB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAQjC;AAQD,wBAAgB,SAAS,CACrB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,aAAa,EACpB,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAAM,GACzE,MAAM,CAiBR;AAED,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,SAAS,CAOpF"}
@@ -0,0 +1,70 @@
1
+ // Shared drawing primitives: the typography and stroke helpers every layer of
2
+ // the SVG renderer draws with, plus the rectangle frame and the box
3
+ // intersection the item, wave and non-working-band layers share. Nothing here
4
+ // knows about a particular roadmap element.
5
+ import { CORNER_RADIUS_PX, TEXT_SIZE_PX } from '@nowline/layout';
6
+ import { num, tag } from './xml.js';
7
+ // `TEXT_SIZE_PX`, `CORNER_RADIUS_PX`, `FONT_STACK` come from
8
+ // `@nowline/layout` (themes/shared) so a typography or radius change
9
+ // flows from one place to both layout and renderer.
10
+ //
11
+ // `WEIGHT_NUM` lives here only because no DSL `weight` table exists in
12
+ // shared yet. If/when it does, hoist this alongside `FONT_STACK`.
13
+ const WEIGHT_NUM = {
14
+ thin: 100,
15
+ light: 300,
16
+ normal: 400,
17
+ bold: 700,
18
+ };
19
+ // `style.textSize` is `SizeBucket` which includes `'full'`; the shared
20
+ // `TEXT_SIZE_PX` table only carries the size buckets (no `'full'` —
21
+ // that's a corner-radius-only value). Widen the lookup so a stray
22
+ // `'full'` falls through to the `?? 14` fallback instead of compiling.
23
+ function textSizePx(bucket) {
24
+ return TEXT_SIZE_PX[bucket] ?? 14;
25
+ }
26
+ export function fontAttrs(style, fonts, overrideSize) {
27
+ return {
28
+ 'font-family': fonts[style.font],
29
+ 'font-size': overrideSize ?? textSizePx(style.textSize),
30
+ 'font-weight': WEIGHT_NUM[style.weight] ?? 400,
31
+ 'font-style': style.italic ? 'italic' : 'normal',
32
+ fill: style.text,
33
+ };
34
+ }
35
+ function strokeDash(style) {
36
+ if (style.border === 'dashed')
37
+ return '4 3';
38
+ if (style.border === 'dotted')
39
+ return '1 3';
40
+ return undefined;
41
+ }
42
+ export function rectFrame(x, y, w, h, style, extra = {}) {
43
+ // The radius is a maximum: a frame narrower than two radii, such as a
44
+ // short bar drawn at its true width, rounds into a pill, then a line.
45
+ const rx = Math.min(CORNER_RADIUS_PX[style.cornerRadius] ?? 4, h / 2, w / 2);
46
+ return tag('rect', {
47
+ x: num(x),
48
+ y: num(y),
49
+ width: num(w),
50
+ height: num(h),
51
+ rx: num(rx),
52
+ ry: num(rx),
53
+ fill: style.bg === 'none' ? 'transparent' : style.bg,
54
+ stroke: style.fg,
55
+ 'stroke-width': 1,
56
+ 'stroke-dasharray': strokeDash(style) ?? null,
57
+ ...extra,
58
+ });
59
+ }
60
+ /** `a ∩ b`, or undefined when they do not overlap. */
61
+ export function intersectBox(a, b) {
62
+ const x1 = Math.max(a.x, b.x);
63
+ const y1 = Math.max(a.y, b.y);
64
+ const x2 = Math.min(a.x + a.width, b.x + b.width);
65
+ const y2 = Math.min(a.y + a.height, b.y + b.height);
66
+ if (x2 <= x1 || y2 <= y1)
67
+ return undefined;
68
+ return { x: x1, y: y1, width: x2 - x1, height: y2 - y1 };
69
+ }
70
+ //# sourceMappingURL=primitives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../src/svg/primitives.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,10 @@
1
- import type { PositionedDependencyEdge, PositionedHeader, PositionedItem, PositionedRoadmap, PositionedSwimlane, PositionedTimelineScale, Theme } from '@nowline/layout';
1
+ import type { PositionedRoadmap } from '@nowline/layout';
2
+ import type { LoadedLogo } from '../logo.js';
3
+ import { renderEdge } from './edges.js';
4
+ import { renderHeader } from './header.js';
5
+ import { renderItem } from './item.js';
6
+ import { renderSwimlane } from './swimlanes.js';
7
+ import { renderTimeline } from './timeline.js';
2
8
  export interface AssetBytes {
3
9
  bytes: Uint8Array;
4
10
  mime: string;
@@ -15,6 +21,12 @@ export type AssetResolver = (ref: string) => Promise<AssetBytes>;
15
21
  export type FontFamilies = Record<'sans' | 'serif' | 'mono', string>;
16
22
  export interface RenderOptions {
17
23
  assetResolver?: AssetResolver;
24
+ /**
25
+ * The logo `loadLogo` already read. Its bytes are embedded as they are,
26
+ * so the asset is not resolved a second time. Omitted: `renderSvg`
27
+ * resolves the logo through `assetResolver`.
28
+ */
29
+ logo?: LoadedLogo;
18
30
  noLinks?: boolean;
19
31
  strict?: boolean;
20
32
  warn?: (message: string) => void;
@@ -25,11 +37,6 @@ export interface RenderOptions {
25
37
  */
26
38
  fontFamilies?: FontFamilies;
27
39
  }
28
- declare function renderHeader(h: PositionedHeader, idPrefix: string, palette: Theme, fonts: FontFamilies): string;
29
- declare function renderTimeline(t: PositionedTimelineScale, palette: Theme, fonts: FontFamilies): string;
30
- declare function renderItem(i: PositionedItem, options: RenderOptions, idPrefix: string, palette: Theme, fonts: FontFamilies): string;
31
- declare function renderSwimlane(s: PositionedSwimlane, options: RenderOptions, idPrefix: string, palette: Theme, fonts: FontFamilies): string;
32
- declare function renderEdge(e: PositionedDependencyEdge, palette: Theme): string;
33
40
  export declare function renderSvg(model: PositionedRoadmap, options?: RenderOptions): Promise<string>;
34
41
  export declare const __internal: {
35
42
  renderItem: typeof renderItem;
@@ -38,5 +45,4 @@ export declare const __internal: {
38
45
  renderHeader: typeof renderHeader;
39
46
  renderEdge: typeof renderEdge;
40
47
  };
41
- export {};
42
48
  //# sourceMappingURL=render.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/svg/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKR,wBAAwB,EAGxB,gBAAgB,EAEhB,cAAc,EAId,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EAGvB,KAAK,EACR,MAAM,iBAAiB,CAAC;AAsEzB,MAAM,WAAW,UAAU;IACvB,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,MAAM,CAAC,CAAC;AAErE,MAAM,WAAW,aAAa;IAC1B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAEjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC/B;AAkWD,iBAAS,YAAY,CACjB,CAAC,EAAE,gBAAgB,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,KAAK,EACd,KAAK,EAAE,YAAY,GACpB,MAAM,CAyER;AA6ED,iBAAS,cAAc,CAAC,CAAC,EAAE,uBAAuB,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,CA2G/F;AAwID,iBAAS,UAAU,CACf,CAAC,EAAE,cAAc,EACjB,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,KAAK,EACd,KAAK,EAAE,YAAY,GACpB,MAAM,CA8SR;AAmRD,iBAAS,cAAc,CACnB,CAAC,EAAE,kBAAkB,EACrB,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,KAAK,EACd,KAAK,EAAE,YAAY,GACpB,MAAM,CAyHR;AAkHD,iBAAS,UAAU,CAAC,CAAC,EAAE,wBAAwB,EAAE,OAAO,EAAE,KAAK,GAAG,MAAM,CAmBvE;AA6YD,wBAAsB,SAAS,CAC3B,KAAK,EAAE,iBAAiB,EACxB,OAAO,GAAE,aAAkB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAyHjB;AAGD,eAAO,MAAM,UAAU;;;;;;CAMtB,CAAC"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/svg/render.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAoC,YAAY,EAAE,MAAM,aAAa,CAAC;AAG7E,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AASvC,OAAO,EAAE,cAAc,EAAoB,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAIH,cAAc,EACjB,MAAM,eAAe,CAAC;AAevB,MAAM,WAAW,UAAU;IACvB,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,MAAM,CAAC,CAAC;AAErE,MAAM,WAAW,aAAa;IAC1B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;OAIG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAEjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC/B;AAED,wBAAsB,SAAS,CAC3B,KAAK,EAAE,iBAAiB,EACxB,OAAO,GAAE,aAAkB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAoIjB;AAGD,eAAO,MAAM,UAAU;;;;;;CAMtB,CAAC"}