vortex-nwp 2.0.0__py3-none-any.whl
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.
- vortex/__init__.py +159 -0
- vortex/algo/__init__.py +13 -0
- vortex/algo/components.py +2462 -0
- vortex/algo/mpitools.py +1953 -0
- vortex/algo/mpitools_templates/__init__.py +1 -0
- vortex/algo/mpitools_templates/envelope_wrapper_default.tpl +27 -0
- vortex/algo/mpitools_templates/envelope_wrapper_mpiauto.tpl +29 -0
- vortex/algo/mpitools_templates/wrapstd_wrapper_default.tpl +18 -0
- vortex/algo/serversynctools.py +171 -0
- vortex/config.py +112 -0
- vortex/data/__init__.py +19 -0
- vortex/data/abstractstores.py +1510 -0
- vortex/data/containers.py +835 -0
- vortex/data/contents.py +622 -0
- vortex/data/executables.py +275 -0
- vortex/data/flow.py +119 -0
- vortex/data/geometries.ini +2689 -0
- vortex/data/geometries.py +799 -0
- vortex/data/handlers.py +1230 -0
- vortex/data/outflow.py +67 -0
- vortex/data/providers.py +487 -0
- vortex/data/resources.py +207 -0
- vortex/data/stores.py +1390 -0
- vortex/data/sync_templates/__init__.py +0 -0
- vortex/gloves.py +309 -0
- vortex/layout/__init__.py +20 -0
- vortex/layout/contexts.py +577 -0
- vortex/layout/dataflow.py +1220 -0
- vortex/layout/monitor.py +969 -0
- vortex/nwp/__init__.py +14 -0
- vortex/nwp/algo/__init__.py +21 -0
- vortex/nwp/algo/assim.py +537 -0
- vortex/nwp/algo/clim.py +1086 -0
- vortex/nwp/algo/coupling.py +831 -0
- vortex/nwp/algo/eda.py +840 -0
- vortex/nwp/algo/eps.py +785 -0
- vortex/nwp/algo/forecasts.py +886 -0
- vortex/nwp/algo/fpserver.py +1303 -0
- vortex/nwp/algo/ifsnaming.py +463 -0
- vortex/nwp/algo/ifsroot.py +404 -0
- vortex/nwp/algo/monitoring.py +263 -0
- vortex/nwp/algo/mpitools.py +694 -0
- vortex/nwp/algo/odbtools.py +1258 -0
- vortex/nwp/algo/oopsroot.py +916 -0
- vortex/nwp/algo/oopstests.py +220 -0
- vortex/nwp/algo/request.py +660 -0
- vortex/nwp/algo/stdpost.py +1641 -0
- vortex/nwp/data/__init__.py +30 -0
- vortex/nwp/data/assim.py +380 -0
- vortex/nwp/data/boundaries.py +314 -0
- vortex/nwp/data/climfiles.py +521 -0
- vortex/nwp/data/configfiles.py +153 -0
- vortex/nwp/data/consts.py +954 -0
- vortex/nwp/data/ctpini.py +149 -0
- vortex/nwp/data/diagnostics.py +209 -0
- vortex/nwp/data/eda.py +147 -0
- vortex/nwp/data/eps.py +432 -0
- vortex/nwp/data/executables.py +1045 -0
- vortex/nwp/data/fields.py +111 -0
- vortex/nwp/data/gridfiles.py +380 -0
- vortex/nwp/data/logs.py +584 -0
- vortex/nwp/data/modelstates.py +363 -0
- vortex/nwp/data/monitoring.py +193 -0
- vortex/nwp/data/namelists.py +696 -0
- vortex/nwp/data/obs.py +840 -0
- vortex/nwp/data/oopsexec.py +74 -0
- vortex/nwp/data/providers.py +207 -0
- vortex/nwp/data/query.py +206 -0
- vortex/nwp/data/stores.py +160 -0
- vortex/nwp/data/surfex.py +337 -0
- vortex/nwp/syntax/__init__.py +9 -0
- vortex/nwp/syntax/stdattrs.py +437 -0
- vortex/nwp/tools/__init__.py +10 -0
- vortex/nwp/tools/addons.py +40 -0
- vortex/nwp/tools/agt.py +67 -0
- vortex/nwp/tools/bdap.py +59 -0
- vortex/nwp/tools/bdcp.py +41 -0
- vortex/nwp/tools/bdm.py +24 -0
- vortex/nwp/tools/bdmp.py +54 -0
- vortex/nwp/tools/conftools.py +1661 -0
- vortex/nwp/tools/drhook.py +66 -0
- vortex/nwp/tools/grib.py +294 -0
- vortex/nwp/tools/gribdiff.py +104 -0
- vortex/nwp/tools/ifstools.py +203 -0
- vortex/nwp/tools/igastuff.py +273 -0
- vortex/nwp/tools/mars.py +68 -0
- vortex/nwp/tools/odb.py +657 -0
- vortex/nwp/tools/partitioning.py +258 -0
- vortex/nwp/tools/satrad.py +71 -0
- vortex/nwp/util/__init__.py +6 -0
- vortex/nwp/util/async.py +212 -0
- vortex/nwp/util/beacon.py +40 -0
- vortex/nwp/util/diffpygram.py +447 -0
- vortex/nwp/util/ens.py +279 -0
- vortex/nwp/util/hooks.py +139 -0
- vortex/nwp/util/taskdeco.py +85 -0
- vortex/nwp/util/usepygram.py +697 -0
- vortex/nwp/util/usetnt.py +101 -0
- vortex/proxy.py +6 -0
- vortex/sessions.py +374 -0
- vortex/syntax/__init__.py +9 -0
- vortex/syntax/stdattrs.py +867 -0
- vortex/syntax/stddeco.py +185 -0
- vortex/toolbox.py +1117 -0
- vortex/tools/__init__.py +20 -0
- vortex/tools/actions.py +523 -0
- vortex/tools/addons.py +316 -0
- vortex/tools/arm.py +96 -0
- vortex/tools/compression.py +325 -0
- vortex/tools/date.py +27 -0
- vortex/tools/ddhpack.py +10 -0
- vortex/tools/delayedactions.py +782 -0
- vortex/tools/env.py +541 -0
- vortex/tools/folder.py +834 -0
- vortex/tools/grib.py +738 -0
- vortex/tools/lfi.py +953 -0
- vortex/tools/listings.py +423 -0
- vortex/tools/names.py +637 -0
- vortex/tools/net.py +2124 -0
- vortex/tools/odb.py +10 -0
- vortex/tools/parallelism.py +368 -0
- vortex/tools/prestaging.py +210 -0
- vortex/tools/rawfiles.py +10 -0
- vortex/tools/schedulers.py +480 -0
- vortex/tools/services.py +940 -0
- vortex/tools/storage.py +996 -0
- vortex/tools/surfex.py +61 -0
- vortex/tools/systems.py +3976 -0
- vortex/tools/targets.py +440 -0
- vortex/util/__init__.py +9 -0
- vortex/util/config.py +1122 -0
- vortex/util/empty.py +24 -0
- vortex/util/helpers.py +216 -0
- vortex/util/introspection.py +69 -0
- vortex/util/iosponge.py +80 -0
- vortex/util/roles.py +49 -0
- vortex/util/storefunctions.py +129 -0
- vortex/util/structs.py +26 -0
- vortex/util/worker.py +162 -0
- vortex_nwp-2.0.0.dist-info/METADATA +67 -0
- vortex_nwp-2.0.0.dist-info/RECORD +144 -0
- vortex_nwp-2.0.0.dist-info/WHEEL +5 -0
- vortex_nwp-2.0.0.dist-info/licenses/LICENSE +517 -0
- vortex_nwp-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Abstract for any "Resource" class that deal with some kind of :class:`Script` or
|
|
3
|
+
:class:`Binary` executable.
|
|
4
|
+
|
|
5
|
+
Mode specialised version are also provided for various physical models:
|
|
6
|
+
|
|
7
|
+
* :class:`NWPModel`;
|
|
8
|
+
* :class:`OceanographicModel`;
|
|
9
|
+
* :class:`SurfaceModel`;
|
|
10
|
+
* :class:`ChemistryModel`.
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from bronx.syntax import mktuple
|
|
15
|
+
import footprints
|
|
16
|
+
|
|
17
|
+
from .resources import Resource
|
|
18
|
+
from vortex.syntax.stdattrs import model_deco
|
|
19
|
+
from vortex.util.config import JacketConfigParser
|
|
20
|
+
|
|
21
|
+
#: No automatic export
|
|
22
|
+
__all__ = []
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Jacket:
|
|
26
|
+
"""The class definition of in and out resources from a given executable."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, afile=None):
|
|
29
|
+
if afile:
|
|
30
|
+
self.config = JacketConfigParser(afile)
|
|
31
|
+
self.virtual = False
|
|
32
|
+
else:
|
|
33
|
+
self.virtual = True
|
|
34
|
+
self._initfile = afile
|
|
35
|
+
|
|
36
|
+
def as_dump(self):
|
|
37
|
+
return "file={!r}".format(self._initfile)
|
|
38
|
+
|
|
39
|
+
def export_dict(self):
|
|
40
|
+
return self._initfile
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class Executable(Resource):
|
|
44
|
+
"""Abstract class for resources that could be executed."""
|
|
45
|
+
|
|
46
|
+
_abstract = True
|
|
47
|
+
_footprint = dict(
|
|
48
|
+
info="Miscellaneaous executable resource",
|
|
49
|
+
attr=dict(
|
|
50
|
+
cycle=dict(
|
|
51
|
+
info="Any kind of cycle name",
|
|
52
|
+
optional=True,
|
|
53
|
+
default=None,
|
|
54
|
+
access="rwx",
|
|
55
|
+
),
|
|
56
|
+
kind=dict(
|
|
57
|
+
info="The resource's kind.",
|
|
58
|
+
doc_zorder=90,
|
|
59
|
+
),
|
|
60
|
+
nativefmt=dict(
|
|
61
|
+
doc_visibility=footprints.doc.visibility.GURU,
|
|
62
|
+
),
|
|
63
|
+
clscontents=dict(
|
|
64
|
+
doc_visibility=footprints.doc.visibility.GURU,
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def stdin_text(self, **opts):
|
|
70
|
+
"""Abstract method."""
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class Script(Executable):
|
|
75
|
+
"""Basic interpreted executable associated to a specific language."""
|
|
76
|
+
|
|
77
|
+
_footprint = dict(
|
|
78
|
+
attr=dict(
|
|
79
|
+
rawopts=dict(
|
|
80
|
+
info="Options that will be passed directly to the script",
|
|
81
|
+
optional=True,
|
|
82
|
+
default="",
|
|
83
|
+
),
|
|
84
|
+
language=dict(
|
|
85
|
+
info="The programming language",
|
|
86
|
+
values=["perl", "python", "ksh", "bash", "sh", "awk"],
|
|
87
|
+
),
|
|
88
|
+
kind=dict(
|
|
89
|
+
optional=True,
|
|
90
|
+
default="script",
|
|
91
|
+
values=["script"],
|
|
92
|
+
),
|
|
93
|
+
),
|
|
94
|
+
fastkeys={"language"},
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def realkind(self):
|
|
99
|
+
return "script"
|
|
100
|
+
|
|
101
|
+
def command_line(self, **opts):
|
|
102
|
+
"""Returns optional attribute :attr:`rawopts`."""
|
|
103
|
+
if self.rawopts is None:
|
|
104
|
+
return ""
|
|
105
|
+
else:
|
|
106
|
+
return self.rawopts
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class GnuScript(Executable):
|
|
110
|
+
"""Basic interpreted executable with standard command line arguments."""
|
|
111
|
+
|
|
112
|
+
_footprint = dict(
|
|
113
|
+
attr=dict(
|
|
114
|
+
language=dict(
|
|
115
|
+
info="The programming language",
|
|
116
|
+
values=["perl", "python", "ksh", "bash", "sh", "awk"],
|
|
117
|
+
),
|
|
118
|
+
kind=dict(
|
|
119
|
+
default="gnuscript",
|
|
120
|
+
values=["gnuscript", "argscript"],
|
|
121
|
+
),
|
|
122
|
+
),
|
|
123
|
+
fastkeys={"kind", "language"},
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def realkind(self):
|
|
128
|
+
return "script"
|
|
129
|
+
|
|
130
|
+
def command_line(self, **opts):
|
|
131
|
+
"""Returns a blank separated list of options."""
|
|
132
|
+
return " ".join(
|
|
133
|
+
[
|
|
134
|
+
"--" + k + " " + " ".join([str(x) for x in mktuple(v)])
|
|
135
|
+
for k, v in opts.items()
|
|
136
|
+
]
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class Binary(Executable):
|
|
141
|
+
"""Basic compiled executable."""
|
|
142
|
+
|
|
143
|
+
_abstract = True
|
|
144
|
+
_footprint = dict(
|
|
145
|
+
attr=dict(
|
|
146
|
+
static=dict(
|
|
147
|
+
info="Statically linked binary.",
|
|
148
|
+
type=bool,
|
|
149
|
+
optional=True,
|
|
150
|
+
doc_visibility=footprints.doc.visibility.ADVANCED,
|
|
151
|
+
),
|
|
152
|
+
jacket=dict(
|
|
153
|
+
type=Jacket,
|
|
154
|
+
optional=True,
|
|
155
|
+
default=Jacket(),
|
|
156
|
+
doc_visibility=footprints.doc.visibility.ADVANCED,
|
|
157
|
+
),
|
|
158
|
+
)
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def realkind(self):
|
|
163
|
+
return "binary"
|
|
164
|
+
|
|
165
|
+
def guess_binary_sources(self, provider): # @UnusedVariable
|
|
166
|
+
"""A list of path that contains source files (for debugging purposes)."""
|
|
167
|
+
return []
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class BlackBox(Binary):
|
|
171
|
+
"""Binary resource with explicit command line options."""
|
|
172
|
+
|
|
173
|
+
_footprint = dict(
|
|
174
|
+
attr=dict(
|
|
175
|
+
binopts=dict(
|
|
176
|
+
info="Options that will be passed directly to the binary",
|
|
177
|
+
optional=True,
|
|
178
|
+
default="",
|
|
179
|
+
),
|
|
180
|
+
kind=dict(
|
|
181
|
+
values=["binbox", "blackbox"],
|
|
182
|
+
remap=dict(binbox="blackbox"),
|
|
183
|
+
),
|
|
184
|
+
)
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
def command_line(self, **opts):
|
|
188
|
+
"""Returns current attribute :attr:`binopts`."""
|
|
189
|
+
return self.binopts
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class NWPModel(Binary):
|
|
193
|
+
"""Base class for any Numerical Weather Prediction Model."""
|
|
194
|
+
|
|
195
|
+
_abstract = True
|
|
196
|
+
_footprint = [
|
|
197
|
+
model_deco,
|
|
198
|
+
dict(info="NWP Model", attr=dict(kind=dict(values=["nwpmodel"]))),
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def realkind(self):
|
|
203
|
+
return "nwpmodel"
|
|
204
|
+
|
|
205
|
+
def command_line(self, **opts):
|
|
206
|
+
"""Abstract method."""
|
|
207
|
+
return ""
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class OceanographicModel(Binary):
|
|
211
|
+
"""Base class for any Oceanographic Model."""
|
|
212
|
+
|
|
213
|
+
_abstract = True
|
|
214
|
+
_footprint = [
|
|
215
|
+
model_deco,
|
|
216
|
+
dict(
|
|
217
|
+
info="Oceanographic Model",
|
|
218
|
+
attr=dict(kind=dict(values=["oceanmodel"])),
|
|
219
|
+
),
|
|
220
|
+
]
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def realkind(self):
|
|
224
|
+
return "oceanmodel"
|
|
225
|
+
|
|
226
|
+
def command_line(self, **opts):
|
|
227
|
+
"""Abstract method."""
|
|
228
|
+
return ""
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class SurfaceModel(Binary):
|
|
232
|
+
_abstract = True
|
|
233
|
+
_footprint = [
|
|
234
|
+
model_deco,
|
|
235
|
+
dict(
|
|
236
|
+
info="Model used for the Safran-Surfex-Mepra chain.",
|
|
237
|
+
attr=dict(
|
|
238
|
+
kind=dict(
|
|
239
|
+
values=["surfacemodel", "snowmodel"],
|
|
240
|
+
remap=dict(autoremap="first"),
|
|
241
|
+
),
|
|
242
|
+
),
|
|
243
|
+
),
|
|
244
|
+
]
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def realkind(self):
|
|
248
|
+
return "surfacemodel"
|
|
249
|
+
|
|
250
|
+
def command_line(self, **opts):
|
|
251
|
+
"""Abstract method."""
|
|
252
|
+
return ""
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class ChemistryModel(Binary):
|
|
256
|
+
_abstract = True
|
|
257
|
+
_footprint = [
|
|
258
|
+
model_deco,
|
|
259
|
+
dict(
|
|
260
|
+
info="Base class for Chemistry models.",
|
|
261
|
+
attr=dict(
|
|
262
|
+
kind=dict(
|
|
263
|
+
values=["chemistrymodel"],
|
|
264
|
+
),
|
|
265
|
+
),
|
|
266
|
+
),
|
|
267
|
+
]
|
|
268
|
+
|
|
269
|
+
@property
|
|
270
|
+
def realkind(self):
|
|
271
|
+
return "chemistrymodel"
|
|
272
|
+
|
|
273
|
+
def command_line(self, **opts):
|
|
274
|
+
"""Abstract method."""
|
|
275
|
+
return ""
|
vortex/data/flow.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Abstract class for any flow-dependant "Resource".
|
|
3
|
+
|
|
4
|
+
By "flow-dependant", we mean a "Resource" that has to be described by ``model``,
|
|
5
|
+
``date`` and ``cutoff`` attributes. See :class:`FlowResource`
|
|
6
|
+
|
|
7
|
+
The :class:`GeoFlowResource` abstract class is to be used for flow-dependant
|
|
8
|
+
resources associated with an horizontal geometry.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .resources import Resource
|
|
12
|
+
from .geometries import hgeometry_deco
|
|
13
|
+
from .contents import FormatAdapter
|
|
14
|
+
|
|
15
|
+
from vortex.syntax.stdattrs import (
|
|
16
|
+
model_deco,
|
|
17
|
+
date_deco,
|
|
18
|
+
dateperiod_deco,
|
|
19
|
+
cutoff_deco,
|
|
20
|
+
term_deco,
|
|
21
|
+
)
|
|
22
|
+
from vortex.syntax.stddeco import namebuilding_insert
|
|
23
|
+
|
|
24
|
+
#: No automatic export
|
|
25
|
+
__all__ = []
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class FlowResource(Resource):
|
|
29
|
+
"""Abstract resource bound to a model, a date and a cutoff."""
|
|
30
|
+
|
|
31
|
+
_abstract = True
|
|
32
|
+
_footprint = [model_deco, date_deco, cutoff_deco]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@namebuilding_insert("radical", lambda s: s.nickname)
|
|
36
|
+
class UnknownFlow(FlowResource):
|
|
37
|
+
_footprint = [
|
|
38
|
+
term_deco,
|
|
39
|
+
dict(
|
|
40
|
+
info="Unknown assumed NWP Flow-Resource (development only !)",
|
|
41
|
+
attr=dict(
|
|
42
|
+
unknownflow=dict(
|
|
43
|
+
info="Activate the unknown flow resource", type=bool
|
|
44
|
+
),
|
|
45
|
+
term=dict(
|
|
46
|
+
optional=True,
|
|
47
|
+
),
|
|
48
|
+
nickname=dict(
|
|
49
|
+
info="The string that serves the purpose of Vortex's basename radical",
|
|
50
|
+
optional=True,
|
|
51
|
+
default="unknown",
|
|
52
|
+
),
|
|
53
|
+
clscontents=dict(default=FormatAdapter),
|
|
54
|
+
),
|
|
55
|
+
fastkeys={"unknownflow"},
|
|
56
|
+
),
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
_extension_remap = {
|
|
60
|
+
k: None for k in ("auto", "autoconfig", "foo", "unknown")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
def olive_basename(self):
|
|
64
|
+
target = self.nickname
|
|
65
|
+
if self.term is not None:
|
|
66
|
+
target += "+" + self.term.fmth
|
|
67
|
+
return target
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class GeoFlowResource(FlowResource):
|
|
71
|
+
"""Class which is a :class:`FlowResource` bound to a geometry."""
|
|
72
|
+
|
|
73
|
+
_abstract = True
|
|
74
|
+
_footprint = [
|
|
75
|
+
hgeometry_deco,
|
|
76
|
+
dict(
|
|
77
|
+
attr=dict(
|
|
78
|
+
clscontents=dict(
|
|
79
|
+
default=FormatAdapter,
|
|
80
|
+
),
|
|
81
|
+
)
|
|
82
|
+
),
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class PeriodFlowResource(Resource):
|
|
87
|
+
"""Abstract resource bound to a model, a begindate, enddate and a cutoff."""
|
|
88
|
+
|
|
89
|
+
_abstract = True
|
|
90
|
+
_footprint = [model_deco, dateperiod_deco, cutoff_deco]
|
|
91
|
+
|
|
92
|
+
_footprint = [
|
|
93
|
+
model_deco,
|
|
94
|
+
dateperiod_deco,
|
|
95
|
+
cutoff_deco,
|
|
96
|
+
dict(
|
|
97
|
+
attr=dict(
|
|
98
|
+
cutoff=dict(
|
|
99
|
+
optional=True,
|
|
100
|
+
),
|
|
101
|
+
)
|
|
102
|
+
),
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class GeoPeriodFlowResource(PeriodFlowResource):
|
|
107
|
+
"""Class which is a :class:`PeriodFlowResource` bound to a geometry."""
|
|
108
|
+
|
|
109
|
+
_abstract = True
|
|
110
|
+
_footprint = [
|
|
111
|
+
hgeometry_deco,
|
|
112
|
+
dict(
|
|
113
|
+
attr=dict(
|
|
114
|
+
clscontents=dict(
|
|
115
|
+
default=FormatAdapter,
|
|
116
|
+
),
|
|
117
|
+
)
|
|
118
|
+
),
|
|
119
|
+
]
|