sibu 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c6ac6fcc8741cda28364f1a319bfa2d24dc605ef
4
- data.tar.gz: ebc4761b97ed9186af7322a5cc51de3f7c5d2988
3
+ metadata.gz: 7635dae443f7cd9cea480558c4d28d1595e8b0dd
4
+ data.tar.gz: dd93b5227313bcd4f6863191261a6fae389b5310
5
5
  SHA512:
6
- metadata.gz: 28bbc4e555c5e63c7bc0316366a2ebcaf3cbe353358ac3894cc127b37a573651cba3c47d7f9f29ee3cb9f750713668234ab29bf7496326618dfcae7663f8882b
7
- data.tar.gz: 3afce7820f8452e608f62c2825cd2ad4c6cf2e6eb008152690a66b8a00ab26481754bfa2a48192262bbbecf1f649277884652ac8dca79d88eb4f720725e2fc40
6
+ metadata.gz: 0525e546145a52500ae365f916c992e8dbb02bb1473dc7e94ef1b3b77975bb77e0b7d1e1f66ab717fcf7dfb5403616d1513cc6a4e035f535d8025f90d8f5bcec
7
+ data.tar.gz: b208922425d9433c712b40356f8be17fb67b32fbd3391028e5ef4b19415c2ed94f7e006d8813b57589a64883bcef70c8d371f4d9bf37bfdb5bf8a4f287aba1d7
@@ -1,3 +1,4 @@
1
1
  //= require jquery
2
2
  //= require jquery_ujs
3
+ //= require tinymce-jquery
3
4
  //= require_self
