carray 3.0.0 → 3.0.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.
- checksums.yaml +4 -4
- data/.yardopts +2 -1
- data/CHANGELOG.md +845 -3
- data/{NEWS.md → CHANGELOG.v1.md} +1 -1
- data/README.md +33 -33
- data/carray.gemspec +12 -8
- data/ext/ca_axis_dispatch.c +33 -4
- data/ext/ca_axis_group.c +256 -114
- data/ext/ca_binop_dispatch.c +5 -6
- data/ext/ca_binop_dispatch.h +0 -7
- data/ext/ca_categorical_iterator.c +121 -67
- data/ext/ca_for_each_element.h +6 -8
- data/ext/ca_group_iter.c +1 -1
- data/ext/ca_kernel_iterator.c +386 -74
- data/ext/ca_kernel_iterator.h +145 -45
- data/ext/ca_obj_array.c +62 -20
- data/ext/ca_obj_bincmp.c +57 -27
- data/ext/ca_obj_binop.c +86 -30
- data/ext/ca_obj_block.c +4 -4
- data/ext/ca_obj_const_string.c +88 -27
- data/ext/ca_obj_face.c +104 -0
- data/ext/ca_obj_face.h +48 -1
- data/ext/ca_obj_fake.c +11 -0
- data/ext/ca_obj_fixlen_string.c +21 -6
- data/ext/ca_obj_grid.c +11 -3
- data/ext/ca_obj_meld.c +125 -22
- data/ext/ca_obj_moncmp.c +33 -14
- data/ext/ca_obj_monop.c +19 -7
- data/ext/ca_obj_object.c +107 -4
- data/ext/ca_obj_record.c +3 -1
- data/ext/ca_obj_refer.c +30 -6
- data/ext/ca_obj_roll.c +13 -5
- data/ext/ca_obj_select.c +49 -34
- data/ext/ca_obj_select_axis.c +16 -6
- data/ext/ca_obj_shift.c +3 -3
- data/ext/ca_obj_stack.c +3 -8
- data/ext/ca_obj_stride.c +178 -24
- data/ext/ca_obj_string.c +11 -5
- data/ext/ca_obj_tile.c +13 -5
- data/ext/ca_obj_time.c +3 -1
- data/ext/ca_obj_timedelta.c +3 -1
- data/ext/ca_obj_transpose.c +1 -1
- data/ext/ca_obj_triop.c +62 -23
- data/ext/ca_obj_window.c +94 -19
- data/ext/ca_op_cmplx64.h +123 -0
- data/ext/ca_op_ipower.c +1 -5
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +5 -5
- data/ext/ca_sweep_engine.c +362 -155
- data/ext/ca_sweep_engine.h +39 -9
- data/ext/ca_transform_common.c +7 -0
- data/ext/carray.h +148 -132
- data/ext/carray_access.c +83 -49
- data/ext/carray_address_basis.c +590 -0
- data/ext/carray_bincount.c +8 -8
- data/ext/carray_broadcast.c +102 -9
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +2010 -335
- data/ext/carray_call_cfunc.h +153 -0
- data/ext/carray_cast.c +184 -72
- data/ext/carray_conversion.c +22 -22
- data/ext/carray_copy.c +67 -32
- data/ext/carray_core.c +140 -13
- data/ext/carray_count.c +10 -11
- data/ext/carray_element.c +7 -7
- data/ext/carray_factorize.c +72 -51
- data/ext/carray_hold.c +1 -1
- data/ext/carray_index_classifier.c +7 -21
- data/ext/carray_internal.h +36 -3
- data/ext/carray_kernels_bincmp.c +1 -0
- data/ext/carray_kernels_binop.c +320 -298
- data/ext/carray_kernels_init.c +1095 -0
- data/ext/carray_kernels_map.c +1 -0
- data/ext/carray_kernels_moncmp.c +1 -0
- data/ext/carray_kernels_monop.c +412 -411
- data/ext/carray_kernels_reduce_aggregate.c +256 -87
- data/ext/carray_kernels_reduce_boolean.c +1 -0
- data/ext/carray_kernels_reduce_cumulative.c +324 -54
- data/ext/carray_kernels_reduce_extreme.c +605 -58
- data/ext/carray_kernels_reduce_variance.c +1 -0
- data/ext/carray_kernels_scan.c +5 -4
- data/ext/carray_kernels_search.c +187 -106
- data/ext/carray_kernels_sort.c +1 -0
- data/ext/carray_kernels_triop.c +1 -0
- data/ext/carray_lazy.c +175 -5
- data/ext/carray_loop.c +7 -1
- data/ext/carray_mask.c +29 -13
- data/ext/carray_median_percentile.c +56 -1
- data/ext/carray_memory_view.c +46 -21
- data/ext/carray_operator.c +50 -53
- data/ext/carray_order.c +1 -1
- data/ext/carray_partition.c +4 -4
- data/ext/carray_random.c +391 -47
- data/ext/carray_scatter.c +1 -1
- data/ext/carray_slab.c +13 -0
- data/ext/carray_sort.c +22 -24
- data/ext/carray_sort_kernel.c +10 -10
- data/ext/carray_test.c +1 -1
- data/ext/extconf.rb +18 -0
- data/ext/mk_call_cfunc.rb +323 -145
- data/ext/mkkernel.rb +651 -129
- data/ext/ruby_carray.c +28 -17
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +14 -1
- data/lib/carray/axis_group.rb +84 -7
- data/lib/carray/basics.rb +63 -59
- data/lib/carray/bincount_nd.rb +12 -12
- data/lib/carray/block_iterator.rb +111 -25
- data/lib/carray/categorical.rb +154 -37
- data/lib/carray/categorical_iterator.rb +300 -151
- data/lib/carray/conditional.rb +14 -14
- data/lib/carray/const_string.rb +131 -27
- data/lib/carray/construct.rb +61 -0
- data/lib/carray/core_extensions.rb +62 -5
- data/lib/carray/data_type_extension.rb +21 -1
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +3 -3
- data/lib/carray/frame/convert.rb +1 -1
- data/lib/carray/frame/csv_parser.rb +11 -4
- data/lib/carray/frame/frame.rb +85 -21
- data/lib/carray/frame/group.rb +36 -3
- data/lib/carray/frame/io.rb +224 -15
- data/lib/carray/frame/records.rb +18 -4
- data/lib/carray/frame/sort.rb +1 -1
- data/lib/carray/frame/verbs.rb +32 -12
- data/lib/carray/fuse_source.rb +123 -0
- data/lib/carray/fusion.rb +218 -0
- data/lib/carray/histogram.rb +16 -16
- data/lib/carray/inspect.rb +43 -16
- data/lib/carray/iterator.rb +147 -3
- data/lib/carray/lazy.rb +88 -73
- data/lib/carray/mask_gap_fill.rb +3 -1
- data/lib/carray/meld_reduce.rb +2 -2
- data/lib/carray/methods/align_addr.rb +1 -1
- data/lib/carray/methods/composition.rb +1 -1
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/is_in.rb +25 -14
- data/lib/carray/methods/locate_addr.rb +81 -3
- data/lib/carray/methods/mask_duplicates.rb +36 -2
- data/lib/carray/methods/meshgrid.rb +4 -5
- data/lib/carray/methods/mode.rb +2 -2
- data/lib/carray/methods/nunique.rb +23 -2
- data/lib/carray/methods/repeat.rb +110 -0
- data/lib/carray/methods/snap.rb +7 -2
- data/lib/carray/methods/unique.rb +44 -4
- data/lib/carray/methods/value_counts.rb +2 -2
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +0 -19
- data/lib/carray/slab_iterator.rb +77 -19
- data/lib/carray/string_operation_extension.rb +10 -6
- data/lib/carray/time.rb +906 -491
- data/lib/carray/window_iterator.rb +421 -27
- data/lib/carray.rb +7 -5
- data/yard-stubs/ca_obj_array.rb +385 -0
- data/yard-stubs/ca_obj_bitarray.rb +38 -0
- data/yard-stubs/ca_obj_bitfield.rb +43 -0
- data/yard-stubs/ca_obj_block.rb +68 -0
- data/yard-stubs/ca_obj_byte_swap.rb +56 -0
- data/yard-stubs/ca_obj_fake.rb +31 -0
- data/yard-stubs/ca_obj_farray.rb +32 -0
- data/yard-stubs/ca_obj_field.rb +45 -0
- data/yard-stubs/ca_obj_grid.rb +35 -0
- data/yard-stubs/ca_obj_refer.rb +72 -0
- data/yard-stubs/ca_obj_roll.rb +45 -0
- data/yard-stubs/ca_obj_shift.rb +43 -0
- data/yard-stubs/ca_obj_stride.rb +181 -0
- data/yard-stubs/ca_obj_tile.rb +29 -0
- data/yard-stubs/ca_obj_transpose.rb +40 -0
- data/yard-stubs/ca_obj_window.rb +57 -0
- data/yard-stubs/carray_access.rb +131 -0
- data/yard-stubs/carray_attribute.rb +246 -0
- data/yard-stubs/carray_broadcast.rb +37 -0
- data/yard-stubs/carray_cast.rb +489 -0
- data/yard-stubs/carray_class.rb +65 -0
- data/yard-stubs/carray_conversion.rb +76 -0
- data/yard-stubs/carray_copy.rb +79 -0
- data/yard-stubs/carray_core.rb +34 -0
- data/yard-stubs/carray_count.rb +84 -0
- data/yard-stubs/carray_element.rb +108 -0
- data/yard-stubs/carray_generate.rb +66 -0
- data/yard-stubs/carray_lazy.rb +228 -0
- data/yard-stubs/carray_loop.rb +140 -0
- data/yard-stubs/carray_mask.rb +259 -0
- data/yard-stubs/carray_math.rb +1615 -0
- data/yard-stubs/carray_mathfunc.rb +45 -0
- data/yard-stubs/carray_median_percentile.rb +103 -0
- data/yard-stubs/carray_memory_view.rb +163 -0
- data/yard-stubs/carray_order.rb +252 -0
- data/yard-stubs/carray_random.rb +89 -0
- data/yard-stubs/carray_scatter.rb +106 -0
- data/yard-stubs/carray_slab.rb +59 -0
- data/yard-stubs/carray_sort.rb +165 -0
- data/yard-stubs/carray_test.rb +85 -0
- data/yard-stubs/carray_undef.rb +64 -0
- data/yard-stubs/carray_utils.rb +97 -0
- data/yard-stubs/ruby_carray.rb +193 -0
- metadata +67 -10
- data/ext/ca_obj_unbound_repeat.c +0 -496
data/{NEWS.md → CHANGELOG.v1.md}
RENAMED
|
@@ -2,7 +2,7 @@ ChangeLog of Ruby/CArray
|
|
|
2
2
|
========================
|
|
3
3
|
|
|
4
4
|
Releases from 3.0.0 onward are in [CHANGELOG.md](CHANGELOG.md).
|
|
5
|
-
What follows is the history up to 2.0.1.
|
|
5
|
+
What follows is the history up to the 2.0.0 release; 2.0.1 went unrecorded.
|
|
6
6
|
|
|
7
7
|
1.6.0 -> 2.0.0
|
|
8
8
|
--------------
|
data/README.md
CHANGED
|
@@ -1,37 +1,23 @@
|
|
|
1
1
|
# Ruby/CArray
|
|
2
2
|
|
|
3
|
-
Ruby/CArray is an extension library for the multi-dimensional array class.
|
|
3
|
+
Ruby/CArray is an extension library for the multi-dimensional array class. It provides arrays of a single, uniform data type, with indexing and slicing in many forms, element-wise arithmetic and mathematical functions, reductions and statistics over the whole array or along any axis, and broadcasting between shapes that differ in size-1 axes. The features listed below are in addition to these.
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
3.0.x still moves: behavior can change between releases — see [CHANGELOG.md](CHANGELOG.md). 3.1 is the first release meant to be depended on. Until then, treat it as a place to try things out.
|
|
4
8
|
|
|
5
9
|
## Features
|
|
6
10
|
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
way back to the source data
|
|
18
|
-
* Explicit broadcasting: operating on arrays of different shapes by stretching
|
|
19
|
-
size-1 axes to match, without ever adding axes implicitly
|
|
20
|
-
* Fast reductions built on compiler auto-vectorization
|
|
21
|
-
* Kernel-style iteration from Ruby: drive a Ruby block over each sub-array spanning
|
|
22
|
-
chosen axes
|
|
23
|
-
* Faces: a mechanism for building extended data types on top of CArray (time,
|
|
24
|
-
categorical and variable-length string columns are such types)
|
|
25
|
-
* Easily define record types that bind several data together as one element
|
|
26
|
-
* User-defined array classes, written in Ruby, that share the full CArray interface
|
|
27
|
-
so your own type behaves like a CArray everywhere
|
|
28
|
-
* A DataFrame (`CAFrame`) whose columns are plain CArrays — it adds names and row
|
|
29
|
-
operations (select, filter, sort, join, group-by, CSV I/O) and hands a column
|
|
30
|
-
back as the array itself, so masks, views and Faces keep working on it
|
|
31
|
-
* Writing per-axis methods and functions in C extensions with ease — a single
|
|
32
|
-
kernel runs across every view type, with no per-view branching to write yourself
|
|
33
|
-
* MemoryView protocol support — interoperate with other numerical libraries as both
|
|
34
|
-
producer and consumer
|
|
11
|
+
* Every array carries a per-element mask for missing values, respected by reductions and statistics
|
|
12
|
+
* Views compose without copying — a write through the outermost view reaches the source data
|
|
13
|
+
* MemoryView protocol on both sides: share buffers with other numerical libraries without copying
|
|
14
|
+
* Kernel-style iteration: run a Ruby block over each sub-array spanning the axes you choose
|
|
15
|
+
* Attach domain meaning (time, angle, quantity with units…) without changing storage — a Face
|
|
16
|
+
* Define your own array class in pure Ruby while keeping the full CArray interface
|
|
17
|
+
* Pack multiple values into one element as a record type
|
|
18
|
+
* Comes with a DataFrame (`CAFrame`) whose columns are plain CArrays, so masks and views keep working on them
|
|
19
|
+
|
|
20
|
+
Each of these is shown, briefly and with a runnable example, in [A tour of the features](docs/FeatureTour.md).
|
|
35
21
|
|
|
36
22
|
## Install
|
|
37
23
|
|
|
@@ -124,14 +110,28 @@ b.strip_mask(Float::NAN).sum(axis: 0)
|
|
|
124
110
|
|
|
125
111
|
## Documentation
|
|
126
112
|
|
|
127
|
-
* [
|
|
113
|
+
* [Introduction](guides/users/introduction.md) — what Ruby/CArray is
|
|
114
|
+
* [Getting started](guides/users/00_getting_started.md) — install, and a first array
|
|
115
|
+
* [Creating arrays](guides/users/01_creating_arrays.md) — constructors, data types, filling
|
|
116
|
+
* [Indexing and slicing](guides/users/02_indexing_and_slicing.md) — elements, rows, blocks, conditions
|
|
117
|
+
* [Indexer reference](guides/users/16_indexer_reference.md) — every form `[]` accepts
|
|
118
|
+
* [Element-wise operations](guides/users/03_elementwise.md) — arithmetic and mathematical functions
|
|
119
|
+
* [Broadcasting](guides/users/07_broadcasting.md) — shapes that differ
|
|
120
|
+
* [Views](guides/users/06_views.md) — referring to data without copying
|
|
121
|
+
* [Reduction and statistics](guides/users/04_reduction_and_statistics.md) — summaries, whole or per axis
|
|
122
|
+
* [Masks and missing values](guides/users/05_masks.md) — undefined elements, and how calculations treat them
|
|
123
|
+
|
|
124
|
+
## Contributing
|
|
125
|
+
|
|
126
|
+
Bug reports and feature requests are welcome — please open an issue.
|
|
127
|
+
|
|
128
|
+
**Before opening a pull request, read [CONTRIBUTING.md](CONTRIBUTING.md).** It is short, and it says which form a contribution is best sent in. A small, self-contained bug fix is fine as a pull request. Anything larger is better started as an issue: code here gets rewritten as a matter of course, so a patch for a larger change is likely to end up reimplemented rather than merged, and describing the problem gets you further than writing one.
|
|
128
129
|
|
|
129
130
|
## Credits
|
|
130
131
|
|
|
131
|
-
|
|
132
|
+
CArray is created and maintained by himotoyoshi.
|
|
132
133
|
|
|
133
|
-
|
|
134
|
-
produced in collaboration with AI coding tools.
|
|
134
|
+
Versions up to 2.0 were written by the author. For version 3.0, the author provided the design, and most of the implementation was rewritten with AI coding tools; it has been verified primarily through the test suite and practical use.
|
|
135
135
|
|
|
136
136
|
## License
|
|
137
137
|
|
data/carray.gemspec
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
Gem::Specification.new do |s|
|
|
2
2
|
s.name = "carray"
|
|
3
|
-
s.version = "3.0.
|
|
3
|
+
s.version = "3.0.2"
|
|
4
4
|
s.authors = ["himotoyoshi"]
|
|
5
5
|
s.email = ["himotoyoshi@users.noreply.github.com"]
|
|
6
|
-
s.summary = "Multi-
|
|
6
|
+
s.summary = "Multi-dimensional numerical array class for Ruby"
|
|
7
7
|
s.description = <<-HERE
|
|
8
|
-
Ruby/CArray
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
Ruby/CArray adds multi-dimensional numerical arrays to Ruby. Elements are held
|
|
9
|
+
in a single flat memory block, so whole-array work -- element-wise arithmetic,
|
|
10
|
+
reductions along any axis, sorting, searching -- runs in C. Slicing, transposing,
|
|
11
|
+
reshaping, and selecting by a boolean condition all return views that share
|
|
12
|
+
storage with the original array and can be chained freely; nothing is copied
|
|
13
|
+
until you ask for a copy. Any array, view included, can carry a mask marking
|
|
14
|
+
individual elements as undefined, and arrays are exchanged with other numerical
|
|
15
|
+
libraries without copying through Ruby's MemoryView protocol.
|
|
13
16
|
HERE
|
|
14
17
|
s.homepage = "https://github.com/himotoyoshi/carray"
|
|
15
18
|
s.license = "MIT"
|
|
@@ -17,13 +20,14 @@ Gem::Specification.new do |s|
|
|
|
17
20
|
s.required_ruby_version = ">= 3.0"
|
|
18
21
|
s.files = [
|
|
19
22
|
*Dir.glob("lib/**/*.rb"),
|
|
23
|
+
*Dir.glob("yard-stubs/**/*.rb"),
|
|
20
24
|
*(Dir.glob("ext/*.c") - %w[ext/carray_kernels.c ext/carray_cast_func.c ext/carray_math.c]),
|
|
21
25
|
*Dir.glob("ext/*.h"),
|
|
22
26
|
*Dir.glob("ext/*.rb"),
|
|
23
27
|
"LICENSE",
|
|
24
28
|
"README.md",
|
|
25
|
-
"NEWS.md",
|
|
26
29
|
"CHANGELOG.md",
|
|
30
|
+
"CHANGELOG.v1.md",
|
|
27
31
|
".yardopts",
|
|
28
32
|
"carray.gemspec",
|
|
29
33
|
].select { |f| File.file?(f) }
|
data/ext/ca_axis_dispatch.c
CHANGED
|
@@ -339,13 +339,27 @@ ca_axis_dispatch_scatter_cb (ca_size_t off, int oob, ca_size_t n, void *vctx)
|
|
|
339
339
|
/* Callback context for fill_value (broadcast a single value). parent is set
|
|
340
340
|
when the value goes through the parent's own fill_stride instead of a
|
|
341
341
|
buffer this side has attached. */
|
|
342
|
+
/* Same size as the window ca_fill_stride_via_addrs collects into. */
|
|
343
|
+
#define CA_AXIS_FILL_ADDR_WINDOW 1024
|
|
344
|
+
|
|
342
345
|
typedef struct {
|
|
343
346
|
const void *val;
|
|
344
347
|
ca_size_t bytes;
|
|
345
348
|
char *parent_ptr;
|
|
346
349
|
CArray *parent;
|
|
350
|
+
ca_size_t window[CA_AXIS_FILL_ADDR_WINDOW];
|
|
351
|
+
ca_size_t nw;
|
|
347
352
|
} ca_axis_fill_ctx_t;
|
|
348
353
|
|
|
354
|
+
static void
|
|
355
|
+
ca_axis_dispatch_fill_flush (ca_axis_fill_ctx_t *c)
|
|
356
|
+
{
|
|
357
|
+
if ( c->nw ) {
|
|
358
|
+
ca_fill_addrs(c->parent, c->nw, c->window, (void *) c->val);
|
|
359
|
+
c->nw = 0;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
349
363
|
static void
|
|
350
364
|
ca_axis_dispatch_fill_value_cb (ca_size_t off, int oob, ca_size_t n, void *vctx)
|
|
351
365
|
{
|
|
@@ -354,11 +368,25 @@ ca_axis_dispatch_fill_value_cb (ca_size_t off, int oob, ca_size_t n, void *vctx)
|
|
|
354
368
|
if ( c->parent ) {
|
|
355
369
|
/* One slab is one contiguous run of parent cells, which is a region the
|
|
356
370
|
parent can fill for itself -- no borrowed buffer, so nothing outside
|
|
357
|
-
the run is read or written.
|
|
371
|
+
the run is read or written. A run of one cell is not worth a call of
|
|
372
|
+
its own, though: when the innermost selected axis picks individual
|
|
373
|
+
indices every run is one cell, and the same cell count that costs the
|
|
374
|
+
parent eight calls on an outer axis cost it one per cell here. Collect
|
|
375
|
+
those and hand them over as a list. The value is the same for every
|
|
376
|
+
cell and the walk visits each cell once, so batching cannot change
|
|
377
|
+
which cells are written. */
|
|
358
378
|
ca_size_t count = n / c->bytes;
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
379
|
+
if ( count == 1 ) {
|
|
380
|
+
c->window[c->nw++] = off / c->bytes;
|
|
381
|
+
if ( c->nw == CA_AXIS_FILL_ADDR_WINDOW ) {
|
|
382
|
+
ca_axis_dispatch_fill_flush(c);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
ca_size_t step = 1;
|
|
387
|
+
ca_fill_stride(c->parent, off / c->bytes, 1, &count, &step,
|
|
388
|
+
(void *) c->val);
|
|
389
|
+
}
|
|
362
390
|
}
|
|
363
391
|
else {
|
|
364
392
|
ca_axis_dispatch_fill_slab(c->parent_ptr + off, c->val, c->bytes, n);
|
|
@@ -895,6 +923,7 @@ ca_axis_dispatch_fill_value_via_parent (CArray *parent,
|
|
|
895
923
|
ca_axis_dispatch_for_each_slab(parent, parent_axis_dims, axes, ndim,
|
|
896
924
|
bytes, total_elements,
|
|
897
925
|
ca_axis_dispatch_fill_value_cb, &ctx);
|
|
926
|
+
ca_axis_dispatch_fill_flush(&ctx);
|
|
898
927
|
}
|
|
899
928
|
|
|
900
929
|
/* ==========================================================================
|