inheritance_integer_type 0.1.2 → 0.2.0
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 +5 -5
- data/.github/workflows/ci.yaml +47 -0
- data/.github/workflows/gem-push.yaml +30 -0
- data/.gitignore +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +13 -0
- data/README.md +8 -6
- data/dev.yml +11 -0
- data/inheritance_integer_type.gemspec +3 -3
- data/lib/inheritance_integer_type/extensions.rb +37 -47
- data/lib/inheritance_integer_type/version.rb +1 -1
- data/lib/inheritance_integer_type.rb +1 -6
- data/overlord.yml +3 -0
- data/spec/inheritance_integer_type_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -3
- data/spec/support/active_record.rb +2 -5
- data/spec/support/base.rb +0 -2
- data/spec/support/migrations/1_create_base_table.rb +1 -1
- data/spec/support/migrations/2_create_belong_to_table.rb +1 -1
- data/spec/support/migrations/3_create_other_table.rb +1 -1
- metadata +19 -16
- data/Gemfile.lock +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5eed88208785bd41ac4e3b7959526aaa500c744d1d00e0914df67fc3d4595e37
|
4
|
+
data.tar.gz: b5309eae3ff8d8b826497ec05390a12b709d3b00fb9e3a6a28be89954b981101
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1bbd3b8a7f178423902628e11598c65352350c0f8c509e484597c003cee66b2decfa8cdb8fba5a0e322330211d71b3069ff99ba455df0edda2778389a28cb3b0
|
7
|
+
data.tar.gz: afba16f3559dc14dd7cae13c8bbdea82a12f9bd0860a6517d0e0971cb0dcf898a3cd3cbdb8530145254c683922c689c7b15791bb54ba58da4d98fe3c5d8daa8e
|
@@ -0,0 +1,47 @@
|
|
1
|
+
---
|
2
|
+
name: CI
|
3
|
+
|
4
|
+
on:
|
5
|
+
workflow_dispatch:
|
6
|
+
pull_request:
|
7
|
+
|
8
|
+
permissions:
|
9
|
+
contents: read
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
test:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
strategy:
|
15
|
+
fail-fast: false
|
16
|
+
matrix:
|
17
|
+
ruby-version:
|
18
|
+
- 3.0
|
19
|
+
- 3.1
|
20
|
+
- 3.2
|
21
|
+
active-record-version:
|
22
|
+
- 6.1.0
|
23
|
+
- 7.0.0
|
24
|
+
- 7.1.0
|
25
|
+
exclude:
|
26
|
+
- ruby-version: 3.2
|
27
|
+
active-record-version: 6.0.0
|
28
|
+
- ruby-version: 3.2
|
29
|
+
active-record-version: 6.1.0
|
30
|
+
- ruby-version: 3.2
|
31
|
+
active-record-version: 7.0.0
|
32
|
+
- ruby-version: 3.1
|
33
|
+
active-record-version: 6.0.0
|
34
|
+
- ruby-version: 3.1
|
35
|
+
active-record-version: 6.1.0
|
36
|
+
- ruby-version: 3.0
|
37
|
+
active-record-version: 6.0.0
|
38
|
+
env:
|
39
|
+
ACTIVE_RECORD_VERSION: "${{ matrix.active-record-version }}"
|
40
|
+
steps:
|
41
|
+
- uses: actions/checkout@v4
|
42
|
+
- uses: ruby/setup-ruby@v1
|
43
|
+
with:
|
44
|
+
ruby-version: "${{ matrix.ruby-version }}"
|
45
|
+
bundler-cache: true
|
46
|
+
- name: Run tests
|
47
|
+
run: bundle exec rspec --format documentation
|
@@ -0,0 +1,30 @@
|
|
1
|
+
name: Ruby Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
release:
|
5
|
+
types: [ published ]
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
build:
|
9
|
+
name: Build + Publish
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
permissions:
|
12
|
+
contents: read
|
13
|
+
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v3
|
16
|
+
- name: Set up Ruby 3.1
|
17
|
+
uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: 3.1
|
20
|
+
|
21
|
+
- name: Publish to RubyGems
|
22
|
+
env:
|
23
|
+
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
|
24
|
+
run: |
|
25
|
+
mkdir -p $HOME/.gem
|
26
|
+
touch $HOME/.gem/credentials
|
27
|
+
chmod 0600 $HOME/.gem/credentials
|
28
|
+
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
29
|
+
gem build *.gemspec
|
30
|
+
gem push *.gem
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.1.4
|
data/Gemfile
CHANGED
@@ -2,3 +2,16 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in inheritance_integer_type.gemspec
|
4
4
|
gemspec
|
5
|
+
|
6
|
+
ar_version = ENV["ACTIVE_RECORD_VERSION"] || "default"
|
7
|
+
|
8
|
+
ar = case ar_version
|
9
|
+
when "master"
|
10
|
+
{ github: "rails/rails" }
|
11
|
+
when "default"
|
12
|
+
">= 6.0"
|
13
|
+
else
|
14
|
+
"~> #{ar_version}"
|
15
|
+
end
|
16
|
+
|
17
|
+
gem "activerecord", ar
|
data/README.md
CHANGED
@@ -22,10 +22,12 @@ class CreateCompanies < ActiveRecord::Migration
|
|
22
22
|
end
|
23
23
|
```
|
24
24
|
|
25
|
-
The problem with this approach is that `type` is a string (and by default it is 255 characters). This is a little ridiculous. For comparison, if we had a state machine with X states, would we describe the states with strings `"State1", "State2", etc` or would we just enumerate the state column and make it an integer? This gem will allow us to use an integer for the `type` column.
|
25
|
+
The problem with this approach is that `type` is a string (and by default it is 255 characters). This is a little ridiculous. For comparison, if we had a state machine with X states, would we describe the states with strings `"State1", "State2", etc` or would we just enumerate the state column and make it an integer? This gem will allow us to use an integer for the `type` column.
|
26
26
|
|
27
27
|
## Installation
|
28
28
|
|
29
|
+
_Current versions of this gem (>= v0.2.0) only support Ruby 3+ and ActiveRecord >= v6.1. For Ruby <= v2.7 or ActiveRecord <= 6.0, use v0.1.3._
|
30
|
+
|
29
31
|
Add this line to your application's Gemfile:
|
30
32
|
|
31
33
|
gem 'inheritance_integer_type'
|
@@ -42,28 +44,28 @@ Or install it yourself as:
|
|
42
44
|
|
43
45
|
The gem is pretty straightforward to use.
|
44
46
|
|
45
|
-
First, set the `integer_inheritance` value on each of the subclasses.
|
47
|
+
First, set the `integer_inheritance` value on each of the subclasses.
|
46
48
|
```ruby
|
47
49
|
class Firm < Company
|
48
50
|
self.integer_inheritance = 1
|
49
51
|
end
|
50
|
-
|
52
|
+
|
51
53
|
class Client < Company
|
52
54
|
self.integer_inheritance = 2
|
53
55
|
end
|
54
|
-
|
56
|
+
|
55
57
|
class PriorityClient < Client
|
56
58
|
self.integer_inheritance = 3
|
57
59
|
end
|
58
60
|
```
|
59
61
|
|
60
62
|
|
61
|
-
Note: The mapping here can start from whatever integer you wish, but I would advise not using 0. The reason being that if you had a new class, for instance `PriorityFirm`, but forgot to include set the mapping, it would effectively get `to_i` called on it and stored in the database. `"Priority".to_i == 0`, so if your mapping included 0, this would create a weird bug.
|
63
|
+
Note: The mapping here can start from whatever integer you wish, but I would advise not using 0. The reason being that if you had a new class, for instance `PriorityFirm`, but forgot to include set the mapping, it would effectively get `to_i` called on it and stored in the database. `"Priority".to_i == 0`, so if your mapping included 0, this would create a weird bug.
|
62
64
|
|
63
65
|
If you want to convert a polymorphic association that is already a string, you'll need to set up a migration. (Assuming SQL for the time being, but this should be pretty straightforward.)
|
64
66
|
```ruby
|
65
67
|
class CompanyToIntegerType < ActiveRecord::Migration
|
66
|
-
|
68
|
+
|
67
69
|
def up
|
68
70
|
change_table :companies do |t|
|
69
71
|
t.integer :new_type
|
data/dev.yml
ADDED
@@ -18,10 +18,10 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_development_dependency "bundler"
|
21
|
+
spec.add_development_dependency "bundler"
|
22
22
|
spec.add_development_dependency "rake"
|
23
23
|
spec.add_development_dependency "rspec"
|
24
|
-
spec.add_development_dependency "activerecord"
|
25
|
-
spec.add_development_dependency "
|
24
|
+
spec.add_development_dependency "activerecord", ">= 5.2"
|
25
|
+
spec.add_development_dependency "sqlite3", "~> 1.4"
|
26
26
|
spec.add_development_dependency "pry"
|
27
27
|
end
|
@@ -1,63 +1,53 @@
|
|
1
1
|
module InheritanceIntegerType
|
2
2
|
module Extensions
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
self._inheritance_mapping[val] = sti_name_without_integer_types
|
8
|
-
end
|
3
|
+
def sti_name
|
4
|
+
klass = super
|
5
|
+
self._inheritance_mapping.key(klass) || klass
|
6
|
+
end
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
rescue NameError
|
23
|
-
raise SubclassNotFound,
|
24
|
-
"The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " +
|
25
|
-
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
|
26
|
-
"Please rename this column if you didn't intend it to be used for storing the inheritance class " +
|
27
|
-
"or overwrite #{name}.inheritance_column to use another column for that information."
|
8
|
+
def find_sti_class(type_name)
|
9
|
+
lookup = self._inheritance_mapping[type_name.to_i]
|
10
|
+
if lookup
|
11
|
+
if ActiveRecord::VERSION::MAJOR < 5
|
12
|
+
super(lookup)
|
13
|
+
else
|
14
|
+
begin
|
15
|
+
if store_full_sti_class
|
16
|
+
lookup.constantize
|
17
|
+
else
|
18
|
+
compute_type(lookup)
|
28
19
|
end
|
20
|
+
rescue NameError
|
21
|
+
raise SubclassNotFound,
|
22
|
+
"The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " +
|
23
|
+
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
|
24
|
+
"Please rename this column if you didn't intend it to be used for storing the inheritance class " +
|
25
|
+
"or overwrite #{name}.inheritance_column to use another column for that information."
|
29
26
|
end
|
30
|
-
else
|
31
|
-
super
|
32
27
|
end
|
33
|
-
|
34
|
-
|
35
|
-
def sti_name_with_integer_types
|
36
|
-
klass = sti_name_without_integer_types
|
37
|
-
self._inheritance_mapping.key(klass) || klass
|
28
|
+
else
|
29
|
+
super
|
38
30
|
end
|
39
31
|
end
|
40
32
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@_inheritance_mapping ||= (superclass == ActiveRecord::Base ? {} : superclass._inheritance_mapping.dup)
|
45
|
-
end
|
33
|
+
def integer_inheritance=(val)
|
34
|
+
self._inheritance_mapping[val] = method(:sti_name).super_method.call
|
35
|
+
end
|
46
36
|
|
47
|
-
|
48
|
-
|
49
|
-
|
37
|
+
def _inheritance_mapping
|
38
|
+
@_inheritance_mapping ||= (superclass == ActiveRecord::Base ? {} : superclass._inheritance_mapping.dup)
|
39
|
+
end
|
50
40
|
|
51
|
-
|
52
|
-
|
53
|
-
|
41
|
+
def _inheritance_mapping=(val)
|
42
|
+
@_inheritance_mapping = val
|
43
|
+
end
|
54
44
|
|
55
|
-
|
56
|
-
|
45
|
+
def merge_mapping!(mapping)
|
46
|
+
conflicts = _inheritance_mapping.keys & mapping.keys
|
47
|
+
raise ArgumentError.new("Duplicate mapping detected for keys: #{conflicts}") if conflicts.any?
|
57
48
|
|
58
|
-
|
59
|
-
end
|
49
|
+
_inheritance_mapping.merge!(mapping)
|
60
50
|
end
|
61
|
-
|
62
51
|
end
|
52
|
+
|
63
53
|
end
|
@@ -2,10 +2,5 @@ require "inheritance_integer_type/version"
|
|
2
2
|
require "inheritance_integer_type/extensions"
|
3
3
|
|
4
4
|
class ActiveRecord::Base
|
5
|
-
|
6
|
-
def self.inherited(child_class)
|
7
|
-
child_class.include InheritanceIntegerType::Extensions
|
8
|
-
super
|
9
|
-
end
|
10
|
-
|
5
|
+
singleton_class.prepend(InheritanceIntegerType::Extensions)
|
11
6
|
end
|
data/overlord.yml
ADDED
@@ -48,7 +48,7 @@ describe InheritanceIntegerType do
|
|
48
48
|
describe "Has many associations" do
|
49
49
|
let(:other) { Other.create }
|
50
50
|
before do
|
51
|
-
[base, left, deep].each{|a| a.
|
51
|
+
[base, left, deep].each{|a| a.update_attribute(:other, other) }
|
52
52
|
end
|
53
53
|
subject { other }
|
54
54
|
it "properly finds the classes through the association" do
|
data/spec/spec_helper.rb
CHANGED
@@ -8,9 +8,8 @@ require 'support/other'
|
|
8
8
|
require 'support/belongs_to'
|
9
9
|
|
10
10
|
RSpec.configure do |config|
|
11
|
-
|
12
11
|
config.before(:suite) do
|
13
|
-
ActiveRecord::
|
12
|
+
ActiveRecord::MigrationContext.new("#{File.dirname(__FILE__)}/support/migrations", ::ActiveRecord::SchemaMigration).migrate
|
14
13
|
end
|
15
14
|
|
16
15
|
# No need to return the run the down migration after the test
|
@@ -19,7 +18,6 @@ RSpec.configure do |config|
|
|
19
18
|
# ActiveRecord::Migrator.down "#{File.dirname(__FILE__)}/support/migrations"
|
20
19
|
# end
|
21
20
|
|
22
|
-
|
23
21
|
config.around do |example|
|
24
22
|
ActiveRecord::Base.transaction do
|
25
23
|
example.run
|
@@ -2,10 +2,7 @@ require 'active_record'
|
|
2
2
|
Dir["#{File.dirname(__FILE__)}/migrations/*.rb"].each {|f| require f}
|
3
3
|
|
4
4
|
config = {
|
5
|
-
:adapter => "
|
6
|
-
:
|
7
|
-
:database => "inheritance_integer_type_test",
|
8
|
-
:username => "iit",
|
9
|
-
:password => ""
|
5
|
+
:adapter => "sqlite3",
|
6
|
+
:database => ":memory:",
|
10
7
|
}
|
11
8
|
ActiveRecord::Base.establish_connection(config)
|
data/spec/support/base.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inheritance_integer_type
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kyle d'Oliveira
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,28 +58,28 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '5.2'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '5.2'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: sqlite3
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: '1.4'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: '1.4'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: pry
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,17 +102,21 @@ executables: []
|
|
102
102
|
extensions: []
|
103
103
|
extra_rdoc_files: []
|
104
104
|
files:
|
105
|
+
- ".github/workflows/ci.yaml"
|
106
|
+
- ".github/workflows/gem-push.yaml"
|
105
107
|
- ".gitignore"
|
108
|
+
- ".ruby-version"
|
106
109
|
- Gemfile
|
107
|
-
- Gemfile.lock
|
108
110
|
- LICENSE
|
109
111
|
- LICENSE.txt
|
110
112
|
- README.md
|
111
113
|
- Rakefile
|
114
|
+
- dev.yml
|
112
115
|
- inheritance_integer_type.gemspec
|
113
116
|
- lib/inheritance_integer_type.rb
|
114
117
|
- lib/inheritance_integer_type/extensions.rb
|
115
118
|
- lib/inheritance_integer_type/version.rb
|
119
|
+
- overlord.yml
|
116
120
|
- spec/inheritance_integer_type_spec.rb
|
117
121
|
- spec/spec_helper.rb
|
118
122
|
- spec/spec_helper~
|
@@ -145,8 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
149
|
- !ruby/object:Gem::Version
|
146
150
|
version: '0'
|
147
151
|
requirements: []
|
148
|
-
|
149
|
-
rubygems_version: 2.5.2
|
152
|
+
rubygems_version: 3.3.27
|
150
153
|
signing_key:
|
151
154
|
specification_version: 4
|
152
155
|
summary: Allow the type field in teh DB to be an integer rather than a string
|
data/Gemfile.lock
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
inheritance_integer_type (0.1.2)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
activemodel (3.2.11)
|
10
|
-
activesupport (= 3.2.11)
|
11
|
-
builder (~> 3.0.0)
|
12
|
-
activerecord (3.2.11)
|
13
|
-
activemodel (= 3.2.11)
|
14
|
-
activesupport (= 3.2.11)
|
15
|
-
arel (~> 3.0.2)
|
16
|
-
tzinfo (~> 0.3.29)
|
17
|
-
activesupport (3.2.11)
|
18
|
-
i18n (~> 0.6)
|
19
|
-
multi_json (~> 1.0)
|
20
|
-
arel (3.0.3)
|
21
|
-
builder (3.0.4)
|
22
|
-
coderay (1.1.2)
|
23
|
-
diff-lcs (1.2.5)
|
24
|
-
i18n (0.6.9)
|
25
|
-
method_source (0.9.0)
|
26
|
-
multi_json (1.10.1)
|
27
|
-
mysql2 (0.3.18)
|
28
|
-
pry (0.11.3)
|
29
|
-
coderay (~> 1.1.0)
|
30
|
-
method_source (~> 0.9.0)
|
31
|
-
rake (10.3.2)
|
32
|
-
rspec (3.0.0)
|
33
|
-
rspec-core (~> 3.0.0)
|
34
|
-
rspec-expectations (~> 3.0.0)
|
35
|
-
rspec-mocks (~> 3.0.0)
|
36
|
-
rspec-core (3.0.0)
|
37
|
-
rspec-support (~> 3.0.0)
|
38
|
-
rspec-expectations (3.0.0)
|
39
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
40
|
-
rspec-support (~> 3.0.0)
|
41
|
-
rspec-mocks (3.0.1)
|
42
|
-
rspec-support (~> 3.0.0)
|
43
|
-
rspec-support (3.0.0)
|
44
|
-
tzinfo (0.3.39)
|
45
|
-
|
46
|
-
PLATFORMS
|
47
|
-
ruby
|
48
|
-
|
49
|
-
DEPENDENCIES
|
50
|
-
activerecord
|
51
|
-
bundler (~> 1.6)
|
52
|
-
inheritance_integer_type!
|
53
|
-
mysql2 (= 0.3.18)
|
54
|
-
pry
|
55
|
-
rake
|
56
|
-
rspec
|
57
|
-
|
58
|
-
BUNDLED WITH
|
59
|
-
1.16.1
|