surrounded 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +11 -20
  3. data/LICENSE.txt +1 -1
  4. data/README.md +3 -3
  5. data/Rakefile +12 -5
  6. data/lib/surrounded/access_control.rb +12 -11
  7. data/lib/surrounded/context/forwarding.rb +10 -10
  8. data/lib/surrounded/context/initializing.rb +8 -6
  9. data/lib/surrounded/context/name_collision_detector.rb +17 -17
  10. data/lib/surrounded/context/negotiator.rb +7 -8
  11. data/lib/surrounded/context/role_builders.rb +7 -7
  12. data/lib/surrounded/context/role_map.rb +6 -8
  13. data/lib/surrounded/context/trigger_controls.rb +11 -13
  14. data/lib/surrounded/context.rb +61 -56
  15. data/lib/surrounded/east_oriented.rb +4 -4
  16. data/lib/surrounded/exceptions.rb +1 -1
  17. data/lib/surrounded/shortcuts.rb +6 -8
  18. data/lib/surrounded/version.rb +1 -1
  19. data/lib/surrounded.rb +7 -7
  20. data/surrounded.gemspec +21 -15
  21. data/test/{casting_role_player_test.rb → casting_test_helper.rb} +4 -3
  22. data/test/collection_role_players_test.rb +16 -16
  23. data/test/context_access_test.rb +31 -30
  24. data/test/context_forwarding_test.rb +30 -30
  25. data/test/context_reuse_test.rb +14 -14
  26. data/test/context_shortcuts_test.rb +18 -16
  27. data/test/east_oriented_triggers_test.rb +14 -13
  28. data/test/example_delegate_class_test.rb +8 -8
  29. data/test/example_proxy_test.rb +25 -23
  30. data/test/example_threaded_test.rb +13 -13
  31. data/test/example_wrapper_test.rb +7 -7
  32. data/test/initialization_test.rb +24 -25
  33. data/test/name_collisions_test.rb +48 -42
  34. data/test/non_surrounded_role_player_test.rb +8 -8
  35. data/test/override_methods_test.rb +9 -9
  36. data/test/role_context_method_test.rb +129 -119
  37. data/test/surrounded_context_test.rb +71 -62
  38. data/test/surrounded_test.rb +13 -15
  39. data/test/test_helper.rb +5 -4
  40. data/test/threaded_context_test.rb +70 -0
  41. metadata +8 -38
  42. data/.codeclimate.yml +0 -4
  43. data/.github/workflows/codeql-analysis.yml +0 -70
  44. data/.github/workflows/test.yml +0 -18
  45. data/.gitignore +0 -19
  46. data/.pullreview.yml +0 -4
  47. data/.simplecov +0 -3
  48. data/Gemfile +0 -9
  49. data/examples/bottles.rb +0 -135
  50. data/examples/rails.rb +0 -57
@@ -1,32 +1,32 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class Sending
4
4
  extend Surrounded::Context
5
-
5
+
6
6
  initialize :one, :two
7
-
7
+
8
8
  forwarding [:hello, :goodbye] => :one
9
9
  forward_trigger :two, :ping
10
10
  forward_trigger :two, :argumentative
11
11
  forwards :two, :blockhead
12
-
12
+
13
13
  role :one do
14
14
  def hello
15
- 'hello'
15
+ "hello"
16
16
  end
17
-
17
+
18
18
  def goodbye
19
- 'goodbye'
19
+ "goodbye"
20
20
  end
21
21
  end
22
-
22
+
23
23
  role :two do
24
24
  def ping
25
25
  one.hello
26
26
  end
27
27
 
28
28
  def argumentative(yes, no)
29
- [yes, no].join(' and ')
29
+ [yes, no].join(" and ")
30
30
  end
31
31
 
32
32
  def blockhead
@@ -35,31 +35,31 @@ class Sending
35
35
  end
36
36
  end
37
37
 
