loga 1.3.0 → 1.4.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +4 -0
  3. data/circle.yml +4 -4
  4. data/gemfiles/rails50.gemfile +11 -0
  5. data/lib/loga/ext/rails/rack/{logger4.rb → logger.rb} +0 -0
  6. data/lib/loga/rack/logger.rb +1 -0
  7. data/lib/loga/rack/request.rb +11 -0
  8. data/lib/loga/railtie.rb +12 -3
  9. data/lib/loga/version.rb +1 -1
  10. data/loga.gemspec +2 -7
  11. data/spec/fixtures/README.md +5 -2
  12. data/spec/fixtures/rails50/Rakefile +6 -0
  13. data/spec/fixtures/rails50/app/controllers/application_controller.rb +28 -0
  14. data/spec/fixtures/rails50/app/helpers/application_helper.rb +2 -0
  15. data/spec/fixtures/rails50/app/views/layouts/application.html.erb +13 -0
  16. data/spec/fixtures/rails50/app/views/user.html.erb +1 -0
  17. data/spec/fixtures/rails50/bin/bundle +3 -0
  18. data/spec/fixtures/rails50/bin/rails +4 -0
  19. data/spec/fixtures/rails50/bin/rake +4 -0
  20. data/spec/fixtures/rails50/bin/setup +34 -0
  21. data/spec/fixtures/rails50/bin/update +29 -0
  22. data/spec/fixtures/rails50/config.ru +5 -0
  23. data/spec/fixtures/rails50/config/application.rb +34 -0
  24. data/spec/fixtures/rails50/config/boot.rb +3 -0
  25. data/spec/fixtures/rails50/config/cable.yml +9 -0
  26. data/spec/fixtures/rails50/config/environment.rb +5 -0
  27. data/spec/fixtures/rails50/config/environments/development.rb +44 -0
  28. data/spec/fixtures/rails50/config/environments/production.rb +75 -0
  29. data/spec/fixtures/rails50/config/environments/test.rb +42 -0
  30. data/spec/fixtures/rails50/config/initializers/application_controller_renderer.rb +6 -0
  31. data/spec/fixtures/rails50/config/initializers/backtrace_silencers.rb +7 -0
  32. data/spec/fixtures/rails50/config/initializers/cookies_serializer.rb +5 -0
  33. data/spec/fixtures/rails50/config/initializers/filter_parameter_logging.rb +4 -0
  34. data/spec/fixtures/rails50/config/initializers/inflections.rb +16 -0
  35. data/spec/fixtures/rails50/config/initializers/mime_types.rb +4 -0
  36. data/spec/fixtures/rails50/config/initializers/new_framework_defaults.rb +21 -0
  37. data/spec/fixtures/rails50/config/initializers/session_store.rb +3 -0
  38. data/spec/fixtures/rails50/config/initializers/wrap_parameters.rb +9 -0
  39. data/spec/fixtures/rails50/config/locales/en.yml +23 -0
  40. data/spec/fixtures/rails50/config/puma.rb +47 -0
  41. data/spec/fixtures/rails50/config/routes.rb +9 -0
  42. data/spec/fixtures/rails50/config/secrets.yml +23 -0
  43. data/spec/fixtures/rails50/public/404.html +67 -0
  44. data/spec/fixtures/rails50/public/422.html +67 -0
  45. data/spec/fixtures/rails50/public/500.html +66 -0
  46. data/spec/fixtures/rails50/public/apple-touch-icon-precomposed.png +0 -0
  47. data/spec/fixtures/rails50/public/apple-touch-icon.png +0 -0
  48. data/spec/fixtures/rails50/public/favicon.ico +0 -0
  49. data/spec/fixtures/rails50/public/robots.txt +5 -0
  50. data/spec/integration/rails/railtie_spec.rb +25 -0
  51. data/spec/integration/rails/request_spec.rb +23 -8
  52. data/spec/integration/sinatra_spec.rb +5 -0
  53. data/spec/support/request_spec.rb +5 -5
  54. data/spec/unit/loga/rack/request_spec.rb +48 -0
  55. metadata +79 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4d80b5262e82d731ffe726e5d5ac426fdb45ff2b
4
- data.tar.gz: c381e133eeab921a94eaef9da70cca372cc72481
3
+ metadata.gz: 7c78d0451e64bdc2c8d119392f4843a92b492173
4
+ data.tar.gz: c48cbbab79d4fd61ad15de32328905feecec51f6
5
5
  SHA512:
