mirror of https://github.com/sveltejs/svelte
commit
11a0b471a7
File diff suppressed because it is too large
Load Diff
@ -1,57 +1,57 @@
|
|||||||
{
|
{
|
||||||
"name": "svelte.dev",
|
"name": "svelte.dev",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Docs and examples for Svelte",
|
"description": "Docs and examples for Svelte",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node scripts/update.js && vite dev",
|
"dev": "node scripts/update.js && vite dev",
|
||||||
"build": "node scripts/update.js && vite build",
|
"build": "node scripts/update.js && vite build",
|
||||||
"update": "node scripts/update.js --force=true",
|
"update": "node scripts/update.js --force=true",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"start": "node build",
|
"start": "node build",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch",
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch",
|
||||||
"format": "npm run check:format -- --write",
|
"format": "npm run check:format -- --write",
|
||||||
"check:format": "prettier --check . --ignore-path .gitignore --plugin-search-dir=.",
|
"check:format": "prettier --check . --ignore-path .gitignore --plugin-search-dir=.",
|
||||||
"test": "uvu -r ts-node/register src/lib/server/markdown"
|
"test": "uvu -r ts-node/register src/lib/server/markdown"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@supabase/supabase-js": "^2.7.1",
|
"@supabase/supabase-js": "^2.12.1",
|
||||||
"@sveltejs/repl": "^0.1.2",
|
"@sveltejs/repl": "^0.2.0",
|
||||||
"cookie": "^0.5.0",
|
"cookie": "^0.5.0",
|
||||||
"devalue": "^4.3.0",
|
"devalue": "^4.3.0",
|
||||||
"do-not-zip": "^1.0.0",
|
"do-not-zip": "^1.0.0",
|
||||||
"flexsearch": "^0.7.31",
|
"flexsearch": "^0.7.31",
|
||||||
"flru": "^1.0.2",
|
"flru": "^1.0.2",
|
||||||
"sourcemap-codec": "^1.4.8",
|
"sourcemap-codec": "^1.4.8",
|
||||||
"svelte-local-storage-store": "^0.4.0"
|
"svelte-local-storage-store": "^0.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@resvg/resvg-js": "^2.4.0",
|
"@resvg/resvg-js": "^2.4.1",
|
||||||
"@sveltejs/adapter-auto": "^2.0.0",
|
"@sveltejs/adapter-auto": "^2.0.0",
|
||||||
"@sveltejs/kit": "^1.5.6",
|
"@sveltejs/kit": "^1.14.0",
|
||||||
"@sveltejs/site-kit": "^3.2.2",
|
"@sveltejs/site-kit": "^3.3.6",
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.0.2",
|
"@sveltejs/vite-plugin-svelte": "^2.0.3",
|
||||||
"@types/marked": "^4.0.8",
|
"@types/marked": "^4.0.8",
|
||||||
"@types/prismjs": "^1.26.0",
|
"@types/prismjs": "^1.26.0",
|
||||||
"degit": "^2.8.4",
|
"degit": "^2.8.4",
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"jimp": "^0.22.4",
|
"jimp": "^0.22.7",
|
||||||
"marked": "^4.2.12",
|
"marked": "^4.3.0",
|
||||||
"node-fetch": "^3.3.0",
|
"node-fetch": "^3.3.1",
|
||||||
"prettier": "^2.8.4",
|
"prettier": "^2.8.7",
|
||||||
"prettier-plugin-svelte": "^2.9.0",
|
"prettier-plugin-svelte": "^2.10.0",
|
||||||
"prism-svelte": "^0.5.0",
|
"prism-svelte": "^0.5.0",
|
||||||
"prismjs": "^1.29.0",
|
"prismjs": "^1.29.0",
|
||||||
"satori": "^0.3.1",
|
"satori": "^0.4.4",
|
||||||
"satori-html": "^0.3.2",
|
"satori-html": "^0.3.2",
|
||||||
"shelljs": "^0.8.5",
|
"shelljs": "^0.8.5",
|
||||||
"shiki": "^0.14.1",
|
"shiki": "^0.14.1",
|
||||||
"shiki-twoslash": "^3.1.0",
|
"shiki-twoslash": "^3.1.1",
|
||||||
"svelte": "^3.55.1",
|
"svelte": "^3.57.0",
|
||||||
"svelte-check": "^3.0.3",
|
"svelte-check": "^3.1.4",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^5.0.2",
|
||||||
"vite": "^4.1.1",
|
"vite": "^4.2.1",
|
||||||
"vite-imagetools": "^4.0.18"
|
"vite-imagetools": "^4.0.18"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
// A puppeteer test because JSDOM doesn't support contenteditable
|
||||||
|
export default {
|
||||||
|
html: '<div contenteditable="false"></div>',
|
||||||
|
|
||||||
|
async test({ assert, target, component, window }) {
|
||||||
|
const div = target.querySelector('div');
|
||||||
|
const text = window.document.createTextNode('a');
|
||||||
|
div.insertBefore(text, null);
|
||||||
|
assert.equal(div.textContent, 'a');
|
||||||
|
component.text = 'bcde';
|
||||||
|
assert.equal(div.textContent, 'bcdea');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
<script>
|
||||||
|
export let text = '';
|
||||||
|
const updater = (event) => {text = event.target.textContent}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div contenteditable="false" on:input={updater}>{text}</div>
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
// A puppeteer test because JSDOM doesn't support contenteditable
|
||||||
|
export default {
|
||||||
|
html: '<div contenteditable="true"></div>',
|
||||||
|
ssrHtml: '<div contenteditable=""></div>',
|
||||||
|
|
||||||
|
async test({ assert, target, window }) {
|
||||||
|
// this tests that by going from contenteditable=true to false, the
|
||||||
|
// content is correctly updated before that. This relies on the order
|
||||||
|
// of the updates: first updating the content, then setting contenteditable
|
||||||
|
// to false, which means that `set_data_maybe_contenteditable` is used and not `set_data`.
|
||||||
|
// If the order is reversed, https://github.com/sveltejs/svelte/issues/5018
|
||||||
|
// would be happening. The caveat is that if we go from contenteditable=false to true
|
||||||
|
// then we will have the same issue. To fix this reliably we probably need to
|
||||||
|
// overhaul the way we handle text updates in general.
|
||||||
|
// If due to some refactoring this test fails, it's probably fine to ignore it since
|
||||||
|
// this is a very specific edge case and the behavior is unstable anyway.
|
||||||
|
const div = target.querySelector('div');
|
||||||
|
const text = window.document.createTextNode('a');
|
||||||
|
div.insertBefore(text, null);
|
||||||
|
const event = new window.InputEvent('input');
|
||||||
|
await div.dispatchEvent(event);
|
||||||
|
assert.equal(div.textContent, 'a');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
let text = "";
|
||||||
|
const updater = (event) => {
|
||||||
|
text = event.target.textContent;
|
||||||
|
};
|
||||||
|
$: spread = {
|
||||||
|
contenteditable: text !== "a",
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div {...spread} on:input={updater}>{text}</div>
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
// A puppeteer test because JSDOM doesn't support contenteditable
|
||||||
|
export default {
|
||||||
|
html: '<div contenteditable=""></div>',
|
||||||
|
|
||||||
|
// Failing test for https://github.com/sveltejs/svelte/issues/5018, fix pending
|
||||||
|
// It's hard to fix this because in order to do that, we would need to change the
|
||||||
|
// way the value is compared completely. Right now it compares the value of the
|
||||||
|
// first text node, but it should compare the value of the whole content
|
||||||
|
skip: true,
|
||||||
|
|
||||||
|
async test({ assert, target, window }) {
|
||||||
|
const div = target.querySelector('div');
|
||||||
|
|
||||||
|
let text = window.document.createTextNode('a');
|
||||||
|
div.insertBefore(text, null);
|
||||||
|
let event = new window.InputEvent('input');
|
||||||
|
await div.dispatchEvent(event);
|
||||||
|
assert.equal(div.textContent, 'a');
|
||||||
|
|
||||||
|
// When a user types a newline, the browser inserts a <div> element
|
||||||
|
const inner_div = window.document.createElement('div');
|
||||||
|
div.insertBefore(inner_div, null);
|
||||||
|
event = new window.InputEvent('input');
|
||||||
|
await div.dispatchEvent(event);
|
||||||
|
assert.equal(div.textContent, 'a');
|
||||||
|
|
||||||
|
text = window.document.createTextNode('b');
|
||||||
|
inner_div.insertBefore(text, null);
|
||||||
|
event = new window.InputEvent('input');
|
||||||
|
await div.dispatchEvent(event);
|
||||||
|
assert.equal(div.textContent, 'ab');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,15 +0,0 @@
|
|||||||
export default {
|
|
||||||
html: `
|
|
||||||
<div contenteditable=""></div>
|
|
||||||
`,
|
|
||||||
|
|
||||||
async test({ assert, target, window }) {
|
|
||||||
const div = target.querySelector('div');
|
|
||||||
const text = window.document.createTextNode('a');
|
|
||||||
div.insertBefore(text, null);
|
|
||||||
const event = new window.InputEvent('input');
|
|
||||||
await div.dispatchEvent(event);
|
|
||||||
|
|
||||||
assert.equal(div.textContent, 'a');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
export default {
|
||||||
|
html:'<div>same text</div>',
|
||||||
|
async test({ assert, target }) {
|
||||||
|
await new Promise(f => setTimeout(f, 10));
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<div>same text text</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<script>
|
||||||
|
let text = 'same';
|
||||||
|
setTimeout(() => {
|
||||||
|
text = 'same text';
|
||||||
|
}, 5);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>{text} text</div>
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
<!-- VALID -->
|
||||||
|
<div aria-hidden role="button" on:keypress={() => {}} />
|
||||||
|
<div aria-disabled role="button" on:keypress={() => {}} />
|
||||||
|
<div disabled role="button" on:keypress={() => {}} />
|
||||||
|
<div role="presentation" on:keypress={() => {}} />
|
||||||
|
<button on:click={() => {}} />
|
||||||
|
<div role="menuitem" tabindex="0" on:click={() => {}} on:keypress={() => {}} />
|
||||||
|
<div role="button" tabindex="-1" on:click={() => {}} on:keypress={() => {}} />
|
||||||
|
|
||||||
|
<!-- INVALID -->
|
||||||
|
<div role="button" on:keypress={() => {}} />
|
||||||
|
<span role="menuitem" on:keydown={() => {}} />
|
||||||
|
<div role="button" on:keyup={() => {}} />
|
||||||
|
<span role="menuitem" on:click={() => {}} on:keypress={() => {}} />
|
||||||
|
<div role="button" on:contextmenu={() => {}} />
|
||||||
|
<span role="menuitem" on:dblclick={() => {}} />
|
||||||
|
<div role="button" on:drag={() => {}} />
|
||||||
|
<span role="menuitem" on:dragend={() => {}} />
|
||||||
|
<div role="button" on:dragenter={() => {}} />
|
||||||
|
<span role="menuitem" on:dragexit={() => {}} />
|
||||||
|
<div role="button" on:dragleave={() => {}} />
|
||||||
|
<span role="menuitem" on:dragover={() => {}} />
|
||||||
|
<div role="button" on:dragstart={() => {}} />
|
||||||
|
<span role="menuitem" on:drop={() => {}} />
|
||||||
|
<div role="button" on:mousedown={() => {}} />
|
||||||
|
<span role="menuitem" on:mouseenter={() => {}} />
|
||||||
|
<div role="button" on:mouseleave={() => {}} />
|
||||||
|
<span role="menuitem" on:mousemove={() => {}} />
|
||||||
|
<div role="button" on:mouseout={() => {}} />
|
||||||
|
<span role="menuitem" on:mouseover={() => {}} />
|
||||||
|
<div role="button" on:mouseup={() => {}} />
|
||||||
|
|
||||||
@ -0,0 +1,278 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 44,
|
||||||
|
"line": 11
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 11
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 46,
|
||||||
|
"line": 12
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 12
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 41,
|
||||||
|
"line": 13
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 13
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 67,
|
||||||
|
"line": 14
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 47,
|
||||||
|
"line": 15
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 15
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 47,
|
||||||
|
"line": 16
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 16
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 40,
|
||||||
|
"line": 17
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 17
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 46,
|
||||||
|
"line": 18
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 45,
|
||||||
|
"line": 19
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 19
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 47,
|
||||||
|
"line": 20
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 45,
|
||||||
|
"line": 21
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 21
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 47,
|
||||||
|
"line": 22
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 22
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 45,
|
||||||
|
"line": 23
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 23
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 43,
|
||||||
|
"line": 24
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 45,
|
||||||
|
"line": 25
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 25
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 49,
|
||||||
|
"line": 26
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 26
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 46,
|
||||||
|
"line": 27
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 27
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 48,
|
||||||
|
"line": 28
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 28
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 44,
|
||||||
|
"line": 29
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 29
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-mouse-events-have-key-events",
|
||||||
|
"end": {
|
||||||
|
"column": 44,
|
||||||
|
"line": 29
|
||||||
|
},
|
||||||
|
"message": "A11y: on:mouseout must be accompanied by on:blur",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 29
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 48,
|
||||||
|
"line": 30
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'menuitem' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-mouse-events-have-key-events",
|
||||||
|
"end": {
|
||||||
|
"column": 48,
|
||||||
|
"line": 30
|
||||||
|
},
|
||||||
|
"message": "A11y: on:mouseover must be accompanied by on:focus",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "a11y-interactive-supports-focus",
|
||||||
|
"end": {
|
||||||
|
"column": 43,
|
||||||
|
"line": 31
|
||||||
|
},
|
||||||
|
"message": "A11y: Elements with the 'button' interactive role must have a tabindex value.",
|
||||||
|
"start": {
|
||||||
|
"column": 0,
|
||||||
|
"line": 31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
Loading…
Reference in new issue