breeze_cms 0.9.5

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 (151) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +24 -0
  4. data/Rakefile +6 -0
  5. data/app/assets/config/breeze_manifest.js +2 -0
  6. data/app/assets/images/breeze/breeze_logo.png +0 -0
  7. data/app/assets/images/breeze/card_preview/card_feature_box.png +0 -0
  8. data/app/assets/images/breeze/card_preview/card_feature_normal.png +0 -0
  9. data/app/assets/images/breeze/card_preview/card_full_image.png +0 -0
  10. data/app/assets/images/breeze/card_preview/card_gap_square.png +0 -0
  11. data/app/assets/images/breeze/card_preview/card_large_image.png +0 -0
  12. data/app/assets/images/breeze/card_preview/card_normal_round.png +0 -0
  13. data/app/assets/images/breeze/card_preview/card_normal_square.png +0 -0
  14. data/app/assets/images/breeze/card_preview/card_wide_square.png +0 -0
  15. data/app/assets/images/breeze/card_preview/form_field.png +0 -0
  16. data/app/assets/images/breeze/home.jpg +0 -0
  17. data/app/assets/images/breeze/section_preview/blog_header.png +0 -0
  18. data/app/assets/images/breeze/section_preview/form_section.png +0 -0
  19. data/app/assets/images/breeze/section_preview/section_cards.png +0 -0
  20. data/app/assets/images/breeze/section_preview/section_feature.png +0 -0
  21. data/app/assets/images/breeze/section_preview/section_full_image.png +0 -0
  22. data/app/assets/images/breeze/section_preview/section_full_up.png +0 -0
  23. data/app/assets/images/breeze/section_preview/section_half_image.png +0 -0
  24. data/app/assets/images/breeze/section_preview/section_large_image.png +0 -0
  25. data/app/assets/images/breeze/section_preview/section_news.png +0 -0
  26. data/app/assets/images/breeze/section_preview/section_slider.png +0 -0
  27. data/app/assets/images/breeze/section_preview/section_small_image.png +0 -0
  28. data/app/assets/images/breeze/section_preview/section_spacer.png +0 -0
  29. data/app/assets/images/breeze/section_preview/section_text.png +0 -0
  30. data/app/assets/javascript/breeze_application.js.rb +101 -0
  31. data/app/assets/javascript/marked.js +6 -0
  32. data/app/assets/stylesheets/breeze/breeze.css +3633 -0
  33. data/app/assets/stylesheets/breeze/breeze.email.css +1344 -0
  34. data/app/assets/stylesheets/breeze.tailwind.css +2 -0
  35. data/app/assets/stylesheets/breeze_tailwind_styles.css +21 -0
  36. data/app/assets/stylesheets/tailwind_base.css +3 -0
  37. data/app/controllers/breeze/application_controller.rb +4 -0
  38. data/app/controllers/breeze/breeze_controller.rb +16 -0
  39. data/app/controllers/breeze/cards_controller.rb +58 -0
  40. data/app/controllers/breeze/changes_controller.rb +45 -0
  41. data/app/controllers/breeze/form_controller.rb +67 -0
  42. data/app/controllers/breeze/images_controller.rb +100 -0
  43. data/app/controllers/breeze/pages_controller.rb +66 -0
  44. data/app/controllers/breeze/sections_controller.rb +96 -0
  45. data/app/controllers/breeze/styles_controller.rb +11 -0
  46. data/app/controllers/breeze/translations_controller.rb +56 -0
  47. data/app/controllers/breeze/view_controller.rb +10 -0
  48. data/app/helpers/breeze/breeze_helper.rb +54 -0
  49. data/app/helpers/breeze/cards_helper.rb +11 -0
  50. data/app/helpers/breeze/changes_helper.rb +29 -0
  51. data/app/helpers/breeze/form_helper.rb +5 -0
  52. data/app/helpers/breeze/images_helper.rb +57 -0
  53. data/app/helpers/breeze/options_helper.rb +120 -0
  54. data/app/helpers/breeze/pages_helper.rb +5 -0
  55. data/app/helpers/breeze/sections_helper.rb +14 -0
  56. data/app/helpers/breeze/styles_helper.rb +4 -0
  57. data/app/helpers/breeze/translations_helper.rb +14 -0
  58. data/app/helpers/breeze/view_helper.rb +74 -0
  59. data/app/jobs/breeze/application_job.rb +4 -0
  60. data/app/mailers/breeze/application_mailer.rb +6 -0
  61. data/app/models/breeze/active_base.rb +34 -0
  62. data/app/models/breeze/active_yaml.rb +143 -0
  63. data/app/models/breeze/card.rb +90 -0
  64. data/app/models/breeze/card_style.rb +12 -0
  65. data/app/models/breeze/change_set.rb +58 -0
  66. data/app/models/breeze/image.rb +104 -0
  67. data/app/models/breeze/option_definition.rb +43 -0
  68. data/app/models/breeze/page.rb +97 -0
  69. data/app/models/breeze/page_style.rb +12 -0
  70. data/app/models/breeze/section.rb +137 -0
  71. data/app/models/breeze/section_style.rb +17 -0
  72. data/app/models/breeze/shared_base.rb +20 -0
  73. data/app/models/breeze/style.rb +17 -0
  74. data/app/models/breeze/translation.rb +83 -0
  75. data/app/models/breeze/view_base.rb +134 -0
  76. data/app/views/breeze/cards/index.haml +84 -0
  77. data/app/views/breeze/changes/index.haml +52 -0
  78. data/app/views/breeze/form/_editor.haml +33 -0
  79. data/app/views/breeze/form/form.haml +8 -0
  80. data/app/views/breeze/images/_editor.haml +144 -0
  81. data/app/views/breeze/images/index.haml +83 -0
  82. data/app/views/breeze/images/new.haml +12 -0
  83. data/app/views/breeze/images/show.haml +60 -0
  84. data/app/views/breeze/pages/_sections.rabl +4 -0
  85. data/app/views/breeze/pages/index.haml +49 -0
  86. data/app/views/breeze/pages/show.haml +85 -0
  87. data/app/views/breeze/sections/_option_form_date.haml +4 -0
  88. data/app/views/breeze/sections/_option_form_select.haml +4 -0
  89. data/app/views/breeze/sections/_option_form_text.haml +4 -0
  90. data/app/views/breeze/sections/_overlay.haml +33 -0
  91. data/app/views/breeze/sections/_section.rabl +5 -0
  92. data/app/views/breeze/sections/_sections_pagination.haml +29 -0
  93. data/app/views/breeze/sections/index.haml +88 -0
  94. data/app/views/breeze/sections/new.haml +12 -0
  95. data/app/views/breeze/sections/select_card_template.haml +13 -0
  96. data/app/views/breeze/sections/select_template.haml +15 -0
  97. data/app/views/breeze/sections/show.haml +91 -0
  98. data/app/views/breeze/styles/_options.haml +9 -0
  99. data/app/views/breeze/styles/index.haml +84 -0
  100. data/app/views/breeze/translations/_row.haml +29 -0
  101. data/app/views/breeze/translations/show.haml +79 -0
  102. data/app/views/breeze/view/_blog_header.haml +13 -0
  103. data/app/views/breeze/view/_form_section.haml +21 -0
  104. data/app/views/breeze/view/_section_cards.haml +17 -0
  105. data/app/views/breeze/view/_section_feature.haml +13 -0
  106. data/app/views/breeze/view/_section_full_image.haml +10 -0
  107. data/app/views/breeze/view/_section_full_up.haml +11 -0
  108. data/app/views/breeze/view/_section_half_image.haml +13 -0
  109. data/app/views/breeze/view/_section_large_image.haml +13 -0
  110. data/app/views/breeze/view/_section_news.haml +16 -0
  111. data/app/views/breeze/view/_section_slider.haml +51 -0
  112. data/app/views/breeze/view/_section_small_image.haml +11 -0
  113. data/app/views/breeze/view/_section_spacer.haml +1 -0
  114. data/app/views/breeze/view/_section_text.haml +17 -0
  115. data/app/views/breeze/view/cards/_card_feature_box.haml +13 -0
  116. data/app/views/breeze/view/cards/_card_feature_normal.haml +7 -0
  117. data/app/views/breeze/view/cards/_card_full_image.haml +10 -0
  118. data/app/views/breeze/view/cards/_card_gap_square.haml +11 -0
  119. data/app/views/breeze/view/cards/_card_large_image.haml +6 -0
  120. data/app/views/breeze/view/cards/_card_normal_round.haml +8 -0
  121. data/app/views/breeze/view/cards/_card_normal_square.haml +9 -0
  122. data/app/views/breeze/view/cards/_card_wide_square.haml +8 -0
  123. data/app/views/breeze/view/cards/_form_field.haml +8 -0
  124. data/app/views/breeze/view/elements/_button.haml +4 -0
  125. data/app/views/breeze/view/page.haml +2 -0
  126. data/app/views/layouts/breeze/_header.haml +37 -0
  127. data/app/views/layouts/breeze/_messages.haml +28 -0
  128. data/app/views/layouts/breeze/application.haml +20 -0
  129. data/app/views/layouts/mailer.html.haml +8 -0
  130. data/app/views/layouts/mailer.text.erb +1 -0
  131. data/config/breeze/card_styles.yml +129 -0
  132. data/config/breeze/option_definitions.yml +129 -0
  133. data/config/breeze/page_styles.yml +12 -0
  134. data/config/breeze/section_styles.yml +199 -0
  135. data/config/initializers/breeze.rb +13 -0
  136. data/config/initializers/rabl.rb +31 -0
  137. data/config/initializers/simple_form.rb +212 -0
  138. data/config/routes.rb +40 -0
  139. data/config/tailwind.config.js +17 -0
  140. data/config/tailwind.email.js +14 -0
  141. data/lib/breeze/engine.rb +97 -0
  142. data/lib/breeze/shared_helper.rb +44 -0
  143. data/lib/breeze/version.rb +3 -0
  144. data/lib/breeze.rb +104 -0
  145. data/lib/generators/breeze/install/install_generator.rb +19 -0
  146. data/lib/generators/breeze/install/templates/empty.yml +1 -0
  147. data/lib/generators/breeze/install/templates/initializer.rb +70 -0
  148. data/lib/generators/breeze/update/update_generator.rb +11 -0
  149. data/lib/tasks/condense.rake +60 -0
  150. data/lib/tasks/consistency.rake +84 -0
  151. metadata +371 -0
