decidim-admin 0.8.4 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of decidim-admin might be problematic. Click here for more details.

Files changed (94) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +1 -1
  3. data/app/assets/javascripts/decidim/admin/application.js.es6 +5 -2
  4. data/app/assets/stylesheets/decidim/admin/_decidim.scss +2 -5
  5. data/app/assets/stylesheets/decidim/admin/extra/_action-icon.scss +4 -4
  6. data/app/assets/stylesheets/decidim/admin/extra/_cards.scss +3 -2
  7. data/app/assets/stylesheets/decidim/admin/extra/_categories.scss +1 -1
  8. data/app/assets/stylesheets/decidim/admin/extra/_dropdown_inverted.scss +8 -1
  9. data/app/assets/stylesheets/decidim/admin/extra/_label-required.scss +1 -1
  10. data/app/assets/stylesheets/decidim/admin/extra/_login.scss +1 -0
  11. data/app/assets/stylesheets/decidim/admin/extra/_quill.scss +2 -2
  12. data/app/assets/stylesheets/decidim/admin/extra/_select_multiple.scss +1 -1
  13. data/app/assets/stylesheets/decidim/admin/extra/_sort.scss +5 -4
  14. data/app/assets/stylesheets/decidim/admin/extra/_title_bar.scss +17 -7
  15. data/app/assets/stylesheets/decidim/admin/modules/_action-icon.scss +2 -2
  16. data/app/assets/stylesheets/decidim/admin/modules/_buttons.scss +6 -2
  17. data/app/assets/stylesheets/decidim/admin/modules/_callouts.scss +3 -0
  18. data/app/assets/stylesheets/decidim/admin/modules/_cards.scss +12 -0
  19. data/app/assets/stylesheets/decidim/admin/modules/_char-counter.scss +2 -0
  20. data/app/assets/stylesheets/decidim/admin/modules/_forms.scss +5 -1
  21. data/app/assets/stylesheets/decidim/admin/modules/_icons.scss +1 -0
  22. data/app/assets/stylesheets/decidim/admin/modules/_layout.scss +9 -1
  23. data/app/assets/stylesheets/decidim/admin/modules/_main-nav.scss +5 -0
  24. data/app/assets/stylesheets/decidim/admin/modules/_process-header.scss +1 -0
  25. data/app/assets/stylesheets/decidim/admin/modules/_secondary-nav.scss +10 -5
  26. data/app/assets/stylesheets/decidim/admin/modules/_table-list.scss +7 -1
  27. data/app/assets/stylesheets/decidim/admin/modules/_tabs.scss +7 -0
  28. data/app/assets/stylesheets/decidim/admin/modules/_title-bar.scss +3 -0
  29. data/app/assets/stylesheets/decidim/admin/modules/_user-login.scss +2 -0
  30. data/app/assets/stylesheets/decidim/admin/plugins/_foundation-datepicker.scss +36 -36
  31. data/app/assets/stylesheets/decidim/admin/utils/_fontface.scss +22 -20
  32. data/app/assets/stylesheets/decidim/admin/utils/_helpers.scss +6 -6
  33. data/app/assets/stylesheets/decidim/admin/utils/_keyframes.scss +6 -6
  34. data/app/assets/stylesheets/decidim/admin/utils/_mixins.scss +2 -3
  35. data/app/assets/stylesheets/decidim/admin/utils/_settings.scss +406 -129
  36. data/app/assets/stylesheets/decidim/admin/utils/_toggle-expand.scss +1 -0
  37. data/app/commands/decidim/admin/create_attachment.rb +13 -3
  38. data/app/commands/decidim/admin/create_feature.rb +1 -0
  39. data/app/commands/decidim/admin/create_managed_user.rb +20 -10
  40. data/app/commands/decidim/admin/impersonate_managed_user.rb +7 -9
  41. data/app/commands/decidim/admin/officialize_user.rb +47 -0
  42. data/app/commands/decidim/admin/unofficialize_user.rb +35 -0
  43. data/app/commands/decidim/admin/update_organization_appearance.rb +32 -5
  44. data/app/controllers/decidim/admin/categories_controller.rb +1 -1
  45. data/app/controllers/decidim/admin/features/base_controller.rb +1 -1
  46. data/app/controllers/decidim/admin/features_controller.rb +7 -0
  47. data/app/controllers/decidim/admin/managed_users/impersonations_controller.rb +1 -1
  48. data/app/controllers/decidim/admin/managed_users_controller.rb +23 -9
  49. data/app/controllers/decidim/admin/newsletters_controller.rb +2 -2
  50. data/app/controllers/decidim/admin/officializations_controller.rb +64 -0
  51. data/app/events/decidim/attachment_created_event.rb +25 -0
  52. data/app/events/decidim/feature_published_event.rb +27 -0
  53. data/app/events/decidim/participatory_process_step_activated_event.rb +31 -0
  54. data/app/forms/decidim/admin/managed_user_form.rb +0 -11
  55. data/app/forms/decidim/admin/officialization_form.rb +30 -0
  56. data/app/forms/decidim/admin/organization_appearance_form.rb +46 -1
  57. data/app/helpers/decidim/admin/application_helper.rb +1 -3
  58. data/app/models/decidim/admin/abilities/admin_ability.rb +1 -0
  59. data/app/models/decidim/admin/abilities/participatory_process_moderator_ability.rb +1 -1
  60. data/app/queries/decidim/admin/user_groups_evaluation.rb +9 -8
  61. data/app/queries/decidim/admin/users_officialization.rb +53 -0
  62. data/app/views/decidim/admin/managed_users/new.html.erb +5 -5
  63. data/app/views/decidim/admin/officializations/index.html.erb +82 -0
  64. data/app/views/decidim/admin/officializations/new.html.erb +18 -0
  65. data/app/views/decidim/admin/organization_appearance/_form.html.erb +60 -0
  66. data/app/views/layouts/decidim/admin/_title_bar.html.erb +1 -1
  67. data/app/views/layouts/decidim/admin/users.html.erb +5 -0
  68. data/config/locales/ca.yml +44 -2
  69. data/config/locales/en.yml +44 -1
  70. data/config/locales/es.yml +47 -5
  71. data/config/locales/eu.yml +46 -3
  72. data/config/locales/fi.yml +55 -12
  73. data/config/locales/fr.yml +45 -2
  74. data/config/locales/gl.yml +514 -0
  75. data/config/locales/it.yml +47 -4
  76. data/config/locales/nl.yml +47 -4
  77. data/config/locales/pl.yml +44 -1
  78. data/config/locales/pt-BR.yml +514 -0
  79. data/config/locales/pt.yml +106 -63
  80. data/config/locales/ru.yml +36 -6
  81. data/config/locales/sv.yml +514 -0
  82. data/config/locales/uk.yml +36 -8
  83. data/config/routes.rb +2 -0
  84. data/db/migrate/20171219154507_add_officialization_to_users.rb +10 -0
  85. data/lib/decidim/admin/engine.rb +1 -2
  86. data/lib/decidim/admin/test/manage_feature_permissions_examples.rb +0 -1
  87. data/lib/decidim/admin/test/manage_moderations_examples.rb +64 -0
  88. data/lib/decidim/admin/test.rb +5 -0
  89. data/lib/decidim/admin/version.rb +1 -1
  90. data/vendor/assets/javascripts/moment.min.js +1 -7
  91. metadata +37 -38
  92. data/app/assets/javascripts/decidim/admin/scopes.js.es6 +0 -20
  93. data/app/assets/javascripts/decidim/admin/select2.js.es6 +0 -8
  94. data/app/assets/stylesheets/decidim/admin/plugins/_select2.scss +0 -27
