shopic 0.0.1 → 0.1.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.
- package/README.md +59 -30
- package/dist/index.js +1 -1
- package/dist/index.js.map +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,46 +16,75 @@ is public even though this repository is not — that is the price of a free CDN
|
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
pnpm install
|
|
19
|
-
pnpm dev
|
|
19
|
+
pnpm dev # watch + rebuild; also serves dist/ on http://localhost:3000
|
|
20
|
+
pnpm check # tsc
|
|
21
|
+
pnpm lint # eslint + prettier
|
|
20
22
|
```
|
|
21
23
|
|
|
22
|
-
`pnpm dev`
|
|
24
|
+
`pnpm dev` is for building and type-checking while you work. It is **not** a way
|
|
25
|
+
to preview against the live site — see below.
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
flipped into dev mode:
|
|
27
|
+
The site loads the bundle from jsDelivr. One line in
|
|
28
|
+
**Site Settings → Custom Code → Footer**, and that is the whole integration:
|
|
27
29
|
|
|
28
30
|
```html
|
|
29
|
-
<script>
|
|
30
|
-
(() => {
|
|
31
|
-
const PROD = 'https://cdn.jsdelivr.net/npm/shopic@0.0.1/dist/index.js';
|
|
32
|
-
const DEV = 'http://localhost:3000/index.js';
|
|
33
|
-
|
|
34
|
-
const load = (src, fallback) => {
|
|
35
|
-
const s = document.createElement('script');
|
|
36
|
-
s.src = src;
|
|
37
|
-
if (fallback) s.onerror = fallback;
|
|
38
|
-
document.head.appendChild(s);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
if (localStorage.getItem('shopic-dev') === 'on') load(DEV, () => load(PROD));
|
|
42
|
-
else load(PROD);
|
|
43
|
-
})();
|
|
44
|
-
</script>
|
|
31
|
+
<script src="https://cdn.jsdelivr.net/npm/shopic@0.0.2/dist/index.js"></script>
|
|
45
32
|
```
|
|
46
33
|
|
|
47
|
-
|
|
34
|
+
GSAP is **not** loaded there. It comes from Webflow's native Site Settings
|
|
35
|
+
toggle (3.15.0 with SplitText); a second copy would register ScrollTrigger twice.
|
|
48
36
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
37
|
+
## Seeing a change on the site
|
|
38
|
+
|
|
39
|
+
Publish it. There is no localhost preview.
|
|
52
40
|
|
|
53
|
-
|
|
54
|
-
|
|
41
|
+
```bash
|
|
42
|
+
pnpm check && pnpm lint && pnpm build
|
|
43
|
+
npm version patch --no-git-tag-version
|
|
44
|
+
git add -A && git commit -m "…" && git push
|
|
45
|
+
npm publish # needs the 2FA passkey
|
|
46
|
+
```
|
|
55
47
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
Then bump the version in the footer snippet and reload the site. jsDelivr serves
|
|
49
|
+
a new version within a minute or so.
|
|
50
|
+
|
|
51
|
+
### Why there is no localhost preview
|
|
52
|
+
|
|
53
|
+
The obvious setup — footer script pointing at `http://localhost:3000` behind a
|
|
54
|
+
localStorage flag — does not work from a published Webflow page, and cannot be
|
|
55
|
+
made to work without dismantling browser protections. Established by measurement
|
|
56
|
+
on 2026-09-01, in this order:
|
|
57
|
+
|
|
58
|
+
1. **Mixed content.** An http subresource on an https page is blocked. Silently:
|
|
59
|
+
the script tag is in the DOM, the request never completes, nothing is logged.
|
|
60
|
+
It looks exactly like a bundle that loaded and did nothing.
|
|
61
|
+
2. **Private Network Access.** Clearing the first one only reveals this:
|
|
62
|
+
`Permission was denied for this request to access the loopback address space`.
|
|
63
|
+
esbuild's server cannot opt in — it answers OPTIONS with a 404 and never sends
|
|
64
|
+
`Access-Control-Allow-Private-Network`.
|
|
65
|
+
3. **Local Network Access.** Sending those headers from a proxy is still not
|
|
66
|
+
enough. Chrome now requires the *user* to grant permission before any site
|
|
67
|
+
reaches a loopback address, and a `<script src>` cannot request it —
|
|
68
|
+
`targetAddressSpace` is a `fetch()` option, so it would mean fetching the code
|
|
69
|
+
and injecting it by hand.
|
|
70
|
+
|
|
71
|
+
Each of those exists to stop a public page from reaching services on the
|
|
72
|
+
visitor's machine. Getting a preview would mean a browser flag, plus a proxy,
|
|
73
|
+
plus a granted permission — three mitigations bypassed so that a reload is
|
|
74
|
+
faster.
|
|
75
|
+
|
|
76
|
+
Two other routes were tried and rejected:
|
|
77
|
+
|
|
78
|
+
- **A local TLS certificate (`mkcert`).** Solves step 1, but `mkcert -install`
|
|
79
|
+
puts a private CA in the system trust store, and whoever reads that CA's key
|
|
80
|
+
can mint a certificate for *any* domain that the browser accepts without
|
|
81
|
+
warning. Permanent, machine-wide exposure for a development convenience.
|
|
82
|
+
- **A Chrome flag on a throwaway profile.** Also solves step 1, but stops at
|
|
83
|
+
step 3.
|
|
84
|
+
|
|
85
|
+
**Do not reopen this.** If a preview loop becomes genuinely necessary, the answer
|
|
86
|
+
is a local page that loads the bundle over plain http from a plain http page —
|
|
87
|
+
not a way to make the published site reach this machine.
|
|
59
88
|
|
|
60
89
|
## Releasing
|
|
61
90
|
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(()=>{var
|
|
1
|
+
"use strict";(()=>{var M=new Map,f=(e,n)=>{if(M.has(e))throw new Error(`[shopic] Animation "${e}" is registered twice.`);M.set(e,n)},C=(e,n=document)=>{let r=n.querySelectorAll("[data-anim]");for(let t of r){let l=t.dataset.anim;if(!l||t.dataset.animState==="ready")continue;let a=M.get(l);if(!a){console.warn(`[shopic] No animation registered for data-anim="${l}".`,t);continue}t.dataset.animState="ready",a(t,e)}};var $=2,F=150,U=[0,.25,.5,.6,.7,.8,.9,1],x="shopic:slide-enter";f("carousel",(e,{reducedMotion:n})=>{let r=Array.from(e.querySelectorAll(":scope > [data-slide]"));if(r.length<2)return;let t=e.closest("section")??e.parentElement??document.body,l=Array.from(t.querySelectorAll("[data-tab]")),a=n?"auto":"smooth",s=o=>o.getBoundingClientRect().left-e.getBoundingClientRect().left+e.scrollLeft,d=()=>parseFloat(getComputedStyle(e).paddingLeft)||0,i=(o,c)=>{e.scrollTo({left:s(o)-d(),behavior:c?a:"auto"})},m=r[r.length-1].cloneNode(!0),g=r[0].cloneNode(!0);for(let o of[m,g]){o.dataset.slideClone="true",o.setAttribute("aria-hidden","true");for(let c of o.querySelectorAll("[data-anim]"))c.dataset.animState="ready"}e.insertBefore(m,r[0]),e.append(g);let L=Array.from(e.querySelectorAll(":scope > [data-slide]")),A=o=>{for(let c of l)c.classList.toggle("is-active",c.dataset.tab===o)};for(let o of l)o.addEventListener("click",c=>{c.preventDefault();let T=o.dataset.tab,y=r.find(u=>u.dataset.slide===T);y&&i(y,!0)});let S=new Map(L.map(o=>[o,0])),p=null,b=new IntersectionObserver(o=>{for(let u of o)S.set(u.target,u.isIntersecting?u.intersectionRatio:0);let c=null,T=0;for(let u of L){let N=S.get(u)??0;N>T&&(T=N,c=u)}if(!c)return;let y=c.dataset.slide;y&&A(y);for(let u of L)u.classList.toggle("is-current",u===c);c!==p&&(p=c,c.dispatchEvent(new CustomEvent(x)))},{root:e,threshold:U});for(let o of L)b.observe(o);e.scrollLeft=s(r[0])-d();let h=()=>{let o=null,c=1/0;for(let T of L){let y=Math.abs(s(T)-d()-e.scrollLeft);y<c&&(c=y,o=T)}return o},w=()=>{let o=h();if(!o?.dataset.slideClone)return;let c=r.find(T=>T.dataset.slide===o.dataset.slide);c&&(e.style.scrollSnapType="none",e.scrollLeft-=s(o)-s(c),e.offsetHeight,e.style.scrollSnapType="")};if("onscrollend"in window)e.addEventListener("scrollend",w);else{let o;e.addEventListener("scroll",()=>{clearTimeout(o),o=setTimeout(w,F)})}let E=!1,H=0,I=0;e.addEventListener("pointerdown",o=>{E=!0,e.classList.add("is-dragging"),H=o.clientX,I=e.scrollLeft}),window.addEventListener("pointermove",o=>{E&&(e.scrollLeft=I-(o.clientX-H)*$)}),window.addEventListener("pointerup",()=>{if(!E)return;E=!1,e.classList.remove("is-dragging");let o=h();o&&i(o,!0)})});var R="!<>-_\\/[]{}=+*^?#$%01",O=new WeakMap,v=(e,{duration:n=1050,stagger:r=.75,text:t,reducedMotion:l=!1}={})=>{if(l){t!==void 0&&(e.textContent=t);return}if(t!==void 0)e.dataset.scrambleText=t;else if(!e.dataset.scrambleText){let p=e.textContent;if(!p||!p.trim())return;e.dataset.scrambleText=p}let a=e.dataset.scrambleText;if(!a||!a.trim())return;let s=Array.from(a),d=s.length;e.textContent="";let i=document.createDocumentFragment(),m=s.map(p=>{let b=document.createElement("span");return b.textContent=p,i.append(b),b});e.append(i);let g=Symbol("scramble");O.set(e,g);let L=s.map((p,b)=>d<=1?0:b/(d-1)*n*r),A=performance.now(),S=p=>{if(O.get(e)!==g)return;let b=p-A,h=!0;s.forEach((w,E)=>{w!==" "&&(b>=L[E]?m[E].textContent=w:(h=!1,m[E].textContent=R[Math.random()*R.length|0]))}),h||requestAnimationFrame(S)};requestAnimationFrame(S)},_=(e,n={})=>{e.dataset.scrambleHoverBound||(e.dataset.scrambleHoverBound="true",e.addEventListener("pointerenter",()=>v(e,n)))};var X=.5,V="power2.out",j=".status-pill, .evidence_label, .evidence_sku";f("evidence",(e,{gsap:n,reducedMotion:r})=>{let t=Array.from(e.children);if(!t.length)return;if(r){for(let i of t)i.style.height="auto",i.style.opacity="1";return}let l=()=>{n.killTweensOf(t),n.set(t,{height:0,opacity:0,overflow:"hidden"});let i=n.timeline();for(let m of t)i.call(()=>{for(let g of m.querySelectorAll(j))v(g,{duration:630,stagger:.6})}),i.to(m,{height:"auto",opacity:1,duration:X,ease:V,onComplete:()=>n.set(m,{height:"auto"})})},a=!1,s=!1,d=()=>{if(!a)return;let i=e.closest("[data-slide]");i&&!i.classList.contains("is-current")||(s=!0,l())};if("IntersectionObserver"in window){let i=new IntersectionObserver(m=>{for(let g of m)g.isIntersecting&&(a=!0,d(),s&&i.disconnect())},{threshold:.2});i.observe(e)}else a=!0,d();e.closest("[data-slide]")?.addEventListener(x,d)});var D="split_line",z="split_word",G="split_word-inner",J=e=>{let n=document.createDocumentFragment(),r=[],t=document.createElement("span");t.className=D,n.appendChild(t);let l=(s,d)=>{if(!s)return;let i=document.createElement("span");i.className=z;let m=document.createElement("span");m.className=d?`${G} ${d}`:G,m.textContent=s,i.appendChild(m),t.appendChild(i),r.push(m)},a=(s,d)=>{for(let i of s.split(/(\s+)/))i&&(/^\s+$/.test(i)?t.appendChild(document.createTextNode(" ")):l(i,d))};for(let s of Array.from(e.childNodes))s.nodeType===Node.TEXT_NODE?a(s.textContent??""):s instanceof HTMLBRElement?(t=document.createElement("span"),t.className=D,n.appendChild(t)):s instanceof HTMLElement&&a(s.textContent??"",s.className||void 0);return e.textContent="",e.appendChild(n),r},q={yPercent:0,duration:.9,ease:"power4.out",stagger:.035};f("headline",(e,{gsap:n,ScrollTrigger:r,reducedMotion:t})=>{if(t){e.style.visibility="visible";return}let l=J(e);if(n.set(l,{yPercent:110}),e.style.visibility="visible",e.dataset.animTrigger==="load"||!r){n.to(l,{...q,delay:.3});return}n.to(l,{...q,scrollTrigger:{trigger:e,start:"top 85%"}})});var K=26;f("marquee",(e,{gsap:n,reducedMotion:r})=>{if(r)return;let t=Number(e.dataset.animSets??4),l=Number(e.dataset.animDuration??K);if(!Number.isFinite(t)||t<2)return;let a=()=>e.scrollWidth/t,s=n.to(e,{x:()=>-a(),duration:l,ease:"none",repeat:-1,modifiers:{x:i=>`${Number.parseFloat(i)%a()}px`}}),d=e.parentElement;d&&(d.addEventListener("pointerenter",()=>s.pause()),d.addEventListener("pointerleave",()=>s.resume()))});var B="is-visible";f("reveal",(e,{reducedMotion:n})=>{let r=Number(e.dataset.animDelay??0);if(r&&(e.style.transitionDelay=`${r}ms`),n||!("IntersectionObserver"in window)){e.classList.add(B);return}let t=new IntersectionObserver(l=>{for(let a of l)a.isIntersecting&&(a.target.classList.add(B),t.unobserve(a.target))},{threshold:.15});t.observe(e)});f("scramble",(e,{reducedMotion:n})=>{let r={duration:Number(e.dataset.animDuration??1050),stagger:Number(e.dataset.animStagger??.75),reducedMotion:n};if(n||!("IntersectionObserver"in window)){v(e,r);return}let t=new IntersectionObserver(l=>{for(let a of l)a.isIntersecting&&(v(e,r),_(e,r),t.unobserve(a.target))},{threshold:.2});t.observe(e)});var P=()=>{let{gsap:e,ScrollTrigger:n}=window;if(!e)throw new Error("[shopic] GSAP is not on the page. Enable it in Webflow \u2192 Site Settings \u2192 Custom Code \u2192 GSAP.");return n&&e.registerPlugin(n),{gsap:e,ScrollTrigger:n}},W=()=>window.matchMedia("(prefers-reduced-motion: reduce)").matches;window.Webflow||(window.Webflow=[]);window.Webflow.push(()=>{let{gsap:e,ScrollTrigger:n}=P();C({gsap:e,ScrollTrigger:n,reducedMotion:W()})});})();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../bin/live-reload.js", "../src/anim/registry.ts", "../src/anim/headline.ts", "../src/anim/marquee.ts", "../src/anim/reveal.ts", "../src/lib/gsap.ts", "../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener('change', () => location.reload());\n", "import type { Gsap, ScrollTriggerType } from '$lib/gsap';\n\nexport type AnimationContext = {\n gsap: Gsap;\n ScrollTrigger?: ScrollTriggerType;\n reducedMotion: boolean;\n};\n\nexport type AnimationInit = (element: HTMLElement, context: AnimationContext) => void;\n\nconst registry = new Map<string, AnimationInit>();\n\n/**\n * Registers an animation under the name used in `data-anim`.\n * The client edits content in the Designer; the attribute is the only contract\n * between their markup and this bundle.\n */\nexport const registerAnimation = (name: string, init: AnimationInit): void => {\n if (registry.has(name)) {\n throw new Error(`[shopic] Animation \"${name}\" is registered twice.`);\n }\n\n registry.set(name, init);\n};\n\n/**\n * Runs every registered animation against the elements that ask for it.\n * Unknown names warn rather than throw \u2014 a stray attribute in the Designer\n * must not take the whole bundle down.\n *\n * Initialisation is once per element, and the marker lives on the element\n * rather than in module scope so that a *second copy* of this bundle sees it\n * too. That is not hypothetical: a stale inlined copy alongside the CDN one\n * re-split an already-split headline, and because the splitter carries a\n * parent's className onto the words it produces, every word inherited\n * `split_line` (display: block) and stacked one per line.\n */\nexport const runAnimations = (context: AnimationContext, root: ParentNode = document): void => {\n const elements = root.querySelectorAll<HTMLElement>('[data-anim]');\n\n for (const element of elements) {\n const name = element.dataset.anim;\n if (!name) continue;\n if (element.dataset.animState === 'ready') continue;\n\n const init = registry.get(name);\n\n if (!init) {\n // eslint-disable-next-line no-console\n console.warn(`[shopic] No animation registered for data-anim=\"${name}\".`, element);\n continue;\n }\n\n element.dataset.animState = 'ready';\n init(element, context);\n }\n};\n", "import { registerAnimation } from './registry';\n\nconst LINE = 'split_line';\nconst WORD = 'split_word';\nconst INNER = 'split_word-inner';\n\n/**\n * Wraps every word in an overflow-hidden span so it can slide up into view.\n * `<br>` starts a new line; existing child spans (accent colours) survive as\n * single words and keep their class. The class names are real Webflow styles \u2014\n * a class that only ever exists at runtime gets stripped from the published CSS.\n */\nconst splitHeadline = (element: HTMLElement): HTMLElement[] => {\n const fragment = document.createDocumentFragment();\n const words: HTMLElement[] = [];\n let line = document.createElement('span');\n line.className = LINE;\n fragment.appendChild(line);\n\n const addWord = (text: string, className?: string): void => {\n if (!text) return;\n\n const outer = document.createElement('span');\n outer.className = WORD;\n\n const inner = document.createElement('span');\n inner.className = className ? `${INNER} ${className}` : INNER;\n inner.textContent = text;\n\n outer.appendChild(inner);\n line.appendChild(outer);\n words.push(inner);\n };\n\n const addChunks = (text: string, className?: string): void => {\n for (const chunk of text.split(/(\\s+)/)) {\n if (!chunk) continue;\n if (/^\\s+$/.test(chunk)) line.appendChild(document.createTextNode(' '));\n else addWord(chunk, className);\n }\n };\n\n for (const node of Array.from(element.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n addChunks(node.textContent ?? '');\n } else if (node instanceof HTMLBRElement) {\n line = document.createElement('span');\n line.className = LINE;\n fragment.appendChild(line);\n } else if (node instanceof HTMLElement) {\n addChunks(node.textContent ?? '', node.className || undefined);\n }\n }\n\n element.textContent = '';\n element.appendChild(fragment);\n\n return words;\n};\n\nconst TWEEN = { yPercent: 0, duration: 0.9, ease: 'power4.out', stagger: 0.035 } as const;\n\nregisterAnimation('headline', (element, { gsap, ScrollTrigger, reducedMotion }) => {\n if (reducedMotion) {\n element.style.visibility = 'visible';\n return;\n }\n\n const words = splitHeadline(element);\n gsap.set(words, { yPercent: 110 });\n element.style.visibility = 'visible';\n\n // The hero headline is above the fold, so it plays on load; everything else\n // waits for the scroll to reach it.\n if (element.dataset.animTrigger === 'load' || !ScrollTrigger) {\n gsap.to(words, { ...TWEEN, delay: 0.3 });\n return;\n }\n\n gsap.to(words, { ...TWEEN, scrollTrigger: { trigger: element, start: 'top 85%' } });\n});\n", "import { registerAnimation } from './registry';\n\nconst DEFAULT_DURATION = 26;\n\n/**\n * Infinite logo strip. The track holds the same set of logos repeated N times,\n * so translating by exactly one set's width lands on an identical frame \u2014 no\n * measuring loop, no drift. N comes from the DOM, not a constant, so adding a\n * logo in the Designer cannot desync the loop.\n */\nregisterAnimation('marquee', (element, { gsap, reducedMotion }) => {\n if (reducedMotion) return;\n\n const sets = Number(element.dataset.animSets ?? 4);\n const duration = Number(element.dataset.animDuration ?? DEFAULT_DURATION);\n if (!Number.isFinite(sets) || sets < 2) return;\n\n const distance = () => element.scrollWidth / sets;\n\n const tween = gsap.to(element, {\n x: () => -distance(),\n duration,\n ease: 'none',\n repeat: -1,\n modifiers: {\n // wrap inside one set so the tween never accumulates a huge offset\n x: (value: string) => `${Number.parseFloat(value) % distance()}px`,\n },\n });\n\n const parent = element.parentElement;\n if (!parent) return;\n\n parent.addEventListener('pointerenter', () => tween.pause());\n parent.addEventListener('pointerleave', () => tween.resume());\n});\n", "import { registerAnimation } from './registry';\n\nconst VISIBLE = 'is-visible';\n\n/**\n * Fade-and-rise on entry. The motion itself is a CSS transition on\n * `.hero_media`; this only decides when to add the state class, so the\n * client can restyle the easing in the Designer without touching the bundle.\n */\nregisterAnimation('reveal', (element, { reducedMotion }) => {\n const delay = Number(element.dataset.animDelay ?? 0);\n if (delay) element.style.transitionDelay = `${delay}ms`;\n\n if (reducedMotion || !('IntersectionObserver' in window)) {\n element.classList.add(VISIBLE);\n return;\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (!entry.isIntersecting) continue;\n entry.target.classList.add(VISIBLE);\n observer.unobserve(entry.target);\n }\n },\n { threshold: 0.15 }\n );\n\n observer.observe(element);\n});\n", "import type { gsap as GsapStatic } from 'gsap';\nimport type { ScrollTrigger as ScrollTriggerStatic } from 'gsap/ScrollTrigger';\n\ndeclare global {\n interface Window {\n gsap?: typeof GsapStatic;\n ScrollTrigger?: typeof ScrollTriggerStatic;\n }\n}\n\nexport type Gsap = typeof GsapStatic;\nexport type ScrollTriggerType = typeof ScrollTriggerStatic;\n\n/**\n * GSAP ships from Webflow's native Site Settings toggle, not from this bundle.\n * A site transfer wipes Site Settings, so the toggle can silently disappear and\n * take every animation with it. Fail loudly here instead.\n */\nexport const requireGsap = (): { gsap: Gsap; ScrollTrigger?: ScrollTriggerType } => {\n const { gsap, ScrollTrigger } = window;\n\n if (!gsap) {\n throw new Error(\n '[shopic] GSAP is not on the page. Enable it in Webflow \u2192 Site Settings \u2192 Custom Code \u2192 GSAP.'\n );\n }\n\n if (ScrollTrigger) gsap.registerPlugin(ScrollTrigger);\n\n return { gsap, ScrollTrigger };\n};\n\n/**\n * Whether the visitor asked the OS to cut down on motion.\n */\nexport const prefersReducedMotion = (): boolean =>\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n", "import { runAnimations } from '$anim/index';\nimport { prefersReducedMotion, requireGsap } from '$lib/gsap';\n\nwindow.Webflow ||= [];\nwindow.Webflow.push(() => {\n const { gsap, ScrollTrigger } = requireGsap();\n\n runAnimations({ gsap, ScrollTrigger, reducedMotion: prefersReducedMotion() });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|