@@ -1,33 +1,11 @@
1
- sb-edit,
2
- [class*='sb-'] {
3
- position: relative;
4
-
5
- &:hover > .sb-overlay {
1
+ sb-edit {
2
+ .sb-edit-active {
6
3
  cursor: pointer;
7
- display: flex;
8
- }
9
- }
10
-
11
- .sb-overlay {
12
- position: absolute;
13
- top: 0;
14
- left: 0;
15
- z-index: 999;
16
- width: 100%;
17
- height: 100%;
18
- display: none;
19
- flex-wrap: wrap;
20
- align-items: center;
21
- justify-content: center;
22
- text-align: center;
23
-
24
- > * {
25
- flex: 1 1 0%;
26
4
  }
27
5
  }
28
6
 
29
7
  #edit_panel {
30
- position: absolute;
8
+ position: fixed;
31
9
  left: 0;
32
10
  bottom: 0;
33
11
  width: 100%;
@@ -16,6 +16,7 @@ module Sibu
16
16
  @site = Sibu::Site.find_by_domain(request.domain)
17
17
  if @site
18
18
  @page = @site.page(params[:path])
19
+ @links = @site.internal_links
19
20
  view_template = @page ? 'show' : @site.not_found
20
21
  else
21
22
  view_template = Rails.application.config.sibu[:not_found]
@@ -23,6 +24,7 @@ module Sibu
23
24
  else
24
25
  @site = Sibu::Site.find(params[:site_id])
25
26
  @page = Sibu::Page.find(params[:id])
27
+ @links = @site.internal_links
26
28
  view_template = 'show'
27
29
  end
28
30
 
@@ -60,7 +62,8 @@ module Sibu
60
62
 
61
63
  def edit_content
62
64
  @page = Sibu::Page.find(params[:page_id])
63
- @site = @page.site if @page
65
+ @site = Sibu::Site.includes(:pages).find(@page.site_id) if @page
66
+ @links = @site.internal_links if @site
64
67
  render :edit_content, layout: 'sibu/edit_content'
65
68
  end
66
69
 
@@ -68,7 +71,7 @@ module Sibu
68
71
  end
69
72
 
70
73
  def update_element
71
- @updated = @entity.update_element(@section_id, @element_id, element_params)
74
+ @updated = @entity.update_element(@section_id, element_params)
72
75
  end
73
76
 
74
77
  def edit_section
@@ -81,7 +84,7 @@ module Sibu
81
84
 
82
85
  def set_page
83
86
  @page = Sibu::Page.find(params[:id])
84
- @site = @page.site if @page
87
+ @site = Sibu::Site.includes(:pages).find(@page.site_id) if @page
85
88
  end
86
89
 
87
90
  def set_site
@@ -20,8 +20,7 @@ module Sibu
20
20
 
21
21
  def create
22
22
  @site = Sibu::Site.new(site_params)
23
- @site.init_data(:default)
24
- if @site.save
23
+ if @site.save_and_init(:default)
25
24
  redirect_to sites_url, notice: "Le site a bien été créé."
26
25
  else
27
26
  flash.now[:alert] = "Une erreur s'est produite lors de la création du site."
@@ -1,5 +1,7 @@
1
1
  module Sibu
2
2
  module PagesHelper
3
+ include Sibu::Engine.routes.url_helpers
4
+
3
5
  def link_path(page_id)
4
6
  p = @site.page_by_id(page_id)
5
7
  p ? (@site.domain.blank? ? site_page_path(@site.id, p.id) : "/#{p.path}") : "#"
@@ -12,5 +14,67 @@ module Sibu
12
14
  def page_languages
13
15
  [['Français', 'fr'], ['Anglais', 'en']]
14
16
  end
17
+
18
+ [:h1, :h2, :h3, :h4, :h5, :h6, :p, :span, :div, :label].each do |t|
19
+ define_method(t) do |id_or_elt, html_opts = {}|
20
+ content = id_or_elt.is_a?(Hash) ? (id_or_elt || {"text" => "Texte à modifier"}) : (select(id_or_elt) || {"text" => "Texte à modifier"})
21
+ html_opts.merge!({class: "sb-#{t} #{html_opts[:class]}", data: {id: id_or_elt.is_a?(Hash) ? id_or_elt["id"] : id_or_elt}}) if action_name != 'show'
22
+ content_tag(t, raw(content["text"]).html_safe, html_opts)
23
+ end
24
+ end
25
+
26
+ def sb
27
+ self
28
+ end
29
+
30
+ def select(id)
31
+ @sb_entity.section(@sb_section).select {|elt| elt["id"] == id}.first
32
+ end
33
+
34
+ def site_section(id, &block)
35
+ @sb_entity = @site
36
+ @sb_section = id
37
+ capture(self, &block)
38
+ end
39
+
40
+ def section(id, &block)
41
+ @sb_entity = @page
42
+ @sb_section = id
43
+ capture(self, &block)
44
+ end
45
+
46
+ def each
47
+ # Todo : init array when empty
48
+ @sb_entity.section(@sb_section).each do |elt|
49
+ yield(elt.except("elements"), elt["elements"])
50
+ end
51
+ end
52
+
53
+ def each_elements
54
+ @sb_entity.section(@sb_section).each do |elt|
55
+ yield(*elt["elements"])
56
+ end
57
+ end
58
+
59
+ def img(id_or_elt, html_opts = {})
60
+ content = id_or_elt.is_a?(Hash) ? (id_or_elt || {"src" => "/default.jpg"}) : (select(id_or_elt) || {"src" => "/default.jpg"})
61
+ opts = action_name == 'show' ? html_opts.merge({class: "sb-img #{html_opts[:class]}", data: {id: id_or_elt.is_a?(Hash) ? id_or_elt["id"] : id_or_elt}}) : html_opts
62
+ content_tag(:img, nil, content.except("id").merge(opts))
63
+ end
64
+
65
+ def link(id_or_elt, html_opts = {}, &block)
66
+ content = id_or_elt.is_a?(Hash) ? (id_or_elt || {"value" => "", "text" => "Nouveau lien"}) : (select(id_or_elt) || {"value" => "", "text" => "Nouveau lien"})
67
+ val = content["value"] || ""
68
+ if val.to_s.include?('http')
69
+ href = val
70
+ else
71
+ href = @links.keys.include?(val) ? (action_name == 'show' ? site_page_path(@site.id, val) : site_page_edit_content_path(@site.id, val)) : '#'
72
+ end
73
+ if block_given?
74
+ content_tag(:a, {href: href}.merge(html_opts), &block)
75
+ else
76
+ content_tag(:a, content["text"], {href: href}.merge(html_opts))
77
+ end
78
+ end
15
79
  end
16
80
  end
@@ -2,34 +2,47 @@ module Sibu
2
2
  module SectionsConcern
3
3
  include ActiveSupport::Concern
4
4
 
5
- def section(*ids)
6
- if ids.length == 1
5
+ def section(id)
6
+ # elts = nil
7
+ # if ids.length == 1
7
8
  s = nil
8
9
  if sections.blank?
9
10
  self.sections = {}
10
11
  else
11
- s = sections[ids[0]]
12
+ s = sections[id]
12
13
  end
13
14
  if s.nil?
14
15
  s = []
15
- self.sections[ids[0]] = s
16
+ self.sections[id] = s
16
17
  save
17
18
  end
18
19
  s
19
- elsif ids.length == 2
20
- s = section(ids[0])
21
- sub = s.select {|elt| elt["id"] == ids[1]}
22
- unless sub
23
- sub = {"id" => ids[1], "elements" => []}
24
- self.sections[ids[0]] << sub
25
- save
26
- end
27
- sub
20
+ # elsif ids.length == 2
21
+ # s = section(ids[0])
22
+ # sub = s.select {|elt| elt["id"] == ids[1]}
23
+ # unless sub
24
+ # sub = {"id" => ids[1], "elements" => []}
25
+ # self.sections[ids[0]] << sub
26
+ # save
27
+ # end
28
+ # elts = sub
29
+ # end
30
+ # elts.blank? ? {"default" => {}} : Hash[elts.map {|e| [e["id"], e.except("id")]}]
31
+ end
32
+
33
+ def subsection(id, subid)
34
+ s = section(id)
35
+ sub = s.select {|elt| elt["id"] == ids[1]}
36
+ unless sub
37
+ sub = {"id" => ids[1], "elements" => []}
38
+ self.sections[ids[0]] << sub
39
+ save
28
40
  end
41
+ elts = sub
29
42
  end
30
43
 
31
44
  def element(section_id, element_id)
32
- elt = section(section_id).select {|e| e["id"] == element_id}.first
45
+ elt = section(section_id)[element_id]
33
46
  elt || {}
34
47
  end
35
48
 
@@ -37,17 +50,13 @@ module Sibu
37
50
  end
38
51
 
39
52
  # Note : only 2 levels supported for now
40
- def update_element(*ids, value)
41
- updated = nil
42
- if ids.length > 1
43
- if self.sections[ids[0]].any? {|elt| elt["id"] == ids[1]}
44
- self.sections[ids[0]].map! {|elt| elt["id"] == ids[1] ? elt.value : elt}
45
- else
46
- self.sections[ids[0]] << {"id" => ids[1]}.merge(value)
47
- end
48
- updated = value if save
53
+ def update_element(section_id, value)
54
+ if self.sections[section_id].any? {|elt| elt["id"] == value["id"]}
55
+ self.sections[section_id].map! {|elt| elt["id"] == value["id"] ? value : elt}
56
+ else
57
+ self.sections[section_id] << value
49
58
  end
50
- updated
59
+ value if save
51
60
  end
52
61
  end
53
62
  end
@@ -23,12 +23,30 @@ module Sibu
23
23
  pages.where(id: page_id).first
24
24
  end
25
25
 
26
- def init_data(source)
26
+ def save_and_init(source)
27
+ ActiveRecord::Base.transaction do
28
+ save!
29
+ init_pages(source)
30
+ init_sections(source)
31
+ end
32
+ end
33
+
34
+ def internal_links
35
+ Hash[pages.collect {|p| [p.id, p.path]}]
36
+ end
37
+
38
+ def init_pages(source)
27
39
  site_data = Rails.application.config.sibu[:site_data][source]
28
- self.sections = site_data.sections
29
40
  site_data.pages.each do |p|
30
41
  self.pages << Sibu::Page.new(p)
31
42
  end
43
+ save!
44
+ end
45
+
46
+ def init_sections(source)
47
+ site_data = Rails.application.config.sibu[:site_data][source]
48
+ self.sections = site_data.sections(self)
49
+ save!
32
50
  end
33
51
  end
34
52
  end
@@ -8,7 +8,7 @@
8
8
  <%= javascript_include_tag 'sibu/sibu' %>
9
9
  <% if @site %>
10
10
  <%= stylesheet_link_tag @site.site_template.path, media: "all" %>
11
- <%= javascript_include_tag @site.site_template.path %>
11
+ <%= javascript_include_tag "#{@site.site_template.path}-core" %>
12
12
  <% end %>
13
13
  <%= csrf_meta_tags %>
14
14
  </head>
@@ -23,26 +23,64 @@
23
23
  <div id="edit_panel" class="sibu_view"></div>
24
24
 
25
25
  <script>
26
- $(function() {
27
- initOverlays();
28
- });
29
-
30
- function initOverlays() {
31
- var elts = $("[class*='sb-']");
32
- elts.each(function() {
33
- var elt = $(this);
34
- elt.find(".sb-overlay").remove();
35
- var section = elt.parents("sb-edit").first();
36
- var eltId = elt.data("id"), sectionId = section.data("id"), entity = section.data("entity");
37
- elt.append(
38
- '<div class="sb-overlay sibu_panel">' +
39
- '<a href="<%= edit_element_site_page_path(@site.id, @page.id) %>?element_id=' + eltId + '&section_id=' + sectionId +
40
- '&entity=' + entity + '" data-remote="true">Modifier</a>' +
41
- '</div>'
42
- );
43
- });
44
-
45
- }
26
+ $(function () {
27
+ initOverlays();
28
+ });
29
+
30
+ function initOverlays() {
31
+ const textTags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'p', 'span'];
32
+
33
+ var elts = $("[class*='sb-']");
34
+ elts.each(function () {
35
+ var previous;
36
+ var elt = $(this), tag = elt.prop("tagName").toLowerCase(), width = elt.width(),
37
+ height = elt.height(), display = elt.css("display"), padding = elt.css("padding"), margin = elt.css("margin");
38
+ var section = elt.parents("sb-edit").first();
39
+ var eltId = elt.data("id"), sectionId = section.data("id"), entity = section.data("entity");
40
+ var overlayElt = $(editOverlay(width, height, display, padding, margin));
41
+ bindMouseEnter(elt, overlayElt, eltId, sectionId, entity);
42
+ });
43
+
44
+ function bindMouseEnter(element, overlay, elementId, sectionId, entity) {
45
+ element.mouseenter(function () {
46
+ overlay.replaceAll(element);
47
+ overlay.addClass("sb-edit-active sibu_panel");
48
+ overlay.click(function() {
49
+ editContent(elementId, sectionId, entity)
50
+ });
51
+ bindMouseLeave(element, overlay, elementId, sectionId, entity);
52
+ });
53
+ }
54
+
55
+ function bindMouseLeave(element, overlay, elementId, sectionId, entity) {
56
+ overlay.mouseleave(function() {
57
+ overlay.removeClass("sb-edit-active sibu_panel");
58
+ element.replaceAll(overlay);
59
+ bindMouseEnter(element, overlay, elementId, sectionId, entity);
60
+ });
61
+ }
62
+
63
+ function editOverlay(width, height, display, padding, margin) {
64
+ return '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
65
+ 'style="box-sizing: content-box; display: ' + display + '; padding: ' + padding + '; margin: ' + margin + ';"' +
66
+ 'viewBox="0 0 ' + width + ' ' + height + '" width="' + width + 'px" height="' + height + 'px">' +
67
+ '<rect width="' + width + '" height="' + height + '" x="0" y="0" fill="#dedede"/>' +
68
+ '</svg>';
69
+ }
70
+
71
+ function editContent(eltId, sectionId, entity) {
72
+ $.ajax({
73
+ url: "<%= edit_element_site_page_path(@site.id, @page.id) %>",
74
+ method: "GET",
75
+ data: {
76
+ element_id: eltId,
77
+ section_id: sectionId,
78
+ entity: entity
79
+ }
80
+ })
81
+ }
82
+
83
+ }
46
84
  </script>
47
85
  <%= yield :scripts %>
48
86
  </body>
@@ -3,11 +3,10 @@
3
3
  <div class="sibu_form">
4
4
  <%= form_tag(update_element_site_page_path(@site.id, @page.id), method: :patch, remote: true) do |f| %>
5
5
  <div class="sibu_field">
6
- <%= label_tag 'element[text]', 'Texte' %>
7
- <%= text_area_tag 'element[text]' %>
6
+ <%= text_area_tag 'element[text]', '', class: 'tinymce' %>
8
7
  </div>
8
+ <%= hidden_field_tag 'element[id]', @element_id %>
9
9
  <%= hidden_field_tag :section_id, @section_id %>
10
- <%= hidden_field_tag :element_id, @element_id %>
11
10
  <%= hidden_field_tag :entity, @entity_type %>
12
11
  <div class="sibu_actions">
13
12
  <%= submit_tag 'Valider' %>
@@ -15,5 +14,3 @@
15
14
  </div>
16
15
  <% end %>
17
16
  </div>
18
-
19
-
@@ -1,4 +1,12 @@
1
1
  var editPanel = $("#edit_panel");
2
2
  editPanel.html("<%= j(render 'edit_panel') %>");
3
- editPanel.find("#element").val("<%= @entity.element(@section_id, @element_id)["text"] %>");
4
- editPanel.slideDown("fast");
3
+ editPanel.find("#element_text").val("<%= j(raw @entity.element(@section_id, @element_id)["text"]) %>");
4
+ editPanel.slideDown("fast");
5
+ tinyMCE.remove();
6
+ tinyMCE.init({
7
+ selector: 'textarea.tinymce',
8
+ branding: false,
9
+ menubar: false,
10
+ toolbar: 'bold italic underline alignleft aligncenter alignright alignjustify',
11
+ forced_root_block : false
12
+ });
@@ -2,6 +2,5 @@
2
2
  $("#edit_panel #edit_msg").html("<p class='sibu_alert'>Une erreur s'est produite lors de l'enregistrement.</p>");
3
3
  <% else %>
4
4
  $("#edit_panel").slideUp();
5
- $("sb-edit[data-id='<%= @section_id %>']").find("[data-id='<%= @element_id %>']").text("<%= @updated["text"] %>");
6
- initOverlays();
5
+ $("sb-edit[data-id='<%= @section_id %>']").find("[data-id='<%= @updated["id"] %>']").html("<%= j(raw @updated["text"]) %>");
7
6
  <% end %>
@@ -0,0 +1,6 @@
1
+ default:
2
+ toolbar:
3
+ - styleselect | bold italic
4
+ - link
5
+ plugins:
6
+ - link
data/lib/sibu/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Sibu
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sibu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean-Baptiste Vilain
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-29 00:00:00.000000000 Z
11
+ date: 2018-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -56,30 +56,30 @@ dependencies:
56
56
  name: jquery-rails
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 4.3.1
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 4.3.1
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: tinymce-rails
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: 4.7.6
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: 4.7.6
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: tinymce-rails-langs
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -145,8 +145,8 @@ files:
145
145
  - app/views/sibu/sites/show.html.erb
146
146
  - app/views/sibu/sites/update.html.erb
147
147
  - config/initializers/shrine.rb
148
- - config/initializers/tag_helper.rb
149
148
  - config/routes.rb
149
+ - config/tinymce.yml
150
150
  - db/migrate/20180124095041_create_sibu_sites.rb
151
151
  - db/migrate/20180124095213_create_sibu_pages.rb
152
152
  - db/migrate/20180124145030_create_sibu_site_templates.rb
@@ -1,75 +0,0 @@
1
- module ActionView
2
- module Helpers
3
- module TagHelper
4
- # Todo : handle default values => sections can be totally empty or have at least 1 elt
5
- # If "emptyable", how do we add the 1st elt ? If not, how do we provide a default value ?
6
- class SectionHelper
7
- include ActionView::Helpers::TagHelper
8
-
9
- attr_reader :entity_type
10
-
11
- [:h1, :h2, :h3, :h4, :h5, :h6, :p, :span, :div].each do |t|
12
- define_method(t) do |id, html_opts = {}|
13
- html_opts.merge!({class: "sb-#{t} #{html_opts[:class]}", data: {id: id}}) if @edit
14
- content_tag(t, (@elements.dig(id, "text") || "Texte à modifier"), html_opts)
15
- end
16
- end
17
-
18
- def initialize(*ids, entity, edit_mode)
19
- @id = ids.join('|')
20
- @entity_type = entity.is_a?(Sibu::Page) ? 'page' : 'site'
21
- elts = entity.section(*ids)
22
- @elements = elts.blank? ? {"default" => {}} : Hash[elts.map {|e| [e["id"], e.except("id")]}]
23
- @edit = edit_mode
24
- end
25
-
26
- # Note : add sb-img back - see how the extra div could be removed
27
- def img(id, html_opts = {})
28
- content = id == "default" ? {"src" => "/default.jpg"} : (@elements[id] || {"src" => "/default.jpg"})
29
- if @edit
30
- content_tag(:div, content_tag(:img, nil, content.merge(html_opts)), {class: "rel h100 #{html_opts[:class]}", data: {id: id}})
31
- else
32
- content_tag(:img, nil, content.merge(html_opts))
33
- end
34
- end
35
-
36
- def lnk(id)
37
- @elements[id] || {"value" => "", "text" => "Nouveau lien"}
38
- end
39
-
40
- # def subsection(id, &block)
41
- # section
42
- # s = SectionHelper.new(id, @entity_type, @elements[id], @edit)
43
- # if !@edit
44
- # capture(s, &block)
45
- # else
46
- # "<sb-edit data-id='#{id}' data-entity='#{@entity_type}'>#{capture(s, &block)}</sb-edit>".html_safe
47
- # end
48
- # end
49
-
50
- def elements(&block)
51
- @elements.each_pair(&block)
52
- end
53
- end
54
-
55
- def section(id, entity = @page, &block)
56
- s = SectionHelper.new(id, entity, action_name != 'show')
57
- if action_name == 'show'
58
- capture(s, &block)
59
- else
60
- "<sb-edit data-id='#{id}' data-entity='#{s.entity_type}'>#{capture(s, &block)}</sb-edit>".html_safe
61
- end
62
- end
63
-
64
- def subsection(id, sub_id, entity = @page, &block)
65
- entity_type = entity.is_a?(Sibu::Page) ? 'page' : 'site'
66
- s = SectionHelper.new(id, sub_id, entity, action_name != 'show')
67
- # if action_name == 'show'
68
- capture(s, &block)
69
- # else
70
- # "<sb-edit data-id='#{id}' data-entity='#{s.entity_type}'>#{capture(s, &block)}</sb-edit>".html_safe
71
- # end
72
- end
73
- end
74
- end
75
- end