@@ -0,0 +1,25 @@
1
+ # frozen-string_literal: true
2
+
3
+ module Decidim
4
+ class AttachmentCreatedEvent < Decidim::Events::SimpleEvent
5
+ i18n_attributes :attached_to_url
6
+
7
+ def resource_path
8
+ @resource.url
9
+ end
10
+
11
+ def resource_url
12
+ @resource.url
13
+ end
14
+
15
+ private
16
+
17
+ def attached_to_url
18
+ resource_locator.url
19
+ end
20
+
21
+ def resource
22
+ @resource.attached_to
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ # frozen-string_literal: true
2
+
3
+ module Decidim
4
+ class FeaturePublishedEvent < Decidim::Events::SimpleEvent
5
+ include Decidim::FeaturePathHelper
6
+
7
+ i18n_attributes :participatory_space_title
8
+
9
+ private
10
+
11
+ def resource_path
12
+ @resource_path ||= main_feature_path(resource)
13
+ end
14
+
15
+ def resource_url
16
+ @resource_url ||= main_feature_url(resource)
17
+ end
18
+
19
+ def participatory_space_title
20
+ resource.participatory_space.title[I18n.locale.to_s]
21
+ end
22
+
23
+ def resource_title
24
+ @resource_title ||= resource.name[I18n.locale.to_s]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,31 @@
1
+ # frozen-string_literal: true
2
+
3
+ module Decidim
4
+ class ParticipatoryProcessStepActivatedEvent < Decidim::Events::SimpleEvent
5
+ include Rails.application.routes.mounted_helpers
6
+
7
+ i18n_attributes :participatory_space_title
8
+
9
+ private
10
+
11
+ def participatory_space
12
+ resource.participatory_process
13
+ end
14
+
15
+ def resource_path
16
+ @resource_path ||= decidim_participatory_processes.participatory_process_participatory_process_steps_path(participatory_space)
17
+ end
18
+
19
+ def resource_url
20
+ @resource_url ||= decidim_participatory_processes
21
+ .participatory_process_participatory_process_steps_url(
22
+ resource.participatory_process,
23
+ host: resource.participatory_process.organization.host
24
+ )
25
+ end
26
+
27
+ def participatory_space_title
28
+ participatory_space.title[I18n.locale.to_s]
29
+ end
30
+ end
31
+ end
@@ -10,7 +10,6 @@ module Decidim
10
10
  attribute :name, String