38
- describe Surrounded::Context, 'forwarding triggers' do
39
- let(:user){ User.new("Jim") }
40
- let(:other_user){ User.new("Guille") }
41
- let(:context){ Sending.new(one: user, two: other_user) }
42
-
43
- it 'forwards multiple configured instance methods as triggers' do
44
- assert_equal 'hello', context.hello
45
- assert_equal 'goodbye', context.goodbye
38
+ describe Surrounded::Context, "forwarding triggers" do
39
+ let(:user) { User.new("Jim") }
40
+ let(:other_user) { User.new("Guille") }
41
+ let(:context) { Sending.new(one: user, two: other_user) }
42
+
43
+ it "forwards multiple configured instance methods as triggers" do
44
+ assert_equal "hello", context.hello
45
+ assert_equal "goodbye", context.goodbye
46
46
  end
47
-
48
- it 'forwards individual configured instance methods as triggers' do
49
- assert_equal 'hello', context.ping
47
+
48
+ it "forwards individual configured instance methods as triggers" do
49
+ assert_equal "hello", context.ping
50
50
  end
51
-
52
- it 'does not forward __id__' do
53
- error = assert_raises(ArgumentError){
51
+
52
+ it "does not forward __id__" do
53
+ error = assert_raises(ArgumentError) {
54
54
  Sending.class_eval do
55
55
  forward_trigger :one, :__id__
56
56
  end
57
57
  }
58
58
  assert_match(/you may not forward '__id__`/i, error.message)
59
59
  end
60
-
61
- it 'does not forward __send__' do
62
- error = assert_raises(ArgumentError){
60
+
61
+ it "does not forward __send__" do
62
+ error = assert_raises(ArgumentError) {
63
63
  Sending.class_eval do
64
64
  forward_trigger :one, :__send__
65
65
  end
@@ -67,14 +67,14 @@ describe Surrounded::Context, 'forwarding triggers' do
67
67
  assert_match(/you may not forward '__send__/i, error.message)
68
68
  end
69
69
 
70
- it 'passes arguments' do
71
- assert_equal 'YES and NO', context.argumentative('YES','NO')
70
+ it "passes arguments" do
71
+ assert_equal "YES and NO", context.argumentative("YES", "NO")
72
72
  end
73
73
 
74
- it 'passes blocks' do
74
+ it "passes blocks" do
75
75
  result = context.blockhead do
76
76
  "Put them in the iron maiden. Excellent!"
77
77
  end
78
78
  assert_equal "Put them in the iron maiden. Excellent!", result
79
79
  end
80
- end
80
+ end
@@ -1,22 +1,22 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
- describe Surrounded::Context, 'reusing context object' do
4
- let(:user){ User.new("Jim") }
5
- let(:other_user){ User.new("Guille") }
6
- let(:context){ TestContext.new(user: user, other_user: other_user) }
3
+ describe Surrounded::Context, "reusing context object" do
4
+ let(:user) { User.new("Jim") }
5
+ let(:other_user) { User.new("Guille") }
6
+ let(:context) { TestContext.new(user: user, other_user: other_user) }
7
7
 
8
- it 'allows rebinding new players' do
9
- expect(context.access_other_object).must_equal 'Guille'
10
- context.rebind(user: User.new('Amy'), other_user: User.new('Elizabeth'))
11
- expect(context.access_other_object).must_equal 'Elizabeth'
8
+ it "allows rebinding new players" do
9
+ expect(context.access_other_object).must_equal "Guille"
10
+ context.rebind(user: User.new("Amy"), other_user: User.new("Elizabeth"))
11
+ expect(context.access_other_object).must_equal "Elizabeth"
12
12
  end
13
13
 
14
- it 'clears internal storage when rebinding' do
15
- originals = context.instance_variables.map{|var| context.instance_variable_get(var) }
16
- context.rebind(user: User.new('Amy'), other_user: User.new('Elizabeth'))
17
- new_ivars = context.instance_variables.map{|var| context.instance_variable_get(var) }
14
+ it "clears internal storage when rebinding" do
15
+ originals = context.instance_variables.map { |var| context.instance_variable_get(var) }
16
+ context.rebind(user: User.new("Amy"), other_user: User.new("Elizabeth"))
17
+ new_ivars = context.instance_variables.map { |var| context.instance_variable_get(var) }
18
18
  originals.zip(new_ivars).each do |original_ivar, new_ivar|
19
19
  expect(original_ivar).wont_equal new_ivar
20
20
  end
21
21
  end
22
- end
22
+ end
@@ -1,24 +1,26 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class ShortcutContext
4
4
  extend Surrounded::Context
5
+
5
6
  shortcut_triggers
6
-
7
+
7
8
  initialize :user, :other
8
-
9
+
9
10
  trigger :shorty do
10
11
  user.speak
11
12
  end
12
-
13
+
13
14
  role :user do
14
15
  def speak
15
- 'it works, shorty!'
16
+ "it works, shorty!"
16
17
  end
17
18
  end
18
19
  end
19
20
 
20
21
  class ShortcutContextNoKeywords
21
22
  extend Surrounded::Context
23
+
22
24
  shortcut_triggers
23
25
 
24
26
  initialize_without_keywords :user, :other
@@ -29,23 +31,23 @@ class ShortcutContextNoKeywords
29
31
 
30
32
  role :user do
31
33
  def speak
32
- 'it works, shorty!'
34
+ "it works, shorty!"
33
35
  end
34
36
  end
35
37
  end
36
38
 
37
- describe Surrounded::Context, 'shortcuts' do
38
- let(:user){ User.new("Jim") }
39
- let(:other){ User.new("Guille") }
40
- it 'creates shortcut class methods for triggers' do
41
- assert_equal 'it works, shorty!', ShortcutContext.shorty(user: user, other: other)
39
+ describe Surrounded::Context, "shortcuts" do
40
+ let(:user) { User.new("Jim") }
41
+ let(:other) { User.new("Guille") }
42
+ it "creates shortcut class methods for triggers" do
43
+ assert_equal "it works, shorty!", ShortcutContext.shorty(user: user, other: other)
42
44
  end
43
45
  end
44
46
 
45
- describe Surrounded::Context, 'shortcuts with initialize_without_keywords' do
46
- let(:user){ User.new("Jim") }
47
- let(:other){ User.new("Guille") }
48
- it 'creates shortcut class methods for triggers' do
49
- assert_equal 'it works, shorty!', ShortcutContextNoKeywords.shorty(user, other)
47
+ describe Surrounded::Context, "shortcuts with initialize_without_keywords" do
48
+ let(:user) { User.new("Jim") }
49
+ let(:other) { User.new("Guille") }
50
+ it "creates shortcut class methods for triggers" do
51
+ assert_equal "it works, shorty!", ShortcutContextNoKeywords.shorty(user, other)
50
52
  end
51
53
  end
@@ -1,36 +1,37 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class EastTestContext
4
4
  extend Surrounded::Context
5
+
5
6
  east_oriented_triggers
6
-
7
+
7
8
  initialize :user, :other_user
8
-
9
+
9
10
  trigger :ask? do
10
11
  "asking a question..."
11
12
  end
12
13
  end
13
14
 
14
- describe Surrounded::Context, '.east_oriented_triggers' do
15
- let(:user){ User.new("Jim") }
16
- let(:other_user){ User.new("Guille") }
17
- let(:context){ EastTestContext.new(user: user, other_user: other_user) }
15
+ describe Surrounded::Context, ".east_oriented_triggers" do
16
+ let(:user) { User.new("Jim") }
17
+ let(:other_user) { User.new("Guille") }
18
+ let(:context) { EastTestContext.new(user: user, other_user: other_user) }
18
19
 
19
- it 'returns the context object from trigger methods' do
20
+ it "returns the context object from trigger methods" do
20
21
  assert_equal context, context.ask?
21
22
  end
22
23
  end
23
24
 
24
- describe Surrounded::Context, '.east_oriented_triggers with protect_triggers' do
25
- let(:user){ User.new("Jim") }
26
- let(:other_user){ User.new("Guille") }
27
- let(:context){
25
+ describe Surrounded::Context, ".east_oriented_triggers with protect_triggers" do
26
+ let(:user) { User.new("Jim") }
27
+ let(:other_user) { User.new("Guille") }
28
+ let(:context) {
28
29
  ctxt = EastTestContext.new(user: user, other_user: other_user)
29
30
  ctxt.singleton_class.send(:protect_triggers)
30
31
  ctxt
31
32
  }
32
33
 
33
- it 'returns the context object from trigger methods' do
34
+ it "returns the context object from trigger methods" do
34
35
  assert_equal context, context.ask?
35
36
  end
36
37
  end
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  # If you want to use wrappers, here's how you could
4
4
  class DelegateClassContext
@@ -6,9 +6,9 @@ class DelegateClassContext
6
6
 
7
7
  initialize(:user, :task)
8
8
 
9
- delegate_class :user, 'User' do
9
+ delegate_class :user, "User" do
10
10
  def some_admin_method
11
- 'hello from the admin DelegateClass wrapper!'
11
+ "hello from the admin DelegateClass wrapper!"
12
12
  end
13
13
  end
14
14
  wrap :task do
@@ -20,10 +20,10 @@ class DelegateClassContext
20
20
  end
21
21
 
22
22
  describe DelegateClassContext do
23
- let(:context){
24
- DelegateClassContext.new(user: User.new('jim'), task: Object.new)
23
+ let(:context) {
24
+ DelegateClassContext.new(user: User.new("jim"), task: Object.new)
25
25
  }
26
- it 'wraps objects using DelegateClass' do
27
- assert_equal 'hello from the admin DelegateClass wrapper!', context.do_something
26
+ it "wraps objects using DelegateClass" do
27
+ assert_equal "hello from the admin DelegateClass wrapper!", context.do_something
28
28
  end
29
- end
29
+ end
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class ProxyContext
4
4
  extend Surrounded::Context
@@ -58,57 +58,59 @@ ProxyUser = Class.new do
58
58
  attr_reader :name
59
59
  end
60
60
 
61
+ ProxyTask = Data.define(:name)
62
+
61
63
  describe ProxyContext do
62
- let(:user){
63
- ProxyUser.new('Jim')
64
+ let(:user) {
65
+ ProxyUser.new("Jim")
64
66
  }
65
- let(:task){
66
- OpenStruct.new(name: 'GTD')
67
+ let(:task) {
68
+ ProxyTask.new(name: "GTD")
67
69
  }
68
- let(:context){
70
+ let(:context) {
69
71
  ProxyContext.new(admin: user, task: task)
70
72
  }
71
- it 'proxys methods between objects and its interface' do
72
- assert_equal 'hello from Jim, the admin interface!', context.do_something
73
+ it "proxys methods between objects and its interface" do
74
+ assert_equal "hello from Jim, the admin interface!", context.do_something
73
75
  end
74
76
 
75
- it 'forwards methods that the object responds to' do
76
- assert_equal 'Jim', context.admin_name
77
+ it "forwards methods that the object responds to" do
78
+ assert_equal "Jim", context.admin_name
77
79
  end
78
80
 
79
- it 'passes missing methods up the ancestry of the object' do
80
- err = _{ context.admin_missing_method }.must_raise(NoMethodError)
81
+ it "passes missing methods up the ancestry of the object" do
82
+ err = _ { context.admin_missing_method }.must_raise(NoMethodError)
81
83
 
82
- assert_match(/ProxyUser.*name="Jim"/, err.message)
84
+ assert_match(/ProxyUser/, err.message)
83
85
  end
84
86
 
85
- it 'fails access to other objects in the context' do
86
- err = _{ context.talking }.must_raise NameError
87
- assert_match(%r{undefined local variable or method `task'}, err.message)
87
+ it "fails access to other objects in the context" do
88
+ err = _ { context.talking }.must_raise NameError
89
+ assert_match(/undefined local variable or method [`']task['`]/, err.message)
88
90
  end
89
91
 
90
- it 'sets roles to respond to role methods' do
92
+ it "sets roles to respond to role methods" do
91
93
  assert context.admin_responds?
92
94
  end
93
95
 
94
96
  # A Negotiator object merely applies methods to another object
95
97
  # so that once the method is called, the object has no knowledge
96
98
  # of the module from which the method was applied.
97
- it 'does not find other interface methods' do
98
- assert_raises(NameError){
99
+ it "does not find other interface methods" do
100
+ assert_raises(NameError) {
99
101
  context.combined_interface_methods
100
102
  }
101
103
  end
102
104
 
103
- it 'is able to grab methods from the object' do
105
+ it "is able to grab methods from the object" do
104
106
  assert_equal :talking_to_others, context.get_admin_method.name
105
107
  end
106
108
 
107
- it 'allows Surrounded objects to interact with others' do
108
- assert context.rebind(admin: User.new('Surrounded'), task: task).talking
109
+ it "allows Surrounded objects to interact with others" do
110
+ assert context.rebind(admin: User.new("Surrounded"), task: task).talking
109
111
  end
110
112
 
111
- it 'works with frozen and primitive objects' do
113
+ it "works with frozen and primitive objects" do
112
114
  context.rebind(admin: "brrr".freeze, task: task)
113
115
  assert context.get_admin_method
114
116
  context.rebind(admin: nil, task: task)
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class ThreadedContext
4
4
  extend Surrounded::Context
@@ -16,7 +16,7 @@ class ThreadedContext
16
16
  result << members.concurrent_map do |member|
17
17
  result << member.greet
18
18
  end
19
- result.flatten.join(' ')
19
+ result.flatten.join(" ")
20
20
  end
21
21
 
22
22
  def greet
@@ -44,21 +44,21 @@ class ThreadedContext
44
44
  end
45
45
 
46
46
  describe ThreadedContext do
47
- let(:jim){ User.new('Jim') }
48
- let(:amy){ User.new('Amy') }
49
- let(:guille){ User.new('Guille') }
50
- let(:jason){ User.new('Jason') }
51
- let(:dave){ User.new('Dave') }
47
+ let(:jim) { User.new("Jim") }
48
+ let(:amy) { User.new("Amy") }
49
+ let(:guille) { User.new("Guille") }
50
+ let(:jason) { User.new("Jason") }
51
+ let(:dave) { User.new("Dave") }
52
52
 
53
- let(:greeter){ jim }
54
- let(:members){ [amy, guille, jason, dave] }
53
+ let(:greeter) { jim }
54
+ let(:members) { [amy, guille, jason, dave] }
55
55
 
56
- it 'works in multi-threaded environments' do
56
+ it "works in multi-threaded environments" do
57
57
  meeting = ThreadedContext.new(leader: jim, members: members)
58
58
 
59
59
  result = meeting.meet
60
60
 
61
- assert_includes result, 'Hello everyone. I am Jim'
62
- assert_includes result, 'Hello Jim, I am Amy'
61
+ assert_includes result, "Hello everyone. I am Jim"
62
+ assert_includes result, "Hello Jim, I am Amy"
63
63
  end
64
- end
64
+ end
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  # If you want to use wrappers, here's how you could
4
4
  class WrapperContext
@@ -8,10 +8,10 @@ class WrapperContext
8
8
 
9
9
  wrap :admin do
10
10
  def some_admin_method
11
- 'hello from the admin wrapper!'
11
+ "hello from the admin wrapper!"
12
12
  end
13
13
  end
14
- wrap :task do; end
14
+ wrap :task, &proc {}
15
15
 
16
16
  trigger :do_something do
17
17
  admin.some_admin_method
@@ -19,10 +19,10 @@ class WrapperContext
19
19
  end
20
20
 
21
21
  describe WrapperContext do
22
- let(:context){
22
+ let(:context) {
23
23
  WrapperContext.new(admin: Object.new, task: Object.new)
24
24
  }
25
- it 'wraps objects and allows them to respond to new methods' do
26
- assert_equal 'hello from the admin wrapper!', context.do_something
25
+ it "wraps objects and allows them to respond to new methods" do
26
+ assert_equal "hello from the admin wrapper!", context.do_something
27
27
  end
28
- end
28
+ end
@@ -1,32 +1,31 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class KeywordContext
4
4
  extend Surrounded::Context
5
5
 
6
6
  keyword_initialize(:user, :other_user) do
7
- @defined_by_initializer_block = 'yup'
7
+ @defined_by_initializer_block = "yup"
8
8
  end
9
9
  end
10
10
 
11
- describe Surrounded::Context, '.initialize' do
12
-
13
- it 'applies a provided block to the instance' do
14
- context = KeywordContext.new(user: User.new('Jim'), other_user: User.new('Amy'))
15
- assert_equal 'yup', context.instance_variable_get(:@defined_by_initializer_block)
11
+ describe Surrounded::Context, ".initialize" do
12
+ it "applies a provided block to the instance" do
13
+ context = KeywordContext.new(user: User.new("Jim"), other_user: User.new("Amy"))
14
+ assert_equal "yup", context.instance_variable_get(:@defined_by_initializer_block)
16
15
  end
17
16
 
18
- it 'keeps track of the original initialize arguments' do
19
- jim = User.new('Jim')
20
- amy = User.new('Amy')
17
+ it "keeps track of the original initialize arguments" do
18
+ jim = User.new("Jim")
19
+ amy = User.new("Amy")
21
20
  context = KeywordContext.new(user: jim, other_user: amy)
22
21
  tracked = context.send(:initializer_arguments)
23
22
  assert_equal jim, tracked[:user]
24
23
  assert_equal amy, tracked[:other_user]
25
24
  end
26
25
 
27
- it 'raises errors with missing keywords' do
28
- err = assert_raises(ArgumentError){
29
- KeywordContext.new(other_user: User.new('Amy'))
26
+ it "raises errors with missing keywords" do
27
+ err = assert_raises(ArgumentError) {
28
+ KeywordContext.new(other_user: User.new("Amy"))
30
29
  }
31
30
  assert_match(/missing keyword: :?user/, err.message)
32
31
  end
@@ -36,7 +35,7 @@ class NonKeyworder
36
35
  extend Surrounded::Context
37
36
 
38
37
  initialize_without_keywords :this, :that do
39
- self.instance_variable_set(:@defined_by_initializer_block, 'yes')
38
+ instance_variable_set(:@defined_by_initializer_block, "yes")
40
39
  end
41
40
 
42
41
  trigger :access_other_object do
@@ -44,23 +43,23 @@ class NonKeyworder
44
43
  end
45
44
  end
46
45
 
47
- describe Surrounded::Context, 'non-keyword initializers' do
48
- it 'defines an initialize method accepting the same arguments' do
46
+ describe Surrounded::Context, "non-keyword initializers" do
47
+ it "defines an initialize method accepting the same arguments" do
49
48
  assert_equal 2, NonKeyworder.instance_method(:initialize).arity
50
49
  end
51
50
 
52
- it 'works without keyword arguments' do
53
- assert NonKeyworder.new(User.new('Jim'), User.new('Guille'))
51
+ it "works without keyword arguments" do
52
+ assert NonKeyworder.new(User.new("Jim"), User.new("Guille"))
54
53
  end
55
54
 
56
- it 'evaluates a given block' do
57
- assert_equal 'yes', NonKeyworder.new(User.new('Jim'), User.new('Guille')).instance_variable_get(:@defined_by_initializer_block)
55
+ it "evaluates a given block" do
56
+ assert_equal "yes", NonKeyworder.new(User.new("Jim"), User.new("Guille")).instance_variable_get(:@defined_by_initializer_block)
58
57
  end
59
58
 
60
- it 'allows rebinding with a hash' do
61
- context = NonKeyworder.new(User.new('Jim'), User.new('Guille'))
62
- expect(context.access_other_object).must_equal 'Guille'
63
- context.rebind(this: User.new('Amy'), that: User.new('Elizabeth'))
64
- expect(context.access_other_object).must_equal 'Elizabeth'
59
+ it "allows rebinding with a hash" do
60
+ context = NonKeyworder.new(User.new("Jim"), User.new("Guille"))
61
+ expect(context.access_other_object).must_equal "Guille"
62
+ context.rebind(this: User.new("Amy"), that: User.new("Elizabeth"))
63
+ expect(context.access_other_object).must_equal "Elizabeth"
65
64
  end
66
65
  end