hydra-head 4.0.0.rc5 → 4.0.0.rc6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/HISTORY.textile +1 -1
  2. data/HOW_TO_GET_STARTED.textile +2 -2
  3. data/INSTALL_PREREQ.textile +1 -20
  4. data/README.textile +12 -16
  5. data/app/assets/stylesheets/hydra/html_refactor.css +1 -5
  6. data/app/assets/stylesheets/hydra/hydrangea.css +0 -4
  7. data/app/assets/stylesheets/hydra/styles.css +12 -595
  8. data/app/controllers/downloads_controller.rb +2 -1
  9. data/app/controllers/hydra/permissions_controller.rb +2 -6
  10. data/app/models/ability.rb +1 -98
  11. data/app/models/hydra/ability.rb +128 -0
  12. data/app/views/_flash_msg.html.erb +1 -1
  13. data/app/views/catalog/_home.html.erb +2 -2
  14. data/app/views/catalog/_home_text.html.erb +2 -8
  15. data/app/views/catalog/_show_partials/_default.html.erb +0 -4
  16. data/app/views/generic_images/_edit.html.erb +0 -2
  17. data/app/views/layouts/hydra-head.html.erb +22 -35
  18. data/lib/hydra-head/version.rb +1 -1
  19. data/lib/hydra/mods_article.rb +22 -2
  20. data/lib/railties/hydra-fixtures.rake +17 -24
  21. data/tasks/hydra-head-fixtures.rake +32 -28
  22. data/tasks/hydra-head.rake +39 -57
  23. data/{lib/railties → tasks}/hyhead_rspec.rake +7 -26
  24. data/test_support/features/file_upload.feature +3 -3
  25. data/test_support/features/step_definitions/edit_metadata_steps.rb +1 -1
  26. data/test_support/features/step_definitions/user_steps.rb +7 -4
  27. data/test_support/spec/models/ability_spec.rb +3 -9
  28. metadata +36 -51
  29. data/DEVELOP_PLUGIN.textile +0 -90
  30. data/GIT_WORKFLOW.textile +0 -106
  31. data/HOW_TO_DEFINE_A_HYDRA_CONTROLLER.textile +0 -21
  32. data/HOW_TO_DEFINE_A_HYDRA_MODEL.textile +0 -64
  33. data/HYDRA_ACCESS_CONTROLS.textile +0 -27
  34. data/INITIAL_APP_MODS.textile +0 -223
  35. data/README_RAILS3_CHANGES.textile +0 -67
  36. data/README_RAKE_TASKS.textile +0 -107
  37. data/README_SUBTREE.textile +0 -87
  38. data/README_TERSE.textile +0 -92
  39. data/RELEASE_NOTES.textile +0 -8
  40. data/TESTING.textile +0 -85
  41. data/TESTING_PLUGIN.textile +0 -133
  42. data/app/views/layouts/application.html.erb +0 -49
  43. data/lib/railties/all_tests.rake +0 -23
  44. data/lib/railties/hyhead_cucumber.rake +0 -126
@@ -7,7 +7,8 @@ class DownloadsController < ApplicationController
7
7
  # in order to avoid ActionController being clever with the filenames/extensions/formats.
8
8
  # To download a datastream, pass the datastream id as ?document_id=#{dsid} in the url
9
9
  def index
10
- fedora_object = ActiveFedora::Base.load_instance(params[:asset_id])
10
+ ActiveSupport::Deprecation.warn("DownloadsController is deprecated. Please use FileAssetsController or create a model specific DownloadsController in your own hydra-head.")
11
+ fedora_object = ActiveFedora::Base.find(params[:asset_id])
11
12
  if params[:download_id]
12
13
  @datastream = fedora_object.datastreams[params[:download_id]]
13
14
  send_datastream @datastream
@@ -3,9 +3,7 @@ class Hydra::PermissionsController < ApplicationController
3
3
  include Hydra::SubmissionWorkflow
4
4
 
5
5
  def index
6
- af_base=ActiveFedora::Base.load_instance(params[:asset_id])
7
- the_model = ActiveFedora::ContentModel.known_models_for( af_base ).first
8
- @document_fedora = af_base.adapt_to(the_model)
6
+ @document_fedora=ActiveFedora::Base.find(params[:asset_id], :cast=>true)
9
7
 