6
- metadata.gz: 2f67f325796cad9a8bdda68808a58be8e9d6b832a8fddf0384ce9fcb78f5c81d4dd9904677d38fb093c77041c725d1a1c289a68099ca9012b98d23e4ad963611
7
- data.tar.gz: 5d7d794111c10736db8fe81ca3e52ec7691d42ad5af713cbe8cb6a715b4e0e96beda1afeb71c53f4e61b524cc63f277e6f2b2fafe9e3f9ec8a16b862002d7dc0
6
+ metadata.gz: 0b26955630b96e19d9e10db0503c24f1ddd5a6bcaee3dd86973ddbf4c294cb2a7cd27fb22b8b75f2c27a3bf915d41f023341920932f0ca524c80116c76a6eeb2
7
+ data.tar.gz: da5cc880a6a53cb8671016e27a5881cece5c4275e6951aa0053e598b78771c2df12921feb1a6488d5193ef112424e109bfc41cc045b742fec597b81277aaca5c
data/Appraisals CHANGED
@@ -10,5 +10,9 @@ appraise 'sinatra14' do
10
10
  gem 'sinatra', '~> 1.4.0'
11
11
  end
12
12
 
13
+ appraise 'rails50' do
14
+ gem 'rails', '~> 5.0.0'
15
+ end
16
+
13
17
  appraise 'unit' do
14
18
  end
data/circle.yml CHANGED
@@ -1,15 +1,15 @@
1
1
  dependencies:
2
2
  override:
3
- - rvm-exec 2.1.0 bundle install -j 4
4
- - rvm-exec 2.1.0 bundle exec appraisal install -j 4
5
3
  - rvm-exec 2.2.2 bundle install -j 4
6
4
  - rvm-exec 2.2.2 bundle exec appraisal install -j 4
5
+ - rvm-exec 2.3.1 bundle install -j 4
6
+ - rvm-exec 2.3.1 bundle exec appraisal install -j 4
7
7
  test:
8
8
  override:
9
- - RACK_ENV=development rvm-exec 2.1.0 bundle exec appraisal rspec
10
- - RACK_ENV=production rvm-exec 2.1.0 bundle exec appraisal rspec
11
9
  - RACK_ENV=development rvm-exec 2.2.2 bundle exec appraisal rspec
12
10
  - RACK_ENV=production rvm-exec 2.2.2 bundle exec appraisal rspec
11
+ - RACK_ENV=development rvm-exec 2.3.1 bundle exec appraisal rspec
12
+ - RACK_ENV=production rvm-exec 2.3.1 bundle exec appraisal rspec
13
13
  - rvm-exec 2.2.2 bundle exec rubocop
14
14
  deployment:
15
15
  gemfury:
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 5.0.0"
6
+
7
+ group :test do
8
+ gem "codeclimate-test-reporter", :require => false
9
+ end
10
+
11
+ gemspec :path => "../"
@@ -44,6 +44,7 @@ module Loga
44
44
  data['request_id'] = request.uuid
45
45
  data['request_ip'] = request.ip
46
46
  data['user_agent'] = request.user_agent
47
+ data['controller'] = request.action_controller if request.action_controller_instance
47
48
  data['duration'] = duration_in_ms(started_at, Time.now)
48
49
  end
49
50
 
@@ -5,6 +5,7 @@ module Loga
5
5
  module Rack
6
6
  class Request < ::Rack::Request
7
7
  ACTION_DISPATCH_REQUEST_ID = 'action_dispatch.request_id'.freeze
8
+ ACTION_CONTROLLER_INSTANCE = 'action_controller.instance'.freeze
8
9
 
9
10
  def initialize(env)
10
11
  super
@@ -15,6 +16,16 @@ module Loga
15
16
  @uuid ||= env[ACTION_DISPATCH_REQUEST_ID]
16
17
  end
17
18
 
19
+ alias request_id uuid
20
+
21
+ def action_controller
22
+ "#{action_controller_instance.class}##{action_controller_instance.action_name}"
23
+ end
24
+
25
+ def action_controller_instance
26
+ @action_controller_instance ||= env[ACTION_CONTROLLER_INSTANCE]
27
+ end
28
+
18
29
  def original_path
19
30
  env['loga.request.original_path']
20
31
  end
@@ -49,9 +49,10 @@ module Loga
49
49
 
50
50
  private
51
51
 
