artfully_ose 1.2.0.pre.27 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +4 -6
- data/app/assets/javascripts/application.js +39 -0
- data/app/assets/javascripts/boxoffice.js +558 -0
- data/app/assets/javascripts/custom/kits-config.js +33 -0
- data/app/assets/javascripts/sales-console.js +29 -24
- data/app/assets/javascripts/store/store.js +11 -0
- data/app/assets/stylesheets/application.sass +66 -52
- data/app/assets/stylesheets/bootstrap-overrides.css +1 -1
- data/app/assets/stylesheets/boxoffice.css.scss +258 -0
- data/app/assets/stylesheets/pages/bootstrap-responsive.css +1109 -0
- data/app/assets/stylesheets/sass/store.sass +52 -62
- data/app/assets/stylesheets/storefront.css +1 -1
- data/app/concerns/itemable.rb +1 -1
- data/app/concerns/pdf_generation.rb +1 -11
- data/app/concerns/search_by_dates.rb +20 -0
- data/app/controllers/events_controller.rb +1 -0
- data/app/controllers/export_controller.rb +11 -1
- data/app/controllers/imports_controller.rb +2 -3
- data/app/controllers/member_cards_controller.rb +2 -3
- data/app/controllers/orders_controller.rb +42 -0
- data/app/controllers/organizations_controller.rb +1 -0
- data/app/controllers/passes_reports_controller.rb +21 -1
- data/app/controllers/regular_donation_kits_controller.rb +32 -0
- data/app/controllers/store/donations_controller.rb +19 -1
- data/app/controllers/store/orders_controller.rb +15 -5
- data/app/helpers/artfully_ose_helper.rb +28 -18
- data/app/models/database_views/item_view.rb +41 -0
- data/app/models/event.rb +10 -2
- data/app/models/ext/integrations.rb +5 -0
- data/app/models/fee_strategy.rb +47 -1
- data/app/models/imports/events_import.rb +6 -7
- data/app/models/item.rb +4 -3
- data/app/models/job/order_processor.rb +4 -3
- data/app/models/kit.rb +18 -0
- data/app/models/kits/regular_donation_kit.rb +51 -9
- data/app/models/member.rb +4 -3
- data/app/models/membership.rb +1 -2
- data/app/models/membership_sale_search.rb +2 -20
- data/app/models/membership_type.rb +1 -2
- data/app/models/order.rb +29 -1
- data/app/models/order_handler.rb +4 -3
- data/app/models/organization.rb +17 -9
- data/app/models/pass.rb +18 -17
- data/app/models/pass_sale_search.rb +18 -0
- data/app/models/pass_type.rb +7 -2
- data/app/models/passes_report.rb +117 -0
- data/app/models/sale_search.rb +3 -21
- data/app/models/user.rb +1 -2
- data/app/serializers/show_serializer.rb +15 -0
- data/app/views/contributions/index.html.haml +2 -2
- data/app/views/events/_header.html.haml +1 -0
- data/app/views/events/_ticket_type_fields.html.haml +31 -15
- data/app/views/events/edit.html.haml +6 -1
- data/app/views/imports/_export_links.html.haml +3 -0
- data/app/views/imports/donations/_pending.html.haml +24 -6
- data/app/views/imports/events/_pending.html.haml +16 -5
- data/app/views/imports/index.html.haml +6 -4
- data/app/views/imports/people/_pending.html.haml +20 -25
- data/app/views/layouts/storefront.html.haml +9 -5
- data/app/views/order_mailer/confirmation_for.html.haml +11 -5
- data/app/views/order_mailer/confirmation_for_refund.html.haml +6 -2
- data/app/views/order_mailer/confirmation_for_refund.text.haml +4 -3
- data/app/views/orders/membership.html.haml +15 -19
- data/app/views/orders/passes.html.haml +97 -0
- data/app/views/orders/sales.html.haml +2 -2
- data/app/views/organizations/_form.html.haml +4 -37
- data/app/views/pass_types/index.html.haml +1 -1
- data/app/views/passes_reports/index.html.haml +79 -1
- data/app/views/people/show.html.haml +16 -15
- data/app/views/regular_donation_kits/edit.html.haml +140 -0
- data/app/views/store/checkouts/thanks.html.haml +14 -6
- data/app/views/store/donations/index.html.haml +19 -2
- data/app/views/store/events/calendar.html.haml +1 -0
- data/app/views/store/events/index.html.haml +1 -0
- data/app/views/store/events/show.html.haml +1 -0
- data/app/views/store/events/single_show.html.haml +2 -0
- data/app/views/store/orders/show.html.haml +10 -10
- data/app/views/store/passes/index.html.haml +2 -2
- data/app/views/store/shared/_donate_form.html.haml +31 -12
- data/app/views/store/shared/_small_donate_form.html.haml +22 -0
- data/app/views/users/invitations/edit.html.haml +3 -42
- data/config/locales/en.yml +3 -1
- data/config/routes.rb +4 -1
- data/db/migrate/20140603200735_add_subtitle_to_events.rb +5 -0
- data/lib/artfully_ose/version.rb +1 -1
- data/spec/factories/kit_factories.rb +5 -4
- metadata +25 -13
- data/app/assets/javascripts/box-office.js +0 -262
@@ -123,8 +123,6 @@ h4
|
|
123
123
|
img#logo
|
124
124
|
float: left
|
125
125
|
margin-right: 10px
|
126
|
-
|
127
|
-
h1#logo
|
128
126
|
|
129
127
|
ul#shows, ul#memberships
|
130
128
|
clear: both
|
@@ -230,56 +228,6 @@ table.calendar
|
|
230
228
|
#shopping-cart
|
231
229
|
width: auto
|
232
230
|
background-color: #e6e6e6 !important
|
233
|
-
#steps
|
234
|
-
display: none
|
235
|
-
position: static
|
236
|
-
background: #fff
|
237
|
-
position: static
|
238
|
-
width: 650px
|
239
|
-
margin: 0px auto
|
240
|
-
padding: 50px
|
241
|
-
padding-top: 10px
|
242
|
-
padding-bottom: 0
|
243
|
-
height: 380px
|
244
|
-
overflow: auto
|
245
|
-
ul#nav
|
246
|
-
width: 650px
|
247
|
-
margin: 0 auto
|
248
|
-
overflow: hidden
|
249
|
-
margin-bottom: 20px
|
250
|
-
li
|
251
|
-
float: left
|
252
|
-
list-style: none
|
253
|
-
letter-spacing: 0
|
254
|
-
font-family: "Helvetica", Arial, arial, sans-serif
|
255
|
-
word-spacing: normal
|
256
|
-
&.active a
|
257
|
-
background-color: $compliment_highlight
|
258
|
-
color: #fff
|
259
|
-
font-weight: normal
|
260
|
-
&.disabled a
|
261
|
-
color: #BBB
|
262
|
-
cursor: default
|
263
|
-
a
|
264
|
-
@include rounded-corners(15px, 15px, 15px, 15px)
|
265
|
-
font-size: 12px
|
266
|
-
padding-top: 8px
|
267
|
-
padding-bottom: 8px
|
268
|
-
margin-top: 4px
|
269
|
-
padding-right: 12px
|
270
|
-
padding-left: 12px
|
271
|
-
margin-right: 2px
|
272
|
-
line-height: 14px
|
273
|
-
display: block
|
274
|
-
color: #333
|
275
|
-
&:hover
|
276
|
-
text-decoration: none
|
277
|
-
lable.error
|
278
|
-
color: red
|
279
|
-
.tab-pane
|
280
|
-
display: none
|
281
|
-
&.active
|
282
|
-
display: block
|
283
231
|
|
284
232
|
#cart
|
285
233
|
width: 100%
|
@@ -412,15 +360,7 @@ table.calendar
|
|
412
360
|
text-shadow: none
|
413
361
|
color: #fff
|
414
362
|
background-color: #a85300
|
415
|
-
background-image:
|
416
|
-
background-image: -moz-linear-gradient(top, #f8930a, #a85300)
|
417
|
-
background-image: -ms-linear-gradient(top, #f8930a, #a85300)
|
418
|
-
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8930a), color-stop(100%, #a85300))
|
419
|
-
background-image: -webkit-linear-gradient(top, #f8930a, #a85300)
|
420
|
-
background-image: -o-linear-gradient(top, #f8930a, #a85300)
|
421
|
-
background-image: linear-gradient(top, #f8930a, #a85300)
|
422
|
-
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8930a', endColorstr='#a85300', GradientType=0)
|
423
|
-
border-color: #a85300 #a85300 #003f81
|
363
|
+
background-image: none
|
424
364
|
|
425
365
|
.navbar .btn.primary
|
426
366
|
margin-top: 3px
|
@@ -502,7 +442,7 @@ tr.no-border
|
|
502
442
|
padding: 3px
|
503
443
|
border: 1px solid #eee
|
504
444
|
|
505
|
-
#event-header
|
445
|
+
#event-header, #donate-now-header
|
506
446
|
h1
|
507
447
|
font-family: 'Roboto', sans-serif
|
508
448
|
font-weight: 300
|
@@ -511,6 +451,19 @@ tr.no-border
|
|
511
451
|
font-weight: 100
|
512
452
|
margin: 0px 0px 2px 0px
|
513
453
|
|
454
|
+
#donate-now-header
|
455
|
+
text-align: center
|
456
|
+
margin-bottom: 30px
|
457
|
+
|
458
|
+
#donate-now-container
|
459
|
+
margin-top: -30px
|
460
|
+
padding: 50px 20px 60px 20px
|
461
|
+
box-shadow: 6px 5px 5px -5px #999, -6px 5px 5px -5px #999
|
462
|
+
|
463
|
+
#donate-now
|
464
|
+
text-align: center
|
465
|
+
margin-top: 20px
|
466
|
+
|
514
467
|
.available-ticket-type-table
|
515
468
|
form
|
516
469
|
margin: 0px
|
@@ -538,3 +491,40 @@ tr.no-border
|
|
538
491
|
#poster-modal
|
539
492
|
.modal-body
|
540
493
|
text-align: center
|
494
|
+
|
495
|
+
.add-donation-to-cart
|
496
|
+
.preset-amount
|
497
|
+
float: left
|
498
|
+
width: 227px
|
499
|
+
// height: 28px
|
500
|
+
margin-bottom: 10px
|
501
|
+
text-align: left
|
502
|
+
|
503
|
+
.add-donation-to-cart
|
504
|
+
.preset-amount.last
|
505
|
+
width: 455px
|
506
|
+
|
507
|
+
.add-donation-to-cart
|
508
|
+
.preset-amount
|
509
|
+
label
|
510
|
+
margin: 0
|
511
|
+
padding: 0
|
512
|
+
// height: 28px
|
513
|
+
line-height: 28px
|
514
|
+
|
515
|
+
.add-donation-to-cart
|
516
|
+
.preset-amount
|
517
|
+
label
|
518
|
+
input[type='radio']
|
519
|
+
float: none
|
520
|
+
vertical-align: baseline
|
521
|
+
margin-top: 0
|
522
|
+
|
523
|
+
#event-header.side-section
|
524
|
+
h4
|
525
|
+
padding-bottom: 8px
|
526
|
+
#subtitle
|
527
|
+
padding-bottom: 8px
|
528
|
+
font-weight: bold
|
529
|
+
line-height: 1.4em
|
530
|
+
font-size: 1em
|
data/app/concerns/itemable.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Include this method on objects that can be used to create items using Item.for
|
3
|
-
# Ticket class doesn't
|
3
|
+
# Ticket class doesn't need it because it defines its own sold_price method
|
4
4
|
#
|
5
5
|
module Itemable
|
6
6
|
extend ActiveSupport::Concern
|
@@ -17,17 +17,7 @@ class PdfGeneration
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def generate
|
20
|
-
|
21
|
-
json = JSON.parse(response.body)
|
22
|
-
|
23
|
-
while !json["complete"]
|
24
|
-
response = http_party.get(status_url(json))
|
25
|
-
json = JSON.parse(response.body)
|
26
|
-
|
27
|
-
sleeper.sleep 1 unless json["complete"]
|
28
|
-
end
|
29
|
-
|
30
|
-
download_url(json)
|
20
|
+
Wisepdf::Writer.new.to_pdf(content)
|
31
21
|
end
|
32
22
|
|
33
23
|
def content
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SearchByDates
|
2
|
+
attr_reader :start, :stop
|
3
|
+
attr_reader :organization
|
4
|
+
|
5
|
+
def start_with(start)
|
6
|
+
start.present? ? DateTime.parse(start) : default_start
|
7
|
+
end
|
8
|
+
|
9
|
+
def stop_with(stop)
|
10
|
+
stop.present? ? Sundial.midnightish(@organization, stop) : default_stop
|
11
|
+
end
|
12
|
+
|
13
|
+
def default_start
|
14
|
+
DateTime.now.in_time_zone(@organization.time_zone).beginning_of_month
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_stop
|
18
|
+
DateTime.now.in_time_zone(@organization.time_zone).end_of_day
|
19
|
+
end
|
20
|
+
end
|
@@ -7,6 +7,9 @@ class ExportController < ArtfullyOseController
|
|
7
7
|
send_data @csv_string, :filename => @filename, :type => "text/csv", :disposition => "attachment"
|
8
8
|
end
|
9
9
|
|
10
|
+
#
|
11
|
+
# Artful.ly generates these nightly and provides links directly to s3
|
12
|
+
#
|
10
13
|
def donations
|
11
14
|
@organization = current_user.current_organization
|
12
15
|
@filename = "Artfully-Donations-Export-#{DateTime.now.strftime("%m-%d-%y")}.csv"
|
@@ -15,8 +18,15 @@ class ExportController < ArtfullyOseController
|
|
15
18
|
send_data @csv_string, :filename => @filename, :type => "text/csv", :disposition => "attachment"
|
16
19
|
end
|
17
20
|
|
21
|
+
#
|
22
|
+
# Artful.ly generates these nightly and provides links directly to s3
|
23
|
+
#
|
18
24
|
def ticket_sales
|
19
|
-
|
25
|
+
@organization = current_user.current_organization
|
26
|
+
@filename = "Artfully-Ticket-Sales-Export-#{DateTime.now.strftime("%m-%d-%y")}.csv"
|
27
|
+
@items = ItemView.where(:organization_id => current_organization).where(:product_type => "Ticket").all
|
28
|
+
@csv_string = @items.to_comma(:ticket_sale)
|
29
|
+
send_data @csv_string, :filename => @filename, :type => "text/csv", :disposition => "attachment"
|
20
30
|
end
|
21
31
|
|
22
32
|
end
|
@@ -23,9 +23,8 @@ class ImportsController < ArtfullyOseController
|
|
23
23
|
# Building an import preview was just murdering us. The problem is way down in Array.index in parsed_row.load_value.
|
24
24
|
# Temporarily shutting it off for > 1000
|
25
25
|
#
|
26
|
-
|
27
|
-
|
28
|
-
@parsed_rows = @import.parsed_rows.paginate(:page => params[:page], :per_page => 50)
|
26
|
+
if @import.status == "pending"
|
27
|
+
@imported_rows = @import.import_rows.paginate(:page => params[:page], :per_page => 50)
|
29
28
|
end
|
30
29
|
|
31
30
|
@people = Person.where(:import_id => @import.id).paginate(:page => params[:page], :per_page => 50) unless @import.id.nil?
|
@@ -4,9 +4,8 @@ class MemberCardsController < ArtfullyOseController
|
|
4
4
|
before_filter :find_members
|
5
5
|
|
6
6
|
def new
|
7
|
-
|
8
|
-
|
9
|
-
redirect_to generator.download_url
|
7
|
+
pdf = MemberCardGenerator::BlanksUsaIdc6.new(@members).generate
|
8
|
+
send_data pdf, :filename => "member_cards.pdf", :type => "application/pdf", :disposition => "attachment"
|
10
9
|
end
|
11
10
|
|
12
11
|
private
|
@@ -89,6 +89,48 @@ class OrdersController < ArtfullyOseController
|
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
+
def passes
|
93
|
+
authorize! :view, Order
|
94
|
+
|
95
|
+
@organization = current_organization
|
96
|
+
@pass_type = PassType.find_by_id(params[:pass_type_id]) if params[:pass_type_id].present?
|
97
|
+
@pass_types = @organization.pass_types
|
98
|
+
|
99
|
+
request.format = :csv if params[:commit] == "Download"
|
100
|
+
|
101
|
+
search_terms = {
|
102
|
+
:start => params[:start],
|
103
|
+
:stop => params[:stop],
|
104
|
+
:organization => @organization,
|
105
|
+
:pass_type => @pass_type
|
106
|
+
}
|
107
|
+
|
108
|
+
@search = PassSaleSearch.new(search_terms) do |results|
|
109
|
+
results.paginate(:page => params[:page], :per_page => 25)
|
110
|
+
end
|
111
|
+
|
112
|
+
respond_to do |format|
|
113
|
+
format.html
|
114
|
+
format.csv do
|
115
|
+
filename = "Artfully-Pass-Sales-Export-#{DateTime.now.strftime("%m-%d-%y")}.csv"
|
116
|
+
items = ItemView.where(:product_type => "Pass")
|
117
|
+
.where('items_view.created_at > ? ', @search.start)
|
118
|
+
.where('items_view.created_at < ?', @search.stop)
|
119
|
+
.where('items_view.organization_id = ?', current_organization)
|
120
|
+
.order('items_view.created_at desc')
|
121
|
+
if @pass_type
|
122
|
+
items = items.joins(:item).
|
123
|
+
joins("INNER JOIN passes ON (items.product_type = #{::Item.sanitize('Pass')} AND items.product_id = passes.id)").
|
124
|
+
joins("INNER JOIN pass_types ON (pass_types.id = passes.pass_type_id)").
|
125
|
+
where(:pass_types => {:id => @pass_type}).
|
126
|
+
group('items_view.order_id')
|
127
|
+
end
|
128
|
+
csv_string = items.all.to_comma(:pass_sale)
|
129
|
+
send_data csv_string, :filename => filename, :type => "text/csv", :disposition => "attachment"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
92
134
|
def sales
|
93
135
|
authorize! :view, Order
|
94
136
|
|
@@ -40,6 +40,7 @@ class OrganizationsController < ArtfullyOseController
|
|
40
40
|
|
41
41
|
if @organization.save
|
42
42
|
@organization.users << current_user
|
43
|
+
@organization.make_owner(current_user)
|
43
44
|
redirect_to organizations_url, :notice => "#{@organization.name} has been created"
|
44
45
|
else
|
45
46
|
render :new
|
@@ -1,5 +1,25 @@
|
|
1
1
|
class PassesReportsController < ArtfullyOseController
|
2
2
|
def index
|
3
|
-
@
|
3
|
+
@start_date = params[:start_date]
|
4
|
+
@end_date = params[:end_date]
|
5
|
+
@organization = current_user.current_organization
|
6
|
+
@pass_types = @organization.pass_types
|
7
|
+
@pass_type = PassType.find(params[:pass_type]) if params[:pass_type].present?
|
8
|
+
@report = nil
|
9
|
+
@report = PassesReport.new(@organization, @pass_type, @start_date, @end_date)
|
10
|
+
@rows = @report.rows.paginate(:page => params[:page], :per_page => 100) unless @report.nil?
|
11
|
+
|
12
|
+
@options_for_select = @pass_types.collect{ |p| [p.name, p.id] }
|
13
|
+
@options_for_select.unshift [PassType::ALL_PASSES_STRING, nil]
|
14
|
+
|
15
|
+
respond_to do |format|
|
16
|
+
format.html
|
17
|
+
|
18
|
+
format.csv do
|
19
|
+
@filename = [ @report.header, ".csv" ].join
|
20
|
+
@csv_string = @report.rows.to_comma
|
21
|
+
send_data @csv_string, :filename => @filename, :type => "text/csv", :disposition => "attachment"
|
22
|
+
end
|
23
|
+
end
|
4
24
|
end
|
5
25
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class RegularDonationKitsController < ApplicationController
|
2
|
+
rescue_from CanCan::AccessDenied do |exception|
|
3
|
+
flash[:alert] = exception.message
|
4
|
+
redirect_to root_path, :alert => exception.message
|
5
|
+
end
|
6
|
+
|
7
|
+
before_filter do
|
8
|
+
authorize! :edit, current_user.current_organization
|
9
|
+
end
|
10
|
+
|
11
|
+
def edit
|
12
|
+
@kit = Kit.find(params[:id])
|
13
|
+
end
|
14
|
+
|
15
|
+
def update
|
16
|
+
@kit = Kit.find(params[:id])
|
17
|
+
|
18
|
+
if @kit.update_attributes(kit_params)
|
19
|
+
flash[:notice] = 'Your changes have been saved.'
|
20
|
+
redirect_to organization_path(@kit.organization)
|
21
|
+
else
|
22
|
+
flash[:error] = 'We had a problem configuring your kit. Please try again.'
|
23
|
+
render :edit
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def kit_params
|
30
|
+
params[:regular_donation_kit]
|
31
|
+
end
|
32
|
+
end
|
@@ -1,4 +1,22 @@
|
|
1
1
|
class Store::DonationsController < Store::StoreController
|
2
|
+
rescue_from ActiveRecord::RecordNotFound do
|
3
|
+
render :text => File.read("#{Rails.root}/public/404.html"),
|
4
|
+
:content_type => Mime::HTML,
|
5
|
+
:status => :not_found
|
6
|
+
end
|
7
|
+
|
2
8
|
def index
|
9
|
+
# If there is no kit at all, NotFound
|
10
|
+
raise ActionController::RoutingError.new('Not Found') unless @store_organization.has_kit?(:regular_donation)
|
11
|
+
|
12
|
+
# If there's a kit, and they're logged in, show them a preview if the kit is off
|
13
|
+
if current_user && current_user.current_organization == @store_organization
|
14
|
+
if !@store_organization.has_active_donation_only_storefront?
|
15
|
+
flash[:notice] = "You are seeing a preview of your donation-only storefront. To make this page visible to the general public, go to your 501(c)(3) kit configuration and check \"Display Donation-Only Storefront\""
|
16
|
+
end
|
17
|
+
else
|
18
|
+
# show everyone else NotFound
|
19
|
+
raise ActionController::RoutingError.new('Not Found') unless @store_organization.has_active_donation_only_storefront?
|
20
|
+
end
|
3
21
|
end
|
4
|
-
end
|
22
|
+
end
|
@@ -1,18 +1,29 @@
|
|
1
1
|
class Store::OrdersController < Store::StoreController
|
2
2
|
include ActionView::Helpers::TextHelper
|
3
3
|
include ArtfullyOseHelper
|
4
|
-
|
4
|
+
|
5
5
|
def update
|
6
6
|
handler = OrderHandler.new(current_cart, current_member)
|
7
|
-
handler.handle_tickets(params)
|
7
|
+
handler.handle_tickets(params)
|
8
8
|
handler.handle_donation(params, @store_organization)
|
9
9
|
handler.handle_memberships(params, current_member)
|
10
10
|
handler.handle_passes(params)
|
11
11
|
handler.handle_discount_or_pass_code(params)
|
12
12
|
|
13
|
-
|
13
|
+
if handler.error.present?
|
14
|
+
flash[:alert] = handler.error unless handler.error.blank?
|
15
|
+
|
16
|
+
redirect_url = case params[:_source]
|
17
|
+
when 'storefront'
|
18
|
+
store_donate_path
|
19
|
+
else
|
20
|
+
store_order_path
|
21
|
+
end
|
14
22
|
|
15
|
-
|
23
|
+
redirect_to redirect_url
|
24
|
+
else
|
25
|
+
redirect_to store_order_path
|
26
|
+
end
|
16
27
|
end
|
17
28
|
|
18
29
|
def show
|
@@ -50,7 +61,6 @@ class Store::OrdersController < Store::StoreController
|
|
50
61
|
end
|
51
62
|
|
52
63
|
private
|
53
|
-
|
54
64
|
def event
|
55
65
|
current_cart.tickets.first.event
|
56
66
|
end
|