10
8
  respond_to do |format|
11
9
  format.html
@@ -21,9 +19,7 @@ class Hydra::PermissionsController < ApplicationController
21
19
  end
22
20
 
23
21
  def edit
24
- af_base=ActiveFedora::Base.load_instance(params[:asset_id])
25
- the_model = ActiveFedora::ContentModel.known_models_for( af_base ).first
26
- @document_fedora = af_base.adapt_to(the_model)
22
+ @document_fedora=ActiveFedora::Base.find(params[:asset_id], :cast=>true)
27
23
 
28
24
  respond_to do |format|
29
25
  format.html
@@ -1,101 +1,4 @@
1
1
  class Ability
2
2
  include CanCan::Ability
3
- include Hydra::AccessControlsEnforcement
4
-
5
- attr_reader :user, :user_groups
6
-
7
- def initialize(user, session=nil)
8
- user ||= User.new # guest user (not logged in)
9
- @user = user
10
- @user_groups = RoleMapper.roles(@user.email)
11
- # everyone is automatically a member of the group 'public'
12
- @user_groups.push 'public' unless @user_groups.include?('public')
13
- # logged-in users are automatically members of the group "registered"
14
- @user_groups.push 'registered' unless (@user.email == '' || @user == "public" || @user_groups.include?('registered') )
15
-
16
- logger.debug("Usergroups is " + @user_groups.inspect)
17
-
18
- if @user.is_being_superuser?(session)
19
- can :manage, :all
20
- else
21
- hydra_default_permissions
22
- end
23
- end
24
-
25
- def hydra_default_permissions
26
- can :edit, String do |pid|
27
- @response, @permissions_solr_document = get_permissions_solr_response_for_doc_id(pid)
28
- test_edit
29
- end
30
-
31
- can :edit, ActiveFedora::Base do |obj|
32
- @response, @permissions_solr_document = get_permissions_solr_response_for_doc_id(obj.pid)
33
- test_edit
34
- end
35
-
36
- can :edit, SolrDocument do |obj|
37
- test_edit
38
- end
39
-
40
- can :read, String do |pid|
41
- @response, @permissions_solr_document = get_permissions_solr_response_for_doc_id(pid)
42
- test_read
43
- end
44
-
45
- can :read, ActiveFedora::Base do |obj|
46
- @response, @permissions_solr_document = get_permissions_solr_response_for_doc_id(obj.pid)
47
- test_read
48
- end
49
-
50
- can :read, SolrDocument do |obj|
51
- test_read
52
- end
53
- end
54
-
55
- private
56
- def test_edit
57
- logger.debug("CANCAN Checking edit permissions for user: #{@user}")
58
- group_intersection = @user_groups & edit_groups
59
- result = !group_intersection.empty? || edit_persons.include?(@user.email)
60
- logger.debug("CANCAN decision: #{result}")
61
- result
62
- end
63
-
64
- def test_read
65
- logger.debug("CANCAN Checking edit permissions for user: #{@user}")
66
- group_intersection = @user_groups & read_groups
67
- result = !group_intersection.empty? || read_persons.include?(@user.email)
68
- logger.debug("CANCAN decision: #{result}")
69
- result
70
- end
71
-
72
- def edit_groups
73
- edit_group_field = Hydra.config[:permissions][:edit][:group]
74
- eg = ((@permissions_solr_document == nil || @permissions_solr_document.fetch(edit_group_field,nil) == nil) ? [] : @permissions_solr_document.fetch(edit_group_field,nil))
75
- logger.debug("edit_groups: #{eg.inspect}")
76
- return eg
77
- end
78
-
79
- # edit implies read, so read_groups is the union of edit and read groups
80
- def read_groups
81
- read_group_field = Hydra.config[:permissions][:read][:group]
82
- rg = edit_groups | ((@permissions_solr_document == nil || @permissions_solr_document.fetch(read_group_field,nil) == nil) ? [] : @permissions_solr_document.fetch(read_group_field,nil))
83
- logger.debug("read_groups: #{rg.inspect}")
84
- return rg
85
- end
86
-
87
- def edit_persons
88
- edit_person_field = Hydra.config[:permissions][:edit][:individual]
89
- ep = ((@permissions_solr_document == nil || @permissions_solr_document.fetch(edit_person_field,nil) == nil) ? [] : @permissions_solr_document.fetch(edit_person_field,nil))
90
- logger.debug("edit_persons: #{ep.inspect}")
91
- return ep
92
- end
93
-
94
- # edit implies read, so read_persons is the union of edit and read persons
95
- def read_persons
96
- read_individual_field = Hydra.config[:permissions][:read][:individual]
97
- rp = edit_persons | ((@permissions_solr_document == nil || @permissions_solr_document.fetch(read_individual_field,nil) == nil) ? [] : @permissions_solr_document.fetch(read_individual_field,nil))
98
- logger.debug("read_persons: #{rp.inspect}")
99
- return rp
100
- end
3
+ include Hydra::Ability
101
4
  end