52
- def render_exception_with_loga(env, exception)
52
+ def render_exception_with_loga(arg, exception)
53
+ env = arg.is_a?(ActionDispatch::Request) ? arg.env : arg
53
54
  env['loga.exception'] = exception
54
- render_exception_without_loga(env, exception)
55
+ render_exception_without_loga(arg, exception)
55
56
  end
56
57
  end
57
58
 
@@ -85,7 +86,8 @@ module Loga
85
86
 
86
87
  case Rails::VERSION::MAJOR
87
88
  when 3 then require 'loga/ext/rails/rack/logger3.rb'
88
- when 4 then require 'loga/ext/rails/rack/logger4.rb'
89
+ else
90
+ require 'loga/ext/rails/rack/logger.rb'
89
91
  end
90
92
  end
91
93
 
@@ -113,14 +115,21 @@ module Loga
113
115
 
114
116
  private
115
117
 
118
+ # rubocop:disable Metrics/CyclomaticComplexity
116
119
  def remove_existing_log_subscriptions
120
+ ActionView::Base if defined?(ActionView::Base)
121
+ ActionController::Base if defined?(ActionController::Base)
122
+
117
123
  ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
118
124
  case subscriber
119
125
  when defined?(ActionView::LogSubscriber) && ActionView::LogSubscriber
120
126
  unsubscribe(:action_view, subscriber)
127
+ when defined?(ActionController::LogSubscriber) && ActionController::LogSubscriber
128
+ unsubscribe(:action_controller, subscriber)
121
129
  end
122
130
  end
123
131
  end
132
+ # rubocop:enable Metrics/CyclomaticComplexity
124
133
 
125
134
  def unsubscribe(component, subscriber)
126
135
  events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' }
@@ -1,3 +1,3 @@
1
1
  module Loga
2
- VERSION = '1.3.0'.freeze
2
+ VERSION = '1.4.0'.freeze
3
3
  end
@@ -17,13 +17,8 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(/^(test|spec|features)/)
18
18
  spec.require_paths = ['lib']
19
19
 
20
- if RUBY_VERSION < '2.2'
21
- spec.add_dependency 'activesupport', '>= 2.3.8', '< 5.0'
22
- spec.add_dependency 'rack', '< 2.0'
23
- else
24
- spec.add_dependency 'activesupport', '>= 2.3.8'
25
- spec.add_dependency 'rack'
26
- end
20
+ spec.add_dependency 'activesupport', '>= 2.3.8'
21
+ spec.add_dependency 'rack'
27
22
 
28
23
  spec.add_development_dependency 'appraisal', '~> 2.0.2'
29
24
  spec.add_development_dependency 'bundler', '~> 1.6'
@@ -1,8 +1,11 @@
1
1
  # Generating fixture Apps
2
2
 
3
3
  ## Rails 3.2
4
- `appraisal rails_3.2 rails new spec/fixtures/rails32 --skip-gemfile --skip-git --skip-active-record --skip-sprockets --skip-javascript --skip-test-unit`
4
+ `appraisal rails32 rails new spec/fixtures/rails32 --skip-gemfile --skip-git --skip-active-record --skip-sprockets --skip-javascript --skip-test-unit`
5
5
 
6
6
 
7
7
  ## Rails 4.0
