sys-filesystem 1.4.3 → 1.4.5
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
- checksums.yaml.gz.sig +0 -0
- data/CHANGES.md +8 -0
- data/Rakefile +13 -0
- data/lib/sys/filesystem.rb +17 -16
- data/lib/sys/unix/sys/filesystem/constants.rb +2 -0
- data/lib/sys/unix/sys/filesystem/functions.rb +15 -5
- data/lib/sys/unix/sys/filesystem/structs.rb +84 -70
- data/lib/sys/unix/sys/filesystem.rb +3 -3
- data/lib/sys/windows/sys/filesystem/functions.rb +1 -0
- data/lib/sys/windows/sys/filesystem/helper.rb +3 -0
- data/lib/sys/windows/sys/filesystem.rb +13 -11
- data/lib/sys-filesystem.rb +2 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/sys_filesystem_shared.rb +14 -0
- data/spec/sys_filesystem_unix_spec.rb +240 -124
- data/spec/sys_filesystem_windows_spec.rb +263 -151
- data/sys-filesystem.gemspec +15 -7
- data.tar.gz.sig +0 -0
- metadata +34 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 867cb33509a3fa99a58dbf3e0ee69107470a3cecebe4efc2346f49ec1dc1cea6
|
4
|
+
data.tar.gz: 9b1de11209f227d00584c021323b3de75db44e399823941bbad5bf9dd407cab2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29b4307434bda5a5447b45675a447d90421c104ba138f296c932272d6054c1cd81d4a3ddd68bdd9b099c30b012409a66ca9befd0275491d448fc2ae6f2184825
|
7
|
+
data.tar.gz: 5a6ee063a349093b3b0161814ce6f3b56af683d2a87960ab26d2975530bce91b4a1b31b1f2af1949fb315589116ef8ce5896a95802739a3e85573b436d6c5b6e
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 1.4.5 - 22-May-2024
|
2
|
+
* Handle the possibility that a statvs64 alias may not exist on some Linux
|
3
|
+
platforms. Thanks go to Antoine Martin for the report.
|
4
|
+
|
5
|
+
## 1.4.4 - 12-Sep-2023
|
6
|
+
* Yet another fix for 32-bit vs 64-bit linux, specifically for the Statvfs
|
7
|
+
struct. Thanks go to Josh Cooper for the spot and the patch.
|
8
|
+
|
1
9
|
## 1.4.3 - 20-Oct-2021
|
2
10
|
* Another fix for 32-bit vs 64-bit Linux since it was realized we cannot always
|
3
11
|
rely on the host architecture information. Handling for JRuby was improved
|
data/Rakefile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/clean'
|
3
3
|
require 'rspec/core/rake_task'
|
4
|
+
require 'rubocop/rake_task'
|
4
5
|
|
5
6
|
CLEAN.include('**/*.gem', '**/*.rbc', '**/*.rbx', '**/*.lock')
|
6
7
|
|
@@ -25,6 +26,18 @@ task :example do
|
|
25
26
|
sh "ruby -Ilib -Ilib/unix -Ilib/windows examples/example_stat.rb"
|
26
27
|
end
|
27
28
|
|
29
|
+
RuboCop::RakeTask.new
|
30
|
+
|
31
|
+
namespace :rubocop do
|
32
|
+
RuboCop::RakeTask.new(:unix) do |task|
|
33
|
+
task.patterns = ['lib/sys/unix/sys/**/*.rb', 'spec/*unix*']
|
34
|
+
end
|
35
|
+
|
36
|
+
RuboCop::RakeTask.new(:windows) do |task|
|
37
|
+
task.patterns = ['lib/sys/windows/sys/**/*.rb', 'spec/*windows*']
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
28
41
|
desc "Run the test suite"
|
29
42
|
RSpec::Core::RakeTask.new(:spec)
|
30
43
|
|
data/lib/sys/filesystem.rb
CHANGED
@@ -1,9 +1,4 @@
|
|
1
|
-
|
2
|
-
class Filesystem
|
3
|
-
# The version of the sys-filesystem library
|
4
|
-
VERSION = '1.4.3'.freeze
|
5
|
-
end
|
6
|
-
end
|
1
|
+
# frozen_string_literal: true
|
7
2
|
|
8
3
|
require 'rbconfig'
|
9
4
|
|
@@ -13,10 +8,18 @@ else
|
|
13
8
|
require_relative 'unix/sys/filesystem'
|
14
9
|
end
|
15
10
|
|
16
|
-
# Methods universal to all platforms
|
11
|
+
# Methods and properties universal to all platforms
|
17
12
|
|
13
|
+
# The Sys module serves as a namespace only.
|
18
14
|
module Sys
|
15
|
+
# The Filesystem class serves as an abstract base class. Its methods
|
16
|
+
# return objects of other types. Do not instantiate.
|
19
17
|
class Filesystem
|
18
|
+
# The version of the sys-filesystem library
|
19
|
+
VERSION = '1.4.5'
|
20
|
+
|
21
|
+
# Stat objects are returned by the Sys::Filesystem.stat method. Here
|
22
|
+
# we're adding universal methods.
|
20
23
|
class Stat
|
21
24
|
# Returns true if the filesystem is case sensitive for the current path.
|
22
25
|
# Typically this will be any path on MS Windows or Macs using HFS.
|
@@ -26,14 +29,12 @@ module Sys
|
|
26
29
|
# general rule, I do not recommend using this method for a root path.
|
27
30
|
#
|
28
31
|
def case_insensitive?
|
29
|
-
if path
|
30
|
-
if RbConfig::CONFIG['host_os'] =~ /darwin|mac|windows|mswin|mingw/i
|
31
|
-
true # Assumes HFS
|
32
|
-
else
|
33
|
-
false
|
34
|
-
end
|
35
|
-
else
|
32
|
+
if path =~ /\w+/
|
36
33
|
File.identical?(path, path.swapcase)
|
34
|
+
elsif RbConfig::CONFIG['host_os'] =~ /darwin|mac|windows|mswin|mingw/i
|
35
|
+
true # Assumes HFS/APFS on Mac
|
36
|
+
else
|
37
|
+
false
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
@@ -46,8 +47,8 @@ module Sys
|
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
49
|
-
#
|
50
|
-
#
|
50
|
+
# Reopen the Numeric class and add some convenient methods
|
51
|
+
# for converting bytes to kb, mb, and gb.
|
51
52
|
class Numeric
|
52
53
|
# call-seq:
|
53
54
|
# <tt>num</tt>.to_kb
|
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'ffi'
|
2
4
|
|
3
5
|
module Sys
|
4
6
|
class Filesystem
|
7
|
+
# A scoped module for internal FFI functions to be used by the main code.
|
5
8
|
module Functions
|
6
9
|
extend FFI::Library
|
7
10
|
|
@@ -9,19 +12,26 @@ module Sys
|
|
9
12
|
|
10
13
|
def self.linux64?
|
11
14
|
if RUBY_PLATFORM == 'java'
|
12
|
-
|
15
|
+
RbConfig::CONFIG['host_os'] =~ /linux/i &&
|
16
|
+
ENV_JAVA['sun.arch.data.model'].to_i == 64
|
13
17
|
else
|
14
18
|
RbConfig::CONFIG['host_os'] =~ /linux/i &&
|
15
19
|
(RbConfig::CONFIG['arch'] =~ /64/ || RbConfig::CONFIG['DEFS'] =~ /64/)
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
23
|
+
def self.solaris?
|
24
|
+
RbConfig::CONFIG['host_os'] =~ /sunos|solaris/i
|
25
|
+
end
|
26
|
+
|
19
27
|
private_class_method :linux64?
|
20
28
|
|
21
|
-
if
|
22
|
-
|
23
|
-
|
24
|
-
|
29
|
+
if linux64? || solaris?
|
30
|
+
begin
|
31
|
+
attach_function(:statvfs, :statvfs64, %i[string pointer], :int)
|
32
|
+
rescue FFI::NotFoundError # Not every Linux distro has an alias
|
33
|
+
attach_function(:statvfs, %i[string pointer], :int)
|
34
|
+
end
|
25
35
|
else
|
26
36
|
attach_function(:statvfs, %i[string pointer], :int)
|
27
37
|
end
|
@@ -1,11 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'ffi'
|
2
4
|
require 'rbconfig'
|
3
5
|
|
4
6
|
module Sys
|
5
7
|
class Filesystem
|
6
8
|
module Structs
|
9
|
+
# The Statfs struct is a subclass of FFI::Struct that corresponds to a struct statfs.
|
7
10
|
class Statfs < FFI::Struct
|
8
|
-
|
11
|
+
# Private method that will determine the layout of the struct on Linux.
|
9
12
|
def self.linux64?
|
10
13
|
if RUBY_PLATFORM == 'java'
|
11
14
|
ENV_JAVA['sun.arch.data.model'].to_i == 64
|
@@ -20,92 +23,103 @@ module Sys
|
|
20
23
|
# FreeBSD 12.0 MNAMELEN from 88 => 1024.
|
21
24
|
MNAMELEN =
|
22
25
|
if RbConfig::CONFIG['host_os'] =~ /freebsd(.*)/i
|
23
|
-
|
26
|
+
Regexp.last_match(1).to_f < 12.0 ? 88 : 1024
|
24
27
|
else
|
25
28
|
88
|
26
29
|
end
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
:f_version, :uint32,
|
31
|
-
:f_type, :uint32,
|
32
|
-
:f_flags, :uint64,
|
33
|
-
:f_bsize, :uint64,
|
34
|
-
:f_iosize, :int64,
|
35
|
-
:f_blocks, :uint64,
|
36
|
-
:f_bfree, :uint64,
|
37
|
-
:f_bavail, :int64,
|
38
|
-
:f_files, :uint64,
|
39
|
-
:f_ffree, :uint64,
|
40
|
-
:f_syncwrites, :uint64,
|
41
|
-
:f_asyncwrites, :uint64,
|
42
|
-
:f_syncreads, :uint64,
|
43
|
-
:f_asyncreads, :uint64,
|
44
|
-
:f_spare, [:uint64, 10],
|
45
|
-
:f_namemax, :uint32,
|
46
|
-
:f_owner, :int32,
|
47
|
-
:f_fsid, [:int32, 2],
|
48
|
-
:f_charspare, [:char, 80],
|
49
|
-
:f_fstypename, [:char, 16],
|
50
|
-
:f_mntfromname, [:char, MNAMELEN],
|
51
|
-
:f_mntonname, [:char, MNAMELEN]
|
52
|
-
)
|
53
|
-
elsif RbConfig::CONFIG['host_os'] =~ /linux/i
|
54
|
-
if linux64?
|
31
|
+
case RbConfig::CONFIG['host_os']
|
32
|
+
when /bsd/i
|
55
33
|
layout(
|
56
|
-
:
|
57
|
-
:
|
34
|
+
:f_version, :uint32,
|
35
|
+
:f_type, :uint32,
|
36
|
+
:f_flags, :uint64,
|
37
|
+
:f_bsize, :uint64,
|
38
|
+
:f_iosize, :int64,
|
58
39
|
:f_blocks, :uint64,
|
59
40
|
:f_bfree, :uint64,
|
60
|
-
:f_bavail, :
|
41
|
+
:f_bavail, :int64,
|
61
42
|
:f_files, :uint64,
|
62
43
|
:f_ffree, :uint64,
|
63
|
-
:
|
64
|
-
:
|
65
|
-
:
|
66
|
-
:
|
67
|
-
:f_spare, [:
|
44
|
+
:f_syncwrites, :uint64,
|
45
|
+
:f_asyncwrites, :uint64,
|
46
|
+
:f_syncreads, :uint64,
|
47
|
+
:f_asyncreads, :uint64,
|
48
|
+
:f_spare, [:uint64, 10],
|
49
|
+
:f_namemax, :uint32,
|
50
|
+
:f_owner, :int32,
|
51
|
+
:f_fsid, [:int32, 2],
|
52
|
+
:f_charspare, [:char, 80],
|
53
|
+
:f_fstypename, [:char, 16],
|
54
|
+
:f_mntfromname, [:char, MNAMELEN],
|
55
|
+
:f_mntonname, [:char, MNAMELEN]
|
68
56
|
)
|
57
|
+
when /linux/i
|
58
|
+
if linux64?
|
59
|
+
layout(
|
60
|
+
:f_type, :ulong,
|
61
|
+
:f_bsize, :ulong,
|
62
|
+
:f_blocks, :uint64,
|
63
|
+
:f_bfree, :uint64,
|
64
|
+
:f_bavail, :uint64,
|
65
|
+
:f_files, :uint64,
|
66
|
+
:f_ffree, :uint64,
|
67
|
+
:f_fsid, [:int, 2],
|
68
|
+
:f_namelen, :ulong,
|
69
|
+
:f_frsize, :ulong,
|
70
|
+
:f_flags, :ulong,
|
71
|
+
:f_spare, [:ulong, 4]
|
72
|
+
)
|
73
|
+
else
|
74
|
+
layout(
|
75
|
+
:f_type, :ulong,
|
76
|
+
:f_bsize, :ulong,
|
77
|
+
:f_blocks, :uint32,
|
78
|
+
:f_bfree, :uint32,
|
79
|
+
:f_bavail, :uint32,
|
80
|
+
:f_files, :uint32,
|
81
|
+
:f_ffree, :uint32,
|
82
|
+
:f_fsid, [:int, 2],
|
83
|
+
:f_namelen, :ulong,
|
84
|
+
:f_frsize, :ulong,
|
85
|
+
:f_flags, :ulong,
|
86
|
+
:f_spare, [:ulong, 4]
|
87
|
+
)
|
88
|
+
end
|
69
89
|
else
|
70
90
|
layout(
|
71
|
-
:
|
72
|
-
:
|
73
|
-
:f_blocks, :
|
74
|
-
:f_bfree, :
|
75
|
-
:f_bavail, :
|
76
|
-
:f_files, :
|
77
|
-
:f_ffree, :
|
78
|
-
:f_fsid, [:
|
79
|
-
:
|
80
|
-
:
|
81
|
-
:f_flags, :
|
82
|
-
:
|
91
|
+
:f_bsize, :uint32,
|
92
|
+
:f_iosize, :int32,
|
93
|
+
:f_blocks, :uint64,
|
94
|
+
:f_bfree, :uint64,
|
95
|
+
:f_bavail, :uint64,
|
96
|
+
:f_files, :uint64,
|
97
|
+
:f_ffree, :uint64,
|
98
|
+
:f_fsid, [:int32, 2],
|
99
|
+
:f_owner, :int32,
|
100
|
+
:f_type, :uint32,
|
101
|
+
:f_flags, :uint32,
|
102
|
+
:f_fssubtype, :uint32,
|
103
|
+
:f_fstypename, [:char, 16],
|
104
|
+
:f_mntonname, [:char, 1024],
|
105
|
+
:f_mntfromname, [:char, 1024],
|
106
|
+
:f_reserved, [:uint32, 8]
|
83
107
|
)
|
84
|
-
end
|
85
|
-
else
|
86
|
-
layout(
|
87
|
-
:f_bsize, :uint32,
|
88
|
-
:f_iosize, :int32,
|
89
|
-
:f_blocks, :uint64,
|
90
|
-
:f_bfree, :uint64,
|
91
|
-
:f_bavail, :uint64,
|
92
|
-
:f_files, :uint64,
|
93
|
-
:f_ffree, :uint64,
|
94
|
-
:f_fsid, [:int32, 2],
|
95
|
-
:f_owner, :int32,
|
96
|
-
:f_type, :uint32,
|
97
|
-
:f_flags, :uint32,
|
98
|
-
:f_fssubtype, :uint32,
|
99
|
-
:f_fstypename, [:char, 16],
|
100
|
-
:f_mntonname, [:char, 1024],
|
101
|
-
:f_mntfromname, [:char, 1024],
|
102
|
-
:f_reserved, [:uint32, 8]
|
103
|
-
)
|
104
108
|
end
|
105
109
|
end
|
106
110
|
|
107
111
|
# The Statvfs struct represents struct statvfs from sys/statvfs.h.
|
108
112
|
class Statvfs < FFI::Struct
|
113
|
+
# Private method that will determine the layout of the struct on Linux.
|
114
|
+
def self.linux64?
|
115
|
+
if RUBY_PLATFORM == 'java'
|
116
|
+
ENV_JAVA['sun.arch.data.model'].to_i == 64
|
117
|
+
else
|
118
|
+
RbConfig::CONFIG['host_os'] =~ /linux/i &&
|
119
|
+
(RbConfig::CONFIG['arch'] =~ /64/ || RbConfig::CONFIG['DEFS'] =~ /64/)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
109
123
|
if RbConfig::CONFIG['host_os'] =~ /darwin|osx|mach/i
|
110
124
|
layout(
|
111
125
|
:f_bsize, :ulong,
|
@@ -151,7 +165,7 @@ module Sys
|
|
151
165
|
:f_fstr, [:char, 32],
|
152
166
|
:f_filler, [:ulong, 16]
|
153
167
|
)
|
154
|
-
elsif
|
168
|
+
elsif !linux64?
|
155
169
|
layout(
|
156
170
|
:f_bsize, :ulong,
|
157
171
|
:f_frsize, :ulong,
|
@@ -224,7 +224,7 @@ module Sys
|
|
224
224
|
fs = Statvfs.new
|
225
225
|
|
226
226
|
if statvfs(path, fs) < 0
|
227
|
-
raise Error,
|
227
|
+
raise Error, "statvfs() function failed: #{strerror(FFI.errno)}"
|
228
228
|
end
|
229
229
|
|
230
230
|
obj = Sys::Filesystem::Stat.new
|
@@ -275,7 +275,7 @@ module Sys
|
|
275
275
|
num = getmntinfo(buf, 2)
|
276
276
|
|
277
277
|
if num == 0
|
278
|
-
raise Error,
|
278
|
+
raise Error, "getmntinfo() function failed: #{strerror(FFI.errno)}"
|
279
279
|
end
|
280
280
|
|
281
281
|
ptr = buf.get_pointer(0)
|
@@ -419,7 +419,7 @@ module Sys
|
|
419
419
|
#
|
420
420
|
def self.mount(source, target, fstype = 'ext2', flags = 0, data = nil)
|
421
421
|
if mount_c(source, target, fstype, flags, data) != 0
|
422
|
-
raise Error,
|
422
|
+
raise Error, "mount() function failed: #{strerror(FFI.errno)}"
|
423
423
|
end
|
424
424
|
|
425
425
|
self
|
@@ -1,6 +1,9 @@
|
|
1
|
+
# Reopen core Ruby classes here and add some custom methods.
|
1
2
|
class String
|
2
3
|
# Convenience method for converting strings to UTF-16LE for wide character
|
3
4
|
# functions that require it.
|
5
|
+
#--
|
6
|
+
# TODO: Use a refinement.
|
4
7
|
def wincode
|
5
8
|
(tr(File::SEPARATOR, File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE')
|
6
9
|
end
|
@@ -9,7 +9,6 @@ require 'time'
|
|
9
9
|
|
10
10
|
# The Sys module serves as a namespace only.
|
11
11
|
module Sys
|
12
|
-
|
13
12
|
# The Filesystem class encapsulates information about your filesystem.
|
14
13
|
class Filesystem
|
15
14
|
include Sys::Filesystem::Constants
|
@@ -20,6 +19,7 @@ module Sys
|
|
20
19
|
|
21
20
|
private_class_method :new
|
22
21
|
|
22
|
+
# Mount objects are returned by the Sys::Filesystem.mounts method.
|
23
23
|
class Mount
|
24
24
|
# The name of the volume. This is the device mapping.
|
25
25
|
attr_reader :name
|
@@ -50,6 +50,7 @@ module Sys
|
|
50
50
|
alias freq frequency
|
51
51
|
end
|
52
52
|
|
53
|
+
# Stat objects are returned by the Sys::Filesystem.stat method.
|
53
54
|
class Stat
|
54
55
|
# The path of the file system.
|
55
56
|
attr_reader :path
|
@@ -160,6 +161,8 @@ module Sys
|
|
160
161
|
#--
|
161
162
|
# I couldn't really find a good reason to use the wide functions for this
|
162
163
|
# method. If you have one, patches welcome.
|
164
|
+
#--
|
165
|
+
# rubocop:disable Metrics/BlockLength
|
163
166
|
#
|
164
167
|
def self.mounts
|
165
168
|
# First call, get needed buffer size
|
@@ -196,14 +199,14 @@ module Sys
|
|
196
199
|
filesystem_flags = FFI::MemoryPointer.new(:ulong)
|
197
200
|
|
198
201
|
bool = GetVolumeInformationA(
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
202
|
+
drive,
|
203
|
+
volume,
|
204
|
+
volume.size,
|
205
|
+
volume_serial_number,
|
206
|
+
max_component_length,
|
207
|
+
filesystem_flags,
|
208
|
+
fsname,
|
209
|
+
fsname.size
|
207
210
|
)
|
208
211
|
|
209
212
|
# Skip unmounted floppies or cd-roms, or inaccessible drives
|
@@ -237,6 +240,7 @@ module Sys
|
|
237
240
|
|
238
241
|
mounts # Nil if the block form was used.
|
239
242
|
end
|
243
|
+
# rubocop:enable Metrics/BlockLength
|
240
244
|
|
241
245
|
# Returns the mount point for the given +file+. For MS Windows this
|
242
246
|
# means the root of the path.
|
@@ -250,8 +254,6 @@ module Sys
|
|
250
254
|
|
251
255
|
if PathStripToRootW(wfile)
|
252
256
|
wfile.read_string(wfile.size).split("\000\000").first.tr(0.chr, '')
|
253
|
-
else
|
254
|
-
nil
|
255
257
|
end
|
256
258
|
end
|
257
259
|
|
data/lib/sys-filesystem.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rspec'
|
4
|
+
require 'sys_filesystem_shared'
|
2
5
|
|
3
6
|
RSpec.configure do |config|
|
7
|
+
config.include_context(Sys::Filesystem)
|
4
8
|
config.filter_run_excluding(:windows) unless Gem.win_platform?
|
5
9
|
config.filter_run_excluding(:unix) if Gem.win_platform?
|
6
10
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sys-filesystem'
|
4
|
+
|
5
|
+
RSpec.shared_examples Sys::Filesystem do
|
6
|
+
example 'version number is set to the expected value' do
|
7
|
+
expect(Sys::Filesystem::VERSION).to eq('1.4.5')
|
8
|
+
expect(Sys::Filesystem::VERSION).to be_frozen
|
9
|
+
end
|
10
|
+
|
11
|
+
example 'you cannot instantiate an instance' do
|
12
|
+
expect{ described_class.new }.to raise_error(NoMethodError)
|
13
|
+
end
|
14
|
+
end
|