@@ -0,0 +1,128 @@
1
+ module Hydra::Ability
2
+ include Hydra::AccessControlsEnforcement
3
+
4
+ attr_reader :user, :user_groups
5
+
6
+ def initialize(user, session=nil)
7
+ user ||= User.new # guest user (not logged in)
8
+ @user = user
9
+ @user_groups = RoleMapper.roles(user_key)
10
+ # # everyone is automatically a member of the group 'public'
11
+ # @user_groups.push 'public' unless @user_groups.include?('public')
12
+ # # logged-in users are automatically members of the group "registered"
13
+ # @user_groups.push 'registered' unless (@user.email == '' || @user == "public" || @user_groups.include?('registered') )
14
+
15
+ logger.debug("Usergroups is " + @user_groups.inspect)
16
+
17
+ if @user.is_being_superuser?(session)
18
+ can :manage, :all
19
+ else
20
+ hydra_default_permissions(user, session)
21
+ end
22
+ end
23
+
24
+ def hydra_default_permissions(user, session)
25
+ edit_permissions(user, session)
26
+ read_permissions(user, session)
27
+ custom_permissions(user, session)
28
+ end
29
+
30
+ def edit_permissions(user, session)
31
+ can :edit, String do |pid|
32
+ @response, @permissions_solr_document = get_permissions_solr_response_for_doc_id(pid)
33
+ test_edit
34
+ end
35
+
36
+ can :edit, ActiveFedora::Base do |obj|
37
+ @response, @permissions_solr_document = get_permissions_solr_response_for_doc_id(obj.pid)
38
+ test_edit
39
+ end
40
+
41
+ can :edit, SolrDocument do |obj|
42
+ @permissions_solr_document = obj
43
+ test_edit
44
+ end
45
+
46
+ can :edit, SolrDocument do |obj|
47
+ test_edit
48
+ end
49
+ end
50
+
51
+ def read_permissions(user, session)
52
+ can :read, String do |pid|
53
+ @response, @permissions_solr_document = get_permissions_solr_response_for_doc_id(pid)
54
+ test_read
55
+ end
56
+
57
+ can :read, ActiveFedora::Base do |obj|
58
+ @response, @permissions_solr_document = get_permissions_solr_response_for_doc_id(obj.pid)
59
+ test_read
60
+ end
61
+
62
+ can :read, SolrDocument do |obj|
63
+ @permissions_solr_document = obj
64
+ test_read
65
+ end
66
+ end
67
+
68
+
69
+ ## Override custom permissions in your own app to add more permissions beyond what is defined by default.
70
+ def custom_permissions(user, session)
71
+ end
72
+
73
+ protected
74
+ def test_edit
75
+ logger.debug("CANCAN Checking edit permissions for user: #{@user}")
76
+ group_intersection = @user_groups & edit_groups
77
+ result = !group_intersection.empty? || edit_persons.include?(@user.email)
78
+ logger.debug("CANCAN decision: #{result}")
79
+ result
80
+ end
81
+
82
+ def test_read
83
+ logger.debug("CANCAN Checking edit permissions for user: #{@user}")
84
+ group_intersection = @user_groups & read_groups
85
+ result = !group_intersection.empty? || read_persons.include?(@user.email)
86
+ logger.debug("CANCAN decision: #{result}")
87
+ result
88
+ end
89
+
90
+ def edit_groups
91
+ edit_group_field = Hydra.config[:permissions][:edit][:group]
92
+ eg = ((@permissions_solr_document == nil || @permissions_solr_document.fetch(edit_group_field,nil) == nil) ? [] : @permissions_solr_document.fetch(edit_group_field,nil))
93
+ logger.debug("edit_groups: #{eg.inspect}")
94
+ return eg
95
+ end
96
+
97
+ # edit implies read, so read_groups is the union of edit and read groups
98
+ def read_groups
99
+ read_group_field = Hydra.config[:permissions][:read][:group]
100
+ rg = edit_groups | ((@permissions_solr_document == nil || @permissions_solr_document.fetch(read_group_field,nil) == nil) ? [] : @permissions_solr_document.fetch(read_group_field,nil))
101
+ logger.debug("read_groups: #{rg.inspect}")
102
+ return rg
103
+ end
104
+
105
+ def edit_persons
106
+ edit_person_field = Hydra.config[:permissions][:edit][:individual]
107
+ ep = ((@permissions_solr_document == nil || @permissions_solr_document.fetch(edit_person_field,nil) == nil) ? [] : @permissions_solr_document.fetch(edit_person_field,nil))
108
+ logger.debug("edit_persons: #{ep.inspect}")
109
+ return ep
110
+ end
111
+
112
+ # edit implies read, so read_persons is the union of edit and read persons
113
+ def read_persons
114
+ read_individual_field = Hydra.config[:permissions][:read][:individual]
115
+ rp = edit_persons | ((@permissions_solr_document == nil || @permissions_solr_document.fetch(read_individual_field,nil) == nil) ? [] : @permissions_solr_document.fetch(read_individual_field,nil))
116
+ logger.debug("read_persons: #{rp.inspect}")
117
+ return rp
118
+ end
119
+
120
+
121
+ # get the currently configured user identifier. Can be overridden to return whatever (ie. login, email, etc)
122
+ # defaults to using whatever you have set as the Devise authentication_key
123
+ def user_key
124
+ @user.send(Devise.authentication_keys.first)
125
+ end
126
+
127
+
128
+ end
@@ -1,5 +1,5 @@
1
1
  <% [:notice, :error, :alert].each do |type| %>
