if user&.active?
can :welcome, :site
- can :read, [:deletion, :account_terms]
+ can :read, [:deletion, :account_terms, :account_pd_declaration]
if Settings.status != "database_offline"
can [:read, :create, :destroy], :changeset_subscription
can [:read, :create, :destroy], :oauth2_authorization
can [:update, :destroy], :account
can :update, :account_terms
+ can :create, :account_pd_declaration
can :read, :dashboard
can [:create, :subscribe, :unsubscribe], DiaryEntry
can :update, DiaryEntry, :user => user
// See https://turbo.hotwired.dev/reference/drive#turbo.session.drive
Turbo.session.drive = false;
- var headerWidth = 0,
- compactWidth = 0;
+ const $expandedSecondaryMenu = $("header nav.secondary > ul"),
+ $collapsedSecondaryMenu = $("#compact-secondary-nav > ul"),
+ secondaryMenuItems = [],
+ breakpointWidth = 768;
+ let moreItemWidth = 0;
function updateHeader() {
var windowWidth = $(window).width();
- if (windowWidth < compactWidth) {
- $("body").removeClass("compact-nav").addClass("small-nav");
- } else if (windowWidth < headerWidth) {
- $("body").addClass("compact-nav").removeClass("small-nav");
+ if (windowWidth < breakpointWidth) {
+ $("body").addClass("small-nav");
+ expandAllSecondaryMenuItems();
} else {
- $("body").removeClass("compact-nav").removeClass("small-nav");
+ $("body").removeClass("small-nav");
+ const availableWidth = $expandedSecondaryMenu.width();
+ secondaryMenuItems.forEach(function (item) {
+ $(item[0]).remove();
+ });
+ let runningWidth = 0,
+ i = 0,
+ requiredWidth;
+ for (; i < secondaryMenuItems.length; i++) {
+ runningWidth += secondaryMenuItems[i][1];
+ if (i < secondaryMenuItems.length - 1) {
+ requiredWidth = runningWidth + moreItemWidth;
+ } else {
+ requiredWidth = runningWidth;
+ }
+ if (requiredWidth > availableWidth) {
+ break;
+ }
+ expandSecondaryMenuItem($(secondaryMenuItems[i][0]));
+ }
+ for (; i < secondaryMenuItems.length; i++) {
+ collapseSecondaryMenuItem($(secondaryMenuItems[i][0]));
+ }
}
}
+ function expandAllSecondaryMenuItems() {
+ secondaryMenuItems.forEach(function (item) {
+ expandSecondaryMenuItem($(item[0]));
+ });
+ }
+
+ function expandSecondaryMenuItem($item) {
+ $item.children("a")
+ .removeClass("dropdown-item")
+ .addClass("nav-link")
+ .addClass(function () {
+ return $(this).hasClass("active") ? "text-secondary-emphasis" : "text-secondary";
+ });
+ $item.addClass("nav-item").insertBefore("#compact-secondary-nav");
+ toggleCompactSecondaryNav();
+ }
+
+ function collapseSecondaryMenuItem($item) {
+ $item.children("a")
+ .addClass("dropdown-item")
+ .removeClass("nav-link text-secondary text-secondary-emphasis");
+ $item.removeClass("nav-item").appendTo($collapsedSecondaryMenu);
+ toggleCompactSecondaryNav();
+ }
+
+ function toggleCompactSecondaryNav() {
+ $("#compact-secondary-nav").toggle(
+ $collapsedSecondaryMenu.find("li").length > 0
+ );
+ }
+
/*
* Chrome 60 and later seem to fire the "ready" callback
* before the DOM is fully ready causing us to measure the
* to defer the measurement slightly as a workaround.
*/
setTimeout(function () {
- $("header").children(":visible").each(function (i, e) {
- headerWidth += $(e).outerWidth();
+ $expandedSecondaryMenu.find("li:not(#compact-secondary-nav)").each(function () {
+ secondaryMenuItems.push([this, $(this).width()]);
});
-
- $("body").addClass("compact-nav");
-
- $("header").children(":visible").each(function (i, e) {
- compactWidth += $(e).outerWidth();
- });
-
- $("body").removeClass("compact-nav");
-
- $("header").removeClass("text-nowrap");
- $("header nav.secondary > ul").removeClass("flex-nowrap");
+ moreItemWidth = $("#compact-secondary-nav").width();
updateHeader();
font-size: 14px;
}
- nav.primary {
- margin-right: auto;
- }
-
.username {
max-width: 12em;
}
nav.secondary {
.nav-link {
- padding: 0.3rem;
+ padding: 0 0.3rem;
+ }
+
+ > ul {
+ height: 1.5em;
}
}
display: none;
}
-body.compact-nav {
- #compact-secondary-nav {
- display: inline-block;
- }
- .compact-hide {
- display: none;
- }
-}
-
body.small-nav {
#menu-icon {
display: block;
nav.secondary {
flex-direction: column;
+ > ul {
+ height: auto;
+ }
+
.user-menu, .login-menu {
width: 100%;
}
--- /dev/null
+module Accounts
+ class PdDeclarationsController < ApplicationController
+ layout "site"
+
+ before_action :authorize_web
+ before_action :set_locale
+
+ authorize_resource :class => :account_pd_declaration
+
+ def show; end
+
+ def create
+ if current_user.consider_pd
+ flash[:warning] = t(".already_declared")
+ else
+ current_user.consider_pd = params[:consider_pd]
+
+ if current_user.consider_pd
+ flash[:notice] = t(".successfully_declared") if current_user.save
+ else
+ flash[:warning] = t(".did_not_confirm")
+ end
+ end
+
+ redirect_to edit_account_path
+ end
+ end
+end
flash[:notice] = { :partial => "accounts/terms/terms_declined_flash" } if current_user.save
else
unless current_user.terms_agreed?
- current_user.consider_pd = params[:user][:consider_pd]
current_user.tou_agreed = Time.now.utc
current_user.terms_agreed = Time.now.utc
current_user.terms_seen = true
def user_params
params.require(:user).permit(:email, :display_name,
:auth_provider, :auth_uid,
- :pass_crypt, :pass_crypt_confirmation,
- :consider_pd)
+ :pass_crypt, :pass_crypt_confirmation)
end
##
end
def header_nav_link_class(path)
- ["nav-link", current_page?(path) ? "text-secondary-emphasis" : "text-secondary"]
+ ["nav-link", current_page?(path) ? "active text-secondary-emphasis" : "text-secondary"]
end
def application_data
<small class="form-text text-body-secondary">(<a href="<%= t ".openid.link" %>" target="_new"><%= t ".openid.link text" %></a>)</small>
</fieldset>
- <div class="mb-3">
- <label class="form-label"><%= t ".contributor terms.heading" %></label>
+ <div class="mb-3 d-flex flex-column flex-sm-row column-gap-1">
+ <label class="form-label text-nowrap mb-0"><%= t ".contributor terms.heading" %></label>
<span class="form-text text-body-secondary">
<% if current_user.terms_agreed? %>
<%= t ".contributor terms.agreed" %>
(<a href="<%= t ".contributor terms.link" %>" target="_new"><%= t ".contributor terms.link text" %></a>)
+ <br>
<% if current_user.consider_pd? %>
<%= t ".contributor terms.agreed_with_pd" %>
+ <% else %>
+ <%= t ".contributor terms.not_agreed_with_pd" %>
+ (<%= link_to t(".contributor terms.pd_link_text"), account_pd_declaration_path %>)
<% end %>
<% else %>
<%= t ".contributor terms.not yet agreed" %>
--- /dev/null
+<% content_for :heading do %>
+ <h1><%= t ".title" %></h1>
+<% end %>
+
+<%= bootstrap_form_tag do |f| %>
+ <%= f.form_group :help => link_to(t(".consider_pd_why"), t(".consider_pd_why_url"), :target => :new) do %>
+ <%= f.check_box :consider_pd,
+ :label => t(".consider_pd"),
+ :autocomplete => :off,
+ :checked => current_user.consider_pd,
+ :disabled => current_user.consider_pd %>
+ <% end %>
+ <%= f.primary t(".confirm"), :disabled => current_user.consider_pd %>
+<% end %>
<%= submit_tag(t(".continue"), :name => "continue", :id => "continue", :disabled => true, :class => "btn btn-primary") %>
<%= submit_tag(t(".cancel"), :name => "decline", :id => "decline", :class => "btn btn-outline-secondary") %>
</div>
-
- <div class="mb-3">
- <div class="form-check">
- <%= check_box("user", "consider_pd", :class => "form-check-input") %>
- <label for="user_consider_pd" class="form-check-label">
- <%= t ".consider_pd" %>
- </label>
- <span class="minorNote">(<%= link_to(t(".consider_pd_why"), t(".consider_pd_why_url"), :target => :new) %>)</span>
- </div>
<% end %>
</ul>
</div>
</nav>
- <nav class='secondary d-flex gap-2 align-items-center'>
- <ul class='nav flex-nowrap'>
+ <nav class='secondary d-flex gap-2 flex-grow-1 align-items-center'>
+ <ul id='secondary-nav-menu' class='nav flex-grow-1' data-turbo-permanent>
<% if Settings.status != "database_offline" && can?(:index, Issue) %>
- <li class="compact-hide nav-item">
+ <li class="nav-item">
<%= link_to issues_path(:status => "open"), :class => header_nav_link_class(issues_path) do %>
<%= t("layouts.issues") %>
<%= open_issues_count %>
<% end -%>
</li>
<% end %>
- <li class="compact-hide nav-item">
+ <li class="nav-item">
<%= link_to t("layouts.history"), history_path, :class => header_nav_link_class(history_path) %>
</li>
- <li class="compact-hide nav-item">
+ <li class="nav-item">
<%= link_to t("layouts.export"), export_path, :class => header_nav_link_class(export_path) %>
</li>
- <li class="compact-hide nav-item">
+ <li class="nav-item">
<%= link_to t("layouts.gps_traces"), traces_path, :class => header_nav_link_class(traces_path) %>
</li>
- <li class="compact-hide nav-item">
+ <li class="nav-item">
<%= link_to t("layouts.user_diaries"), diary_entries_path, :class => header_nav_link_class(diary_entries_path) %>
</li>
- <li class="compact-hide nav-item">
+ <li class="nav-item">
<%= link_to t("layouts.communities"), communities_path, :class => header_nav_link_class(communities_path) %>
</li>
- <li class="compact-hide nav-item">
+ <li class="nav-item">
<%= link_to t("layouts.copyright"), copyright_path, :class => header_nav_link_class(copyright_path) %>
</li>
- <li class="compact-hide nav-item">
+ <li class="nav-item">
<%= link_to t("layouts.help"), help_path, :class => header_nav_link_class(help_path) %>
</li>
- <li class="compact-hide nav-item">
+ <li class="nav-item">
<%= link_to t("layouts.about"), about_path, :class => header_nav_link_class(about_path) %>
</li>
- <li id="compact-secondary-nav" class="dropdown nav-item">
+ <li id="compact-secondary-nav" class="dropdown nav-item ms-auto">
<button class="dropdown-toggle nav-link btn btn-outline-secondary border-0 bg-body text-secondary" type="button" data-bs-toggle="dropdown"><%= t "layouts.more" %></button>
<ul class="dropdown-menu">
- <% if Settings.status != "database_offline" && can?(:index, Issue) %>
- <li>
- <%= link_to issues_path(:status => "open"), :class => "dropdown-item" do %>
- <%= t("layouts.issues") %>
- <%= open_issues_count %>
- <% end -%>
- </li>
- <% end %>
- <li><%= link_to t("layouts.history"), history_path, :class => "dropdown-item" %></li>
- <li><%= link_to t("layouts.export"), export_path, :class => "dropdown-item" %></li>
- <li><%= link_to t("layouts.gps_traces"), traces_path, :class => "dropdown-item" %></li>
- <li><%= link_to t("layouts.user_diaries"), diary_entries_path, :class => "dropdown-item" %></li>
- <li><%= link_to t("layouts.communities"), communities_path, :class => "dropdown-item" %></li>
- <li><%= link_to t("layouts.copyright"), copyright_path, :class => "dropdown-item" %></li>
- <li><%= link_to t("layouts.help"), help_path, :class => "dropdown-item" %></li>
- <li><%= link_to t("layouts.about"), about_path, :class => "dropdown-item" %></li>
</ul>
</li>
</ul>
:contributor_terms_link => link_to(t(".by_signing_up.contributor_terms"),
t(".by_signing_up.contributor_terms_url"),
:target => :new)) %></p>
- <%= f.form_group do %>
- <%= f.check_box :consider_pd,
- :tabindex => 5,
- :label => t(".consider_pd_html",
- :consider_pd_link => link_to(t(".consider_pd"),
- t(".consider_pd_url"),
- :target => :new)) %>
- <% end %>
<div class="mb-3">
- <%= submit_tag(t(".continue"), :name => "continue", :id => "continue", :class => "btn btn-primary", :tabindex => 6) %>
+ <%= submit_tag(t(".continue"), :name => "continue", :id => "continue", :class => "btn btn-primary", :tabindex => 5) %>
</div>
<% end %>
agreed_with_pd: "You have also declared that you consider your edits to be in the Public Domain."
link: "https://osmfoundation.org/wiki/Licence/Contributor_Terms"
link text: "what is this?"
+ not_agreed_with_pd: "You haven't declared that you consider your edits to be in the Public Domain."
+ pd_link_text: "declare"
save changes button: Save Changes
delete_account: Delete Account...
go_public:
read_ct: "I have read and agree to the above contributor terms"
tou_explain_html: "These %{tou_link} govern the use of the website and other infrastructure provided by the OSMF. Please click on the link, read and agree to the text."
read_tou: "I have read and agree to the Terms of Use"
- consider_pd: "In addition to the above, I consider my contributions to be in the Public Domain"
- consider_pd_why: "what's this?"
- consider_pd_why_url: https://osmfoundation.org/wiki/Licence_and_Legal_FAQ/Why_would_I_want_my_contributions_to_be_public_domain
guidance_info_html: "Information to help understand these terms: a %{readable_summary_link} and some %{informal_translations_link}"
readable_summary: human readable summary
informal_translations: informal translations
terms_declined_html: We are sorry that you have decided to not accept the new Contributor Terms. For more information, please see %{terms_declined_link}.
terms_declined_link: this wiki page
terms_declined_url: https://wiki.openstreetmap.org/wiki/Contributor_Terms_Declined
+ pd_declarations:
+ show:
+ title: Consider my contributions to be in the Public Domain
+ consider_pd: "I consider my contributions to be in the Public Domain"
+ consider_pd_why: "Why would I want my contributions to be Public Domain?"
+ consider_pd_why_url: https://osmfoundation.org/wiki/Licence_and_Legal_FAQ/Why_would_I_want_my_contributions_to_be_public_domain
+ confirm: Confirm
+ create:
+ successfully_declared: "You have successfully declared that you consider your edits to be in the Public Domain."
+ already_declared: "You have already declared that you consider your edits to be in the Public Domain."
+ did_not_confirm: "You didn't confirm that you consider your edits to be in the Public Domain."
browse:
deleted_ago_by_html: "Deleted %{time_ago} by %{user}"
edited_ago_by_html: "Edited %{time_ago} by %{user}"
privacy_policy_url: https://osmfoundation.org/wiki/Privacy_Policy
privacy_policy_title: OSMF privacy policy including section on email addresses
html: 'Your address is not displayed publicly, see our %{privacy_policy_link} for more information.'
- consider_pd_html: "I consider my contributions to be in the %{consider_pd_link}."
- consider_pd: "public domain"
- consider_pd_url: https://osmfoundation.org/wiki/Licence_and_Legal_FAQ/Why_would_I_want_my_contributions_to_be_public_domain
or: "or"
use external auth: "or sign up with a third party"
no_such_user:
resource :account, :only => [:edit, :update, :destroy] do
scope :module => :accounts do
resource :terms, :only => [:show, :update]
+ resource :pd_declaration, :only => [:show, :create]
resource :deletion, :only => :show
end
end
--- /dev/null
+require "test_helper"
+
+module Accounts
+ class PdDeclarationsControllerTest < ActionDispatch::IntegrationTest
+ ##
+ # test all routes which lead to this controller
+ def test_routes
+ assert_routing(
+ { :path => "/account/pd_declaration", :method => :get },
+ { :controller => "accounts/pd_declarations", :action => "show" }
+ )
+ assert_routing(
+ { :path => "/account/pd_declaration", :method => :post },
+ { :controller => "accounts/pd_declarations", :action => "create" }
+ )
+ end
+
+ def test_show_not_logged_in
+ get account_pd_declaration_path
+
+ assert_redirected_to login_path(:referer => account_pd_declaration_path)
+ end
+
+ def test_show_agreed
+ user = create(:user)
+ session_for(user)
+
+ get account_pd_declaration_path
+
+ assert_response :success
+ end
+
+ def test_create_not_logged_in
+ post account_pd_declaration_path
+
+ assert_response :forbidden
+ end
+
+ def test_create_unconfirmed
+ user = create(:user)
+ session_for(user)
+
+ post account_pd_declaration_path
+
+ assert_redirected_to edit_account_path
+ assert_nil flash[:notice]
+ assert_equal "You didn't confirm that you consider your edits to be in the Public Domain.", flash[:warning]
+
+ user.reload
+ assert_not_predicate user, :consider_pd
+ end
+
+ def test_create_confirmed
+ user = create(:user)
+ session_for(user)
+
+ post account_pd_declaration_path, :params => { :consider_pd => true }
+
+ assert_equal "You have successfully declared that you consider your edits to be in the Public Domain.", flash[:notice]
+ assert_nil flash[:warning]
+
+ user.reload
+ assert_predicate user, :consider_pd
+ end
+
+ def test_create_already_declared_unconfirmed
+ user = create(:user, :consider_pd => true)
+ session_for(user)
+
+ post account_pd_declaration_path
+
+ assert_nil flash[:notice]
+ assert_equal "You have already declared that you consider your edits to be in the Public Domain.", flash[:warning]
+
+ user.reload
+ assert_predicate user, :consider_pd
+ end
+
+ def test_create_already_declared_confirmed
+ user = create(:user, :consider_pd => true)
+ session_for(user)
+
+ post account_pd_declaration_path, :params => { :consider_pd => true }
+
+ assert_nil flash[:notice]
+ assert_equal "You have already declared that you consider your edits to be in the Public Domain.", flash[:warning]
+
+ user.reload
+ assert_predicate user, :consider_pd
+ end
+ end
+end
user = create(:user, :terms_seen => false, :terms_agreed => nil)
session_for(user)
- put account_terms_path, :params => { :user => { :consider_pd => true }, :read_ct => 1, :read_tou => 1 }
+ put account_terms_path, :params => { :read_ct => 1, :read_tou => 1 }
assert_redirected_to edit_account_path
assert_equal "Thanks for accepting the new contributor terms!", flash[:notice]
user.reload
- assert user.consider_pd
assert_not_nil user.terms_agreed
assert user.terms_seen
end
user = create(:user, :terms_seen => false, :terms_agreed => nil)
session_for(user)
- put account_terms_path, :params => { :user => { :consider_pd => true }, :referer => "/test", :read_ct => 1, :read_tou => 1 }
+ put account_terms_path, :params => { :referer => "/test", :read_ct => 1, :read_tou => 1 }
assert_redirected_to "/test"
assert_equal "Thanks for accepting the new contributor terms!", flash[:notice]
user.reload
- assert user.consider_pd
assert_not_nil user.terms_agreed
assert user.terms_seen
end
:params => { :user => { :email => dup_email,
:display_name => display_name,
:pass_crypt => "testtest",
- :pass_crypt_confirmation => "testtest",
- :consider_pd => "1" } }
+ :pass_crypt_confirmation => "testtest" } }
end
end
end
:pass_crypt => "testtest",
:pass_crypt_confirmation => "testtest",
:auth_provider => "google",
- :auth_uid => "123454321",
- :consider_pd => "1" } }
+ :auth_uid => "123454321" } }
end
end
end
:params => { :user => { :email => email,
:display_name => display_name,
:pass_crypt => "testtest",
- :pass_crypt_confirmation => "blahblah",
- :consider_pd => "1" } }
+ :pass_crypt_confirmation => "blahblah" } }
end
end
end
:params => { :user => { :email => email,
:display_name => dup_display_name,
:auth_provider => "google",
- :auth_uid => "123454321",
- :consider_pd => "1" } }
+ :auth_uid => "123454321" } }
end
end
end
:params => { :user => { :email => new_email,
:display_name => display_name,
:pass_crypt => "testtest",
- :pass_crypt_confirmation => "testtest",
- :consider_pd => "1" } }
+ :pass_crypt_confirmation => "testtest" } }
assert_redirected_to :controller => :confirmations, :action => :confirm, :display_name => display_name
follow_redirect!
end
:params => { :user => { :email => new_email,
:display_name => display_name,
:pass_crypt => password,
- :pass_crypt_confirmation => password,
- :consider_pd => "1" },
+ :pass_crypt_confirmation => password },
:referer => referer }
assert_response(:redirect)
assert_redirected_to :controller => :confirmations, :action => :confirm, :display_name => display_name
:params => { :user => { :email => new_email,
:display_name => display_name,
:auth_provider => "openid",
- :auth_uid => auth_uid,
- :consider_pd => "1" } }
+ :auth_uid => auth_uid } }
end
end
end
:params => { :user => { :email => new_email,
:display_name => display_name,
:auth_provider => "openid",
- :auth_uid => auth_uid,
- :consider_pd => "1" } }
+ :auth_uid => auth_uid } }
follow_redirect!
end
end
:params => { :user => { :email => new_email,
:display_name => display_name,
:auth_provider => "google",
- :auth_uid => auth_uid,
- :consider_pd => "1" },
+ :auth_uid => auth_uid },
:email_hmac => email_hmac }
assert_redirected_to welcome_path
follow_redirect!
:email_hmac => email_hmac,
:display_name => display_name,
:auth_provider => "google",
- :auth_uid => auth_uid,
- :consider_pd => "1" } }
+ :auth_uid => auth_uid } }
assert_response :redirect
follow_redirect!
end
:params => { :user => { :email => new_email,
:display_name => display_name,
:auth_provider => "facebook",
- :auth_uid => auth_uid,
- :consider_pd => "1" },
+ :auth_uid => auth_uid },
:email_hmac => email_hmac }
assert_redirected_to welcome_path
follow_redirect!
:email_hmac => email_hmac,
:display_name => display_name,
:auth_provider => "facebook",
- :auth_uid => auth_uid,
- :consider_pd => "1" } }
+ :auth_uid => auth_uid } }
assert_response :redirect
follow_redirect!
end
:params => { :user => { :email => new_email,
:display_name => display_name,
:auth_provider => "microsoft",
- :auth_uid => auth_uid,
- :consider_pd => "1" },
+ :auth_uid => auth_uid },
:email_hmac => email_hmac }
assert_redirected_to welcome_path
follow_redirect!
:email_hmac => email_hmac,
:display_name => display_name,
:auth_provider => "microsoft",
- :auth_uid => auth_uid,
- :consider_pd => "1" } }
+ :auth_uid => auth_uid } }
assert_response :redirect
follow_redirect!
end
:email_hmac => email_hmac,
:display_name => display_name,
:auth_provider => "github",
- :auth_uid => auth_uid,
- :consider_pd => "1" } }
+ :auth_uid => auth_uid } }
assert_response :redirect
follow_redirect!
end
:email_hmac => email_hmac,
:display_name => display_name,
:auth_provider => "wikipedia",
- :auth_uid => auth_uid,
- :consider_pd => "1" } }
+ :auth_uid => auth_uid } }
assert_response :redirect
follow_redirect!
end
--- /dev/null
+require "application_system_test_case"
+
+class AccountPdDeclarationTest < ApplicationSystemTestCase
+ def setup
+ @user = create(:user, :display_name => "test user")
+ sign_in_as(@user)
+ end
+
+ test "can decline declaration if no declaration was made" do
+ visit account_pd_declaration_path
+
+ within_content_body do
+ assert_unchecked_field "I consider my contributions to be in the Public Domain"
+ assert_button "Confirm"
+
+ click_on "Confirm"
+
+ assert_no_text "You have also declared that you consider your edits to be in the Public Domain."
+ end
+ end
+
+ test "can confirm declaration if no declaration was made" do
+ visit account_pd_declaration_path
+
+ within_content_body do
+ assert_unchecked_field "I consider my contributions to be in the Public Domain"
+ assert_button "Confirm"
+
+ check "I consider my contributions to be in the Public Domain"
+ click_on "Confirm"
+
+ assert_text "You have also declared that you consider your edits to be in the Public Domain."
+ end
+ end
+
+ test "show disabled checkbox if declaration was made" do
+ @user.update(:consider_pd => true)
+
+ visit account_pd_declaration_path
+
+ within_content_body do
+ assert_checked_field "I consider my contributions to be in the Public Domain", :disabled => true
+ assert_button "Confirm", :disabled => true
+ end
+ end
+end