@lobehub/ui 5.33.1 → 5.33.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/es/Mermaid/SyntaxMermaid/MermaidSvg.mjs +44 -20
- package/es/Mermaid/SyntaxMermaid/MermaidSvg.mjs.map +1 -1
- package/es/Mermaid/SyntaxMermaid/prepareInlineSvg.mjs +2 -0
- package/es/Mermaid/SyntaxMermaid/prepareInlineSvg.mjs.map +1 -1
- package/es/base-ui/Input/style.d.mts +1 -1
- package/es/static-css/baseline.mjs +0 -1
- package/es/static-css/baseline.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { openPreview } from "../../Image/viewer/registry.mjs";
|
|
3
|
+
import PreviewOutlet from "../../Image/viewer/PreviewOutlet.mjs";
|
|
2
4
|
import { toStandaloneSvgString } from "./prepareInlineSvg.mjs";
|
|
3
5
|
import { prepareMermaidSvgString } from "./prepareMermaidSvg.mjs";
|
|
4
6
|
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
|
5
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
-
import { Image } from "antd";
|
|
7
8
|
//#region src/Mermaid/SyntaxMermaid/MermaidSvg.tsx
|
|
9
|
+
const anchorStyle = {
|
|
10
|
+
height: "100%",
|
|
11
|
+
insetBlockStart: 0,
|
|
12
|
+
insetInlineStart: 0,
|
|
13
|
+
pointerEvents: "none",
|
|
14
|
+
position: "absolute",
|
|
15
|
+
visibility: "hidden",
|
|
16
|
+
width: "100%"
|
|
17
|
+
};
|
|
8
18
|
const MermaidSvg = memo(({ className, ref, style, svg }) => {
|
|
9
19
|
const containerRef = useRef(null);
|
|
20
|
+
const anchorRef = useRef(null);
|
|
10
21
|
const [previewUrl, setPreviewUrl] = useState();
|
|
11
|
-
const [open, setOpen] = useState(false);
|
|
12
22
|
useEffect(() => {
|
|
13
23
|
return () => {
|
|
14
24
|
if (previewUrl) URL.revokeObjectURL(previewUrl);
|
|
@@ -16,33 +26,47 @@ const MermaidSvg = memo(({ className, ref, style, svg }) => {
|
|
|
16
26
|
}, [previewUrl]);
|
|
17
27
|
const handleOpen = useCallback(() => {
|
|
18
28
|
const element = containerRef.current?.querySelector("svg");
|
|
19
|
-
|
|
29
|
+
const anchor = anchorRef.current;
|
|
30
|
+
if (!element || !anchor) return;
|
|
20
31
|
const standalone = prepareMermaidSvgString(toStandaloneSvgString(element));
|
|
32
|
+
const url = URL.createObjectURL(new Blob([standalone], { type: "image/svg+xml" }));
|
|
21
33
|
setPreviewUrl((previous) => {
|
|
22
34
|
if (previous) URL.revokeObjectURL(previous);
|
|
23
|
-
return
|
|
35
|
+
return url;
|
|
36
|
+
});
|
|
37
|
+
openPreview({
|
|
38
|
+
element: anchor,
|
|
39
|
+
options: {
|
|
40
|
+
autoZoomThreshold: 2,
|
|
41
|
+
defaultZoom: "auto",
|
|
42
|
+
maxScale: 8
|
|
43
|
+
},
|
|
44
|
+
src: url
|
|
24
45
|
});
|
|
25
|
-
setOpen(true);
|
|
26
46
|
}, []);
|
|
27
47
|
return /* @__PURE__ */ jsxs("div", {
|
|
28
48
|
className,
|
|
29
49
|
ref,
|
|
30
|
-
style
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
50
|
+
style: {
|
|
51
|
+
position: "relative",
|
|
52
|
+
...style
|
|
53
|
+
},
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ jsx("div", {
|
|
56
|
+
dangerouslySetInnerHTML: { __html: svg },
|
|
57
|
+
ref: containerRef,
|
|
58
|
+
style: { cursor: "zoom-in" },
|
|
59
|
+
onClick: handleOpen
|
|
60
|
+
}),
|
|
61
|
+
/* @__PURE__ */ jsx("img", {
|
|
62
|
+
"aria-hidden": true,
|
|
63
|
+
alt: "",
|
|
64
|
+
ref: anchorRef,
|
|
39
65
|
src: previewUrl,
|
|
40
|
-
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
wrapperStyle: { display: "none" }
|
|
45
|
-
})]
|
|
66
|
+
style: anchorStyle
|
|
67
|
+
}),
|
|
68
|
+
/* @__PURE__ */ jsx(PreviewOutlet, { elementRef: anchorRef })
|
|
69
|
+
]
|
|
46
70
|
});
|
|
47
71
|
});
|
|
48
72
|
MermaidSvg.displayName = "MermaidSvg";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MermaidSvg.mjs","names":[
|
|
1
|
+
{"version":3,"file":"MermaidSvg.mjs","names":[],"sources":["../../../src/Mermaid/SyntaxMermaid/MermaidSvg.tsx"],"sourcesContent":["'use client';\n\nimport { memo, type Ref, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { DEFAULT_AUTO_ZOOM_THRESHOLD, DEFAULT_MAX_SCALE } from '@/Image/viewer/geometry';\nimport PreviewOutlet from '@/Image/viewer/PreviewOutlet';\nimport { openPreview } from '@/Image/viewer/registry';\n\nimport { toStandaloneSvgString } from './prepareInlineSvg';\nimport { prepareMermaidSvgString } from './prepareMermaidSvg';\n\ninterface MermaidSvgProps {\n className?: string;\n ref?: Ref<HTMLDivElement>;\n style?: React.CSSProperties;\n svg: string;\n}\n\n// The viewer flies the image out of the element it was opened from, so the\n// diagram needs a real <img> to measure — hence a hidden anchor tracking the\n// diagram box rather than a display:none preview image.\nconst anchorStyle: React.CSSProperties = {\n height: '100%',\n insetBlockStart: 0,\n insetInlineStart: 0,\n pointerEvents: 'none',\n position: 'absolute',\n visibility: 'hidden',\n width: '100%',\n};\n\nconst MermaidSvg = memo<MermaidSvgProps>(({ className, ref, style, svg }) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLImageElement>(null);\n const [previewUrl, setPreviewUrl] = useState<string>();\n\n useEffect(() => {\n return () => {\n if (previewUrl) URL.revokeObjectURL(previewUrl);\n };\n }, [previewUrl]);\n\n // The preview copy is only built on demand: it has to bake in the resolved\n // CSS variables and be XML-well-formed, neither of which the inline copy needs.\n const handleOpen = useCallback(() => {\n const element = containerRef.current?.querySelector('svg');\n const anchor = anchorRef.current;\n if (!element || !anchor) return;\n\n const standalone = prepareMermaidSvgString(toStandaloneSvgString(element));\n const url = URL.createObjectURL(new Blob([standalone], { type: 'image/svg+xml' }));\n setPreviewUrl((previous) => {\n if (previous) URL.revokeObjectURL(previous);\n return url;\n });\n\n openPreview({\n element: anchor,\n options: {\n autoZoomThreshold: DEFAULT_AUTO_ZOOM_THRESHOLD,\n defaultZoom: 'auto',\n maxScale: DEFAULT_MAX_SCALE,\n },\n src: url,\n });\n }, []);\n\n return (\n <div className={className} ref={ref} style={{ position: 'relative', ...style }}>\n <div\n dangerouslySetInnerHTML={{ __html: svg }}\n ref={containerRef}\n style={{ cursor: 'zoom-in' }}\n onClick={handleOpen}\n />\n <img aria-hidden alt=\"\" ref={anchorRef} src={previewUrl} style={anchorStyle} />\n <PreviewOutlet elementRef={anchorRef} />\n </div>\n );\n});\n\nMermaidSvg.displayName = 'MermaidSvg';\n\nexport default MermaidSvg;\n"],"mappings":";;;;;;;;AAqBA,MAAM,cAAmC;CACvC,QAAQ;CACR,iBAAiB;CACjB,kBAAkB;CAClB,eAAe;CACf,UAAU;CACV,YAAY;CACZ,OAAO;AACT;AAEA,MAAM,aAAa,MAAuB,EAAE,WAAW,KAAK,OAAO,UAAU;CAC3E,MAAM,eAAe,OAAuB,IAAI;CAChD,MAAM,YAAY,OAAyB,IAAI;CAC/C,MAAM,CAAC,YAAY,iBAAiB,SAAiB;CAErD,gBAAgB;EACd,aAAa;GACX,IAAI,YAAY,IAAI,gBAAgB,UAAU;EAChD;CACF,GAAG,CAAC,UAAU,CAAC;CAIf,MAAM,aAAa,kBAAkB;EACnC,MAAM,UAAU,aAAa,SAAS,cAAc,KAAK;EACzD,MAAM,SAAS,UAAU;EACzB,IAAI,CAAC,WAAW,CAAC,QAAQ;EAEzB,MAAM,aAAa,wBAAwB,sBAAsB,OAAO,CAAC;EACzE,MAAM,MAAM,IAAI,gBAAgB,IAAI,KAAK,CAAC,UAAU,GAAG,EAAE,MAAM,gBAAgB,CAAC,CAAC;EACjF,eAAe,aAAa;GAC1B,IAAI,UAAU,IAAI,gBAAgB,QAAQ;GAC1C,OAAO;EACT,CAAC;EAED,YAAY;GACV,SAAS;GACT,SAAS;IACP,mBAAA;IACA,aAAa;IACb,UAAA;GACF;GACA,KAAK;EACP,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,OACE,qBAAC,OAAD;EAAgB;EAAgB;EAAK,OAAO;GAAE,UAAU;GAAY,GAAG;EAAM;EAA7E,UAAA;GACE,oBAAC,OAAD;IACE,yBAAyB,EAAE,QAAQ,IAAI;IACvC,KAAK;IACL,OAAO,EAAE,QAAQ,UAAU;IAC3B,SAAS;GACV,CAAA;GACD,oBAAC,OAAD;IAAK,eAAA;IAAY,KAAI;IAAG,KAAK;IAAW,KAAK;IAAY,OAAO;GAAc,CAAA;GAC9E,oBAAC,eAAD,EAAe,YAAY,UAAY,CAAA;EACpC;;AAET,CAAC;AAED,WAAW,cAAc"}
|
|
@@ -42,6 +42,8 @@ const toStandaloneSvgString = (element) => {
|
|
|
42
42
|
const value = computed.getPropertyValue(name).trim();
|
|
43
43
|
if (value) clone.style.setProperty(name, value);
|
|
44
44
|
}
|
|
45
|
+
const background = computed.getPropertyValue("--bg").trim();
|
|
46
|
+
if (background) clone.style.setProperty("background", background);
|
|
45
47
|
const fontFamily = computed.fontFamily;
|
|
46
48
|
if (fontFamily) clone.style.setProperty("font-family", fontFamily);
|
|
47
49
|
return new XMLSerializer().serializeToString(clone);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepareInlineSvg.mjs","names":[],"sources":["../../../src/Mermaid/SyntaxMermaid/prepareInlineSvg.ts"],"sourcesContent":["/**\n * Root custom properties beautiful-mermaid reads; everything else in its\n * stylesheet is derived from these via color-mix().\n */\nexport const MERMAID_ROOT_VARS = [\n '--bg',\n '--fg',\n '--line',\n '--accent',\n '--muted',\n '--surface',\n '--border',\n];\n\nconst styleBlockPattern = /<style>([\\s\\S]*?)<\\/style>/;\n\nconst scopeCssSelectors = (css: string, scope: string): string =>\n css.replaceAll(/(^|})([^{}@]+)\\{/g, (_match, tail: string, selectors: string) => {\n const scoped = selectors\n .split(',')\n .map((selector) => selector.trim())\n .filter(Boolean)\n // The generated sheet targets `svg` for the root itself, not a descendant\n .map((selector) => (selector === 'svg' ? scope : `${scope} ${selector}`))\n .join(', ');\n\n return `${tail}\\n${scoped} {`;\n });\n\n/**\n * A <style> element inside inline SVG applies to the whole document, so the\n * generated rules must be scoped to this diagram before being injected. The\n * font @import is dropped because inline rendering would actually issue the\n * Google Fonts request that an <img>-loaded SVG silently blocks, and the bare\n * `text` rule is dropped so page CSS can supply the theme font instead.\n */\nexport const prepareInlineMermaidSvg = (svg: string, scopeId: string): string => {\n if (!svg) return svg;\n\n const withId = svg.replace(/<svg\\b/, `<svg id=\"${scopeId}\"`);\n\n return withId.replace(styleBlockPattern, (_match, css: string) => {\n const withoutImports = css.replaceAll(/@import[^;]*;/g, '');\n const withoutFontRule = withoutImports.replaceAll(/(^|})\\s*text\\s*\\{[^{}]*\\}/g, '$1');\n\n return `<style>${scopeCssSelectors(withoutFontRule, `#${scopeId}`)}</style>`;\n });\n};\n\n/**\n * Inline SVG resolves `var(--ant-*)` from the page, but a Blob-loaded copy is an\n * isolated document with no access to them, so the root variables are baked in\n * as literal values before serializing for preview or download.\n */\nexport const toStandaloneSvgString = (element: SVGElement): string => {\n const clone = element.cloneNode(true) as SVGElement;\n const computed = globalThis.getComputedStyle(element);\n\n for (const name of MERMAID_ROOT_VARS) {\n const value = computed.getPropertyValue(name).trim();\n if (value) clone.style.setProperty(name, value);\n }\n\n const fontFamily = computed.fontFamily;\n if (fontFamily) clone.style.setProperty('font-family', fontFamily);\n\n return new XMLSerializer().serializeToString(clone);\n};\n"],"mappings":";;;;;AAIA,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,oBAAoB;AAE1B,MAAM,qBAAqB,KAAa,UACtC,IAAI,WAAW,sBAAsB,QAAQ,MAAc,cAAsB;CAS/E,OAAO,GAAG,KAAK,IARA,UACZ,MAAM,GAAG,CAAC,CACV,KAAK,aAAa,SAAS,KAAK,CAAC,CAAC,CAClC,OAAO,OAAO,CAAC,CAEf,KAAK,aAAc,aAAa,QAAQ,QAAQ,GAAG,MAAM,GAAG,UAAW,CAAC,CACxE,KAAK,IAEgB,EAAE;AAC5B,CAAC;;;;;;;;AASH,MAAa,2BAA2B,KAAa,YAA4B;CAC/E,IAAI,CAAC,KAAK,OAAO;CAIjB,OAFe,IAAI,QAAQ,UAAU,YAAY,QAAQ,EAE7C,CAAC,CAAC,QAAQ,oBAAoB,QAAQ,QAAgB;EAEhE,MAAM,kBADiB,IAAI,WAAW,kBAAkB,EACnB,CAAC,CAAC,WAAW,8BAA8B,IAAI;EAEpF,OAAO,UAAU,kBAAkB,iBAAiB,IAAI,SAAS,EAAE;CACrE,CAAC;AACH;;;;;;AAOA,MAAa,yBAAyB,YAAgC;CACpE,MAAM,QAAQ,QAAQ,UAAU,IAAI;CACpC,MAAM,WAAW,WAAW,iBAAiB,OAAO;CAEpD,KAAK,MAAM,QAAQ,mBAAmB;EACpC,MAAM,QAAQ,SAAS,iBAAiB,IAAI,CAAC,CAAC,KAAK;EACnD,IAAI,OAAO,MAAM,MAAM,YAAY,MAAM,KAAK;CAChD;
|
|
1
|
+
{"version":3,"file":"prepareInlineSvg.mjs","names":[],"sources":["../../../src/Mermaid/SyntaxMermaid/prepareInlineSvg.ts"],"sourcesContent":["/**\n * Root custom properties beautiful-mermaid reads; everything else in its\n * stylesheet is derived from these via color-mix().\n */\nexport const MERMAID_ROOT_VARS = [\n '--bg',\n '--fg',\n '--line',\n '--accent',\n '--muted',\n '--surface',\n '--border',\n];\n\nconst styleBlockPattern = /<style>([\\s\\S]*?)<\\/style>/;\n\nconst scopeCssSelectors = (css: string, scope: string): string =>\n css.replaceAll(/(^|})([^{}@]+)\\{/g, (_match, tail: string, selectors: string) => {\n const scoped = selectors\n .split(',')\n .map((selector) => selector.trim())\n .filter(Boolean)\n // The generated sheet targets `svg` for the root itself, not a descendant\n .map((selector) => (selector === 'svg' ? scope : `${scope} ${selector}`))\n .join(', ');\n\n return `${tail}\\n${scoped} {`;\n });\n\n/**\n * A <style> element inside inline SVG applies to the whole document, so the\n * generated rules must be scoped to this diagram before being injected. The\n * font @import is dropped because inline rendering would actually issue the\n * Google Fonts request that an <img>-loaded SVG silently blocks, and the bare\n * `text` rule is dropped so page CSS can supply the theme font instead.\n */\nexport const prepareInlineMermaidSvg = (svg: string, scopeId: string): string => {\n if (!svg) return svg;\n\n const withId = svg.replace(/<svg\\b/, `<svg id=\"${scopeId}\"`);\n\n return withId.replace(styleBlockPattern, (_match, css: string) => {\n const withoutImports = css.replaceAll(/@import[^;]*;/g, '');\n const withoutFontRule = withoutImports.replaceAll(/(^|})\\s*text\\s*\\{[^{}]*\\}/g, '$1');\n\n return `<style>${scopeCssSelectors(withoutFontRule, `#${scopeId}`)}</style>`;\n });\n};\n\n/**\n * Inline SVG resolves `var(--ant-*)` from the page, but a Blob-loaded copy is an\n * isolated document with no access to them, so the root variables are baked in\n * as literal values before serializing for preview or download.\n */\nexport const toStandaloneSvgString = (element: SVGElement): string => {\n const clone = element.cloneNode(true) as SVGElement;\n const computed = globalThis.getComputedStyle(element);\n\n for (const name of MERMAID_ROOT_VARS) {\n const value = computed.getPropertyValue(name).trim();\n if (value) clone.style.setProperty(name, value);\n }\n\n // The diagram is rendered transparent so it inherits the page surface, but a\n // standalone copy has nothing behind it: without an explicit fill the viewer\n // scrim (and whatever it lets through) shows straight through the diagram.\n const background = computed.getPropertyValue('--bg').trim();\n if (background) clone.style.setProperty('background', background);\n\n const fontFamily = computed.fontFamily;\n if (fontFamily) clone.style.setProperty('font-family', fontFamily);\n\n return new XMLSerializer().serializeToString(clone);\n};\n"],"mappings":";;;;;AAIA,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,oBAAoB;AAE1B,MAAM,qBAAqB,KAAa,UACtC,IAAI,WAAW,sBAAsB,QAAQ,MAAc,cAAsB;CAS/E,OAAO,GAAG,KAAK,IARA,UACZ,MAAM,GAAG,CAAC,CACV,KAAK,aAAa,SAAS,KAAK,CAAC,CAAC,CAClC,OAAO,OAAO,CAAC,CAEf,KAAK,aAAc,aAAa,QAAQ,QAAQ,GAAG,MAAM,GAAG,UAAW,CAAC,CACxE,KAAK,IAEgB,EAAE;AAC5B,CAAC;;;;;;;;AASH,MAAa,2BAA2B,KAAa,YAA4B;CAC/E,IAAI,CAAC,KAAK,OAAO;CAIjB,OAFe,IAAI,QAAQ,UAAU,YAAY,QAAQ,EAE7C,CAAC,CAAC,QAAQ,oBAAoB,QAAQ,QAAgB;EAEhE,MAAM,kBADiB,IAAI,WAAW,kBAAkB,EACnB,CAAC,CAAC,WAAW,8BAA8B,IAAI;EAEpF,OAAO,UAAU,kBAAkB,iBAAiB,IAAI,SAAS,EAAE;CACrE,CAAC;AACH;;;;;;AAOA,MAAa,yBAAyB,YAAgC;CACpE,MAAM,QAAQ,QAAQ,UAAU,IAAI;CACpC,MAAM,WAAW,WAAW,iBAAiB,OAAO;CAEpD,KAAK,MAAM,QAAQ,mBAAmB;EACpC,MAAM,QAAQ,SAAS,iBAAiB,IAAI,CAAC,CAAC,KAAK;EACnD,IAAI,OAAO,MAAM,MAAM,YAAY,MAAM,KAAK;CAChD;CAKA,MAAM,aAAa,SAAS,iBAAiB,MAAM,CAAC,CAAC,KAAK;CAC1D,IAAI,YAAY,MAAM,MAAM,YAAY,cAAc,UAAU;CAEhE,MAAM,aAAa,SAAS;CAC5B,IAAI,YAAY,MAAM,MAAM,YAAY,eAAe,UAAU;CAEjE,OAAO,IAAI,cAAc,CAAC,CAAC,kBAAkB,KAAK;AACpD"}
|
|
@@ -24,7 +24,7 @@ declare const styles: {
|
|
|
24
24
|
declare const rootVariants: (props?: ({
|
|
25
25
|
shadow?: boolean | null | undefined;
|
|
26
26
|
size?: "large" | "middle" | "small" | null | undefined;
|
|
27
|
-
variant?: "filled" | "
|
|
27
|
+
variant?: "filled" | "outlined" | "borderless" | null | undefined;
|
|
28
28
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
29
29
|
//#endregion
|
|
30
30
|
export { rootVariants, styles };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseline.mjs","names":[],"sources":["../../src/static-css/baseline.ts"],"sourcesContent":["import type { AntdProbeName } from './registry';\n\n// The antd components @lobehub/ui internals can render. Kept in sync with the\n// source tree by baseline.test.ts — a failure there means this list must change.\nexport const lobeUiAntdBaseline: AntdProbeName[] = [\n 'alert',\n 'anchor',\n 'app',\n 'auto-complete',\n 'avatar',\n 'button',\n 'collapse',\n 'color-picker',\n 'date-picker',\n 'divider',\n 'drawer',\n 'dropdown',\n 'empty',\n 'form',\n '
|
|
1
|
+
{"version":3,"file":"baseline.mjs","names":[],"sources":["../../src/static-css/baseline.ts"],"sourcesContent":["import type { AntdProbeName } from './registry';\n\n// The antd components @lobehub/ui internals can render. Kept in sync with the\n// source tree by baseline.test.ts — a failure there means this list must change.\nexport const lobeUiAntdBaseline: AntdProbeName[] = [\n 'alert',\n 'anchor',\n 'app',\n 'auto-complete',\n 'avatar',\n 'button',\n 'collapse',\n 'color-picker',\n 'date-picker',\n 'divider',\n 'drawer',\n 'dropdown',\n 'empty',\n 'form',\n 'input',\n 'input-number',\n 'input-textarea',\n 'menu',\n 'modal',\n 'popover',\n 'progress',\n 'segmented',\n 'select',\n 'skeleton',\n 'slider',\n 'space',\n 'tabs',\n 'tag',\n 'tag-preset',\n 'tag-status',\n 'upload',\n];\n"],"mappings":";AAIA,MAAa,qBAAsC;CACjD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
|