2
2
  <% if flash[type] %>
3
- <div class="ui-state-<%= type == :error ? 'error' : 'highlight' %> ui-corner-all <%= type.to_s %>"><%= flash[type] %></div>
3
+ <div class="ui-state-<%= type == :error ? 'error' : 'highlight' %> ui-corner-all msg <%= type.to_s %>"><%= flash[type] %></div>
4
4
  <% end %>
5
5
  <% end %>
@@ -1,6 +1,6 @@
1
- <%#= render :partial=>'search_form' %>
1
+ <%= render :partial=>'search_form' %>
2
2
  <%= render :partial=>'home_text' %>
3
3
 
4
4
  <% sidebar_items << capture do %>
5
5
  <%= render :partial=>'facets' %>
6
- <% end %>
6
+ <% end %>
@@ -1,10 +1,4 @@
1
1
  <div id="results" class="home-text">
2
-
3
- <%= render :partial=>'search_form' %>
4
-
5
- <div class="home_text">
6
- <h1>Welcome to Hydra</h1>
7
- <p>Edit or override this page (vendor/plugins/hydra-head/views/catalog/_home_text.html.erb)</p>
8
- </div>
9
-
2
+ <h1>Welcome to Hydra</h1>
3
+ <p>Edit or override this page (views/catalog/_home_text.html.erb)</p>
10
4
  </div>
@@ -18,8 +18,4 @@
18
18
  <div class="<%= params[:action]%>_details">
19
19
  <%= render :partial => "#{params[:controller]}/_#{params[:action]}_partials/default_details", :locals => {:document => document}%>
20
20
  </div>
21
- <% sidebar_items << capture do %>
22
- <%#= render :partial=>"catalog/_show_partials/facets", :locals=>{:document=>document, :facets_display_heading => "This document refers to:"} %>
23
- <% end %>
24
-
25
21
  <%= async_load_tag(hydra_asset_downloads_path(params[:id]), 'downloads') %>
@@ -33,8 +33,6 @@
33
33
  </div>
34
34
  </div>
35
35
  <% sidebar_items << capture do %>
36
- <%#= render :partial=>"catalog/_show_partials/facets", :locals=>{:document=>document, :facets_display_heading => "This document refers to:"} %>
37
- <%#= render :partial=>'facets' %>
38
36
  <%= delete_asset_link(params[:id], "GenericImage") %>