11
11
 
12
12
  validates :name, presence: true
13
- validate :authorization_uniqueness
14
13
 
15
14
  def initialize(attributes)
16
15
  extend(Virtus.model)
@@ -20,16 +19,6 @@ module Decidim
20
19
 
21
20
  super
22
21
  end
23
-
24
- private
25
-
26
- def authorization_uniqueness
27
- errors.add :authorization, :invalid if Authorization.where(
28
- user: current_organization.users,
29
- name: authorization.handler_name,
30
- unique_id: authorization.unique_id
31
- ).exists?
32
- end
33
22
  end
34
23
  end
35
24
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Admin
5
+ # A form object used to officialize users from the admin dashboard.
6
+ class OfficializationForm < Form
7
+ include TranslatableAttributes
8
+
9
+ translatable_attribute :officialized_as, String
10
+
11
+ attribute :user_id, Integer
12
+
13
+ validates :officialized_as, length: { maximum: 300 }
14
+
15
+ validates :user, presence: true, if: ->(form) { form.user_id.present? }
16
+
17
+ def map_model(user)
18
+ self.officialized_as = user.officialized_as
19
+ self.user_id = user.id
20
+ end
21
+
22
+ def user
23
+ @user ||= Decidim::User.find_by(
24
+ id: user_id,
25
+ organization: current_organization
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
@@ -24,18 +24,63 @@ module Decidim
24
24
  attribute :show_statistics, Boolean
25
25
  attribute :header_snippets, String
26
26
  attribute :cta_button_path, String
27
+ attribute :highlighted_content_banner_enabled, Boolean, default: false
28
+ attribute :highlighted_content_banner_action_url, String
29
+ attribute :highlighted_content_banner_image
30
+ attribute :remove_highlighted_content_banner_image
31
+ attribute :enable_omnipresent_banner, Boolean, default: false
32
+ attribute :omnipresent_banner_url, String
27
33
 
28
34
  translatable_attribute :cta_button_text, String
29
35
  translatable_attribute :description, String
30
36
  translatable_attribute :welcome_text, String
37
+ translatable_attribute :highlighted_content_banner_title, String
38
+ translatable_attribute :highlighted_content_banner_short_description, String
39
+ translatable_attribute :highlighted_content_banner_action_title, String
40
+ translatable_attribute :highlighted_content_banner_action_subtitle, String
41
+ translatable_attribute :omnipresent_banner_title, String
42
+ translatable_attribute :omnipresent_banner_short_description, String
31
43
 
32
- validates :cta_button_path, format: { with: %r{\A[a-zA-Z]+[a-zA-Z0-9\-/]+\z} }, allow_blank: true
44
+ validates :cta_button_path, format: { with: %r{\A[a-zA-Z]+[a-zA-Z0-9\-\_/]+\z} }, allow_blank: true
33
45
  validates :official_img_header,
34
46
  :official_img_footer,
35
47
  :homepage_image,
36
48
  :logo,
37
49
  file_size: { less_than_or_equal_to: ->(_record) { Decidim.maximum_attachment_size } },
38
50
  file_content_type: { allow: ["image/jpeg", "image/png"] }
51
+
52
+ validates :highlighted_content_banner_action_url, presence: true, if: :highlighted_content_banner_enabled?
53
+ validates :highlighted_content_banner_image,
54
+ presence: true,
55
+ file_size: { less_than_or_equal_to: ->(_record) { Decidim.maximum_attachment_size } },
56
+ file_content_type: { allow: ["image/jpeg", "image/png"] },
57
+ if: :highlighted_content_banner_enabled?
58
+
59
+ validates :highlighted_content_banner_title,
60
+ translatable_presence: true,
61
+ if: :highlighted_content_banner_enabled?
62
+
63
+ validates :highlighted_content_banner_short_description,
64
+ translatable_presence: true,
65
+ if: :highlighted_content_banner_enabled?
66
+
67
+ validates :highlighted_content_banner_action_title,
68
+ translatable_presence: true,
69
+ if: :highlighted_content_banner_enabled?
70
+
71
+ validates :omnipresent_banner_url, presence: true, if: :enable_omnipresent_banner?
72
+ validates :omnipresent_banner_title, translatable_presence: true, if: :enable_omnipresent_banner?
73
+ validates :omnipresent_banner_short_description, translatable_presence: true, if: :enable_omnipresent_banner?
74
+
75
+ private
76
+
77
+ def highlighted_content_banner_enabled?
78
+ highlighted_content_banner_enabled
79
+ end
80
+
81
+ def enable_omnipresent_banner?
82
+ enable_omnipresent_banner
83
+ end
39
84
  end
40
85
  end
41
86
  end
@@ -17,9 +17,7 @@ module Decidim
17
17
  end
18
18
 
19
19
  def foundation_datepicker_locale_tag
20
- if I18n.locale != :en
21
- javascript_include_tag "datepicker-locales/foundation-datepicker.#{I18n.locale}.js"
22
- end
20
+ javascript_include_tag "datepicker-locales/foundation-datepicker.#{I18n.locale}.js" if I18n.locale != :en
23
21
  end
24
22
  end
25
23
  end
@@ -45,6 +45,7 @@ module Decidim
45
45
  end
46
46
 
47
47
  can [:index, :verify, :reject], UserGroup
48
+ can [:index, :new, :create, :destroy], :officializations
48
49
 
49
50
  can :index, :authorization_workflows
50
51
  can [:index, :update], Authorization
@@ -14,7 +14,7 @@ module Decidim
14
14
  end
15
15
 
16
16
  can :manage, Moderation do |moderation|
17
- can_manage_process?(moderation.participatory_process)
17
+ can_manage_process?(moderation.participatory_space)
18
18
  end
19
19
  end
20
20
  end
@@ -2,26 +2,29 @@
2
2
 
3
3
  module Decidim
4
4
  module Admin
5
- # A class used to find the ParticipatoryProcesses that the given user can
6
- # manage.
5
+ # A class used to find the UserGroup's by their evaluation state.
7
6
  class UserGroupsEvaluation < Rectify::Query
8
7
  # Syntactic sugar to initialize the class and return the queried objects.
9
8
  #
10
- # user - a User Group that needs to be listed.
9
+ # user_groups - the initial User Group relation that needs to be filtered.
10
+ # q - query to filter user group names
11
+ # state - evaluation state to be used as a filter
11
12
  def self.for(user_groups, q = nil, state = nil)
12
13
  new(user_groups, q, state).query
13
14
  end
14
15
 
15
16
  # Initializes the class.
16
17
  #
17
- # user_group - a User groups that need to be lsited
18
+ # user_groups - the User groups that need to be filtered
19
+ # q - query to filter user group names
20
+ # state - evaluation state to be used as a filter
18
21
  def initialize(user_groups, q = nil, state = nil)
19
22
  @user_groups = user_groups
20
23
  @q = q
21
24
  @state = state
22
25
  end
23
26
 
24
- # List the User groups by the diferents filters.
27
+ # List the User groups by the diferent filters.
25
28
  def query
26
29
  @user_groups = filter_by_search(@user_groups)
27
30
  @user_groups = filter_by_state(@user_groups)
@@ -30,11 +33,9 @@ module Decidim
30
33
 
31
34
  private
32
35
 
33
- attr_reader :user_group
34
-
35
36
  def filter_by_search(user_groups)
36
37
  return user_groups if @q.blank?
37
- user_groups.where("LOWER(name) LIKE LOWER('%#{@q}%')")
38
+ user_groups.where("LOWER(name) LIKE LOWER(?)", "%#{@q}%")
38
39
  end
39
40
 
40
41
  def filter_by_state(user_groups)
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Admin
5
+ # A class used to filter User's by their officialization state.
6
+ class UsersOfficialization < Rectify::Query
7
+ # Syntactic sugar to initialize the class and return the queried objects.
8
+ #
9
+ # q - query to filter user group names
10
+ # state - evaluation state to be used as a filter
11
+ def self.for(q = nil, state = nil)
12
+ new(q, state).query
13
+ end
14
+
15
+ # Initializes the class.
16
+ #
17
+ # q - query to filter user group names
18
+ # state - officialization state to be used as a filter
19
+ def initialize(q = nil, state = nil)
20
+ @q = q
21
+ @state = state
22
+ end
23
+
24
+ # List the User groups by the diferents filters.
25
+ def query
26
+ users = Decidim::User.all
27
+ users = filter_by_search(users)
28
+ users = filter_by_state(users)
29
+ users
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :q, :state
35
+
36
+ def filter_by_search(users)
37
+ return users if q.blank?
38
+ users.where("LOWER(name) LIKE LOWER(?)", "%#{q}%")
39
+ end
40
+
41
+ def filter_by_state(users)
42
+ case state
43
+ when "officialized"
44
+ users.where.not(officialized_at: nil)
45
+ when "not_officialized"
46
+ users.where(officialized_at: nil)
47
+ else
48
+ users
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,17 +1,17 @@
1
1
  <h2 class="process-title-summary">
2
2
  <%= t('.new_managed_user') %>
3
- <% if more_than_one_authorization? %>
3
+ <% if more_than_one_authorization_handler? %>
4
4
  <span class="text-muted float-right"><%= t('.step', current: params[:handler_name].present? ? 2 : 1, total: 2) %></span>
5
5
  <% end %>
6
6
  </h2>
7
7
 
8
- <% if more_than_one_authorization? && params[:handler_name].nil? %>
8
+ <% if select_authorization_handler_step? %>
9
9
  <div class="card card--list">
10
10
  <div class="card-divider">
11
11
  <h2 class="card-title"><%= t ".select_authorization_method" %></h2>
12
12
  </div>
13
13
  <div class="card-section">
14
- <% available_authorizations.each do |handler_name| %>
14
+ <% available_authorization_handlers.each do |handler| %>
15
15
  <div class="card--list__item">
16
16
  <div class="card--list__text">
17
17
  <a href="#">
@@ -19,12 +19,12 @@
19
19
  </a>
20
20
  <div>
21
21
  <h5 class="card--list__heading">
22
- <%= link_to t("#{handler_name}.name", scope: "decidim.authorization_handlers"), new_managed_user_path(handler_name: handler_name) %>
22
+ <%= link_to handler.fullname, new_managed_user_path(handler_name: handler.name) %>
23
23
  </h5>
24
24
  </div>
25
25
  </div>
26
26
  <div class="card--list__data">
27
- <%= link_to new_managed_user_path(handler_name: handler_name), class: "card--list__data__icon" do %>
27
+ <%= link_to new_managed_user_path(handler_name: handler.name), class: "card--list__data__icon" do %>
28
28
  <%= icon "chevron-right" %>
29
29
  <% end %>
30
30
  </div>
@@ -0,0 +1,82 @@
1
+ <div class="filters row">
2
+ <div class="column medium-3">
3
+ <span class="dropdown-menu-inverted_label"><%= t(".filter_by") %> :</span>
4
+ <ul class="dropdown menu dropdown-inverted" data-dropdown-menu data-close-on-click-inside="false">
5
+ <li class="is-dropdown-submenu-parent">
6
+ <a href="#">
7
+ <% if @state.present? %>
8
+ <%= t(".filter.#{@state}") %>
9
+ <% else %>
10
+ <%= t(".filter.all") %>
11
+ <% end %>
12
+ </a>
13
+ <ul class="menu is-dropdown-submenu">
14
+ <li><%= link_to t(".filter.officialized"), url_for(state: "officialized", q: @query) %></li>
15
+ <li><%= link_to t(".filter.not_officialized"), url_for(state: "not_officialized", q: @query) %></li>
16
+ <li><%= link_to t(".filter.all"), url_for(q: @query) %></li>
17
+ </ul>
18
+ </li>
19
+ </ul>
20
+ </div>
21
+ <div class="column medium-4">
22
+ <%= form_tag "", method: :get do %>
23
+ <div class="filters__search">
24
+ <div class="input-group">
25
+ <%= search_field_tag :q, @query,label: false, class: "input-group-field", placeholder: t('.search') %>
26
+ <%= hidden_field_tag :state, @state %>
27
+ <div class="input-group-button">
28
+ <button type="submit" class="button button--muted">
29
+ <%= icon "magnifying-glass", aria_label: t('.search') %>
30
+ </button>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ <% end %>
35
+ </div>
36
+ </div>
37
+
38
+ <div class="card" id='user-groups'>
39
+ <div class="card-divider">
40
+ <h2 class="card-title"><%= t "decidim.admin.titles.officializations" %></h2>
41
+ </div>
42
+ <div class="card-section">
43
+ <div class="table-scroll">
44
+ <table class="table-list">
45
+ <thead>
46
+ <tr>
47
+ <th><%= t(".name") %></th>
48
+ <th><%= t(".nickname") %></th>
49
+ <th><%= t(".created_at") %></th>
50
+ <th><%= t(".status") %></th>
51
+ <th><%= t(".badge") %></th>
52
+ <th><%= t(".actions") %></th>
53
+ </tr>
54
+ </thead>
55
+ <tbody>
56
+ <% @users.each do |user| %>
57
+ <tr data-user-id="<%= user.id %>">
58
+ <td><%= user.name %></td>
59
+ <td><%= user.nickname %></td>
60
+ <td><%= l user.created_at, format: :short %></td>
61
+ <td><%= user.officialized? ? t(".officialized") : t(".not_officialized") %></td>
62
+ <td><%= translated_attribute(user.officialized_as) %></td>
63
+
64
+ <td class="table-list__actions">
65
+ <% if user.officialized? %>
66
+ <%= icon "circle-check", class: "action-icon action-icon--disabled" %>
67
+ <%= icon_link_to "pencil", new_officialization_path(user_id: user.id), t(".reofficialize"), class: "action-icon--new" %>
68
+ <%= icon_link_to "circle-x", officialization_path(user.id), t(".unofficialize"), method: :delete, class: "action-icon--reject" %>
69
+ <% else %>
70
+ <%= icon_link_to "circle-check", new_officialization_path(user_id: user.id), t(".officialize"), class: "action-icon--verify" %>
71
+ <%= icon "pencil", class: "action-icon action-icon--disabled" %>
72
+ <%= icon "circle-x", class: "action-icon action-icon--disabled" %>
73
+ <% end %>
74
+ </td>
75
+ </tr>
76
+ <% end %>
77
+ </tbody>
78
+ </table>
79
+ <%= paginate @users, theme: "decidim" %>
80
+ </div>
81
+ </div>
82
+ </div>