gates_of_moria 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/gates_of_moria.gemspec +1 -0
- data/lib/gates_of_moria/data/door.rb +13 -0
- data/lib/gates_of_moria/{motd.txt → data/motd.txt} +4 -0
- data/lib/gates_of_moria/data/questions.json +81 -0
- data/lib/gates_of_moria/quiz.rb +10 -3
- data/lib/gates_of_moria/repl.rb +14 -4
- data/lib/gates_of_moria/version.rb +1 -1
- data/spec/acceptance/answering_last_question_wrong.feature +8 -0
- data/spec/acceptance/{player_starts_the_quiz.feature → answering_questions.feature} +1 -11
- data/spec/acceptance/starting_and_quitting.feature +13 -0
- data/spec/acceptance/steps/player_steps.rb +80 -17
- data/spec/acceptance/winning_the_game.feature +10 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/ending_processes.rb +7 -0
- data/spec/support/greenletters.rb +7 -0
- metadata +33 -6
- data/lib/gates_of_moria/questions.json +0 -13
data/gates_of_moria.gemspec
CHANGED
@@ -33,3 +33,7 @@
|
|
33
33
|
;____: `._ `' _,' ;____:
|
34
34
|
{______} \___________________/ {______}
|
35
35
|
SSt |______|_______________________________|______|
|
36
|
+
|
37
|
+
Welcome to the Gates of Moria! After many adventures, you and your companions have come upon a door to the Dwarven kingdom of Moria. But you cannot open the door by brute strength, so you will have to use your wits.
|
38
|
+
|
39
|
+
You can leave the game at any time by typing 'exit'
|
@@ -0,0 +1,81 @@
|
|
1
|
+
{
|
2
|
+
"questions": [
|
3
|
+
{
|
4
|
+
"help_texts": [ "Are you ready to begin your adventure? Answer in Ruby.",
|
5
|
+
"In Ruby, we say things are correct, or 'truthy', when they are true.",
|
6
|
+
"We often use true to say yes, as well",
|
7
|
+
"Try telling Ruby that it is 'true' that you want to begin your adventure.",
|
8
|
+
"Try reading http://www.ruby-lang.org/en/documentation/quickstart/ to get started!"
|
9
|
+
],
|
10
|
+
"expected_response": "result == true"
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"title": "\nPart 1: Strings\n===============\n",
|
14
|
+
"help_texts": [ "Now give me the name Gandalf as a String.",
|
15
|
+
"Strings are typically wrapped in either single quotes or double quotes.",
|
16
|
+
"Try putting Gandalf's name in quotes."
|
17
|
+
],
|
18
|
+
"expected_response": "result == 'Gandalf'"
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"title": "\nPart 2: Variables\n=================\n",
|
22
|
+
"help_texts": [ "Let me know your name by assigning it to a variable called @name",
|
23
|
+
"Variables hold information. We use the equal sign to assign an object to a variable.",
|
24
|
+
"Here's how I would tell Ruby my name:\n @name = \"Matt\"",
|
25
|
+
"In this case, we want to assign the value of your name, as a String, to the variable @name.",
|
26
|
+
"I think you might like reading about variables:\n http://mislav.uniqpath.com/poignant-guide/book/chapter-3.html#section2"
|
27
|
+
],
|
28
|
+
"expected_response": "@name.class == String && @name.length > 0"
|
29
|
+
},
|
30
|
+
{
|
31
|
+
"title": "\nPart 3: Methods\n===============\n",
|
32
|
+
"help_texts": [ "Now send the String 'sevraq' to the translate method.",
|
33
|
+
"We say that we are sending a message to an object when we invoke a method.",
|
34
|
+
"In this case, the object we are sending the translate message to is the global object. But don't worry too much about that yet!",
|
35
|
+
"You can send a message to Ruby like this:\n method(parameters)",
|
36
|
+
"I think you would like this part of the book Programming Ruby:\n http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_methods.html"
|
37
|
+
],
|
38
|
+
"expected_response": "result == 'friend'",
|
39
|
+
"setup_code": "def translate(s); s.tr!('A-Za-z', 'N-ZA-Mn-za-m'); end",
|
40
|
+
"_comments": [ "So now we know that the strange word 'sevraq' is really the word 'friend' when we run it through the translator!"]
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"title": "\nPart 4: Objects\n===============\n",
|
44
|
+
"help_texts": [ "The great big door is before you.\n\nSend the message 'read' to the Door object to read what it says.",
|
45
|
+
"When we send a message to an object, we're invoking a method with that name on the object.",
|
46
|
+
"The Door class has a method called 'read'.",
|
47
|
+
"If I wanted to blow the Horn of Gondor, I might write in Ruby:\n HornOfGondor.blow!",
|
48
|
+
"If you've got time, you might want to watch this video to get a deep dive into what these object things are:\n\nhttp://confreaks.com/videos/1133-scrc2012-thinking-in-objects\n\n(it is roughly 26 minutes long)"
|
49
|
+
],
|
50
|
+
"expected_response": "result == 'fcrnx sevraq naq ragre'",
|
51
|
+
"setup_code": "load 'lib/gates_of_moria/data/door.rb'"
|
52
|
+
},
|
53
|
+
{
|
54
|
+
"title": "\nPart 5: Putting it all together\n===============================\n",
|
55
|
+
"help_texts": [ "So now we've got this weird text from the Door, and it appears to be the same strange language that we translated before.\n\nLet's use our translate method again on the String returned by reading the Door.",
|
56
|
+
"Remember how we sent the String 'sevraq' as a parameter to translate() before?\n\nWe can do the same thing with Door.read, because Door.read will return the strange text as a String and send it as a parameter to translate().",
|
57
|
+
"If I wanted to translate some text from the first page of a book, I might do this:\n\n translate(OldBook.first_page)"
|
58
|
+
],
|
59
|
+
"expected_response": "result = 'speak friend and enter'"
|
60
|
+
},
|
61
|
+
{
|
62
|
+
"title": "\nPart 6: Solving the Riddle\n==========================\n",
|
63
|
+
"help_texts": [ "Huh, the secret message on the door is the text 'speak friend and enter'\n\nNow that we know that the text on the door is a riddle, and we know how to speak in it's secret language, try sending the Door the message 'tell' with the parameter of the answer to the riddle.",
|
64
|
+
"Remember that we need to speak in the Door's language.\n\n You can use the translate() method to turn the word 'friend' back into its strange language.",
|
65
|
+
"The tell() method on the Door class tries to answer the riddle. Give it another try!",
|
66
|
+
"The Door expects the tell method to receive the string 'sevraq', which is its secret word for 'friend'!"
|
67
|
+
],
|
68
|
+
"expected_response": "result == 'The door opens!'",
|
69
|
+
"setup_code": ""
|
70
|
+
}
|
71
|
+
],
|
72
|
+
|
73
|
+
"question_template":
|
74
|
+
{
|
75
|
+
"title": "\nPart N: Foo\n===============\n",
|
76
|
+
"help_texts": [ ""
|
77
|
+
],
|
78
|
+
"expected_response": "",
|
79
|
+
"setup_code": ""
|
80
|
+
}
|
81
|
+
}
|
data/lib/gates_of_moria/quiz.rb
CHANGED
@@ -5,15 +5,22 @@ module GatesOfMoria
|
|
5
5
|
def initialize(output_buffer, input_buffer, motd = nil)
|
6
6
|
@output_buffer = output_buffer
|
7
7
|
@input_buffer = input_buffer
|
8
|
-
@motd = motd || File.read(File.expand_path("../motd.txt", __FILE__))
|
9
|
-
@questions = File.read(File.expand_path("../questions.json", __FILE__))
|
8
|
+
@motd = motd || File.read(File.expand_path("../data/motd.txt", __FILE__))
|
9
|
+
@questions = File.read(File.expand_path("../data/questions.json", __FILE__))
|
10
10
|
end
|
11
11
|
|
12
12
|
def start
|
13
13
|
@output_buffer.puts @motd
|
14
|
+
|
14
15
|
@repl = GatesOfMoria::REPL.new(@output_buffer, @input_buffer, @questions)
|
15
16
|
|
16
|
-
@repl.start
|
17
|
+
player_won = @repl.start
|
18
|
+
|
19
|
+
if player_won
|
20
|
+
@output_buffer.puts "Congratulations! You've opened the door to the mines.\n\nGood luck on your future adventures.\n\nMight I suggest trying RubyWarrior next?\n"
|
21
|
+
else
|
22
|
+
@output_buffer.puts "\n\nYour adventures with Ruby are not over yet!\n\nMay I suggest trying the game again, or going to read up on how Ruby works at:\n\n http://www.ruby-lang.org/en/documentation/quickstart/\n"
|
23
|
+
end
|
17
24
|
end
|
18
25
|
|
19
26
|
end
|
data/lib/gates_of_moria/repl.rb
CHANGED
@@ -5,28 +5,37 @@ module GatesOfMoria
|
|
5
5
|
@input_buffer = input_buffer
|
6
6
|
|
7
7
|
@questions = JSON.parse(questions)['questions']
|
8
|
+
@last_question = @questions.pop
|
8
9
|
end
|
9
10
|
|
10
11
|
def start
|
11
12
|
ask_the_questions
|
13
|
+
ask_last_question
|
12
14
|
end
|
13
15
|
|
14
16
|
def answer_question(expected_answer, user_input)
|
15
17
|
begin
|
16
18
|
result = eval(user_input)
|
19
|
+
rescue SystemExit
|
20
|
+
display_leaving_game
|
21
|
+
exit 0
|
17
22
|
rescue SyntaxError, Exception
|
18
23
|
politely_say_their_ruby_is_invalid
|
19
24
|
return false
|
20
25
|
end
|
21
|
-
@output_buffer.puts "\n=> #{result}\n"
|
26
|
+
@output_buffer.puts "\n=> #{result}\n\n"
|
22
27
|
eval(expected_answer)
|
23
28
|
end
|
24
29
|
|
25
30
|
private
|
31
|
+
|
32
|
+
def ask_last_question
|
33
|
+
return prompt_with_help_texts @last_question
|
34
|
+
end
|
35
|
+
|
26
36
|
def ask_the_questions
|
27
37
|
@questions.each do |question|
|
28
38
|
if prompt_with_help_texts question
|
29
|
-
display_you_are_correct
|
30
39
|
next
|
31
40
|
end
|
32
41
|
end
|
@@ -35,6 +44,7 @@ module GatesOfMoria
|
|
35
44
|
|
36
45
|
def prompt_with_help_texts question
|
37
46
|
eval(question['setup_code']) if question.has_key?('setup_code')
|
47
|
+
@output_buffer.puts(question['title']) if question.has_key?('title')
|
38
48
|
question['help_texts'].each do |ht|
|
39
49
|
prompt_question ht
|
40
50
|
|
@@ -61,8 +71,8 @@ module GatesOfMoria
|
|
61
71
|
@output_buffer.puts("Sorry, that's not it.")
|
62
72
|
end
|
63
73
|
|
64
|
-
def
|
65
|
-
@output_buffer.puts("
|
74
|
+
def display_leaving_game
|
75
|
+
@output_buffer.puts("\nYou are leaving the game. Play again soon!\n")
|
66
76
|
end
|
67
77
|
end
|
68
78
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
Feature: Answering Last Question Wrong
|
2
|
+
|
3
|
+
Scenario: User answers last question wrong
|
4
|
+
Given I am not playing
|
5
|
+
When I start a new quiz
|
6
|
+
And I answer all questions up to the last one
|
7
|
+
And I answer the last question incorrectly
|
8
|
+
Then I should see encouraging text to keep trying
|
@@ -1,20 +1,10 @@
|
|
1
|
-
Feature:
|
2
|
-
As a player
|
3
|
-
I want to start the quiz
|
4
|
-
So that I can proceed to Ruby Warrior
|
5
|
-
|
6
|
-
Scenario: start quiz
|
7
|
-
Given I am not playing
|
8
|
-
When I start a new quiz
|
9
|
-
Then I should see the Gates of Moria
|
10
|
-
And I should be prompted for the answer to the first question
|
1
|
+
Feature: Answering questions
|
11
2
|
|
12
3
|
Scenario: user answers first question correctly
|
13
4
|
Given I am not playing
|
14
5
|
When I start a new quiz
|
15
6
|
When I answer the first question correctly
|
16
7
|
Then I should not see the first help text
|
17
|
-
And I should see that I was correct
|
18
8
|
And I should be prompted for the answer to the second question
|
19
9
|
|
20
10
|
Scenario: user answers first question incorrectly
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Feature: Starting and Quitting
|
2
|
+
As a player
|
3
|
+
I want to start the quiz
|
4
|
+
So that I can proceed to Ruby Warrior
|
5
|
+
|
6
|
+
Scenario: starting and quitting the game
|
7
|
+
Given I am not playing
|
8
|
+
When I start a new quiz
|
9
|
+
Then I should see the Gates of Moria
|
10
|
+
And I should be prompted for the answer to the first question
|
11
|
+
|
12
|
+
When I quit
|
13
|
+
Then the game should end
|
@@ -1,46 +1,109 @@
|
|
1
|
-
step 'I am not playing' do
|
1
|
+
step 'I am not playing' do
|
2
2
|
end
|
3
3
|
|
4
|
-
step 'I start a new quiz' do
|
5
|
-
|
6
|
-
@
|
7
|
-
|
8
|
-
|
4
|
+
step 'I start a new quiz' do
|
5
|
+
@game = Greenletters::Process.new('bin/gates_of_moria')
|
6
|
+
@game.start!
|
7
|
+
end
|
8
|
+
|
9
|
+
step 'I quit' do
|
10
|
+
@game << prepare_input("exit")
|
11
|
+
end
|
9
12
|
|
10
|
-
|
11
|
-
@
|
13
|
+
step 'the game should end' do
|
14
|
+
@game.kill!
|
12
15
|
end
|
13
16
|
|
14
17
|
step 'I should see the Gates of Moria' do
|
15
|
-
|
18
|
+
expected_pattern = massage_pattern("DOORS OF DURIN")
|
19
|
+
@game.wait_for(:output, expected_pattern)
|
16
20
|
end
|
17
21
|
|
18
22
|
step 'I should be prompted for the answer to the first question' do
|
19
|
-
|
23
|
+
expected_pattern = massage_pattern "Are you ready to begin your adventure"
|
24
|
+
@game.wait_for(:output, expected_pattern)
|
20
25
|
end
|
21
26
|
|
22
27
|
step 'I should be prompted for the answer to the second question' do
|
23
|
-
|
28
|
+
expected_pattern = massage_pattern "Now give me the name Gandalf as a String"
|
29
|
+
@game.wait_for(:output, expected_pattern)
|
24
30
|
end
|
25
31
|
|
26
32
|
step 'I answer the first question correctly' do
|
27
33
|
step 'I should be prompted for the answer to the first question'
|
28
|
-
@
|
34
|
+
@game << prepare_input("true")
|
29
35
|
end
|
30
36
|
|
31
37
|
step 'I answer the first question incorrectly' do
|
32
38
|
step 'I should be prompted for the answer to the first question'
|
33
|
-
@
|
39
|
+
@game << prepare_input("moo")
|
34
40
|
end
|
35
41
|
|
36
42
|
step "I should see the first help text" do
|
37
|
-
|
43
|
+
expected_pattern = massage_pattern('In Ruby, we say things are')
|
44
|
+
@game.wait_for(:output, expected_pattern)
|
38
45
|
end
|
39
46
|
|
40
47
|
step "I should not see the first help text" do
|
41
|
-
|
48
|
+
pattern = massage_pattern('In Ruby, we say things are')
|
49
|
+
@game.check_until(pattern).should be_nil
|
50
|
+
end
|
51
|
+
|
52
|
+
step "I answer all the questions correctly" do
|
53
|
+
step "I answer all questions up to the last one"
|
54
|
+
|
55
|
+
# Part 6:
|
56
|
+
@game << prepare_input("Door.tell('sevraq')")
|
57
|
+
@game.wait_for(:output, massage_pattern('The door opens'))
|
58
|
+
end
|
59
|
+
|
60
|
+
step "I should see that I've won the game" do
|
61
|
+
@game.wait_for(:output, massage_pattern('Congratulations'))
|
62
|
+
end
|
63
|
+
|
64
|
+
step "I answer all questions up to the last one" do
|
65
|
+
step "I answer the first question correctly"
|
66
|
+
# Part 1:
|
67
|
+
@game << prepare_input('"Gandalf"')
|
68
|
+
@game.wait_for(:output, massage_pattern('Part 2'))
|
69
|
+
|
70
|
+
# Part 2:
|
71
|
+
@game << prepare_input("@name = 'Matt'")
|
72
|
+
@game.wait_for(:output, massage_pattern('Part 3'))
|
73
|
+
|
74
|
+
# Part 3:
|
75
|
+
@game << prepare_input("translate('sevraq')")
|
76
|
+
@game.wait_for(:output, massage_pattern('Part 4'))
|
77
|
+
|
78
|
+
# Part 4:
|
79
|
+
@game << prepare_input("Door.read")
|
80
|
+
@game.wait_for(:output, massage_pattern('Part 5'))
|
81
|
+
|
82
|
+
# Part 5:
|
83
|
+
@game << prepare_input("translate(Door.read)")
|
84
|
+
@game.wait_for(:output, massage_pattern('speak friend and enter'))
|
85
|
+
@game.wait_for(:output, massage_pattern('Part 6'))
|
86
|
+
end
|
87
|
+
|
88
|
+
step "I answer the last question incorrectly" do
|
89
|
+
# Part 6:
|
90
|
+
@game.wait_for(:output, massage_pattern('try sending the Door the message'))
|
91
|
+
@game << prepare_input("Door.tell('moo')")
|
92
|
+
@game.wait_for(:output, massage_pattern("=> The door remains firmly shut."))
|
93
|
+
|
94
|
+
#answer second help text wrong:
|
95
|
+
@game << prepare_input("Door.tell('moo')")
|
96
|
+
@game.wait_for(:output, massage_pattern("=> The door remains firmly shut."))
|
97
|
+
|
98
|
+
#answer third help text wrong:
|
99
|
+
@game << prepare_input("Door.tell('moo')")
|
100
|
+
@game.wait_for(:output, massage_pattern("=> The door remains firmly shut."))
|
101
|
+
|
102
|
+
#answer fourth help text wrong:
|
103
|
+
@game << prepare_input("Door.tell('moo')")
|
104
|
+
@game.wait_for(:output, massage_pattern("=> The door remains firmly shut."))
|
42
105
|
end
|
43
106
|
|
44
|
-
step "I should see
|
45
|
-
@output
|
107
|
+
step "I should see encouraging text to keep trying" do
|
108
|
+
@game.wait_for(:output, massage_pattern('Your adventures with Ruby are not over yet'))
|
46
109
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Feature: Winning the game
|
2
|
+
In order to continue on to Ruby Warrior
|
3
|
+
As a player
|
4
|
+
I want to be told that I've won the game
|
5
|
+
|
6
|
+
Scenario: winning the game
|
7
|
+
Given I am not playing
|
8
|
+
When I start a new quiz
|
9
|
+
And I answer all the questions correctly
|
10
|
+
Then I should see that I've won the game
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gates_of_moria
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-01-
|
13
|
+
date: 2013-01-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -60,6 +60,22 @@ dependencies:
|
|
60
60
|
- - ! '>='
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: greenletters
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
63
79
|
description: A simple quiz to test Ruby knowledge
|
64
80
|
email:
|
65
81
|
- matt@bendyworks.com
|
@@ -78,17 +94,23 @@ files:
|
|
78
94
|
- bin/gates_of_moria
|
79
95
|
- gates_of_moria.gemspec
|
80
96
|
- lib/gates_of_moria.rb
|
81
|
-
- lib/gates_of_moria/
|
82
|
-
- lib/gates_of_moria/
|
97
|
+
- lib/gates_of_moria/data/door.rb
|
98
|
+
- lib/gates_of_moria/data/motd.txt
|
99
|
+
- lib/gates_of_moria/data/questions.json
|
83
100
|
- lib/gates_of_moria/quiz.rb
|
84
101
|
- lib/gates_of_moria/repl.rb
|
85
102
|
- lib/gates_of_moria/version.rb
|
86
|
-
- spec/acceptance/
|
103
|
+
- spec/acceptance/answering_last_question_wrong.feature
|
104
|
+
- spec/acceptance/answering_questions.feature
|
105
|
+
- spec/acceptance/starting_and_quitting.feature
|
87
106
|
- spec/acceptance/steps/player_steps.rb
|
107
|
+
- spec/acceptance/winning_the_game.feature
|
88
108
|
- spec/fixtures/one_question.json
|
89
109
|
- spec/gates_of_moria/quiz_spec.rb
|
90
110
|
- spec/gates_of_moria/repl_spec.rb
|
91
111
|
- spec/spec_helper.rb
|
112
|
+
- spec/support/ending_processes.rb
|
113
|
+
- spec/support/greenletters.rb
|
92
114
|
homepage: https://github.com/mathias/gates_of_moria
|
93
115
|
licenses: []
|
94
116
|
post_install_message:
|
@@ -114,9 +136,14 @@ signing_key:
|
|
114
136
|
specification_version: 3
|
115
137
|
summary: A simple quiz to test Ruby knowledge
|
116
138
|
test_files:
|
117
|
-
- spec/acceptance/
|
139
|
+
- spec/acceptance/answering_last_question_wrong.feature
|
140
|
+
- spec/acceptance/answering_questions.feature
|
141
|
+
- spec/acceptance/starting_and_quitting.feature
|
118
142
|
- spec/acceptance/steps/player_steps.rb
|
143
|
+
- spec/acceptance/winning_the_game.feature
|
119
144
|
- spec/fixtures/one_question.json
|
120
145
|
- spec/gates_of_moria/quiz_spec.rb
|
121
146
|
- spec/gates_of_moria/repl_spec.rb
|
122
147
|
- spec/spec_helper.rb
|
148
|
+
- spec/support/ending_processes.rb
|
149
|
+
- spec/support/greenletters.rb
|
@@ -1,13 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"questions": [
|
3
|
-
{
|
4
|
-
"initial_prompt": "Let me know your name by assigning it to a variable called '@name'!",
|
5
|
-
"expected_response": "@name.class == String && @name.length > 0",
|
6
|
-
"help_texts": [ "Let me know your name by assigning it to a variable called '@name'!", "Variables hold information. We use the equal sign to assign information into a variable:\n@name = \"Matt\"", "bar", "baz" ]
|
7
|
-
}, {
|
8
|
-
"expected_response": "result == 'friend'",
|
9
|
-
"help_texts": ["Now send the string 'sevraq' to the translate method."],
|
10
|
-
"setup_code": "def translate(s); s.tr!('A-Za-z', 'N-ZA-Mn-za-m'); end"
|
11
|
-
}
|
12
|
-
]
|
13
|
-
}
|