39
37
  <% end %>
40
38
  <%= async_load_tag(generic_content_object_path(params[:id], :layout=>"false", :method => ":get"), 'uploads') %>
@@ -1,57 +1,44 @@
1
1
  <!DOCTYPE html>
2
-
3
- <!--[if lt IE 7 ]> <html class="ie6"> <![endif]-->
4
- <!--[if IE 7 ]> <html class="ie7"> <![endif]-->
5
- <!--[if IE 8 ]> <html class="ie8"> <![endif]-->
6
- <!--[if IE 9 ]> <html class="ie9"> <![endif]-->
7
- <!--[if gt IE 9]> <html> <![endif]-->
8
- <!--[if !IE]><!--> <html> <!--<![endif]-->
9
-
2
+ <html>
10
3
  <head>
11
4
  <meta charset="utf-8" />
12
-
13
5
  <title><%= h(@page_title || application_name) %></title>
14
6
  <link href="<%= opensearch_catalog_url(:format => 'xml') %>" title="<%= application_name%>" type="application/opensearchdescription+xml" rel="search"/>
15
-
16
- <%= render_head_content %>
17
-
18
- <!--[if IE]>
19
- <%= stylesheet_link_tag('hydra/ie-styles', {:media=>'all'}) %>
20
- <%= stylesheet_link_tag('progressBox-ie6.css', {:media=>'all'}) %>
21
- <![endif]-->
7
+ <%= favicon_link_tag asset_path('favicon.ico') %>
8
+ <%= stylesheet_link_tag "application" %>
9
+ <%= javascript_include_tag "application" %>
10
+ <%= csrf_meta_tags %>
11
+ <%= raw(render_head_content) %>
22
12
  </head>
23
13
 
24
- <body class="<%= render_body_class %>">
14
+ <body class="<%= render_body_class %>">
25
15
 
26
- <div id="doc4" class="yui-t2">
27
-
28
16
  <div id="hd">
29
17
  <%= render :partial => '/user_util_links' %>
30
18
  <%= (params[:controller] == "catalog" and !params[:id]) ? "<span id='results_text'>Search Results</span>".html_safe : "" %>
31
19
  </div>
32
20
 
33
- <div id="bd">
34
- <div id="yui-main">
35
- <%= render :partial=>'/flash_msg' %>
36
- <%= yield %>
21
+ <div id="bd">
22
+ <div id="main">
23
+ <div id="main_container">
24
+ <%= render :partial=>'/flash_msg' %>
25
+ <%= yield %>
26
+ </div>
37
27
  </div>
38
- <div class="yui-b sidebar"><%= sidebar_items.join('').html_safe %></div>
28
+ <div id="sidebar"><%= sidebar_items.join('').html_safe %></div>
39
29
  </div>
40
30
 
41
31
 
42
- <div id="footer">
43
- <div id="container3">
44
- <div class="contact_info"></div>
45
- <div class="aux_links"> </div>
46
- <div id="footer_notices">
47
- <div id="bottom_text">
48
- <div id="hydra_logo"><%= image_tag('hydra/powered_by_hydra.png', :width => 80, :height => 50, :alt => "Hydra logo") %></div>
49
- </div>
50
- </div>
51
- </div>
32
+ <div id="ft">
33
+ <div class="contact_info"></div>
34
+ <div class="aux_links"> </div>
35
+ <div id="footer_notices">
36
+ <div id="bottom_text">
37
+ <div id="hydra_logo"><%= image_tag('hydra/powered_by_hydra.png', :width => 80, :height => 50, :alt => "Hydra logo") %></div>
38
+ </div>
39
+ </div>
52
40
  </div>
53
41
 
54
- </div>
55
42
  </body>
56
43
 
57
44
  </html>
@@ -1,4 +1,4 @@
1
1
  module HydraHead
2
- VERSION = "4.0.0.rc5"
2
+ VERSION = "4.0.0.rc6"
3
3
  end
4
4
 
@@ -1,9 +1,7 @@
1
- require "uva/mods_index_methods"
2
1
  module Hydra
3
2
 
4
3
  class ModsArticle < ActiveFedora::NokogiriDatastream
5
4
  include Hydra::Datastream::CommonModsIndexMethods