data/lib/breeze.rb ADDED
@@ -0,0 +1,104 @@
1
+ require "breeze/version"
2
+ require "breeze/engine"
3
+ require "generators/breeze/install/install_generator"
4
+ require "generators/breeze/update/update_generator"
5
+
6
+ module Breeze
7
+
8
+ # Directory inside the app/assets/images
9
+ mattr_accessor :images_dir
10
+ @@images_dir = "breeze"
11
+
12
+ # Languages (space seperated) for multi-lamguage sites
13
+ mattr_accessor :languages
14
+ @@languages = ""
15
+
16
+ def self.has_language( lang )
17
+ @@languages.include?(lang)
18
+ end
19
+
20
+ def self.language_strings
21
+ @@languages.split
22
+ end
23
+
24
+ # directory in root to store data
25
+ mattr_accessor :data_dir
26
+ @@data_dir = "."
27
+
28
+ # text colors, keys are options shown to user, values what gets replaced
29
+ mattr_accessor :text_color
30
+ @@text_color = { "white" => "text-white",
31
+ "none" => "",
32
+ "light_blue" => "text-cyan-100",
33
+ "light_gray" => "text-gray-100",
34
+ "solid_blue" => "text-cyan-700",
35
+ "solid_red" => "text-orange-800",
36
+ "solid_green" => "text-green-700",
37
+ "solid_petrol" => "text-teal-700",
38
+ "solid_indigo" => "text-indigo-800",
39
+ "solid_black" => "text-slate-800",
40
+ }
41
+
42
+ # margin option, keys are options shown to user, values what gets replaced
43
+ mattr_accessor :margin
44
+ @@margin = { "none" => "m-0",
45
+ "small" => " m-2 md:m-4 lg:6 xl:m-8",
46
+ "medium" => "m-5 md:m-8 lg:10 xl:m-14",
47
+ "large" => " m-8 md:m-12 lg:16 xl:m-20",}
48
+
49
+ # background colors
50
+ mattr_accessor :background
51
+ @@background = {"white" => "bg-white",
52
+ "none" => "",
53
+ "light_blue" => "bg-cyan-100",
54
+ "light_gray" => "bg-gray-100",
55
+ "light_orange" => "bg-orange-50",
56
+ "solid_blue" => "bg-cyan-700 text-white",
57
+ "solid_red" => "bg-amber-600 text-white",
58
+ "solid_green" => "bg-green-700 text-white",
59
+ "solid_petrol" => "bg-teal-700 text-white",
60
+ "solid_indigo" => "bg-cyan-900 text-white",
61
+ "solid_black" => "bg-slate-900 text-white", }
62
+
63
+ # shade options
64
+ mattr_accessor :shade_color
65
+ @@shade_color = {"white_25" => "bg-white/25",
66
+ "none" => "",
67
+ "black_25" => "bg-black/25",
68
+ "light_blue_25" => "bg-cyan-100/25",
69
+ "light_red_25" => "bg-orange-300/25",
70
+ "solid_blue_25" => "bg-cyan-700/25",
71
+ "solid_red_25" => "bg-orange-800/25", }
72
+
73
+ # amount of text columns
74
+ mattr_accessor :text_columns
75
+ @@text_columns = {
76
+ "3" => "columns-1 md:columns-2 lg:columns-3",
77
+ "4" => "columns-1 md:columns-2 lg:columns-3 xl:columns-4",
78
+ "2" => "columns-1 md:columns-2" }
79
+
80
+ # amount of slider columns
81
+ mattr_accessor :slider_columns
82
+ @@slider_columns = {
83
+ "1" => { 640 => { slidesPerView: 1, spaceBetween: 20 }, },
84
+ "2" => { 640 => { slidesPerView: 1, spaceBetween: 20 },
85
+ 1280 => { slidesPerView: 2, spaceBetween: 30 }, },
86
+ "3" => { 640 => { slidesPerView: 1, spaceBetween: 20 },
87
+ 1024 => { slidesPerView: 2, spaceBetween: 30 },
88
+ 1536 => { slidesPerView: 3, spaceBetween: 40 } },
89
+ "4" => { 640 => { slidesPerView: 1, spaceBetween: 20 },
90
+ 1024 => { slidesPerView: 2, spaceBetween: 30 },
91
+ 1536 => { slidesPerView: 4, spaceBetween: 40 } },
92
+ }
93
+
94
+ # amount of text columns
95
+ mattr_accessor :columns
96
+ @@columns = {
97
+ "1" => "grid-cols-1 gap-8 md:gap-12 lg:gap-16",
98
+ "2" => "grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 lg:gap-16" ,
99
+ "3" => "grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 md:gap-12 lg:gap-16",
100
+ "4" => "grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 md:gap-12 lg:gap-16",
101
+ "5" => "grid-cols-1 md:grid-cols-3 lg:grid-cols-5 gap-8 md:gap-12 lg:gap-16",
102
+ "6" => "grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-8 md:gap-12 lg:gap-16", }
103
+
104
+ end
@@ -0,0 +1,19 @@
1
+ require "breeze"
2
+ require "rails/generators"
3
+
4
+ module Breeze
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ def install
9
+ [:card_styles, :option_definitions, :page_styles , :section_styles,
10
+ :cards, :sections , :pages, :images].each do |file|
11
+ copy_file "empty.yml", "breeze/#{file}.yml"
12
+ end
13
+ copy_file "initializer.rb", "config/initializers/breeze.rb"
14
+ empty_directory Breeze::Image.asset_root
15
+ empty_directory Breeze.data_dir + "/breeze"
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,70 @@
1
+ require "breeze"
2
+
3
+ # directory inside /app/assets/images where YOUR images are kept
4
+ # if you change this and add own styles, you will still need a breeze directory
5
+ # for the previews (card_preview and section_preview)
6
+ Breeze.images_dir = "breeze"
7
+
8
+ # If languages are defined to non blank, translations can be made and
9
+ # urls for each langiage are generated, eg /fi/page_name.haml
10
+ Breeze.languages = ""
11
+
12
+ # directory where data and styles are kept
13
+ # Notice that the data is ALWAYS inside a breeze directory,
14
+ # so in the default case Rails.root/breeze/*.yml
15
+ Breeze.data_dir = "."
16
+
17
+
18
+ # text colors, keys are options shown to user, values what gets replaced
19
+ Breeze.text_color = { "white" => "text-white",
20
+ "none" => "",
21
+ "light_blue" => "text-cyan-100",
22
+ "light_gray" => "text-gray-100",
23
+ "solid_blue" => "text-cyan-700",
24
+ "solid_red" => "text-orange-800",
25
+ "solid_green" => "text-green-700",
26
+ "solid_petrol" => "text-teal-700",
27
+ "solid_indigo" => "text-indigo-800",
28
+ "solid_black" => "text-slate-800",
29
+ }
30
+
31
+ # margin option, keys are options shown to user, values what gets replaced
32
+ Breeze.margin = { "none" => "m-0",
33
+ "small" => " m-2 md:m-4 lg:6 xl:m-8",
34
+ "medium" => "m-5 md:m-8 lg:10 xl:m-14",
35
+ "large" => " m-8 md:m-12 lg:16 xl:m-20",}
36
+
37
+ # background colors
38
+ Breeze.background = {"white" => "bg-white",
39
+ "none" => "",
40
+ "light_blue" => "bg-cyan-100",
41
+ "light_gray" => "bg-gray-100",
42
+ "light_orange" => "bg-orange-50",
43
+ "solid_blue" => "bg-cyan-700 text-white",
44
+ "solid_red" => "bg-amber-600 text-white",
45
+ "solid_green" => "bg-green-700 text-white",
46
+ "solid_petrol" => "bg-teal-700 text-white",
47
+ "solid_indigo" => "bg-cyan-900 text-white",
48
+ "solid_black" => "bg-slate-900 text-white", }
49
+
50
+ # shade options
51
+ Breeze.shade_color = {"white_25" => "bg-white/25",
52
+ "none" => "",
53
+ "black_25" => "bg-black/25",
54
+ "light_blue_25" => "bg-cyan-100/25",
55
+ "light_red_25" => "bg-orange-300/25",
56
+ "solid_blue_25" => "bg-cyan-700/25",
57
+ "solid_red_25" => "bg-orange-800/25", }
58
+
59
+ # amount of text columns
60
+ Breeze.text_columns = {
61
+ "3" => "columns-1 md:columns-2 lg:columns-3",
62
+ "4" => "columns-1 md:columns-2 lg:columns-3 xl:columns-4",
63
+ "2" => "columns-1 md:columns-2" }
64
+
65
+ Breeze.columns = { "1" => "grid-cols-1",
66
+ "2" => "grid-cols-1 md:grid-cols-2" ,
67
+ "3" => "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
68
+ "4" => "grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
69
+ "5" => "grid-cols-1 md:grid-cols-3 lg:grid-cols-5",
70
+ "6" => "grid-cols-2 md:grid-cols-4 lg:grid-cols-6", }
@@ -0,0 +1,11 @@
1
+ require 'rails/generators/base'
2
+
3
+ module Breeze
4
+ class UpdateGenerator < Rails::Generators::Base
5
+ source_root File.expand_path("../../../../app/assets/stylesheets", __dir__)
6
+
7
+ def update
8
+ copy_file "breeze_tailwind_styles.css", "app/assets/stylesheets/breeze_tailwind_styles.css"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,60 @@
1
+ module Breeze
2
+ class Converter
3
+ def initialize
4
+ @page_mapping = linearize Page
5
+ @section_mapping = linearize Section
6
+ @card_mapping = linearize Card
7
+ @image_mapping = linearize Image
8
+ end
9
+ def linearize( model )
10
+ id_mapping = {}
11
+ count = 1
12
+ model.all.each do |m|
13
+ # map old to new
14
+ old_file = m.full_filename if model == Image
15
+ id_mapping[m.id] = count
16
+ m.id = count
17
+ if( model == Image && old_file != m.full_filename)
18
+ FileUtils.mv( old_file , m.full_filename )
19
+ end
20
+ count = count + 1
21
+ end
22
+ id_mapping
23
+ end
24
+
25
+ def condense
26
+ fix_sections
27
+ fix_cards
28
+ [Page , Image , Section , Card].each {|m| m.save_all}
29
+ end
30
+
31
+ def fix_images
32
+ #empty as work is done in cards and sections
33
+ end
34
+ def fix_sections
35
+ Section.all.each do |section|
36
+ if( ! section.image_id.blank? )
37
+ section.image_id = @image_mapping[section.image_id]
38
+ end
39
+ section.page_id = @page_mapping[section.page_id]
40
+ end
41
+ end
42
+
43
+ def fix_cards
44
+ Card.all.each do |card|
45
+ if( ! card.image_id.blank? )
46
+ card.image_id = @image_mapping[card.image_id]
47
+ end
48
+ card.section_id = @section_mapping[card.section_id]
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+
55
+ namespace :breeze do
56
+ desc "Make ids consecutive on all models"
57
+ task :condense => :environment do
58
+ Breeze::Converter.new.condense
59
+ end
60
+ end
@@ -0,0 +1,84 @@
1
+ require "rails"
2
+ require "breeze"
3
+
4
+ namespace :breeze do
5
+
6
+ desc "Check the data, usefull after hand edits"
7
+ task :consistency => :environment do
8
+ {Section: [:image, :page] , Card: [:section , :image]}.each do |name , keys|
9
+ Breeze.check_class(name, keys)
10
+ end
11
+ Breeze.check_images
12
+ end
13
+
14
+ desc "Fix missing pages"
15
+ task :fix_pages => :environment do
16
+ Breeze.fix_pages
17
+ end
18
+ desc "Fix screwed indexes"
19
+ task :fix_indexes => :environment do
20
+ Breeze.fix_indexes
21
+ end
22
+ desc "Fix missing images"
23
+ task :fix_images => :environment do
24
+ Breeze.fix_images
25
+ end
26
+
27
+ end
28
+
29
+ module Breeze
30
+
31
+ def self.fix_indexes
32
+ Page.all.each do |page|
33
+ fix_index_for(page)
34
+ end
35
+ Section.save_all
36
+ end
37
+ def self.fix_index_for(page)
38
+ page.sections.each_with_index do |section , index|
39
+ next if section.index == index + 1
40
+ puts "Section #{section.page.id}.#{section.index} == #{index + 1}"
41
+ section.index = index + 1
42
+ end
43
+ end
44
+ def self.fix_pages
45
+ sections = Section.all.to_a.delete_if{|s| s.page}
46
+ sections.each do |section|
47
+ section.delete("rake fix_pages")
48
+ end
49
+ end
50
+
51
+ def self.fix_images
52
+ sections = Section.all.to_a.delete_if{|s| s.image}
53
+ sections.each do |section|
54
+ section.image_id = ""
55
+ section.save
56
+ end
57
+ end
58
+
59
+ def self.check_class(name , ids)
60
+ clazz = self.const_get name.to_s # eg Section , Card
61
+ clazz.all.each do |elem|
62
+ ids.each do |id| # eg image, page
63
+ check_id(elem , id )
64
+ end
65
+ end
66
+ end
67
+
68
+ def self.check_id(elem , id) # eg section instance, :image
69
+ attr = elem.data["#{id}_id".to_sym]
70
+ return if attr.blank?
71
+ begin
72
+ key = self.const_get(id.to_s.capitalize).find( attr.to_i)
73
+ rescue
74
+ puts "#{elem.class.name.split('::').last}:#{elem.id} missing #{id}:#{attr}"
75
+ end
76
+ end
77
+
78
+ def self.check_images
79
+ Image.all.each do |image|
80
+ next if File.exist?(image.full_filename)
81
+ puts "missing image #{image.full_filename}"
82
+ end
83
+ end
84
+ end