rapidfire 2.1.0 → 3.0.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 +4 -4
- data/README.md +28 -13
- data/app/controllers/rapidfire/attempts_controller.rb +29 -0
- data/app/controllers/rapidfire/questions_controller.rb +35 -34
- data/app/controllers/rapidfire/surveys_controller.rb +60 -0
- data/app/models/rapidfire/answer.rb +3 -3
- data/app/models/rapidfire/attempt.rb +11 -0
- data/app/models/rapidfire/question.rb +3 -3
- data/app/models/rapidfire/{question_group.rb → survey.rb} +1 -1
- data/app/services/rapidfire/{answer_group_builder.rb → attempt_builder.rb} +12 -12
- data/app/services/rapidfire/base_service.rb +1 -1
- data/app/services/rapidfire/question_form.rb +4 -4
- data/app/services/rapidfire/{question_group_results.rb → survey_results.rb} +3 -3
- data/app/views/rapidfire/{answer_groups → attempts}/new.html.erb +2 -2
- data/app/views/rapidfire/questions/_question.html.erb +2 -2
- data/app/views/rapidfire/questions/edit.html.erb +1 -1
- data/app/views/rapidfire/questions/index.html.erb +1 -1
- data/app/views/rapidfire/questions/new.html.erb +1 -1
- data/app/views/rapidfire/surveys/_form.html.erb +15 -0
- data/app/views/rapidfire/surveys/_survey.html.erb +18 -0
- data/app/views/rapidfire/{question_groups → surveys}/index.html.erb +4 -4
- data/app/views/rapidfire/surveys/new.html.erb +1 -0
- data/app/views/rapidfire/{question_groups → surveys}/results.html.erb +1 -1
- data/config/routes.rb +3 -3
- data/db/migrate/20130502170733_create_rapidfire_question_groups.rb +1 -1
- data/db/migrate/20130502195310_create_rapidfire_questions.rb +2 -2
- data/db/migrate/20130502195415_create_rapidfire_answer_groups.rb +4 -4
- data/db/migrate/20130502195504_create_rapidfire_answers.rb +2 -2
- data/lib/generators/rapidfire/templates/migrations/rename_answer_groups_and_question_groups.rb +9 -0
- data/lib/generators/rapidfire/upgrade_migration_generator.rb +18 -0
- data/lib/generators/rapidfire/views_generator.rb +4 -4
- data/lib/rapidfire/version.rb +1 -1
- data/lib/tasks/rapidfire.rake +10 -0
- data/spec/controllers/rapidfire/attempts_controller_spec.rb +20 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +11 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +61 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +72 -0
- data/spec/dummy/config/environments/test.rb +41 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +8 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +4 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +53 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +394 -0
- data/spec/dummy/log/test.log +2380 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/factories/answers_factory.rb +7 -0
- data/spec/factories/attempts_factory.rb +5 -0
- data/spec/factories/questions_factory.rb +30 -0
- data/spec/factories/surveys_factory.rb +5 -0
- data/spec/features/rapidfire/answering_questions_spec.rb +55 -0
- data/spec/features/rapidfire/managing_questions_spec.rb +95 -0
- data/spec/features/rapidfire/managing_surveys_spec.rb +141 -0
- data/spec/models/rapidfire/answer_spec.rb +23 -0
- data/spec/models/rapidfire/attempt_spec.rb +9 -0
- data/spec/models/rapidfire/question_spec.rb +123 -0
- data/spec/models/rapidfire/questions/checkbox_spec.rb +90 -0
- data/spec/models/rapidfire/questions/date_spec.rb +78 -0
- data/spec/models/rapidfire/questions/numeric_spec.rb +114 -0
- data/spec/models/rapidfire/questions/select_spec.rb +90 -0
- data/spec/models/rapidfire/survey_spec.rb +11 -0
- data/spec/serializers/rapidfire/question_result_serializer_spec.rb +44 -0
- data/spec/services/rapidfire/attempt_builder_spec.rb +88 -0
- data/spec/services/rapidfire/question_form_spec.rb +93 -0
- data/spec/services/rapidfire/survey_results_spec.rb +63 -0
- data/spec/spec_helper.rb +68 -0
- data/spec/support/rapidfire/answer_spec_helper.rb +23 -0
- data/spec/support/rapidfire/question_spec_helper.rb +13 -0
- data/spec/tasks/change_delimiter_from_comma_to_srsn_spec.rb +31 -0
- metadata +133 -30
- data/app/controllers/rapidfire/answer_groups_controller.rb +0 -29
- data/app/controllers/rapidfire/question_groups_controller.rb +0 -59
- data/app/models/rapidfire/answer_group.rb +0 -11
- data/app/views/rapidfire/question_groups/_form.html.erb +0 -15
- data/app/views/rapidfire/question_groups/_question_group.html.erb +0 -18
- data/app/views/rapidfire/question_groups/new.html.erb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27b98c4be749e5dd26dc5021426543880ad344c8
|
4
|
+
data.tar.gz: 70dd426049dce2c447d567ccf25b1206201e32ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 394966bd048f4932b06c9a7a222f88a1754a85275591c2ab38397bea7d318b1a9ff9bf27ad78f2924592dec81c194fb57db34df01fa235ec2122b1055cba6787
|
7
|
+
data.tar.gz: 95c9d6b0eb5c44d854699fb3b3a64d0f44ab81935f5b2c8916fa4773220e6bfc3155e9cb7f1be29e80178d341d8453874d69c75b6d6b0330f3018e2376e8a992
|
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# Rapidfire
|
2
|
-
[](https://codeclimate.com/github/code-mancers/rapidfire)
|
3
3
|
[](https://travis-ci.org/code-mancers/rapidfire)
|
4
4
|
|
5
5
|
One stop solution for all survey related requirements! Its tad easy!
|
6
6
|
|
7
|
-
This gem supports
|
7
|
+
This gem supports **rails 3.2.13+**, **rails4** and **rails5** versions.
|
8
8
|
|
9
9
|
You can see a demo of this gem [here](https://rapidfire.herokuapp.com).
|
10
10
|
And the source code of demo [here](https://github.com/code-mancers/rapidfire-demo).
|
@@ -12,13 +12,17 @@ And the source code of demo [here](https://github.com/code-mancers/rapidfire-dem
|
|
12
12
|
## Installation
|
13
13
|
Add this line to your application's Gemfile:
|
14
14
|
|
15
|
+
```rb
|
15
16
|
gem 'rapidfire'
|
17
|
+
```
|
16
18
|
|
17
19
|
And then execute:
|
18
20
|
|
21
|
+
```shell
|
19
22
|
$ bundle install
|
20
23
|
$ bundle exec rake rapidfire:install:migrations
|
21
24
|
$ bundle exec rake db:migrate
|
25
|
+
```
|
22
26
|
|
23
27
|
And if you want to customize rapidfire views, you can do
|
24
28
|
|
@@ -28,7 +32,9 @@ And if you want to customize rapidfire views, you can do
|
|
28
32
|
|
29
33
|
Add this line to your routes will and you will be good to go!
|
30
34
|
|
35
|
+
```rb
|
31
36
|
mount Rapidfire::Engine => "/rapidfire"
|
37
|
+
```
|
32
38
|
|
33
39
|
And point your browser to [http://localhost:3000/rapidfire](http://localhost:3000/rapidfire)
|
34
40
|
|
@@ -41,7 +47,7 @@ methods `current_user` and `can_administer?` on your `ApplicationController`
|
|
41
47
|
|
42
48
|
Typical implementation would be:
|
43
49
|
|
44
|
-
```
|
50
|
+
```rb
|
45
51
|
class ApplicationController < ActionController::Base
|
46
52
|
def current_user
|
47
53
|
@current_user ||= User.find(session[:user_id])
|
@@ -66,7 +72,7 @@ You can see them by running `bundle exec rake routes`.
|
|
66
72
|
2. Optionally, each survey can by answered by visiting this path:
|
67
73
|
|
68
74
|
```
|
69
|
-
localhost:3000/rapidfire/
|
75
|
+
localhost:3000/rapidfire/surveys/<survey-id>/answer_groups/new
|
70
76
|
```
|
71
77
|
|
72
78
|
You can distribute this url so that survey takers can answer a particular survey
|
@@ -76,7 +82,7 @@ You can see them by running `bundle exec rake routes`.
|
|
76
82
|
A new api is released which helps in seeing results for each survey. The api is:
|
77
83
|
|
78
84
|
```
|
79
|
-
GET /rapidfire/
|
85
|
+
GET /rapidfire/surveys/<survey-id>/results
|
80
86
|
```
|
81
87
|
This new api supports two formats: `html` and `json`. The `json` format is supported
|
82
88
|
so that end user can use any javascript based chart solutions and render results
|
@@ -179,13 +185,22 @@ The typical flow about how to use this gem is:
|
|
179
185
|
is validated with these values.
|
180
186
|
|
181
187
|
5. Once the questions are populated, you can return to root_path ie by clicking
|
182
|
-
`
|
188
|
+
`Surveys` and share distribute answer url so that others can answer
|
183
189
|
the questions populated.
|
184
190
|
6. Note that answers fail to persist of the criteria that you have provided while
|
185
191
|
creating questions fail.
|
186
192
|
|
187
193
|
|
188
194
|
## Notes on upgrading
|
195
|
+
|
196
|
+
##### Upgrading from 2.1.0 to 3.0.0
|
197
|
+
|
198
|
+
If you are upgrading you need to rename your `rapidfire_question_groups` to `rapidfire_surveys` and `rapidfire_answer_groups` to `rapidfire_attempts`. Run the given task to do that for you.
|
199
|
+
|
200
|
+
```shell
|
201
|
+
$ rake rapidfire:upgrade:migrations:from210to300
|
202
|
+
```
|
203
|
+
|
189
204
|
##### Upgrading from 1.2.0 to 2.0.0
|
190
205
|
|
191
206
|
The default delimiter which is used to store options for questions like select
|
@@ -199,7 +214,8 @@ to make existing questions or stored answers to use new delimiter.
|
|
199
214
|
|
200
215
|
NOTE: Please take database backup before running this rake task.
|
201
216
|
|
202
|
-
```
|
217
|
+
```rb
|
218
|
+
bundle exec rake rapidfire:change_delimiter_from_comma_to_srsn
|
203
219
|
bundle exec rake rapidfire:change_delimiter_from_comma_to_srsn
|
204
220
|
```
|
205
221
|
|
@@ -209,19 +225,18 @@ as delimiter, then please use this initializer, but be warned that in future
|
|
209
225
|
delimiter will be hardcoded to `\r\n`:
|
210
226
|
|
211
227
|
|
212
|
-
```
|
213
|
-
# /<path-to-app>/config/initializers/rapidfire.rb
|
228
|
+
```rb
|
229
|
+
# /<path-to-app>/config/initializers/rapidfire.rb
|
214
230
|
|
215
|
-
Rapidfire.config do |config|
|
216
|
-
|
217
|
-
end
|
231
|
+
Rapidfire.config do |config|
|
232
|
+
config.answers_delimiter = ','
|
233
|
+
end
|
218
234
|
```
|
219
235
|
|
220
236
|
|
221
237
|
## TODO
|
222
238
|
1. Add ability to sort questions, so that order is preserved.
|
223
239
|
2. Add multi tenant support.
|
224
|
-
3. Rename question-groups to surveys, and change routes accordingly.
|
225
240
|
|
226
241
|
## Contributing
|
227
242
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rapidfire
|
2
|
+
class AttemptsController < Rapidfire::ApplicationController
|
3
|
+
before_filter :find_survey!
|
4
|
+
|
5
|
+
def new
|
6
|
+
@attempt_builder = AttemptBuilder.new(attempt_params)
|
7
|
+
end
|
8
|
+
|
9
|
+
def create
|
10
|
+
@attempt_builder = AttemptBuilder.new(attempt_params)
|
11
|
+
|
12
|
+
if @attempt_builder.save
|
13
|
+
redirect_to surveys_path
|
14
|
+
else
|
15
|
+
render :new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def find_survey!
|
21
|
+
@survey = Survey.find(params[:survey_id])
|
22
|
+
end
|
23
|
+
|
24
|
+
def attempt_params
|
25
|
+
answer_params = { params: (params[:attempt] || {}) }
|
26
|
+
answer_params.merge(user: current_user, survey: @survey)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -2,33 +2,21 @@ module Rapidfire
|
|
2
2
|
class QuestionsController < Rapidfire::ApplicationController
|
3
3
|
before_filter :authenticate_administrator!
|
4
4
|
|
5
|
-
before_filter :
|
5
|
+
before_filter :find_survey!
|
6
6
|
before_filter :find_question!, :only => [:edit, :update, :destroy]
|
7
7
|
|
8
8
|
def index
|
9
|
-
@questions = @
|
9
|
+
@questions = @survey.questions
|
10
10
|
end
|
11
11
|
|
12
12
|
def new
|
13
|
-
@question_form = QuestionForm.new(:
|
13
|
+
@question_form = QuestionForm.new(:survey => @survey)
|
14
14
|
end
|
15
15
|
|
16
16
|
def create
|
17
|
-
form_params =
|
18
|
-
@question_form = QuestionForm.new(form_params)
|
19
|
-
@question_form.save
|
17
|
+
form_params = question_params.merge(:survey => @survey)
|
20
18
|
|
21
|
-
|
22
|
-
respond_to do |format|
|
23
|
-
format.html { redirect_to index_location }
|
24
|
-
format.js
|
25
|
-
end
|
26
|
-
else
|
27
|
-
respond_to do |format|
|
28
|
-
format.html { render :new }
|
29
|
-
format.js
|
30
|
-
end
|
31
|
-
end
|
19
|
+
save_and_redirect(form_params, :new)
|
32
20
|
end
|
33
21
|
|
34
22
|
def edit
|
@@ -36,8 +24,23 @@ module Rapidfire
|
|
36
24
|
end
|
37
25
|
|
38
26
|
def update
|
39
|
-
form_params =
|
40
|
-
|
27
|
+
form_params = question_params.merge(:question => @question)
|
28
|
+
|
29
|
+
save_and_redirect(form_params, :edit)
|
30
|
+
end
|
31
|
+
|
32
|
+
def destroy
|
33
|
+
@question.destroy
|
34
|
+
respond_to do |format|
|
35
|
+
format.html { redirect_to index_location }
|
36
|
+
format.js
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def save_and_redirect(params, on_error_key)
|
43
|
+
@question_form = QuestionForm.new(params)
|
41
44
|
@question_form.save
|
42
45
|
|
43
46
|
if @question_form.errors.empty?
|
@@ -47,32 +50,30 @@ module Rapidfire
|
|
47
50
|
end
|
48
51
|
else
|
49
52
|
respond_to do |format|
|
50
|
-
format.html { render
|
53
|
+
format.html { render on_error_key.to_sym }
|
51
54
|
format.js
|
52
55
|
end
|
53
56
|
end
|
54
57
|
end
|
55
58
|
|
56
|
-
def
|
57
|
-
@
|
58
|
-
respond_to do |format|
|
59
|
-
format.html { redirect_to index_location }
|
60
|
-
format.js
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def find_question_group!
|
67
|
-
@question_group = QuestionGroup.find(params[:question_group_id])
|
59
|
+
def find_survey!
|
60
|
+
@survey = Survey.find(params[:survey_id])
|
68
61
|
end
|
69
62
|
|
70
63
|
def find_question!
|
71
|
-
@question = @
|
64
|
+
@question = @survey.questions.find(params[:id])
|
72
65
|
end
|
73
66
|
|
74
67
|
def index_location
|
75
|
-
rapidfire.
|
68
|
+
rapidfire.survey_questions_url(@survey)
|
69
|
+
end
|
70
|
+
|
71
|
+
def question_params
|
72
|
+
if Rails::VERSION::MAJOR == 4 || Rails::VERSION::MAJOR == 5
|
73
|
+
params.require(:question).permit!
|
74
|
+
else
|
75
|
+
params[:question]
|
76
|
+
end
|
76
77
|
end
|
77
78
|
end
|
78
79
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Rapidfire
|
2
|
+
class SurveysController < Rapidfire::ApplicationController
|
3
|
+
before_filter :authenticate_administrator!, except: :index
|
4
|
+
|
5
|
+
def index
|
6
|
+
@surveys = Survey.all
|
7
|
+
end
|
8
|
+
|
9
|
+
def new
|
10
|
+
@survey = Survey.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
@survey = Survey.new(survey_params)
|
15
|
+
if @survey.save
|
16
|
+
respond_to do |format|
|
17
|
+
format.html { redirect_to surveys_path }
|
18
|
+
format.js
|
19
|
+
end
|
20
|
+
else
|
21
|
+
respond_to do |format|
|
22
|
+
format.html { render :new }
|
23
|
+
format.js
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def destroy
|
29
|
+
@survey = Survey.find(params[:id])
|
30
|
+
@survey.destroy
|
31
|
+
|
32
|
+
respond_to do |format|
|
33
|
+
format.html { redirect_to surveys_path }
|
34
|
+
format.js
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def results
|
39
|
+
@survey = Survey.find(params[:id])
|
40
|
+
@survey_results =
|
41
|
+
SurveyResults.new(survey: @survey).extract
|
42
|
+
|
43
|
+
respond_to do |format|
|
44
|
+
format.json { render json: @survey_results, root: false }
|
45
|
+
format.html
|
46
|
+
format.js
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def survey_params
|
53
|
+
if Rails::VERSION::MAJOR >= 4
|
54
|
+
params.require(:survey).permit(:name)
|
55
|
+
else
|
56
|
+
params[:survey]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module Rapidfire
|
2
2
|
class Answer < ActiveRecord::Base
|
3
3
|
belongs_to :question
|
4
|
-
belongs_to :
|
4
|
+
belongs_to :attempt, inverse_of: :answers
|
5
5
|
|
6
|
-
validates :question, :
|
6
|
+
validates :question, :attempt, presence: true
|
7
7
|
validate :verify_answer_text, :if => "question.present?"
|
8
8
|
|
9
9
|
if Rails::VERSION::MAJOR == 3
|
10
|
-
attr_accessible :question_id, :
|
10
|
+
attr_accessible :question_id, :attempt, :answer_text
|
11
11
|
end
|
12
12
|
|
13
13
|
private
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module Rapidfire
|
2
2
|
class Question < ActiveRecord::Base
|
3
|
-
belongs_to :
|
3
|
+
belongs_to :survey, :inverse_of => :questions
|
4
4
|
has_many :answers
|
5
5
|
|
6
6
|
default_scope { order(:position) }
|
7
7
|
|
8
|
-
validates :
|
8
|
+
validates :survey, :question_text, :presence => true
|
9
9
|
serialize :validation_rules
|
10
10
|
|
11
11
|
if Rails::VERSION::MAJOR == 3
|
12
|
-
attr_accessible :
|
12
|
+
attr_accessible :survey, :question_text, :validation_rules, :answer_options
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.inherited(child)
|
@@ -1,19 +1,19 @@
|
|
1
1
|
module Rapidfire
|
2
|
-
class
|
3
|
-
attr_accessor :user, :
|
2
|
+
class AttemptBuilder < Rapidfire::BaseService
|
3
|
+
attr_accessor :user, :survey, :questions, :answers, :params
|
4
4
|
|
5
5
|
def initialize(params = {})
|
6
6
|
super(params)
|
7
|
-
|
7
|
+
build_attempt
|
8
8
|
end
|
9
9
|
|
10
10
|
def to_model
|
11
|
-
@
|
11
|
+
@attempt
|
12
12
|
end
|
13
13
|
|
14
14
|
def save!(options = {})
|
15
15
|
params.each do |question_id, answer_attributes|
|
16
|
-
if answer = @
|
16
|
+
if answer = @attempt.answers.find { |a| a.question_id.to_s == question_id.to_s }
|
17
17
|
text = answer_attributes[:answer_text]
|
18
18
|
|
19
19
|
# in case of checkboxes, values are submitted as an array of
|
@@ -29,24 +29,24 @@ module Rapidfire
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
@
|
32
|
+
@attempt.save!(options)
|
33
33
|
end
|
34
34
|
|
35
35
|
def save(options = {})
|
36
36
|
save!(options)
|
37
37
|
rescue ActiveRecord::ActiveRecordError => e
|
38
38
|
# repopulate answers here in case of failure as they are not getting updated
|
39
|
-
@answers = @
|
40
|
-
@
|
39
|
+
@answers = @survey.questions.collect do |question|
|
40
|
+
@attempt.answers.find { |a| a.question_id == question.id }
|
41
41
|
end
|
42
42
|
false
|
43
43
|
end
|
44
44
|
|
45
45
|
private
|
46
|
-
def
|
47
|
-
@
|
48
|
-
@answers = @
|
49
|
-
@
|
46
|
+
def build_attempt
|
47
|
+
@attempt = Attempt.new(user: user, survey: survey)
|
48
|
+
@answers = @survey.questions.collect do |question|
|
49
|
+
@attempt.answers.build(question_id: question.id)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|