6
- include Uva::ModsIndexMethods
7
5
 
8
6
  def initialize(digital_object, dsid, options={})
9
7
  ActiveSupport::Deprecation.warn("Hydra::ModsArticle has been deprecated. Use Hydra::Datastream::ModsArticle instead")
@@ -510,5 +508,27 @@ module Hydra
510
508
 
511
509
  solr_doc
512
510
  end
511
+
512
+ # extracts the last_name##full_name##computing_id to be used by home view
513
+ def extract_person_full_names_and_computing_ids
514
+ names = {}
515
+ self.find_by_terms(:person).each do |person|
516
+ name_parts = person.children.inject({}) do |hash,child|
517
+ hash[child.get_attribute(:type)] = child.text if ["family","given"].include? child.get_attribute(:type)
518
+ hash["computing_id"] = child.text if child.name == 'computing_id'
519
+ hash
520
+ end
521
+ if name_parts.length == 3 and person.search(:roleTerm).children.text.include?("Author")
522
+ if name_parts["family"].blank? && name_parts["given"].blank? && name_parts["computing_id"].blank?
523
+ value = "Unknown Author"
524
+ else
525
+ value = "#{name_parts["family"]}, #{name_parts["given"]} (#{name_parts["computing_id"]})"
526
+ end
527
+ ::Solrizer::Extractor.insert_solr_field_value(names, "person_full_name_cid_facet", value) if name_parts.length == 3
528
+ end
529
+ end
530
+ names
531
+ end
532
+
513
533
  end
514
534
  end
@@ -14,36 +14,29 @@ namespace :hydra do
14
14
  end
15
15
 
16
16
  namespace :fixtures do
17
- FIXTURES = [
18
- "hydrangea:fixture_mods_article1",
19
- "hydrangea:fixture_mods_article3",
20
- "hydrangea:fixture_file_asset1",
21
- "hydrangea:fixture_mods_article2",
22
- "hydrangea:fixture_uploaded_svg1",
23
- "hydrangea:fixture_archivist_only_mods_article",
24
- "hydrangea:fixture_mods_dataset1",
25
- "libra-oa:1", "libra-oa:2", "libra-oa:7",
26
- "hydrus:admin_class1",
27
- "hydra:test_generic_content",
28
- "hydra:test_generic_image",
29
- "hydra:test_default_partials",
30
- "hydra:test_no_model"
31
- ]
32
- desc "Load default Hydra fixtures"
33
17
  task :load do
34
- ENV["dir"] = File.join("test_support", "fixtures")
35
- FIXTURES.each do |fixture|
36
- ENV["pid"] = fixture
37
- Rake::Task["repo:load"].reenable
38
- Rake::Task["repo:load"].invoke
18
+ ENV["dir"] ||= File.join("spec", "fixtures")
19
+ loader = ActiveFedora::FixtureLoader.new(ENV['dir'])
20
+ Dir.glob("#{ENV['dir']}/*.foxml.xml").each do |fixture_path|
21
+ pid = File.basename(fixture_path, ".foxml.xml").sub("_",":")
22
+ begin
23
+ foo = loader.reload(pid)
24
+ puts "Updated #{pid}"
25
+ rescue Errno::ECONNREFUSED => e
26
+ puts "Can't connect to Fedora! Are you sure jetty is running?"
27
+ rescue Exception => e
28
+ puts("Received a Fedora error while loading #{pid}\n#{e}")
29
+ logger.error("Received a Fedora error while loading #{pid}\n#{e}")
30
+ end
39
31
  end
40
32
  end
41
33
 
42
34
  desc "Remove default Hydra fixtures"
43
35
  task :delete do
44
- ENV["dir"] = File.join("test_support", "fixtures")
45
- FIXTURES.each do |fixture|
46
- ENV["pid"] = fixture
36
+ ENV["dir"] ||= File.join("spec", "fixtures")
37
+ loader = ActiveFedora::FixtureLoader.new(ENV['dir'])
38
+ Dir.glob("#{ENV['dir']}/*.foxml.xml").each do |fixture_path|
39
+ ENV["pid"] = File.basename(fixture_path, ".foxml.xml").sub("_",":")
47
40
  Rake::Task["repo:delete"].reenable
48
41
  Rake::Task["repo:delete"].invoke
49
42
  end