require 'test_helper'

class BuilderTest < ActionView::TestCase
  def with_custom_form_for(object, *args, &block)
    with_concat_custom_form_for(object) do |f|
      assert f.instance_of?(CustomFormBuilder)
      yield f
    end
  end

  def with_collection_radio_buttons(object, attribute, collection, value_method, text_method, options = {}, html_options = {}, &block)
    with_concat_form_for(object) do |f|
      f.collection_radio_buttons attribute, collection, value_method, text_method, options, html_options, &block
    end
  end

  def with_collection_check_boxes(object, attribute, collection, value_method, text_method, options = {}, html_options = {}, &block)
    with_concat_form_for(object) do |f|
      f.collection_check_boxes attribute, collection, value_method, text_method, options, html_options, &block
    end
  end

  # COLLECTION RADIO
  test "collection radio accepts a collection and generate inputs from value method" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s

    assert_select 'form input[type=radio][value=true]#user_active_true'
    assert_select 'form input[type=radio][value=false]#user_active_false'
  end

  test "collection radio accepts a collection and generate inputs from label method" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s

    assert_select 'form label.collection_radio_buttons[for=user_active_true]', 'true'
    assert_select 'form label.collection_radio_buttons[for=user_active_false]', 'false'
  end

  test "collection radio handles camelized collection values for labels correctly" do
    with_collection_radio_buttons @user, :active, ['Yes', 'No'], :to_s, :to_s

    assert_select 'form label.collection_radio_buttons[for=user_active_yes]', 'Yes'
    assert_select 'form label.collection_radio_buttons[for=user_active_no]', 'No'
  end

  test "collection radio sanitizes collection values for labels correctly" do
    with_collection_radio_buttons @user, :name, ['$0.99', '$1.99'], :to_s, :to_s
    assert_select 'label.collection_radio_buttons[for=user_name_099]', '$0.99'
    assert_select 'label.collection_radio_buttons[for=user_name_199]', '$1.99'
  end

  test "collection radio checks the correct value to local variables" do
    user = User.build(active: false)
    with_collection_radio_buttons user, :active, [true, false], :to_s, :to_s

    assert_select 'form input[type=radio][value=true]'
    assert_select 'form input[type=radio][value=false][checked=checked]'
  end

  test "collection radio accepts checked item" do
    with_collection_radio_buttons @user, :active, [[1, true], [0, false]], :last, :first, checked: true

    assert_select 'form input[type=radio][value=true][checked=checked]'
    assert_no_select 'form input[type=radio][value=false][checked=checked]'
  end

  test "collection radio accepts checked item which has a value of false" do
    with_collection_radio_buttons @user, :active, [[1, true], [0, false]], :last, :first, checked: false
    assert_no_select 'form input[type=radio][value=true][checked=checked]'
    assert_select 'form input[type=radio][value=false][checked=checked]'
  end

  test "collection radio accepts multiple disabled items" do
    collection = [[1, true], [0, false], [2, 'other']]
    with_collection_radio_buttons @user, :active, collection, :last, :first, disabled: [true, false]

    assert_select 'form input[type=radio][value=true][disabled=disabled]'
    assert_select 'form input[type=radio][value=false][disabled=disabled]'
    assert_no_select 'form input[type=radio][value=other][disabled=disabled]'
  end

  test "collection radio accepts single disable item" do
    collection = [[1, true], [0, false]]
    with_collection_radio_buttons @user, :active, collection, :last, :first, disabled: true

    assert_select 'form input[type=radio][value=true][disabled=disabled]'
    assert_no_select 'form input[type=radio][value=false][disabled=disabled]'
  end

  test "collection radio accepts html options as input" do
    collection = [[1, true], [0, false]]
    with_collection_radio_buttons @user, :active, collection, :last, :first, {}, class: 'special-radio'

    assert_select 'form input[type=radio][value=true].special-radio#user_active_true'
    assert_select 'form input[type=radio][value=false].special-radio#user_active_false'
  end

  test "collection radio wraps the collection in the given collection wrapper tag" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: :ul

    assert_select 'form ul input[type=radio]', count: 2
  end

  test "collection radio does not render any wrapper tag by default" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s

    assert_select 'form input[type=radio]', count: 2
    assert_no_select 'form ul'
  end

  test "collection radio does not wrap the collection when given falsy values" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: false

    assert_select 'form input[type=radio]', count: 2
    assert_no_select 'form ul'
  end

  test "collection radio uses the given class for collection wrapper tag" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s,
      collection_wrapper_tag: :ul, collection_wrapper_class: "items-list"

    assert_select 'form ul.items-list input[type=radio]', count: 2
  end

  test "collection radio uses no class for collection wrapper tag when no wrapper tag is given" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s,
      collection_wrapper_class: "items-list"

    assert_select 'form input[type=radio]', count: 2
    assert_no_select 'form ul'
    assert_no_select '.items-list'
  end

  test "collection radio uses no class for collection wrapper tag by default" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: :ul

    assert_select 'form ul'
    assert_no_select 'form ul[class]'
  end

  test "collection radio wrap items in a span tag by default" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s

    assert_select 'form span input[type=radio][value=true]#user_active_true + label'
    assert_select 'form span input[type=radio][value=false]#user_active_false + label'
  end

  test "collection radio wraps each item in the given item wrapper tag" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: :li

    assert_select 'form li input[type=radio]', count: 2
  end

  test "collection radio does not wrap each item when given explicitly falsy value" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: false

    assert_select 'form input[type=radio]'
    assert_no_select 'form span input[type=radio]'
  end

  test "collection radio uses the given class for item wrapper tag" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s,
      item_wrapper_tag: :li, item_wrapper_class: "inline"

    assert_select "form li.inline input[type=radio]", count: 2
  end

  test "collection radio uses no class for item wrapper tag when no wrapper tag is given" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s,
      item_wrapper_tag: nil, item_wrapper_class: "inline"

    assert_select 'form input[type=radio]', count: 2
    assert_no_select 'form li'
    assert_no_select '.inline'
  end

  test "collection radio uses no class for item wrapper tag by default" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s,
      item_wrapper_tag: :li

    assert_select "form li", count: 2
    assert_no_select "form li[class]"
  end

  test "collection radio does not wrap input inside the label" do
    with_collection_radio_buttons @user, :active, [true, false], :to_s, :to_s

    assert_select 'form input[type=radio] + label'
    assert_no_select 'form label input'
  end

  test "collection radio accepts a block to render the label as radio button wrapper" do
    with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b|
      b.label { b.radio_button }
    end

    assert_select 'label[for=user_active_true] > input#user_active_true[type=radio]'
    assert_select 'label[for=user_active_false] > input#user_active_false[type=radio]'
  end

  test "collection radio accepts a block to change the order of label and radio button" do
    with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b|
      b.label + b.radio_button
    end

    assert_select 'label[for=user_active_true] + input#user_active_true[type=radio]'
    assert_select 'label[for=user_active_false] + input#user_active_false[type=radio]'
  end

  test "collection radio with block helpers accept extra html options" do
    with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b|
      b.label(class: "radio_button") + b.radio_button(class: "radio_button")
    end

    assert_select 'label.radio_button[for=user_active_true] + input#user_active_true.radio_button[type=radio]'
    assert_select 'label.radio_button[for=user_active_false] + input#user_active_false.radio_button[type=radio]'
  end

  test "collection radio with block helpers allows access to current text and value" do
    with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b|
      b.label(:"data-value" => b.value) { b.radio_button + b.text }
    end

    assert_select 'label[for=user_active_true][data-value=true]', 'true' do
      assert_select 'input#user_active_true[type=radio]'
    end
    assert_select 'label[for=user_active_false][data-value=false]', 'false' do
      assert_select 'input#user_active_false[type=radio]'
    end
  end

  test "collection radio with block helpers allows access to the current object item in the collection to access extra properties" do
    with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b|
      b.label(class: b.object) { b.radio_button + b.text }
    end

    assert_select 'label.true[for=user_active_true]', 'true' do
      assert_select 'input#user_active_true[type=radio]'
    end
    assert_select 'label.false[for=user_active_false]', 'false' do
      assert_select 'input#user_active_false[type=radio]'
    end
  end

  test "collection radio with block helpers does not leak the template" do
    with_concat_form_for(@user) do |f|
      collection_input =  f.collection_radio_buttons :active, [true, false], :to_s, :to_s do |b|
        b.label(class: b.object) { b.radio_button + b.text }
      end
      concat collection_input

      concat f.hidden_field :name
    end

    assert_select 'label.true[for=user_active_true]', text: 'true', count: 1 do
      assert_select 'input#user_active_true[type=radio]'
    end
    assert_select 'label.false[for=user_active_false]', text: 'false', count: 1 do
      assert_select 'input#user_active_false[type=radio]'
    end
  end
  # COLLECTION CHECK BOX
  test "collection check box accepts a collection and generate a serie of checkboxes for value method" do
    collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
    with_collection_check_boxes @user, :tag_ids, collection, :id, :name

    assert_select 'form input#user_tag_ids_1[type=checkbox][value="1"]'
    assert_select 'form input#user_tag_ids_2[type=checkbox][value="2"]'
  end

  test "collection check box generates only one hidden field for the entire collection, to ensure something will be sent back to the server when posting an empty collection" do
    collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
    with_collection_check_boxes @user, :tag_ids, collection, :id, :name

    assert_select "form input[type=hidden][name='user[tag_ids][]'][value='']", count: 1
  end

  test "collection check box accepts a collection and generate a serie of checkboxes with labels for label method" do
    collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
    with_collection_check_boxes @user, :tag_ids, collection, :id, :name

    assert_select 'form label.collection_check_boxes[for=user_tag_ids_1]', 'Tag 1'
    assert_select 'form label.collection_check_boxes[for=user_tag_ids_2]', 'Tag 2'
  end

  test "collection check box handles camelized collection values for labels correctly" do
    with_collection_check_boxes @user, :active, ['Yes', 'No'], :to_s, :to_s

    assert_select 'form label.collection_check_boxes[for=user_active_yes]', 'Yes'
    assert_select 'form label.collection_check_boxes[for=user_active_no]', 'No'
  end

  test "collection check box sanitizes collection values for labels correctly" do
    with_collection_check_boxes @user, :name, ['$0.99', '$1.99'], :to_s, :to_s
    assert_select 'label.collection_check_boxes[for=user_name_099]', '$0.99'
    assert_select 'label.collection_check_boxes[for=user_name_199]', '$1.99'
  end

  test "collection check box checks the correct value to local variables" do
    user = User.build(tag_ids: [1, 3])
    collection = (1..3).map { |i| [i, "Tag #{i}"] }

    with_collection_check_boxes user, :tag_ids, collection, :first, :last

    assert_select 'form input[type=checkbox][value="1"][checked=checked]'
    assert_select 'form input[type=checkbox][value="3"][checked=checked]'
    assert_no_select 'form input[type=checkbox][value="2"][checked=checked]'
  end

  test "collection check box accepts selected values as :checked option" do
    collection = (1..3).map { |i| [i, "Tag #{i}"] }
    with_collection_check_boxes @user, :tag_ids, collection, :first, :last, checked: [1, 3]

    assert_select 'form input[type=checkbox][value="1"][checked=checked]'
    assert_select 'form input[type=checkbox][value="3"][checked=checked]'
    assert_no_select 'form input[type=checkbox][value="2"][checked=checked]'
  end

  test "collection check boxes accepts selected string values as :checked option" do
    collection = (1..3).map { |i| [i, "Category #{i}"] }
    with_collection_check_boxes :user, :category_ids, collection, :first, :last, checked: ['1', '3']

    assert_select 'input[type=checkbox][value="1"][checked=checked]'
    assert_select 'input[type=checkbox][value="3"][checked=checked]'
    assert_no_select 'input[type=checkbox][value="2"][checked=checked]'
  end

  test "collection check box accepts a single checked value" do
    collection = (1..3).map { |i| [i, "Tag #{i}"] }
    with_collection_check_boxes @user, :tag_ids, collection, :first, :last, checked: 3

    assert_select 'form input[type=checkbox][value="3"][checked=checked]'
    assert_no_select 'form input[type=checkbox][value="1"][checked=checked]'
    assert_no_select 'form input[type=checkbox][value="2"][checked=checked]'
  end

  test "collection check box accepts selected values as :checked option and override the model values" do
    collection = (1..3).map { |i| [i, "Tag #{i}"] }
    @user.tag_ids = [2]
    with_collection_check_boxes @user, :tag_ids, collection, :first, :last, checked: [1, 3]

    assert_select 'form input[type=checkbox][value="1"][checked=checked]'
    assert_select 'form input[type=checkbox][value="3"][checked=checked]'
    assert_no_select 'form input[type=checkbox][value="2"][checked=checked]'
  end

  test "collection check box accepts multiple disabled items" do
    collection = (1..3).map { |i| [i, "Tag #{i}"] }
    with_collection_check_boxes @user, :tag_ids, collection, :first, :last, disabled: [1, 3]

    assert_select 'form input[type=checkbox][value="1"][disabled=disabled]'
    assert_select 'form input[type=checkbox][value="3"][disabled=disabled]'
    assert_no_select 'form input[type=checkbox][value="2"][disabled=disabled]'
  end

  test "collection check box accepts single disable item" do
    collection = (1..3).map { |i| [i, "Tag #{i}"] }
    with_collection_check_boxes @user, :tag_ids, collection, :first, :last, disabled: 1

    assert_select 'form input[type=checkbox][value="1"][disabled=disabled]'
    assert_no_select 'form input[type=checkbox][value="3"][disabled=disabled]'
    assert_no_select 'form input[type=checkbox][value="2"][disabled=disabled]'
  end

  test "collection check box accepts a proc to disabled items" do
    collection = (1..3).map { |i| [i, "Tag #{i}"] }
    with_collection_check_boxes @user, :tag_ids, collection, :first, :last, disabled: proc { |i| i.first == 1 }

    assert_select 'form input[type=checkbox][value="1"][disabled=disabled]'
    assert_no_select 'form input[type=checkbox][value="3"][disabled=disabled]'
    assert_no_select 'form input[type=checkbox][value="2"][disabled=disabled]'
  end

  test "collection check box accepts html options" do
    collection = [[1, 'Tag 1'], [2, 'Tag 2']]
    with_collection_check_boxes @user, :tag_ids, collection, :first, :last, {}, class: 'check'

    assert_select 'form input.check[type=checkbox][value="1"]'
    assert_select 'form input.check[type=checkbox][value="2"]'
  end

  test "collection check box with fields for" do
    collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
    with_concat_form_for(@user) do |f|
      f.fields_for(:post) do |p|
        p.collection_check_boxes :tag_ids, collection, :id, :name
      end
    end

    assert_select 'form input#user_post_tag_ids_1[type=checkbox][value="1"]'
    assert_select 'form input#user_post_tag_ids_2[type=checkbox][value="2"]'

    assert_select 'form label.collection_check_boxes[for=user_post_tag_ids_1]', 'Tag 1'
    assert_select 'form label.collection_check_boxes[for=user_post_tag_ids_2]', 'Tag 2'
  end

  test "collection check boxes wraps the collection in the given collection wrapper tag" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: :ul

    assert_select 'form ul input[type=checkbox]', count: 2
  end

  test "collection check boxes does not render any wrapper tag by default" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s

    assert_select 'form input[type=checkbox]', count: 2
    assert_no_select 'form ul'
  end

  test "collection check boxes does not wrap the collection when given falsy values" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: false

    assert_select 'form input[type=checkbox]', count: 2
    assert_no_select 'form ul'
  end

  test "collection check boxes uses the given class for collection wrapper tag" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s,
      collection_wrapper_tag: :ul, collection_wrapper_class: "items-list"

    assert_select 'form ul.items-list input[type=checkbox]', count: 2
  end

  test "collection check boxes uses no class for collection wrapper tag when no wrapper tag is given" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s,
      collection_wrapper_class: "items-list"

    assert_select 'form input[type=checkbox]', count: 2
    assert_no_select 'form ul'
    assert_no_select '.items-list'
  end

  test "collection check boxes uses no class for collection wrapper tag by default" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, collection_wrapper_tag: :ul

    assert_select 'form ul'
    assert_no_select 'form ul[class]'
  end

  test "collection check boxes wrap items in a span tag by default" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s

    assert_select 'form span input[type=checkbox]', count: 2
  end

  test "collection check boxes wraps each item in the given item wrapper tag" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: :li

    assert_select 'form li input[type=checkbox]', count: 2
  end

  test "collection check boxes does not wrap each item when given explicitly falsy value" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, item_wrapper_tag: false

    assert_select 'form input[type=checkbox]'
    assert_no_select 'form span input[type=checkbox]'
  end

  test "collection check boxes uses the given class for item wrapper tag" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s,
      item_wrapper_tag: :li, item_wrapper_class: "inline"

    assert_select "form li.inline input[type=checkbox]", count: 2
  end

  test "collection check boxes uses no class for item wrapper tag when no wrapper tag is given" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s,
      item_wrapper_tag: nil, item_wrapper_class: "inline"

    assert_select 'form input[type=checkbox]', count: 2
    assert_no_select 'form li'
    assert_no_select '.inline'
  end

  test "collection check boxes uses no class for item wrapper tag by default" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s,
      item_wrapper_tag: :li

    assert_select "form li", count: 2
    assert_no_select "form li[class]"
  end

  test "collection check box does not wrap input inside the label" do
    with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s

    assert_select 'form input[type=checkbox] + label'
    assert_no_select 'form label input'
  end

  test "collection check boxes accepts a block to render the label as check box wrapper" do
    with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b|
      b.label { b.check_box }
    end

    assert_select 'label[for=user_active_true] > input#user_active_true[type=checkbox]'
    assert_select 'label[for=user_active_false] > input#user_active_false[type=checkbox]'
  end

  test "collection check boxes accepts a block to change the order of label and check box" do
    with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b|
      b.label + b.check_box
    end

    assert_select 'label[for=user_active_true] + input#user_active_true[type=checkbox]'
    assert_select 'label[for=user_active_false] + input#user_active_false[type=checkbox]'
  end

  test "collection check boxes with block helpers accept extra html options" do
    with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b|
      b.label(class: "check_box") + b.check_box(class: "check_box")
    end

    assert_select 'label.check_box[for=user_active_true] + input#user_active_true.check_box[type=checkbox]'
    assert_select 'label.check_box[for=user_active_false] + input#user_active_false.check_box[type=checkbox]'
  end

  test "collection check boxes with block helpers allows access to current text and value" do
    with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b|
      b.label(:"data-value" => b.value) { b.check_box + b.text }
    end

    assert_select 'label[for=user_active_true][data-value=true]', 'true' do
      assert_select 'input#user_active_true[type=checkbox]'
    end
    assert_select 'label[for=user_active_false][data-value=false]', 'false' do
      assert_select 'input#user_active_false[type=checkbox]'
    end
  end

  test "collection check boxes with block helpers allows access to the current object item in the collection to access extra properties" do
    with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b|
      b.label(class: b.object) { b.check_box + b.text }
    end

    assert_select 'label.true[for=user_active_true]', 'true' do
      assert_select 'input#user_active_true[type=checkbox]'
    end
    assert_select 'label.false[for=user_active_false]', 'false' do
      assert_select 'input#user_active_false[type=checkbox]'
    end
  end

  test "collection check boxes with block helpers does not leak the template" do
    with_concat_form_for(@user) do |f|
      collection_input =  f.collection_check_boxes :active, [true, false], :to_s, :to_s do |b|
        b.label(class: b.object) { b.check_box + b.text }
      end
      concat collection_input

      concat f.hidden_field :name
    end

    assert_select 'label.true[for=user_active_true]', text: 'true', count: 1 do
      assert_select 'input#user_active_true[type=checkbox]'
    end
    assert_select 'label.false[for=user_active_false]', text: 'false', count: 1 do
      assert_select 'input#user_active_false[type=checkbox]'
    end
  end

  # SIMPLE FIELDS
  test "simple fields for is available and yields an instance of FormBuilder" do
    with_concat_form_for(@user) do |f|
      f.simple_fields_for(:posts) do |posts_form|
        assert posts_form.instance_of?(SimpleForm::FormBuilder)
      end
    end
  end

  test "fields for with a hash like model yeilds an instance of FormBuilder" do
    with_concat_form_for(:user) do |f|
      f.simple_fields_for(:author, HashBackedAuthor.new) do |author|
        assert author.instance_of?(SimpleForm::FormBuilder)
        author.input :name
      end
    end

    assert_select "input[name='user[author][name]'][value='hash backed author']"
  end

  test "fields for yields an instance of CustomBuilder if main builder is a CustomBuilder" do
    with_custom_form_for(:user) do |f|
      f.simple_fields_for(:company) do |company|
        assert company.instance_of?(CustomFormBuilder)
      end
    end
  end

  test "fields for yields an instance of FormBuilder if it was set in options" do
    with_custom_form_for(:user) do |f|
      f.simple_fields_for(:company, builder: SimpleForm::FormBuilder) do |company|
        assert company.instance_of?(SimpleForm::FormBuilder)
      end
    end
  end

  test "fields inherits wrapper option from the parent form" do
    swap_wrapper :another do
      simple_form_for(:user, wrapper: :another) do |f|
        f.simple_fields_for(:company) do |company|
          assert_equal :another, company.options[:wrapper]
        end
      end
    end
  end

  test "fields overrides wrapper option from the parent form" do
    swap_wrapper :another do
      simple_form_for(:user, wrapper: :another) do |f|
        f.simple_fields_for(:company, wrapper: false) do |company|
          assert_equal false, company.options[:wrapper]
        end
      end
    end
  end
end