8
- `appraisal rails_4.0 rails new spec/fixtures/rails40 --skip-gemfile --skip-git --skip-keeps --skip-active-record --skip-action-view --skip-sprockets --skip-spring --skip-javascript --skip-test-unit`
8
+ `appraisal rails40 rails new spec/fixtures/rails40 --skip-gemfile --skip-git --skip-keeps --skip-active-record --skip-action-view --skip-sprockets --skip-spring --skip-javascript --skip-test-unit`
9
+
10
+ ## Rails 5.0
11
+ `appraisal rails50 rails new spec/fixtures/rails50 --skip-gemfile --skip-git --skip-keeps --skip-active-record --skip-action-view --skip-sprockets --skip-spring --skip-javascript --skip-test-unit`
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative 'config/application'
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,28 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery with: :null_session
3
+
4
+ def ok
5
+ render text: 'Hello Rails'
6
+ end
7
+
8
+ def error
9
+ nil.name
10
+ end
11
+
12
+ def show
13
+ render json: params
14
+ end
15
+
16
+ def create
17
+ render json: params
18
+ end
19
+
20
+ def new
21
+ redirect_to :ok
22
+ end
23
+
24
+ def update
25
+ @id = params[:id]
26
+ render '/user'
27
+ end
28
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Rails50</title>
5
+ <%= csrf_meta_tags %>
6
+
7
+ <%= stylesheet_link_tag 'application', media: 'all' %>
8
+ </head>
9
+
10
+ <body>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1 @@
1
+ <p>User <%= @id %></p>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../config/application', __dir__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/boot'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+ require 'fileutils'
4
+ include FileUtils
5
+
6
+ # path to your application root.
7
+ APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
8
+
9
+ def system!(*args)
10
+ system(*args) || abort("\n== Command #{args} failed ==")
11
+ end
12
+
13
+ chdir APP_ROOT do
14
+ # This script is a starting point to setup your application.
15
+ # Add necessary setup steps to this file.
16
+
17
+ puts '== Installing dependencies =='
18
+ system! 'gem install bundler --conservative'
19
+ system('bundle check') || system!('bundle install')
20
+
21
+ # puts "\n== Copying sample files =="
22
+ # unless File.exist?('config/database.yml')
23
+ # cp 'config/database.yml.sample', 'config/database.yml'
24
+ # end
25
+
26
+ puts "\n== Preparing database =="
27
+ system! 'bin/rails db:setup'
28
+
29
+ puts "\n== Removing old logs and tempfiles =="
30
+ system! 'bin/rails log:clear tmp:clear'
31
+
32
+ puts "\n== Restarting application server =="
33
+ system! 'bin/rails restart'
34
+ end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+ require 'fileutils'
4
+ include FileUtils
5
+
6
+ # path to your application root.
7
+ APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
8
+
9
+ def system!(*args)
10
+ system(*args) || abort("\n== Command #{args} failed ==")
11
+ end
12
+
13
+ chdir APP_ROOT do
14
+ # This script is a way to update your development environment automatically.
15
+ # Add necessary update steps to this file.
16
+
17
+ puts '== Installing dependencies =='
18
+ system! 'gem install bundler --conservative'
19
+ system('bundle check') || system!('bundle install')
20
+
21
+ puts "\n== Updating database =="
22
+ system! 'bin/rails db:migrate'
23
+
24
+ puts "\n== Removing old logs and tempfiles =="
25
+ system! 'bin/rails log:clear tmp:clear'
26
+
27
+ puts "\n== Restarting application server =="
28
+ system! 'bin/rails restart'
29
+ end
@@ -0,0 +1,5 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require_relative 'config/environment'
4
+
5
+ run Rails.application
@@ -0,0 +1,34 @@
1
+ require_relative 'boot'
2
+
3
+ require "rails"
4
+ # Pick the frameworks you want:
5
+ require "active_model/railtie"
6
+ require "active_job/railtie"
7
+ # require "active_record/railtie"
8
+ require "action_controller/railtie"
9
+ require "action_mailer/railtie"
10
+ require "action_view/railtie"
11
+ require "action_cable/engine"
12
+ # require "sprockets/railtie"
13
+ # require "rails/test_unit/railtie"
14
+
15
+ # Require the gems listed in Gemfile, including any gems
16
+ # you've limited to :test, :development, or :production.
17
+ Bundler.require(*Rails.groups)
18
+
19
+ STREAM = StringIO.new unless defined?(STREAM)
20
+
21
+ module Rails50
22
+ class Application < Rails::Application
23
+ # Settings in config/environments/* take precedence over those specified here.
24
+ # Application configuration should go into files in config/initializers
25
+ # -- all .rb files in that directory are automatically loaded.
26
+ config.log_tags = [ :request_id, 'TEST_TAG' ]
27
+ config.loga.configure do |loga|
28
+ loga.service_name = 'hello_world_app'
29
+ loga.service_version = '1.0'
30
+ loga.host = 'bird.example.com'
31
+ loga.device = STREAM
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
2
+
3
+ require 'bundler/setup' # Set up gems listed in the Gemfile.
@@ -0,0 +1,9 @@
1
+ development:
2
+ adapter: async
3
+
4
+ test:
5
+ adapter: async
6
+
7
+ production:
8
+ adapter: redis
9
+ url: redis://localhost:6379/1
@@ -0,0 +1,5 @@
1
+ # Load the Rails application.
2
+ require_relative 'application'
3
+
4
+ # Initialize the Rails application.
5
+ Rails.application.initialize!
@@ -0,0 +1,44 @@
1
+ Rails.application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
+
4
+ # In the development environment your application's code is reloaded on
5
+ # every request. This slows down response time but is perfect for development
6
+ # since you don't have to restart the web server when you make code changes.
7
+ config.cache_classes = false
8
+
9
+ # Do not eager load code on boot.
10
+ config.eager_load = false
11
+
12
+ # Show full error reports.
13
+ config.consider_all_requests_local = true
14
+
15
+ # Enable/disable caching. By default caching is disabled.
16
+ if Rails.root.join('tmp/caching-dev.txt').exist?
17
+ config.action_controller.perform_caching = true
18
+
19
+ config.cache_store = :memory_store
20
+ config.public_file_server.headers = {
21
+ 'Cache-Control' => 'public, max-age=172800'
22
+ }
23
+ else
24
+ config.action_controller.perform_caching = false
25
+
26
+ config.cache_store = :null_store
27
+ end
28
+
29
+ # Don't care if the mailer can't send.
30
+ config.action_mailer.raise_delivery_errors = false
31
+
32
+ config.action_mailer.perform_caching = false
33
+
34
+ # Print deprecation notices to the Rails logger.
35
+ config.active_support.deprecation = :log
36
+
37
+
38
+ # Raises error for missing translations
39
+ # config.action_view.raise_on_missing_translations = true
40
+
41
+ # Use an evented file watcher to asynchronously detect changes in source code,
42
+ # routes, locales, etc. This feature depends on the listen gem.
43
+ # config.file_watcher = ActiveSupport::EventedFileUpdateChecker
44
+ end
@@ -0,0 +1,75 @@
1
+ Rails.application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
+
4
+ # Code is not reloaded between requests.
5
+ config.cache_classes = true
6
+
7
+ # Eager load code on boot. This eager loads most of Rails and
8
+ # your application in memory, allowing both threaded web servers
9
+ # and those relying on copy on write to perform better.
10
+ # Rake tasks automatically ignore this option for performance.
11
+ config.eager_load = true
12
+
13
+ # Full error reports are disabled and caching is turned on.
14
+ config.consider_all_requests_local = false
15
+ config.action_controller.perform_caching = true
16
+
17
+ # Disable serving static files from the `/public` folder by default since
18
+ # Apache or NGINX already handles this.
19
+ config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
20
+
21
+
22
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server.
23
+ # config.action_controller.asset_host = 'http://assets.example.com'
24
+
25
+ # Specifies the header that your server uses for sending files.
26
+ # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
27
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
28
+
29
+ # Mount Action Cable outside main process or domain
30
+ # config.action_cable.mount_path = nil
31
+ # config.action_cable.url = 'wss://example.com/cable'
32
+ # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
33
+
34
+ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
35
+ # config.force_ssl = true
36
+
37
+ # Use the lowest log level to ensure availability of diagnostic information
38
+ # when problems arise.
39
+ config.log_level = :debug
40
+
41
+ # Prepend all log lines with the following tags.
42
+ # config.log_tags = [ :request_id ]
43
+
44
+ # Use a different cache store in production.
45
+ # config.cache_store = :mem_cache_store
46
+
47
+ # Use a real queuing backend for Active Job (and separate queues per environment)
48
+ # config.active_job.queue_adapter = :resque
49
+ # config.active_job.queue_name_prefix = "rails50_#{Rails.env}"
50
+ config.action_mailer.perform_caching = false
51
+
52
+ # Ignore bad email addresses and do not raise email delivery errors.
53
+ # Set this to true and configure the email server for immediate delivery to raise delivery errors.
54
+ # config.action_mailer.raise_delivery_errors = false
55
+
56
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
57
+ # the I18n.default_locale when a translation cannot be found).
58
+ config.i18n.fallbacks = true
59
+
60
+ # Send deprecation notices to registered listeners.
61
+ config.active_support.deprecation = :notify
62
+
63
+ # Use default logging formatter so that PID and timestamp are not suppressed.
64
+ config.log_formatter = ::Logger::Formatter.new
65
+
66
+ # Use a different logger for distributed setups.
67
+ # require 'syslog/logger'
68
+ # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
69
+
70
+ if ENV["RAILS_LOG_TO_STDOUT"].present?
71
+ logger = ActiveSupport::Logger.new(STDOUT)
72
+ logger.formatter = config.log_formatter
73
+ config.logger = ActiveSupport::TaggedLogging.new(logger)
74
+ end
75
+ end