activesupport 4.0.12 → 7.0.2.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +249 -501
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -5
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +41 -13
- data/lib/active_support/benchmarkable.rb +7 -15
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +96 -74
- data/lib/active_support/cache/mem_cache_store.rb +211 -103
- data/lib/active_support/cache/memory_store.rb +90 -58
- data/lib/active_support/cache/null_store.rb +19 -7
- data/lib/active_support/cache/redis_cache_store.rb +468 -0
- data/lib/active_support/cache/strategy/local_cache.rb +86 -83
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
- data/lib/active_support/cache.rb +580 -241
- data/lib/active_support/callbacks.rb +812 -425
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +103 -14
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +33 -0
- data/lib/active_support/concurrency/share_lock.rb +226 -0
- data/lib/active_support/configurable.rb +21 -19
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +47 -1
- data/lib/active_support/core_ext/array/conversions.rb +35 -44
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +26 -16
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/wrap.rb +7 -4
- data/lib/active_support/core_ext/array.rb +10 -7
- data/lib/active_support/core_ext/benchmark.rb +5 -3
- data/lib/active_support/core_ext/big_decimal/conversions.rb +9 -26
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/class/attribute.rb +52 -49
- data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
- data/lib/active_support/core_ext/class/subclasses.rb +25 -26
- data/lib/active_support/core_ext/class.rb +4 -4
- data/lib/active_support/core_ext/date/acts_like.rb +3 -1
- data/lib/active_support/core_ext/date/blank.rb +14 -0
- data/lib/active_support/core_ext/date/calculations.rb +31 -18
- data/lib/active_support/core_ext/date/conversions.rb +43 -32
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date/zones.rb +5 -34
- data/lib/active_support/core_ext/date.rb +7 -4
- data/lib/active_support/core_ext/date_and_time/calculations.rb +198 -66
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +31 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
- data/lib/active_support/core_ext/date_time/blank.rb +14 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +79 -38
- data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +31 -26
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +8 -4
- data/lib/active_support/core_ext/digest/uuid.rb +79 -0
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +249 -17
- data/lib/active_support/core_ext/file/atomic.rb +41 -32
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +71 -49
- data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +14 -5
- data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
- data/lib/active_support/core_ext/hash/keys.rb +39 -56
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -23
- data/lib/active_support/core_ext/hash.rb +10 -8
- data/lib/active_support/core_ext/integer/inflections.rb +3 -1
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +11 -33
- data/lib/active_support/core_ext/integer.rb +5 -3
- data/lib/active_support/core_ext/kernel/concern.rb +14 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +9 -78
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +5 -4
- data/lib/active_support/core_ext/load_error.rb +5 -21
- data/lib/active_support/core_ext/module/aliasing.rb +6 -44
- data/lib/active_support/core_ext/module/anonymous.rb +12 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +8 -8
- data/lib/active_support/core_ext/module/attribute_accessors.rb +186 -44
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +157 -0
- data/lib/active_support/core_ext/module/concerning.rb +140 -0
- data/lib/active_support/core_ext/module/delegation.rb +172 -45
- data/lib/active_support/core_ext/module/deprecation.rb +3 -3
- data/lib/active_support/core_ext/module/introspection.rb +23 -38
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +8 -3
- data/lib/active_support/core_ext/module.rb +13 -10
- data/lib/active_support/core_ext/name_error.rb +45 -4
- data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +135 -127
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric/time.rb +37 -50
- data/lib/active_support/core_ext/numeric.rb +6 -3
- data/lib/active_support/core_ext/object/acts_like.rb +41 -6
- data/lib/active_support/core_ext/object/blank.rb +70 -20
- data/lib/active_support/core_ext/object/conversions.rb +6 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +19 -10
- data/lib/active_support/core_ext/object/duplicable.rb +17 -47
- data/lib/active_support/core_ext/object/inclusion.rb +18 -15
- data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
- data/lib/active_support/core_ext/object/json.rb +244 -0
- data/lib/active_support/core_ext/object/to_param.rb +3 -1
- data/lib/active_support/core_ext/object/to_query.rb +21 -8
- data/lib/active_support/core_ext/object/try.rb +106 -26
- data/lib/active_support/core_ext/object/with_options.rb +64 -5
- data/lib/active_support/core_ext/object.rb +14 -12
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +57 -0
- data/lib/active_support/core_ext/range/conversions.rb +37 -15
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +18 -17
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
- data/lib/active_support/core_ext/range/overlaps.rb +2 -0
- data/lib/active_support/core_ext/range.rb +7 -4
- data/lib/active_support/core_ext/regexp.rb +10 -1
- data/lib/active_support/core_ext/securerandom.rb +45 -0
- data/lib/active_support/core_ext/string/access.rb +42 -51
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +18 -13
- data/lib/active_support/core_ext/string/exclude.rb +5 -3
- data/lib/active_support/core_ext/string/filters.rb +97 -7
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +106 -25
- data/lib/active_support/core_ext/string/inquiry.rb +4 -1
- data/lib/active_support/core_ext/string/multibyte.rb +18 -9
- data/lib/active_support/core_ext/string/output_safety.rb +227 -54
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
- data/lib/active_support/core_ext/string/strip.rb +6 -5
- data/lib/active_support/core_ext/string/zones.rb +4 -1
- data/lib/active_support/core_ext/string.rb +15 -13
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +178 -116
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +37 -25
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +44 -42
- data/lib/active_support/core_ext/time.rb +8 -5
- data/lib/active_support/core_ext/uri.rb +4 -25
- data/lib/active_support/core_ext.rb +4 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +226 -0
- data/lib/active_support/dependencies/autoload.rb +3 -1
- data/lib/active_support/dependencies/interlock.rb +49 -0
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +71 -696
- data/lib/active_support/deprecation/behaviors.rb +65 -16
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +16 -2
- data/lib/active_support/deprecation/method_wrappers.rb +62 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +82 -31
- data/lib/active_support/deprecation/reporting.rb +81 -18
- data/lib/active_support/deprecation.rb +19 -11
- data/lib/active_support/descendants_tracker.rb +192 -34
- data/lib/active_support/digest.rb +22 -0
- data/lib/active_support/duration/iso8601_parser.rb +123 -0
- data/lib/active_support/duration/iso8601_serializer.rb +67 -0
- data/lib/active_support/duration.rb +437 -39
- data/lib/active_support/encrypted_configuration.rb +56 -0
- data/lib/active_support/encrypted_file.rb +117 -0
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +170 -0
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +151 -0
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +62 -37
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +17 -0
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +207 -54
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +10 -6
- data/lib/active_support/i18n_railtie.rb +48 -19
- data/lib/active_support/inflections.rb +19 -12
- data/lib/active_support/inflector/inflections.rb +97 -37
- data/lib/active_support/inflector/methods.rb +192 -157
- data/lib/active_support/inflector/transliterate.rb +83 -33
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/isolated_execution_state.rb +64 -0
- data/lib/active_support/json/decoding.rb +37 -42
- data/lib/active_support/json/encoding.rb +93 -293
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +30 -47
- data/lib/active_support/lazy_load_hooks.rb +54 -21
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +10 -4
- data/lib/active_support/log_subscriber/test_helper.rb +14 -12
- data/lib/active_support/log_subscriber.rb +61 -18
- data/lib/active_support/logger.rb +40 -4
- data/lib/active_support/logger_silence.rb +17 -20
- data/lib/active_support/logger_thread_safe_level.rb +69 -0
- data/lib/active_support/message_encryptor.rb +178 -55
- data/lib/active_support/message_verifier.rb +195 -26
- data/lib/active_support/messages/metadata.rb +80 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotator.rb +57 -0
- data/lib/active_support/multibyte/chars.rb +45 -92
- data/lib/active_support/multibyte/unicode.rb +44 -377
- data/lib/active_support/multibyte.rb +5 -3
- data/lib/active_support/notifications/fanout.rb +177 -44
- data/lib/active_support/notifications/instrumenter.rb +117 -17
- data/lib/active_support/notifications.rb +106 -39
- data/lib/active_support/number_helper/number_converter.rb +181 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +59 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
- data/lib/active_support/number_helper/rounding_helper.rb +46 -0
- data/lib/active_support/number_helper.rb +152 -394
- data/lib/active_support/option_merger.rb +18 -5
- data/lib/active_support/ordered_hash.rb +8 -6
- data/lib/active_support/ordered_options.rb +43 -7
- data/lib/active_support/parameter_filter.rb +138 -0
- data/lib/active_support/per_thread_registry.rb +24 -11
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +10 -11
- data/lib/active_support/railtie.rb +118 -12
- data/lib/active_support/reloader.rb +130 -0
- data/lib/active_support/rescuable.rb +112 -57
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +38 -0
- data/lib/active_support/string_inquirer.rb +11 -4
- data/lib/active_support/subscriber.rb +109 -39
- data/lib/active_support/tagged_logging.rb +54 -17
- data/lib/active_support/test_case.rb +121 -37
- data/lib/active_support/testing/assertions.rb +177 -39
- data/lib/active_support/testing/autorun.rb +5 -3
- data/lib/active_support/testing/constant_lookup.rb +3 -6
- data/lib/active_support/testing/declarative.rb +10 -22
- data/lib/active_support/testing/deprecation.rb +65 -11
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +56 -87
- data/lib/active_support/testing/method_call_assertions.rb +70 -0
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +55 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/setup_and_teardown.rb +30 -10
- data/lib/active_support/testing/stream.rb +41 -0
- data/lib/active_support/testing/tagged_logging.rb +6 -4
- data/lib/active_support/testing/time_helpers.rb +246 -0
- data/lib/active_support/time.rb +13 -13
- data/lib/active_support/time_with_zone.rb +315 -90
- data/lib/active_support/values/time_zone.rb +306 -135
- data/lib/active_support/version.rb +6 -7
- data/lib/active_support/xml_mini/jdom.rb +117 -115
- data/lib/active_support/xml_mini/libxml.rb +22 -21
- data/lib/active_support/xml_mini/libxmlsax.rb +17 -19
- data/lib/active_support/xml_mini/nokogiri.rb +19 -19
- data/lib/active_support/xml_mini/nokogirisax.rb +16 -17
- data/lib/active_support/xml_mini/rexml.rb +25 -17
- data/lib/active_support/xml_mini.rb +67 -56
- data/lib/active_support.rb +58 -3
- metadata +125 -66
- data/lib/active_support/basic_object.rb +0 -11
- data/lib/active_support/buffered_logger.rb +0 -21
- data/lib/active_support/concurrency/latch.rb +0 -27
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
- data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -40
- data/lib/active_support/core_ext/date_time/zones.rb +0 -24
- data/lib/active_support/core_ext/hash/diff.rb +0 -14
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
- data/lib/active_support/core_ext/logger.rb +0 -67
- data/lib/active_support/core_ext/marshal.rb +0 -21
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
- data/lib/active_support/core_ext/module/reachable.rb +0 -8
- data/lib/active_support/core_ext/object/to_json.rb +0 -27
- data/lib/active_support/core_ext/proc.rb +0 -17
- data/lib/active_support/core_ext/range/include_range.rb +0 -23
- data/lib/active_support/core_ext/string/encoding.rb +0 -8
- data/lib/active_support/core_ext/struct.rb +0 -6
- data/lib/active_support/core_ext/thread.rb +0 -79
- data/lib/active_support/core_ext/time/marshal.rb +0 -30
- data/lib/active_support/file_watcher.rb +0 -36
- data/lib/active_support/json/variable.rb +0 -18
- data/lib/active_support/testing/pending.rb +0 -14
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,8 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rbconfig"
|
4
|
+
|
1
5
|
module ActiveSupport
|
2
6
|
class Deprecation
|
3
7
|
module Reporting
|
4
8
|
# Whether to print a message (silent mode)
|
5
|
-
|
9
|
+
attr_writer :silenced
|
6
10
|
# Name of gem where method is deprecated
|
7
11
|
attr_accessor :gem_name
|
8
12
|
|
@@ -14,9 +18,13 @@ module ActiveSupport
|
|
14
18
|
def warn(message = nil, callstack = nil)
|
15
19
|
return if silenced
|
16
20
|
|
17
|
-
callstack ||=
|
21
|
+
callstack ||= caller_locations(2)
|
18
22
|
deprecation_message(callstack, message).tap do |m|
|
19
|
-
|
23
|
+
if deprecation_disallowed?(message)
|
24
|
+
disallowed_behavior.each { |b| b.call(m, callstack, deprecation_horizon, gem_name) }
|
25
|
+
else
|
26
|
+
behavior.each { |b| b.call(m, callstack, deprecation_horizon, gem_name) }
|
27
|
+
end
|
20
28
|
end
|
21
29
|
end
|
22
30
|
|
@@ -29,15 +37,54 @@ module ActiveSupport
|
|
29
37
|
# ActiveSupport::Deprecation.warn('something broke!')
|
30
38
|
# end
|
31
39
|
# # => nil
|
32
|
-
def silence
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
40
|
+
def silence(&block)
|
41
|
+
@silenced_thread.bind(true, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Allow previously disallowed deprecation warnings within the block.
|
45
|
+
# <tt>allowed_warnings</tt> can be an array containing strings, symbols, or regular
|
46
|
+
# expressions. (Symbols are treated as strings). These are compared against
|
47
|
+
# the text of deprecation warning messages generated within the block.
|
48
|
+
# Matching warnings will be exempt from the rules set by
|
49
|
+
# +ActiveSupport::Deprecation.disallowed_warnings+
|
50
|
+
#
|
51
|
+
# The optional <tt>if:</tt> argument accepts a truthy/falsy value or an object that
|
52
|
+
# responds to <tt>.call</tt>. If truthy, then matching warnings will be allowed.
|
53
|
+
# If falsey then the method yields to the block without allowing the warning.
|
54
|
+
#
|
55
|
+
# ActiveSupport::Deprecation.disallowed_behavior = :raise
|
56
|
+
# ActiveSupport::Deprecation.disallowed_warnings = [
|
57
|
+
# "something broke"
|
58
|
+
# ]
|
59
|
+
#
|
60
|
+
# ActiveSupport::Deprecation.warn('something broke!')
|
61
|
+
# # => ActiveSupport::DeprecationException
|
62
|
+
#
|
63
|
+
# ActiveSupport::Deprecation.allow ['something broke'] do
|
64
|
+
# ActiveSupport::Deprecation.warn('something broke!')
|
65
|
+
# end
|
66
|
+
# # => nil
|
67
|
+
#
|
68
|
+
# ActiveSupport::Deprecation.allow ['something broke'], if: Rails.env.production? do
|
69
|
+
# ActiveSupport::Deprecation.warn('something broke!')
|
70
|
+
# end
|
71
|
+
# # => ActiveSupport::DeprecationException for dev/test, nil for production
|
72
|
+
def allow(allowed_warnings = :all, if: true, &block)
|
73
|
+
conditional = binding.local_variable_get(:if)
|
74
|
+
conditional = conditional.call if conditional.respond_to?(:call)
|
75
|
+
if conditional
|
76
|
+
@explicitly_allowed_warnings.bind(allowed_warnings, &block)
|
77
|
+
else
|
78
|
+
yield
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def silenced
|
83
|
+
@silenced || @silenced_thread.value
|
37
84
|
end
|
38
85
|
|
39
86
|
def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil)
|
40
|
-
caller_backtrace ||=
|
87
|
+
caller_backtrace ||= caller_locations(2)
|
41
88
|
deprecated_method_warning(deprecated_method_name, message).tap do |msg|
|
42
89
|
warn(msg, caller_backtrace)
|
43
90
|
end
|
@@ -46,24 +93,23 @@ module ActiveSupport
|
|
46
93
|
private
|
47
94
|
# Outputs a deprecation warning message
|
48
95
|
#
|
49
|
-
#
|
96
|
+
# deprecated_method_warning(:method_name)
|
50
97
|
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon}"
|
51
|
-
#
|
98
|
+
# deprecated_method_warning(:method_name, :another_method)
|
52
99
|
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon} (use another_method instead)"
|
53
|
-
#
|
100
|
+
# deprecated_method_warning(:method_name, "Optional message")
|
54
101
|
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon} (Optional message)"
|
55
102
|
def deprecated_method_warning(method_name, message = nil)
|
56
103
|
warning = "#{method_name} is deprecated and will be removed from #{gem_name} #{deprecation_horizon}"
|
57
104
|
case message
|
58
|
-
|
59
|
-
|
60
|
-
|
105
|
+
when Symbol then "#{warning} (use #{message} instead)"
|
106
|
+
when String then "#{warning} (#{message})"
|
107
|
+
else warning
|
61
108
|
end
|
62
109
|
end
|
63
110
|
|
64
111
|
def deprecation_message(callstack, message = nil)
|
65
112
|
message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
|
66
|
-
message += '.' unless message =~ /\.$/
|
67
113
|
"DEPRECATION WARNING: #{message} #{deprecation_caller_message(callstack)}"
|
68
114
|
end
|
69
115
|
|
@@ -79,8 +125,19 @@ module ActiveSupport
|
|
79
125
|
end
|
80
126
|
|
81
127
|
def extract_callstack(callstack)
|
82
|
-
|
83
|
-
|
128
|
+
return _extract_callstack(callstack) if callstack.first.is_a? String
|
129
|
+
|
130
|
+
offending_line = callstack.find { |frame|
|
131
|
+
frame.absolute_path && !ignored_callstack(frame.absolute_path)
|
132
|
+
} || callstack.first
|
133
|
+
|
134
|
+
[offending_line.path, offending_line.lineno, offending_line.label]
|
135
|
+
end
|
136
|
+
|
137
|
+
def _extract_callstack(callstack)
|
138
|
+
warn "Please pass `caller_locations` to the deprecation API" if $VERBOSE
|
139
|
+
offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first
|
140
|
+
|
84
141
|
if offending_line
|
85
142
|
if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
|
86
143
|
md.captures
|
@@ -89,6 +146,12 @@ module ActiveSupport
|
|
89
146
|
end
|
90
147
|
end
|
91
148
|
end
|
149
|
+
|
150
|
+
RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/"
|
151
|
+
|
152
|
+
def ignored_callstack(path)
|
153
|
+
path.start_with?(RAILS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG["rubylibdir"])
|
154
|
+
end
|
92
155
|
end
|
93
156
|
end
|
94
157
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
2
4
|
|
3
5
|
module ActiveSupport
|
4
6
|
# \Deprecation specifies the API used by Rails to deprecate methods, instance
|
@@ -12,32 +14,38 @@ module ActiveSupport
|
|
12
14
|
# a circular require warning for active_support/deprecation.rb.
|
13
15
|
#
|
14
16
|
# So, we define the constant first, and load dependencies later.
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
17
|
+
require "active_support/deprecation/instance_delegator"
|
18
|
+
require "active_support/deprecation/behaviors"
|
19
|
+
require "active_support/deprecation/reporting"
|
20
|
+
require "active_support/deprecation/disallowed"
|
21
|
+
require "active_support/deprecation/constant_accessor"
|
22
|
+
require "active_support/deprecation/method_wrappers"
|
23
|
+
require "active_support/deprecation/proxy_wrappers"
|
24
|
+
require "active_support/core_ext/module/deprecation"
|
25
|
+
require "concurrent/atomic/thread_local_var"
|
21
26
|
|
22
27
|
include Singleton
|
23
28
|
include InstanceDelegator
|
24
29
|
include Behavior
|
25
30
|
include Reporting
|
31
|
+
include Disallowed
|
26
32
|
include MethodWrapper
|
27
33
|
|
28
|
-
# The version the deprecated behavior will be removed, by default.
|
34
|
+
# The version number in which the deprecated behavior will be removed, by default.
|
29
35
|
attr_accessor :deprecation_horizon
|
30
36
|
|
31
|
-
# It accepts two parameters on initialization. The first is
|
32
|
-
# and the second is
|
37
|
+
# It accepts two parameters on initialization. The first is a version of library
|
38
|
+
# and the second is a library name.
|
33
39
|
#
|
34
40
|
# ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
|
35
|
-
def initialize(deprecation_horizon =
|
41
|
+
def initialize(deprecation_horizon = "7.1", gem_name = "Rails")
|
36
42
|
self.gem_name = gem_name
|
37
43
|
self.deprecation_horizon = deprecation_horizon
|
38
44
|
# By default, warnings are not silenced and debugging is off.
|
39
45
|
self.silenced = false
|
40
46
|
self.debug = false
|
47
|
+
@silenced_thread = Concurrent::ThreadLocalVar.new(false)
|
48
|
+
@explicitly_allowed_warnings = Concurrent::ThreadLocalVar.new(nil)
|
41
49
|
end
|
42
50
|
end
|
43
51
|
end
|
@@ -1,60 +1,218 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "weakref"
|
4
|
+
require "active_support/ruby_features"
|
5
|
+
|
1
6
|
module ActiveSupport
|
2
7
|
# This module provides an internal implementation to track descendants
|
3
8
|
# which is faster than iterating through ObjectSpace.
|
4
9
|
module DescendantsTracker
|
5
|
-
@@direct_descendants = {}
|
6
|
-
|
7
10
|
class << self
|
8
11
|
def direct_descendants(klass)
|
9
|
-
|
12
|
+
ActiveSupport::Deprecation.warn(<<~MSG)
|
13
|
+
ActiveSupport::DescendantsTracker.direct_descendants is deprecated and will be removed in Rails 7.1.
|
14
|
+
Use ActiveSupport::DescendantsTracker.subclasses instead.
|
15
|
+
MSG
|
16
|
+
subclasses(klass)
|
10
17
|
end
|
18
|
+
end
|
19
|
+
|
20
|
+
@clear_disabled = false
|
21
|
+
|
22
|
+
if RubyFeatures::CLASS_SUBCLASSES
|
23
|
+
@@excluded_descendants = if RUBY_ENGINE == "ruby"
|
24
|
+
# On MRI `ObjectSpace::WeakMap` keys are weak references.
|
25
|
+
# So we can simply use WeakMap as a `Set`.
|
26
|
+
ObjectSpace::WeakMap.new
|
27
|
+
else
|
28
|
+
# On TruffleRuby `ObjectSpace::WeakMap` keys are strong references.
|
29
|
+
# So we use `object_id` as a key and the actual object as a value.
|
30
|
+
#
|
31
|
+
# JRuby for now doesn't have Class#descendant, but when it will, it will likely
|
32
|
+
# have the same WeakMap semantic than Truffle so we future proof this as much as possible.
|
33
|
+
class WeakSet # :nodoc:
|
34
|
+
def initialize
|
35
|
+
@map = ObjectSpace::WeakMap.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def [](object)
|
39
|
+
@map.key?(object.object_id)
|
40
|
+
end
|
11
41
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
42
|
+
def []=(object, _present)
|
43
|
+
@map[object.object_id] = object
|
44
|
+
end
|
45
|
+
end
|
46
|
+
WeakSet.new
|
16
47
|
end
|
17
48
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
49
|
+
class << self
|
50
|
+
def disable_clear! # :nodoc:
|
51
|
+
unless @clear_disabled
|
52
|
+
@clear_disabled = true
|
53
|
+
remove_method(:subclasses)
|
54
|
+
@@excluded_descendants = nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def subclasses(klass)
|
59
|
+
klass.subclasses
|
60
|
+
end
|
61
|
+
|
62
|
+
def descendants(klass)
|
63
|
+
klass.descendants
|
64
|
+
end
|
65
|
+
|
66
|
+
def clear(classes) # :nodoc:
|
67
|
+
raise "DescendantsTracker.clear was disabled because config.cache_classes = true" if @clear_disabled
|
68
|
+
|
69
|
+
classes.each do |klass|
|
70
|
+
@@excluded_descendants[klass] = true
|
71
|
+
klass.descendants.each do |descendant|
|
72
|
+
@@excluded_descendants[descendant] = true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def native? # :nodoc:
|
78
|
+
true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def subclasses
|
83
|
+
subclasses = super
|
84
|
+
subclasses.reject! { |d| @@excluded_descendants[d] }
|
85
|
+
subclasses
|
86
|
+
end
|
87
|
+
|
88
|
+
def descendants
|
89
|
+
subclasses.concat(subclasses.flat_map(&:descendants))
|
90
|
+
end
|
91
|
+
|
92
|
+
def direct_descendants
|
93
|
+
ActiveSupport::Deprecation.warn(<<~MSG)
|
94
|
+
ActiveSupport::DescendantsTracker#direct_descendants is deprecated and will be removed in Rails 7.1.
|
95
|
+
Use #subclasses instead.
|
96
|
+
MSG
|
97
|
+
subclasses
|
98
|
+
end
|
99
|
+
else
|
100
|
+
@@direct_descendants = {}
|
101
|
+
|
102
|
+
class << self
|
103
|
+
def disable_clear! # :nodoc:
|
104
|
+
@clear_disabled = true
|
105
|
+
end
|
106
|
+
|
107
|
+
def subclasses(klass)
|
108
|
+
descendants = @@direct_descendants[klass]
|
109
|
+
descendants ? descendants.to_a : []
|
110
|
+
end
|
111
|
+
|
112
|
+
def descendants(klass)
|
113
|
+
arr = []
|
114
|
+
accumulate_descendants(klass, arr)
|
115
|
+
arr
|
116
|
+
end
|
117
|
+
|
118
|
+
def clear(classes) # :nodoc:
|
119
|
+
raise "DescendantsTracker.clear was disabled because config.cache_classes = true" if @clear_disabled
|
120
|
+
|
121
|
+
@@direct_descendants.each do |klass, direct_descendants_of_klass|
|
122
|
+
if classes.member?(klass)
|
22
123
|
@@direct_descendants.delete(klass)
|
23
124
|
else
|
24
|
-
|
125
|
+
direct_descendants_of_klass.reject! do |direct_descendant_of_class|
|
126
|
+
classes.member?(direct_descendant_of_class)
|
127
|
+
end
|
25
128
|
end
|
26
129
|
end
|
27
|
-
else
|
28
|
-
@@direct_descendants.clear
|
29
130
|
end
|
131
|
+
|
132
|
+
def native? # :nodoc:
|
133
|
+
false
|
134
|
+
end
|
135
|
+
|
136
|
+
# This is the only method that is not thread safe, but is only ever called
|
137
|
+
# during the eager loading phase.
|
138
|
+
def store_inherited(klass, descendant)
|
139
|
+
(@@direct_descendants[klass] ||= DescendantsArray.new) << descendant
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
def accumulate_descendants(klass, acc)
|
144
|
+
if direct_descendants = @@direct_descendants[klass]
|
145
|
+
direct_descendants.each do |direct_descendant|
|
146
|
+
acc << direct_descendant
|
147
|
+
accumulate_descendants(direct_descendant, acc)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
30
151
|
end
|
31
152
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
(@@direct_descendants[klass] ||= []) << descendant
|
153
|
+
def inherited(base)
|
154
|
+
DescendantsTracker.store_inherited(self, base)
|
155
|
+
super
|
36
156
|
end
|
37
157
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
158
|
+
def direct_descendants
|
159
|
+
ActiveSupport::Deprecation.warn(<<~MSG)
|
160
|
+
ActiveSupport::DescendantsTracker#direct_descendants is deprecated and will be removed in Rails 7.1.
|
161
|
+
Use #subclasses instead.
|
162
|
+
MSG
|
163
|
+
DescendantsTracker.subclasses(self)
|
44
164
|
end
|
45
|
-
end
|
46
165
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
166
|
+
def subclasses
|
167
|
+
DescendantsTracker.subclasses(self)
|
168
|
+
end
|
51
169
|
|
52
|
-
|
53
|
-
|
54
|
-
|
170
|
+
def descendants
|
171
|
+
DescendantsTracker.descendants(self)
|
172
|
+
end
|
55
173
|
|
56
|
-
|
57
|
-
|
174
|
+
# DescendantsArray is an array that contains weak references to classes.
|
175
|
+
class DescendantsArray # :nodoc:
|
176
|
+
include Enumerable
|
177
|
+
|
178
|
+
def initialize
|
179
|
+
@refs = []
|
180
|
+
end
|
181
|
+
|
182
|
+
def initialize_copy(orig)
|
183
|
+
@refs = @refs.dup
|
184
|
+
end
|
185
|
+
|
186
|
+
def <<(klass)
|
187
|
+
@refs << WeakRef.new(klass)
|
188
|
+
end
|
189
|
+
|
190
|
+
def each
|
191
|
+
@refs.reject! do |ref|
|
192
|
+
yield ref.__getobj__
|
193
|
+
false
|
194
|
+
rescue WeakRef::RefError
|
195
|
+
true
|
196
|
+
end
|
197
|
+
self
|
198
|
+
end
|
199
|
+
|
200
|
+
def refs_size
|
201
|
+
@refs.size
|
202
|
+
end
|
203
|
+
|
204
|
+
def cleanup!
|
205
|
+
@refs.delete_if { |ref| !ref.weakref_alive? }
|
206
|
+
end
|
207
|
+
|
208
|
+
def reject!
|
209
|
+
@refs.reject! do |ref|
|
210
|
+
yield ref.__getobj__
|
211
|
+
rescue WeakRef::RefError
|
212
|
+
true
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
58
216
|
end
|
59
217
|
end
|
60
218
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "openssl"
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
class Digest # :nodoc:
|
7
|
+
class << self
|
8
|
+
def hash_digest_class
|
9
|
+
@hash_digest_class ||= OpenSSL::Digest::MD5
|
10
|
+
end
|
11
|
+
|
12
|
+
def hash_digest_class=(klass)
|
13
|
+
raise ArgumentError, "#{klass} is expected to implement hexdigest class method" unless klass.respond_to?(:hexdigest)
|
14
|
+
@hash_digest_class = klass
|
15
|
+
end
|
16
|
+
|
17
|
+
def hexdigest(arg)
|
18
|
+
hash_digest_class.hexdigest(arg)[0...32]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "strscan"
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
class Duration
|
7
|
+
# Parses a string formatted according to ISO 8601 Duration into the hash.
|
8
|
+
#
|
9
|
+
# See {ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601#Durations] for more information.
|
10
|
+
#
|
11
|
+
# This parser allows negative parts to be present in pattern.
|
12
|
+
class ISO8601Parser # :nodoc:
|
13
|
+
class ParsingError < ::ArgumentError; end
|
14
|
+
|
15
|
+
PERIOD_OR_COMMA = /\.|,/
|
16
|
+
PERIOD = "."
|
17
|
+
COMMA = ","
|
18
|
+
|
19
|
+
SIGN_MARKER = /\A-|\+|/
|
20
|
+
DATE_MARKER = /P/
|
21
|
+
TIME_MARKER = /T/
|
22
|
+
DATE_COMPONENT = /(-?\d+(?:[.,]\d+)?)(Y|M|D|W)/
|
23
|
+
TIME_COMPONENT = /(-?\d+(?:[.,]\d+)?)(H|M|S)/
|
24
|
+
|
25
|
+
DATE_TO_PART = { "Y" => :years, "M" => :months, "W" => :weeks, "D" => :days }
|
26
|
+
TIME_TO_PART = { "H" => :hours, "M" => :minutes, "S" => :seconds }
|
27
|
+
|
28
|
+
DATE_COMPONENTS = [:years, :months, :days]
|
29
|
+
TIME_COMPONENTS = [:hours, :minutes, :seconds]
|
30
|
+
|
31
|
+
attr_reader :parts, :scanner
|
32
|
+
attr_accessor :mode, :sign
|
33
|
+
|
34
|
+
def initialize(string)
|
35
|
+
@scanner = StringScanner.new(string)
|
36
|
+
@parts = {}
|
37
|
+
@mode = :start
|
38
|
+
@sign = 1
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse!
|
42
|
+
while !finished?
|
43
|
+
case mode
|
44
|
+
when :start
|
45
|
+
if scan(SIGN_MARKER)
|
46
|
+
self.sign = (scanner.matched == "-") ? -1 : 1
|
47
|
+
self.mode = :sign
|
48
|
+
else
|
49
|
+
raise_parsing_error
|
50
|
+
end
|
51
|
+
|
52
|
+
when :sign
|
53
|
+
if scan(DATE_MARKER)
|
54
|
+
self.mode = :date
|
55
|
+
else
|
56
|
+
raise_parsing_error
|
57
|
+
end
|
58
|
+
|
59
|
+
when :date
|
60
|
+
if scan(TIME_MARKER)
|
61
|
+
self.mode = :time
|
62
|
+
elsif scan(DATE_COMPONENT)
|
63
|
+
parts[DATE_TO_PART[scanner[2]]] = number * sign
|
64
|
+
else
|
65
|
+
raise_parsing_error
|
66
|
+
end
|
67
|
+
|
68
|
+
when :time
|
69
|
+
if scan(TIME_COMPONENT)
|
70
|
+
parts[TIME_TO_PART[scanner[2]]] = number * sign
|
71
|
+
else
|
72
|
+
raise_parsing_error
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
validate!
|
79
|
+
parts
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
def finished?
|
84
|
+
scanner.eos?
|
85
|
+
end
|
86
|
+
|
87
|
+
# Parses number which can be a float with either comma or period.
|
88
|
+
def number
|
89
|
+
PERIOD_OR_COMMA.match?(scanner[1]) ? scanner[1].tr(COMMA, PERIOD).to_f : scanner[1].to_i
|
90
|
+
end
|
91
|
+
|
92
|
+
def scan(pattern)
|
93
|
+
scanner.scan(pattern)
|
94
|
+
end
|
95
|
+
|
96
|
+
def raise_parsing_error(reason = nil)
|
97
|
+
raise ParsingError, "Invalid ISO 8601 duration: #{scanner.string.inspect} #{reason}".strip
|
98
|
+
end
|
99
|
+
|
100
|
+
# Checks for various semantic errors as stated in ISO 8601 standard.
|
101
|
+
def validate!
|
102
|
+
raise_parsing_error("is empty duration") if parts.empty?
|
103
|
+
|
104
|
+
# Mixing any of Y, M, D with W is invalid.
|
105
|
+
if parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any?
|
106
|
+
raise_parsing_error("mixing weeks with other date parts not allowed")
|
107
|
+
end
|
108
|
+
|
109
|
+
# Specifying an empty T part is invalid.
|
110
|
+
if mode == :time && (parts.keys & TIME_COMPONENTS).empty?
|
111
|
+
raise_parsing_error("time part marker is present but time part is empty")
|
112
|
+
end
|
113
|
+
|
114
|
+
fractions = parts.values.reject(&:zero?).select { |a| (a % 1) != 0 }
|
115
|
+
unless fractions.empty? || (fractions.size == 1 && fractions.last == @parts.values.reject(&:zero?).last)
|
116
|
+
raise_parsing_error "(only last part can be fractional)"
|
117
|
+
end
|
118
|
+
|
119
|
+
true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/object/blank"
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
class Duration
|
7
|
+
# Serializes duration to string according to ISO 8601 Duration format.
|
8
|
+
class ISO8601Serializer # :nodoc:
|
9
|
+
DATE_COMPONENTS = %i(years months days)
|
10
|
+
|
11
|
+
def initialize(duration, precision: nil)
|
12
|
+
@duration = duration
|
13
|
+
@precision = precision
|
14
|
+
end
|
15
|
+
|
16
|
+
# Builds and returns output string.
|
17
|
+
def serialize
|
18
|
+
parts = normalize
|
19
|
+
return "PT0S" if parts.empty?
|
20
|
+
|
21
|
+
output = +"P"
|
22
|
+
output << "#{parts[:years]}Y" if parts.key?(:years)
|
23
|
+
output << "#{parts[:months]}M" if parts.key?(:months)
|
24
|
+
output << "#{parts[:days]}D" if parts.key?(:days)
|
25
|
+
output << "#{parts[:weeks]}W" if parts.key?(:weeks)
|
26
|
+
time = +""
|
27
|
+
time << "#{parts[:hours]}H" if parts.key?(:hours)
|
28
|
+
time << "#{parts[:minutes]}M" if parts.key?(:minutes)
|
29
|
+
if parts.key?(:seconds)
|
30
|
+
time << "#{format_seconds(parts[:seconds])}S"
|
31
|
+
end
|
32
|
+
output << "T#{time}" unless time.empty?
|
33
|
+
output
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
# Return pair of duration's parts and whole duration sign.
|
38
|
+
# Parts are summarized (as they can become repetitive due to addition, etc).
|
39
|
+
# Zero parts are removed as not significant.
|
40
|
+
# If all parts are negative it will negate all of them and return minus as a sign.
|
41
|
+
def normalize
|
42
|
+
parts = @duration.parts.each_with_object(Hash.new(0)) do |(k, v), p|
|
43
|
+
p[k] += v unless v.zero?
|
44
|
+
end
|
45
|
+
|
46
|
+
# Convert weeks to days and remove weeks if mixed with date parts
|
47
|
+
if week_mixed_with_date?(parts)
|
48
|
+
parts[:days] += parts.delete(:weeks) * SECONDS_PER_WEEK / SECONDS_PER_DAY
|
49
|
+
end
|
50
|
+
|
51
|
+
parts
|
52
|
+
end
|
53
|
+
|
54
|
+
def week_mixed_with_date?(parts)
|
55
|
+
parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any?
|
56
|
+
end
|
57
|
+
|
58
|
+
def format_seconds(seconds)
|
59
|
+
if @precision
|
60
|
+
sprintf("%0.0#{@precision}f", seconds)
|
61
|
+
else
|
62
|
+
seconds.to_s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|