shipit-cli 0.13.3__tar.gz → 0.14.0__tar.gz
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.
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/PKG-INFO +1 -1
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/pyproject.toml +1 -1
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/assets/wordpress/install.sh +1 -1
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/cli.py +4 -2
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/generator.py +3 -1
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/providers/base.py +1 -1
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/providers/hugo.py +2 -2
- shipit_cli-0.14.0/src/shipit/providers/jekyll.py +96 -0
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/providers/laravel.py +2 -2
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/providers/mkdocs.py +2 -2
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/providers/node_static.py +56 -39
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/providers/php.py +2 -2
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/providers/python.py +2 -2
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/providers/registry.py +2 -0
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/providers/staticfile.py +2 -2
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/providers/wordpress.py +2 -2
- shipit_cli-0.14.0/src/shipit/version.py +5 -0
- shipit_cli-0.13.3/src/shipit/version.py +0 -5
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/.gitignore +0 -0
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/README.md +0 -0
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/__init__.py +0 -0
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/assets/php/php.ini +0 -0
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/assets/wordpress/wp-config.php +0 -0
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/src/shipit/procfile.py +0 -0
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/tests/test_e2e.py +0 -0
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/tests/test_generate_shipit_examples.py +0 -0
- {shipit_cli-0.13.3 → shipit_cli-0.14.0}/tests/test_version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shipit-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: Shipit CLI is the best way to build, serve and deploy your projects anywhere.
|
|
5
5
|
Project-URL: homepage, https://wasmer.io
|
|
6
6
|
Project-URL: repository, https://github.com/wasmerio/shipit
|
|
@@ -94,7 +94,7 @@ fi
|
|
|
94
94
|
|
|
95
95
|
if [ -n "${WP_LOCALE:-}" ]; then
|
|
96
96
|
echo "Setting locale: $WP_LOCALE"
|
|
97
|
-
wp language install "$WP_LOCALE"
|
|
97
|
+
wp language core install "$WP_LOCALE"
|
|
98
98
|
wp language theme install --all "$WP_LOCALE"
|
|
99
99
|
wp language plugin install --all "$WP_LOCALE"
|
|
100
100
|
wp site switch-language "$WP_LOCALE"
|
|
@@ -387,7 +387,7 @@ RUN apt-get update \\
|
|
|
387
387
|
dpkg-dev pkg-config re2c locate \\
|
|
388
388
|
libmariadb-dev libmariadb-dev-compat libpq-dev \\
|
|
389
389
|
libvips-dev default-libmysqlclient-dev libmagickwand-dev \\
|
|
390
|
-
libicu-dev libxml2-dev libxslt-dev \\
|
|
390
|
+
libicu-dev libxml2-dev libxslt-dev libyaml-dev \\
|
|
391
391
|
sudo curl ca-certificates \\
|
|
392
392
|
&& rm -rf /var/lib/apt/lists/*
|
|
393
393
|
|
|
@@ -1337,10 +1337,12 @@ class Ctx:
|
|
|
1337
1337
|
def copy(
|
|
1338
1338
|
self,
|
|
1339
1339
|
source: str,
|
|
1340
|
-
target: str,
|
|
1340
|
+
target: Optional[str] = None,
|
|
1341
1341
|
ignore: Optional[List[str]] = None,
|
|
1342
1342
|
base: Optional[Literal["source", "assets"]] = None,
|
|
1343
1343
|
) -> Optional[str]:
|
|
1344
|
+
if target is None:
|
|
1345
|
+
target = source
|
|
1344
1346
|
step = CopyStep(source, target, ignore, base or "source")
|
|
1345
1347
|
return self.add_step(step)
|
|
1346
1348
|
|
|
@@ -92,9 +92,11 @@ def generate_shipit(path: Path, custom_commands: CustomCommands, use_provider: O
|
|
|
92
92
|
provider_cls = detect_provider(path, custom_commands)
|
|
93
93
|
provider = provider_cls(path, custom_commands)
|
|
94
94
|
|
|
95
|
+
default_serve_name = path.absolute().name
|
|
96
|
+
|
|
95
97
|
# Collect parts
|
|
96
98
|
plan = ProviderPlan(
|
|
97
|
-
serve_name=provider.serve_name(),
|
|
99
|
+
serve_name=provider.serve_name() or default_serve_name,
|
|
98
100
|
provider=provider.name(),
|
|
99
101
|
platform=provider.platform(),
|
|
100
102
|
mounts=provider.mounts(),
|
|
@@ -27,7 +27,7 @@ class Provider(Protocol):
|
|
|
27
27
|
def detect(cls, path: Path, custom_commands: CustomCommands) -> Optional[DetectResult]: ...
|
|
28
28
|
def initialize(self) -> None: ...
|
|
29
29
|
# Structured plan steps (no path args; use self.path)
|
|
30
|
-
def serve_name(self) -> str: ...
|
|
30
|
+
def serve_name(self) -> Optional[str]: ...
|
|
31
31
|
def platform(self) -> Optional[str]: ...
|
|
32
32
|
def dependencies(self) -> list["DependencySpec"]: ...
|
|
33
33
|
def declarations(self) -> Optional[str]: ...
|
|
@@ -24,8 +24,8 @@ class HugoProvider(StaticFileProvider):
|
|
|
24
24
|
return DetectResult(cls.name(), 40)
|
|
25
25
|
return None
|
|
26
26
|
|
|
27
|
-
def serve_name(self) -> str:
|
|
28
|
-
return
|
|
27
|
+
def serve_name(self) -> Optional[str]:
|
|
28
|
+
return None
|
|
29
29
|
|
|
30
30
|
def platform(self) -> Optional[str]:
|
|
31
31
|
return "hugo"
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Dict, Optional
|
|
5
|
+
|
|
6
|
+
from .base import (
|
|
7
|
+
DetectResult,
|
|
8
|
+
DependencySpec,
|
|
9
|
+
Provider,
|
|
10
|
+
_exists,
|
|
11
|
+
MountSpec,
|
|
12
|
+
ServiceSpec,
|
|
13
|
+
VolumeSpec,
|
|
14
|
+
CustomCommands,
|
|
15
|
+
)
|
|
16
|
+
from .staticfile import StaticFileProvider
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class JekyllProvider(StaticFileProvider):
|
|
20
|
+
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
21
|
+
self.path = path
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def name(cls) -> str:
|
|
25
|
+
return "jekyll"
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def detect(
|
|
29
|
+
cls, path: Path, custom_commands: CustomCommands
|
|
30
|
+
) -> Optional[DetectResult]:
|
|
31
|
+
if _exists(path, "_config.yml", "_config.yaml"):
|
|
32
|
+
if _exists(path, "Gemfile"):
|
|
33
|
+
return DetectResult(cls.name(), 85)
|
|
34
|
+
return DetectResult(cls.name(), 40)
|
|
35
|
+
if custom_commands.build and custom_commands.build.startswith("jekyll "):
|
|
36
|
+
return DetectResult(cls.name(), 85)
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
def initialize(self) -> None:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
def serve_name(self) -> Optional[str]:
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
def platform(self) -> Optional[str]:
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
def dependencies(self) -> list[DependencySpec]:
|
|
49
|
+
return [
|
|
50
|
+
DependencySpec(
|
|
51
|
+
"ruby",
|
|
52
|
+
env_var="SHIPIT_RUBY_VERSION",
|
|
53
|
+
use_in_build=True,
|
|
54
|
+
use_in_serve=False,
|
|
55
|
+
),
|
|
56
|
+
*super().dependencies(),
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
def declarations(self) -> Optional[str]:
|
|
60
|
+
return 'jekyll_version = getenv("SHIPIT_JEKYLL_VERSION") or "1.6.1"\n'
|
|
61
|
+
|
|
62
|
+
def build_steps(self) -> list[str]:
|
|
63
|
+
if _exists(self.path, "Gemfile"):
|
|
64
|
+
install_deps = ["Gemfile"]
|
|
65
|
+
install_deps_str = ", ".join([f'"{dep}"' for dep in install_deps])
|
|
66
|
+
install_commands = [
|
|
67
|
+
f'run("bundle install", inputs=[{install_deps_str}], group="build")'
|
|
68
|
+
]
|
|
69
|
+
if _exists(self.path, "Gemfile.lock"):
|
|
70
|
+
install_commands = [
|
|
71
|
+
'copy("Gemfile.lock")',
|
|
72
|
+
*install_commands,
|
|
73
|
+
]
|
|
74
|
+
else:
|
|
75
|
+
install_commands = ['run("gem install jekyll", group="build")']
|
|
76
|
+
return [
|
|
77
|
+
'workdir(temp["build"])',
|
|
78
|
+
'copy(".", ignore=[".git"])',
|
|
79
|
+
*install_commands,
|
|
80
|
+
'run("jekyll build --destination={}".format(app["build"]), outputs=["."], group="build")',
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
def prepare_steps(self) -> Optional[list[str]]:
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
def mounts(self) -> list[MountSpec]:
|
|
87
|
+
return [MountSpec("temp", attach_to_serve=False), *super().mounts()]
|
|
88
|
+
|
|
89
|
+
def volumes(self) -> list[VolumeSpec]:
|
|
90
|
+
return []
|
|
91
|
+
|
|
92
|
+
def env(self) -> Optional[Dict[str, str]]:
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
def services(self) -> list[ServiceSpec]:
|
|
96
|
+
return []
|
|
@@ -37,8 +37,8 @@ class MkdocsProvider(StaticFileProvider):
|
|
|
37
37
|
def initialize(self) -> None:
|
|
38
38
|
pass
|
|
39
39
|
|
|
40
|
-
def serve_name(self) -> str:
|
|
41
|
-
return
|
|
40
|
+
def serve_name(self) -> Optional[str]:
|
|
41
|
+
return None
|
|
42
42
|
|
|
43
43
|
def platform(self) -> Optional[str]:
|
|
44
44
|
return None
|
|
@@ -78,8 +78,8 @@ class PackageManager(Enum):
|
|
|
78
78
|
def install_command(self, has_lockfile: bool = False) -> str:
|
|
79
79
|
return {
|
|
80
80
|
PackageManager.NPM: f"npm {'ci' if has_lockfile else 'install'}",
|
|
81
|
-
PackageManager.PNPM:
|
|
82
|
-
PackageManager.YARN:
|
|
81
|
+
PackageManager.PNPM: "pnpm install",
|
|
82
|
+
PackageManager.YARN: "yarn install",
|
|
83
83
|
PackageManager.BUN: f"bun install{' --no-save' if has_lockfile else ''}",
|
|
84
84
|
}[self]
|
|
85
85
|
|
|
@@ -105,6 +105,7 @@ class StaticGenerator(Enum):
|
|
|
105
105
|
VITE = "vite"
|
|
106
106
|
NEXT = "next"
|
|
107
107
|
GATSBY = "gatsby"
|
|
108
|
+
DOCUSAURUS_OLD = "docusaurus-old"
|
|
108
109
|
DOCUSAURUS = "docusaurus"
|
|
109
110
|
SVELTE = "svelte"
|
|
110
111
|
REMIX = "remix"
|
|
@@ -119,6 +120,7 @@ class NodeStaticProvider(StaticFileProvider):
|
|
|
119
120
|
package_json: Optional[Dict[str, Any]]
|
|
120
121
|
extra_dependencies: Set[str]
|
|
121
122
|
static_generator: Optional[StaticGenerator] = None
|
|
123
|
+
build_command: Optional[str] = None
|
|
122
124
|
|
|
123
125
|
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
124
126
|
super().__init__(path, custom_commands)
|
|
@@ -139,6 +141,8 @@ class NodeStaticProvider(StaticFileProvider):
|
|
|
139
141
|
self.static_generator = StaticGenerator.GATSBY
|
|
140
142
|
elif self.has_dependency(self.package_json, "astro"):
|
|
141
143
|
self.static_generator = StaticGenerator.ASTRO
|
|
144
|
+
elif self.has_dependency(self.package_json, "docusaurus"):
|
|
145
|
+
self.static_generator = StaticGenerator.DOCUSAURUS_OLD
|
|
142
146
|
elif self.has_dependency(self.package_json, "@docusaurus/core"):
|
|
143
147
|
self.static_generator = StaticGenerator.DOCUSAURUS
|
|
144
148
|
elif self.has_dependency(self.package_json, "svelte"):
|
|
@@ -160,6 +164,8 @@ class NodeStaticProvider(StaticFileProvider):
|
|
|
160
164
|
elif self.has_dependency(self.package_json, "nuxt"):
|
|
161
165
|
self.static_generator = StaticGenerator.NUXT_V3
|
|
162
166
|
|
|
167
|
+
self.build_command = self.get_build_command(self.package_json, self.package_manager, self.static_generator)
|
|
168
|
+
|
|
163
169
|
# if self.has_dependency(self.package_json, "sharp"):
|
|
164
170
|
# self.extra_dependencies.add("libvips")
|
|
165
171
|
|
|
@@ -217,6 +223,7 @@ class NodeStaticProvider(StaticFileProvider):
|
|
|
217
223
|
"nuxt",
|
|
218
224
|
"gatsby",
|
|
219
225
|
"svelte",
|
|
226
|
+
"docusaurus",
|
|
220
227
|
"@docusaurus/core",
|
|
221
228
|
"@remix-run/dev",
|
|
222
229
|
]
|
|
@@ -227,8 +234,8 @@ class NodeStaticProvider(StaticFileProvider):
|
|
|
227
234
|
def initialize(self) -> None:
|
|
228
235
|
pass
|
|
229
236
|
|
|
230
|
-
def serve_name(self) -> str:
|
|
231
|
-
return
|
|
237
|
+
def serve_name(self) -> Optional[str]:
|
|
238
|
+
return None
|
|
232
239
|
|
|
233
240
|
def platform(self) -> Optional[str]:
|
|
234
241
|
return self.static_generator.value if self.static_generator else None
|
|
@@ -248,7 +255,10 @@ class NodeStaticProvider(StaticFileProvider):
|
|
|
248
255
|
]
|
|
249
256
|
|
|
250
257
|
def declarations(self) -> Optional[str]:
|
|
251
|
-
|
|
258
|
+
output_dir = self.get_output_dir()
|
|
259
|
+
return (
|
|
260
|
+
f'shipit_static_dir = getenv("SHIPIT_STATIC_DIR") or "{output_dir}"\n'
|
|
261
|
+
)
|
|
252
262
|
|
|
253
263
|
def get_output_dir(self) -> str:
|
|
254
264
|
if self.static_generator == StaticGenerator.NEXT:
|
|
@@ -267,60 +277,67 @@ class NodeStaticProvider(StaticFileProvider):
|
|
|
267
277
|
return "build/client"
|
|
268
278
|
elif self.static_generator in [
|
|
269
279
|
StaticGenerator.DOCUSAURUS,
|
|
280
|
+
StaticGenerator.DOCUSAURUS_OLD,
|
|
270
281
|
StaticGenerator.SVELTE,
|
|
271
282
|
]:
|
|
272
283
|
return "build"
|
|
273
284
|
else:
|
|
274
285
|
return "dist"
|
|
275
286
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if
|
|
283
|
-
return
|
|
284
|
-
|
|
285
|
-
return
|
|
286
|
-
elif
|
|
287
|
-
return
|
|
288
|
-
elif
|
|
289
|
-
return
|
|
290
|
-
elif
|
|
291
|
-
return
|
|
292
|
-
elif
|
|
293
|
-
return
|
|
294
|
-
elif
|
|
295
|
-
return
|
|
296
|
-
elif
|
|
297
|
-
return
|
|
298
|
-
elif
|
|
299
|
-
return
|
|
300
|
-
elif
|
|
301
|
-
return
|
|
302
|
-
|
|
287
|
+
@classmethod
|
|
288
|
+
def get_build_command(cls, package_json: Optional[Dict[str, Any]], package_manager: PackageManager, static_generator: StaticGenerator) -> Optional[str]:
|
|
289
|
+
if package_json:
|
|
290
|
+
build_command = package_json.get("scripts", {}).get("build")
|
|
291
|
+
if build_command:
|
|
292
|
+
return package_manager.run_command("build")
|
|
293
|
+
if static_generator == StaticGenerator.GATSBY:
|
|
294
|
+
return package_manager.run_execute_command("gatsby build")
|
|
295
|
+
elif static_generator == StaticGenerator.ASTRO:
|
|
296
|
+
return package_manager.run_execute_command("astro build")
|
|
297
|
+
elif static_generator == StaticGenerator.REMIX_OLD:
|
|
298
|
+
return package_manager.run_execute_command("remix-ssg build")
|
|
299
|
+
elif static_generator == StaticGenerator.REMIX_V2:
|
|
300
|
+
return package_manager.run_execute_command("vite build")
|
|
301
|
+
elif static_generator == StaticGenerator.DOCUSAURUS:
|
|
302
|
+
return package_manager.run_execute_command("docusaurus build")
|
|
303
|
+
elif static_generator == StaticGenerator.DOCUSAURUS_OLD:
|
|
304
|
+
return package_manager.run_execute_command("docusaurus build")
|
|
305
|
+
elif static_generator == StaticGenerator.SVELTE:
|
|
306
|
+
return package_manager.run_execute_command("svelte-kit build")
|
|
307
|
+
elif static_generator == StaticGenerator.VITE:
|
|
308
|
+
return package_manager.run_execute_command("vite build")
|
|
309
|
+
elif static_generator == StaticGenerator.NEXT:
|
|
310
|
+
return package_manager.run_execute_command("next export")
|
|
311
|
+
elif static_generator == StaticGenerator.NUXT_V3:
|
|
312
|
+
return package_manager.run_execute_command("nuxi generate")
|
|
313
|
+
elif static_generator == StaticGenerator.NUXT_OLD:
|
|
314
|
+
return package_manager.run_execute_command("nuxt generate")
|
|
315
|
+
return None
|
|
303
316
|
|
|
304
317
|
def build_steps(self) -> list[str]:
|
|
305
|
-
output_dir = self.get_output_dir()
|
|
306
|
-
get_build_command = self.get_build_command()
|
|
307
318
|
lockfile = self.package_manager.lockfile()
|
|
308
319
|
has_lockfile = (self.path / lockfile).exists()
|
|
309
320
|
install_command = self.package_manager.install_command(
|
|
310
321
|
has_lockfile=has_lockfile
|
|
311
322
|
)
|
|
312
323
|
input_files = ["package.json"]
|
|
313
|
-
if has_lockfile:
|
|
314
|
-
|
|
324
|
+
# if has_lockfile:
|
|
325
|
+
# input_files.append(lockfile)
|
|
315
326
|
inputs_install_files = ", ".join([f'"{file}"' for file in input_files])
|
|
316
327
|
|
|
328
|
+
ignored_files = ["node_modules", ".git"]
|
|
329
|
+
if has_lockfile:
|
|
330
|
+
ignored_files.append(lockfile)
|
|
331
|
+
all_ignored_files = ", ".join([f'"{file}"' for file in ignored_files])
|
|
332
|
+
|
|
317
333
|
return [
|
|
318
334
|
'workdir(temp["build"])',
|
|
335
|
+
f'copy("{lockfile}")' if has_lockfile else None,
|
|
319
336
|
# 'run("npx corepack enable", inputs=["package.json"], group="install")',
|
|
320
337
|
f'run("{install_command}", inputs=[{inputs_install_files}], group="install")',
|
|
321
|
-
'copy(".",
|
|
322
|
-
f'run("{
|
|
323
|
-
f'run("cp -R {
|
|
338
|
+
f'copy(".", ignore=[{all_ignored_files}])',
|
|
339
|
+
f'run("{self.build_command}", outputs=[shipit_static_dir], group="build")',
|
|
340
|
+
f'run("cp -R {{}}/* {{}}/".format(shipit_static_dir, app["build"]))',
|
|
324
341
|
]
|
|
325
342
|
|
|
326
343
|
def prepare_steps(self) -> Optional[list[str]]:
|
|
@@ -225,8 +225,8 @@ class PythonProvider:
|
|
|
225
225
|
def initialize(self) -> None:
|
|
226
226
|
pass
|
|
227
227
|
|
|
228
|
-
def serve_name(self) -> str:
|
|
229
|
-
return
|
|
228
|
+
def serve_name(self) -> Optional[str]:
|
|
229
|
+
return None
|
|
230
230
|
|
|
231
231
|
def platform(self) -> Optional[str]:
|
|
232
232
|
return self.framework.value if self.framework else None
|
|
@@ -8,6 +8,7 @@ from .node_static import NodeStaticProvider
|
|
|
8
8
|
from .wordpress import WordPressProvider
|
|
9
9
|
from .php import PhpProvider
|
|
10
10
|
from .python import PythonProvider
|
|
11
|
+
from .jekyll import JekyllProvider
|
|
11
12
|
from .staticfile import StaticFileProvider
|
|
12
13
|
|
|
13
14
|
|
|
@@ -21,5 +22,6 @@ def providers() -> list[type[Provider]]:
|
|
|
21
22
|
WordPressProvider,
|
|
22
23
|
PhpProvider,
|
|
23
24
|
NodeStaticProvider,
|
|
25
|
+
JekyllProvider,
|
|
24
26
|
StaticFileProvider,
|
|
25
27
|
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|