railties 4.1.16 → 4.2.0.beta1
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/CHANGELOG.md +80 -439
- data/RDOC_MAIN.rdoc +1 -1
- data/README.rdoc +6 -2
- data/lib/rails.rb +7 -1
- data/lib/rails/all.rb +1 -0
- data/lib/rails/api/task.rb +7 -0
- data/lib/rails/app_rails_loader.rb +4 -2
- data/lib/rails/application.rb +74 -47
- data/lib/rails/application/configuration.rb +23 -1
- data/lib/rails/application/finisher.rb +0 -2
- data/lib/rails/code_statistics.rb +4 -2
- data/lib/rails/commands/commands_tasks.rb +1 -6
- data/lib/rails/commands/console.rb +24 -12
- data/lib/rails/commands/dbconsole.rb +2 -2
- data/lib/rails/commands/plugin.rb +1 -1
- data/lib/rails/commands/server.rb +22 -9
- data/lib/rails/engine.rb +7 -7
- data/lib/rails/gem_version.rb +3 -3
- data/lib/rails/generators.rb +68 -15
- data/lib/rails/generators/actions.rb +27 -7
- data/lib/rails/generators/actions/create_migration.rb +2 -1
- data/lib/rails/generators/app_base.rb +55 -65
- data/lib/rails/generators/base.rb +2 -2
- data/lib/rails/generators/erb/scaffold/templates/_form.html.erb +0 -5
- data/lib/rails/generators/erb/scaffold/templates/edit.html.erb +1 -1
- data/lib/rails/generators/erb/scaffold/templates/index.html.erb +3 -1
- data/lib/rails/generators/erb/scaffold/templates/new.html.erb +1 -1
- data/lib/rails/generators/generated_attribute.rb +24 -4
- data/lib/rails/generators/model_helpers.rb +28 -0
- data/lib/rails/generators/rails/app/app_generator.rb +8 -2
- data/lib/rails/generators/rails/app/templates/Gemfile +21 -6
- data/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +1 -1
- data/lib/rails/generators/rails/app/templates/bin/setup +28 -0
- data/lib/rails/generators/rails/app/templates/config/application.rb +5 -1
- data/lib/rails/generators/rails/app/templates/config/boot.rb +1 -2
- data/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml +1 -3
- data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml +1 -1
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +4 -0
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +8 -10
- data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +3 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb +1 -1
- data/lib/rails/generators/rails/app/templates/gitignore +2 -0
- data/lib/rails/generators/rails/controller/USAGE +0 -1
- data/lib/rails/generators/rails/controller/controller_generator.rb +6 -2
- data/lib/rails/generators/rails/helper/USAGE +0 -4
- data/lib/rails/generators/rails/model/USAGE +11 -1
- data/lib/rails/generators/rails/model/model_generator.rb +4 -0
- data/lib/rails/generators/rails/plugin/plugin_generator.rb +1 -3
- data/lib/rails/generators/rails/plugin/templates/%name%.gemspec +1 -1
- data/lib/rails/generators/rails/plugin/templates/Gemfile +10 -6
- data/lib/rails/generators/rails/plugin/templates/Rakefile +4 -0
- data/lib/rails/generators/rails/plugin/templates/app/controllers/%name%/application_controller.rb.tt +0 -1
- data/lib/rails/generators/rails/plugin/templates/rails/javascripts.js +1 -1
- data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb +2 -10
- data/lib/rails/generators/rails/resource_route/resource_route_generator.rb +2 -4
- data/lib/rails/generators/rails/scaffold/USAGE +7 -1
- data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +0 -1
- data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +1 -1
- data/lib/rails/generators/resource_helpers.rb +2 -11
- data/lib/rails/generators/test_unit/helper/helper_generator.rb +1 -5
- data/lib/rails/generators/testing/behaviour.rb +17 -0
- data/lib/rails/info.rb +1 -1
- data/lib/rails/info_controller.rb +1 -1
- data/lib/rails/mailers_controller.rb +14 -16
- data/lib/rails/paths.rb +1 -1
- data/lib/rails/rack.rb +1 -1
- data/lib/rails/rack/log_tailer.rb +4 -0
- data/lib/rails/rack/logger.rb +1 -1
- data/lib/rails/railtie.rb +2 -2
- data/lib/rails/ruby_version_check.rb +1 -1
- data/lib/rails/source_annotation_extractor.rb +23 -16
- data/lib/rails/tasks/framework.rake +1 -1
- data/lib/rails/tasks/statistics.rake +8 -3
- data/lib/rails/templates/rails/mailers/email.html.erb +2 -13
- data/lib/rails/templates/rails/mailers/index.html.erb +2 -2
- data/lib/rails/templates/rails/mailers/mailer.html.erb +1 -1
- data/lib/rails/test_unit/sub_test_task.rb +2 -2
- metadata +13 -13
- data/lib/rails/generators/test_unit/helper/templates/helper_test.rb +0 -6
- data/lib/rails/rubyprof_ext.rb +0 -35
@@ -83,7 +83,7 @@ module Rails
|
|
83
83
|
#
|
84
84
|
# The first and last part used to find the generator to be invoked are
|
85
85
|
# guessed based on class invokes hook_for, as noticed in the example above.
|
86
|
-
# This can be customized with two options: :
|
86
|
+
# This can be customized with two options: :in and :as.
|
87
87
|
#
|
88
88
|
# Let's suppose you are creating a generator that needs to invoke the
|
89
89
|
# controller generator from test unit. Your first attempt is:
|
@@ -108,7 +108,7 @@ module Rails
|
|
108
108
|
# "test_unit:controller", "test_unit"
|
109
109
|
#
|
110
110
|
# Similarly, if you want it to also lookup in the rails namespace, you just
|
111
|
-
# need to provide the :
|
111
|
+
# need to provide the :in value:
|
112
112
|
#
|
113
113
|
# class AwesomeGenerator < Rails::Generators::Base
|
114
114
|
# hook_for :test_framework, in: :rails, as: :controller
|
@@ -21,13 +21,8 @@
|
|
21
21
|
<%%= f.label :password_confirmation %><br>
|
22
22
|
<%%= f.password_field :password_confirmation %>
|
23
23
|
<% else -%>
|
24
|
-
<%- if attribute.reference? -%>
|
25
24
|
<%%= f.label :<%= attribute.column_name %> %><br>
|
26
25
|
<%%= f.<%= attribute.field_type %> :<%= attribute.column_name %> %>
|
27
|
-
<%- else -%>
|
28
|
-
<%%= f.label :<%= attribute.name %> %><br>
|
29
|
-
<%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
|
30
|
-
<%- end -%>
|
31
26
|
<% end -%>
|
32
27
|
</div>
|
33
28
|
<% end -%>
|
@@ -44,8 +44,11 @@ module Rails
|
|
44
44
|
return $1, limit: $2.to_i
|
45
45
|
when /decimal\{(\d+)[,.-](\d+)\}/
|
46
46
|
return :decimal, precision: $1.to_i, scale: $2.to_i
|
47
|
-
when /(references|belongs_to)\{
|
48
|
-
|
47
|
+
when /(references|belongs_to)\{(.+)\}/
|
48
|
+
type = $1
|
49
|
+
provided_options = $2.split(/[,.-]/)
|
50
|
+
options = Hash[provided_options.map { |opt| [opt.to_sym, true] }]
|
51
|
+
return type, options
|
49
52
|
else
|
50
53
|
return type, {}
|
51
54
|
end
|
@@ -94,6 +97,10 @@ module Rails
|
|
94
97
|
name.sub(/_id$/, '').pluralize
|
95
98
|
end
|
96
99
|
|
100
|
+
def singular_name
|
101
|
+
name.sub(/_id$/, '').singularize
|
102
|
+
end
|
103
|
+
|
97
104
|
def human_name
|
98
105
|
name.humanize
|
99
106
|
end
|
@@ -119,7 +126,11 @@ module Rails
|
|
119
126
|
end
|
120
127
|
|
121
128
|
def polymorphic?
|
122
|
-
self.attr_options
|
129
|
+
self.attr_options[:polymorphic]
|
130
|
+
end
|
131
|
+
|
132
|
+
def required?
|
133
|
+
self.attr_options[:required]
|
123
134
|
end
|
124
135
|
|
125
136
|
def has_index?
|
@@ -135,12 +146,21 @@ module Rails
|
|
135
146
|
end
|
136
147
|
|
137
148
|
def inject_options
|
138
|
-
"".tap { |s|
|
149
|
+
"".tap { |s| options_for_migration.each { |k,v| s << ", #{k}: #{v.inspect}" } }
|
139
150
|
end
|
140
151
|
|
141
152
|
def inject_index_options
|
142
153
|
has_uniq_index? ? ", unique: true" : ""
|
143
154
|
end
|
155
|
+
|
156
|
+
def options_for_migration
|
157
|
+
@attr_options.dup.tap do |options|
|
158
|
+
if required?
|
159
|
+
options.delete(:required)
|
160
|
+
options[:null] = false
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
144
164
|
end
|
145
165
|
end
|
146
166
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rails/generators/active_model'
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module Generators
|
5
|
+
module ModelHelpers # :nodoc:
|
6
|
+
PLURAL_MODEL_NAME_WARN_MESSAGE = "[WARNING] The model name '%s' was recognized as a plural, using the singular '%s' instead. " \
|
7
|
+
"Override with --force-plural or setup custom inflection rules for this noun before running the generator."
|
8
|
+
mattr_accessor :skip_warn
|
9
|
+
|
10
|
+
def self.included(base) #:nodoc:
|
11
|
+
base.class_option :force_plural, type: :boolean, default: false, desc: 'Forces the use of the given model name'
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(args, *_options)
|
15
|
+
super
|
16
|
+
if name == name.pluralize && name.singularize != name.pluralize && !options[:force_plural]
|
17
|
+
singular = name.singularize
|
18
|
+
unless ModelHelpers.skip_warn
|
19
|
+
say PLURAL_MODEL_NAME_WARN_MESSAGE % [name, singular]
|
20
|
+
ModelHelpers.skip_warn = true
|
21
|
+
end
|
22
|
+
name.replace singular
|
23
|
+
assign_names!(name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -50,7 +50,7 @@ module Rails
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def gitignore
|
53
|
-
|
53
|
+
template "gitignore", ".gitignore"
|
54
54
|
end
|
55
55
|
|
56
56
|
def app
|
@@ -259,6 +259,12 @@ module Rails
|
|
259
259
|
public_task :apply_rails_template, :run_bundle
|
260
260
|
public_task :generate_spring_binstubs
|
261
261
|
|
262
|
+
def run_after_bundle_callbacks
|
263
|
+
@after_bundle_callbacks.each do |callback|
|
264
|
+
callback.call
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
262
268
|
protected
|
263
269
|
|
264
270
|
def self.banner
|
@@ -334,7 +340,7 @@ module Rails
|
|
334
340
|
#
|
335
341
|
# This class should be called before the AppGenerator is required and started
|
336
342
|
# since it configures and mutates ARGV correctly.
|
337
|
-
class ARGVScrubber # :nodoc
|
343
|
+
class ARGVScrubber # :nodoc
|
338
344
|
def initialize(argv = ARGV)
|
339
345
|
@argv = argv
|
340
346
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
<% max_width = gemfile_entries.map { |g| g.name.length }.max -%>
|
4
3
|
<% gemfile_entries.each do |gem| -%>
|
5
4
|
<% if gem.comment -%>
|
6
5
|
|
@@ -8,7 +7,7 @@ source 'https://rubygems.org'
|
|
8
7
|
<% end -%>
|
9
8
|
<%= gem.commented_out ? '# ' : '' %>gem '<%= gem.name %>'<%= %(, '#{gem.version}') if gem.version -%>
|
10
9
|
<% if gem.options.any? -%>
|
11
|
-
|
10
|
+
, <%= gem.options.map { |k,v|
|
12
11
|
"#{k}: #{v.inspect}" }.join(', ') %>
|
13
12
|
<% end -%>
|
14
13
|
<% end -%>
|
@@ -16,18 +15,34 @@ source 'https://rubygems.org'
|
|
16
15
|
# Use ActiveModel has_secure_password
|
17
16
|
# gem 'bcrypt', '~> 3.1.7'
|
18
17
|
|
19
|
-
# Use
|
18
|
+
# Use Rails Html Sanitizer for HTML sanitization
|
19
|
+
gem 'rails-html-sanitizer', '~> 1.0'
|
20
|
+
|
21
|
+
# Use Unicorn as the app server
|
20
22
|
# gem 'unicorn'
|
21
23
|
|
22
24
|
# Use Capistrano for deployment
|
23
25
|
# gem 'capistrano-rails', group: :development
|
24
26
|
|
27
|
+
group :development, :test do
|
25
28
|
<% unless defined?(JRUBY_VERSION) -%>
|
26
|
-
#
|
27
|
-
|
29
|
+
# Call 'debugger' anywhere in the code to stop execution and get a debugger console
|
30
|
+
<%- if RUBY_VERSION < '2.0.0' -%>
|
31
|
+
gem 'debugger'
|
32
|
+
<%- else -%>
|
33
|
+
gem 'byebug'
|
34
|
+
<%- end -%>
|
35
|
+
|
36
|
+
# Access an IRB console on exceptions page and /console in development
|
37
|
+
gem 'web-console', '~> 2.0.0.beta2'
|
38
|
+
<%- if spring_install? %>
|
39
|
+
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
|
40
|
+
gem 'spring'
|
41
|
+
<% end -%>
|
28
42
|
<% end -%>
|
43
|
+
end
|
29
44
|
|
30
45
|
<% if RUBY_PLATFORM.match(/bccwin|cygwin|emx|mingw|mswin|wince/) -%>
|
31
46
|
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
32
|
-
gem 'tzinfo-data', platforms: [:mingw, :mswin]
|
47
|
+
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw]
|
33
48
|
<% end -%>
|
@@ -7,7 +7,7 @@
|
|
7
7
|
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
8
|
// compiled file.
|
9
9
|
//
|
10
|
-
// Read Sprockets README (https://github.com/
|
10
|
+
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
11
11
|
// about supported directives.
|
12
12
|
//
|
13
13
|
<% unless options[:skip_javascript] -%>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
# path to your application root.
|
4
|
+
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
|
5
|
+
|
6
|
+
Dir.chdir APP_ROOT do
|
7
|
+
# This script is a starting point to setup your application.
|
8
|
+
# Add necessary setup steps to this file:
|
9
|
+
|
10
|
+
puts "== Installing dependencies =="
|
11
|
+
system "gem install bundler --conservative"
|
12
|
+
system "bundle check || bundle install"
|
13
|
+
|
14
|
+
# puts "\n== Copying sample files =="
|
15
|
+
# unless File.exist?("config/database.yml")
|
16
|
+
# system "cp config/database.yml.sample config/database.yml"
|
17
|
+
# end
|
18
|
+
|
19
|
+
puts "\n== Preparing database =="
|
20
|
+
system "bin/rake db:setup"
|
21
|
+
|
22
|
+
puts "\n== Removing old logs and tempfiles =="
|
23
|
+
system "rm -f log/*"
|
24
|
+
system "rm -rf tmp/cache"
|
25
|
+
|
26
|
+
puts "\n== Restarting application server =="
|
27
|
+
system "touch tmp/restart.txt"
|
28
|
+
end
|
@@ -3,7 +3,6 @@ require File.expand_path('../boot', __FILE__)
|
|
3
3
|
<% if include_all_railties? -%>
|
4
4
|
require 'rails/all'
|
5
5
|
<% else -%>
|
6
|
-
require "rails"
|
7
6
|
# Pick the frameworks you want:
|
8
7
|
require "active_model/railtie"
|
9
8
|
<%= comment_if :skip_active_record %>require "active_record/railtie"
|
@@ -31,5 +30,10 @@ module <%= app_const_base %>
|
|
31
30
|
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
32
31
|
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
33
32
|
# config.i18n.default_locale = :de
|
33
|
+
<%- unless options.skip_active_record? -%>
|
34
|
+
|
35
|
+
# For not swallow errors in after_commit/after_rollback callbacks.
|
36
|
+
config.active_record.raise_in_transactional_callbacks = true
|
37
|
+
<%- end -%>
|
34
38
|
end
|
35
39
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# IBM Dataservers
|
2
2
|
#
|
3
3
|
# Home Page
|
4
|
-
#
|
4
|
+
# https://github.com/dparnell/ibm_db
|
5
5
|
#
|
6
6
|
# To install the ibm_db gem:
|
7
7
|
#
|
@@ -31,8 +31,6 @@
|
|
31
31
|
# Configure Using Gemfile
|
32
32
|
# gem 'ibm_db'
|
33
33
|
#
|
34
|
-
# For more details on the installation and the connection parameters below,
|
35
|
-
# please refer to the latest documents at http://rubyforge.org/docman/?group_id=2361
|
36
34
|
#
|
37
35
|
default: &default
|
38
36
|
adapter: ibm_db
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Oracle/OCI 8i, 9, 10g
|
2
2
|
#
|
3
3
|
# Requires Ruby/OCI8:
|
4
|
-
#
|
4
|
+
# https://github.com/kubo/ruby-oci8
|
5
5
|
#
|
6
6
|
# Specify your database using any valid connection syntax, such as a
|
7
7
|
# tnsnames.ora service name, or an SQL connect string of the form:
|
@@ -30,6 +30,10 @@ Rails.application.configure do
|
|
30
30
|
# number of complex assets.
|
31
31
|
config.assets.debug = true
|
32
32
|
|
33
|
+
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
|
34
|
+
# yet still be able to expire them through the digest params.
|
35
|
+
config.assets.digest = true
|
36
|
+
|
33
37
|
# Adds additional error checking when serving assets at runtime.
|
34
38
|
# Checks for improperly declared sprockets dependencies.
|
35
39
|
# Raises helpful error messages.
|
@@ -16,10 +16,10 @@ Rails.application.configure do
|
|
16
16
|
|
17
17
|
# Enable Rack::Cache to put a simple HTTP cache in front of your application
|
18
18
|
# Add `rack-cache` to your Gemfile before enabling this.
|
19
|
-
# For large-scale production use, consider using a caching reverse proxy like
|
19
|
+
# For large-scale production use, consider using a caching reverse proxy like NGINX, varnish or squid.
|
20
20
|
# config.action_dispatch.rack_cache = true
|
21
21
|
|
22
|
-
# Disable Rails's static asset server (Apache or
|
22
|
+
# Disable Rails's static asset server (Apache or NGINX will already do this).
|
23
23
|
config.serve_static_assets = false
|
24
24
|
|
25
25
|
<%- unless options.skip_sprockets? -%>
|
@@ -30,21 +30,22 @@ Rails.application.configure do
|
|
30
30
|
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
31
31
|
config.assets.compile = false
|
32
32
|
|
33
|
-
#
|
33
|
+
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
|
34
|
+
# yet still be able to expire them through the digest params.
|
34
35
|
config.assets.digest = true
|
35
36
|
|
36
37
|
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
|
37
38
|
<%- end -%>
|
38
39
|
|
39
40
|
# Specifies the header that your server uses for sending files.
|
40
|
-
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for
|
41
|
-
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for
|
41
|
+
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
|
42
|
+
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
|
42
43
|
|
43
44
|
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
44
45
|
# config.force_ssl = true
|
45
46
|
|
46
|
-
# Set to :
|
47
|
-
config.log_level = :
|
47
|
+
# Set to :info to decrease the log volume.
|
48
|
+
config.log_level = :debug
|
48
49
|
|
49
50
|
# Prepend all log lines with the following tags.
|
50
51
|
# config.log_tags = [ :subdomain, :uuid ]
|
@@ -69,9 +70,6 @@ Rails.application.configure do
|
|
69
70
|
# Send deprecation notices to registered listeners.
|
70
71
|
config.active_support.deprecation = :notify
|
71
72
|
|
72
|
-
# Disable automatic flushing of the log to improve performance.
|
73
|
-
# config.autoflush_log = false
|
74
|
-
|
75
73
|
# Use default logging formatter so that PID and timestamp are not suppressed.
|
76
74
|
config.log_formatter = ::Logger::Formatter.new
|
77
75
|
<%- unless options.skip_active_record? -%>
|
@@ -3,6 +3,9 @@
|
|
3
3
|
# Version of your assets, change this if you want to expire all your assets.
|
4
4
|
Rails.application.config.assets.version = '1.0'
|
5
5
|
|
6
|
+
# Add additional assets to the asset load path
|
7
|
+
# Rails.application.config.assets.paths << Emoji.images_path
|
8
|
+
|
6
9
|
# Precompile additional assets.
|
7
10
|
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
|
8
11
|
# Rails.application.config.assets.precompile += %w( search.js )
|
@@ -2,6 +2,8 @@ module Rails
|
|
2
2
|
module Generators
|
3
3
|
class ControllerGenerator < NamedBase # :nodoc:
|
4
4
|
argument :actions, type: :array, default: [], banner: "action action"
|
5
|
+
class_option :skip_routes, type: :boolean, desc: "Don't add routes to config/routes.rb."
|
6
|
+
|
5
7
|
check_class_collision suffix: "Controller"
|
6
8
|
|
7
9
|
def create_controller_files
|
@@ -9,8 +11,10 @@ module Rails
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def add_routes
|
12
|
-
|
13
|
-
|
14
|
+
unless options[:skip_routes]
|
15
|
+
actions.reverse.each do |action|
|
16
|
+
route generate_routing_code(action)
|
17
|
+
end
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|