gamefic 1.6.0 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +16 -0
  5. data/.solargraph.yml +5 -0
  6. data/CHANGELOG.md +6 -0
  7. data/Gemfile +7 -0
  8. data/LICENSE +20 -0
  9. data/README.md +28 -0
  10. data/Rakefile +10 -0
  11. data/gamefic.gemspec +27 -0
  12. data/lib/gamefic.rb +11 -8
  13. data/lib/gamefic/action.rb +68 -58
  14. data/lib/gamefic/active.rb +331 -0
  15. data/lib/gamefic/actor.rb +8 -0
  16. data/lib/gamefic/command.rb +9 -7
  17. data/lib/gamefic/core_ext/array.rb +27 -49
  18. data/lib/gamefic/core_ext/string.rb +25 -16
  19. data/lib/gamefic/describable.rb +37 -22
  20. data/lib/gamefic/element.rb +47 -0
  21. data/lib/gamefic/entity.rb +24 -48
  22. data/lib/gamefic/{matchable.rb → keywords.rb} +52 -50
  23. data/lib/gamefic/messaging.rb +43 -45
  24. data/lib/gamefic/node.rb +14 -5
  25. data/lib/gamefic/plot.rb +73 -85
  26. data/lib/gamefic/plot/darkroom.rb +80 -0
  27. data/lib/gamefic/plot/host.rb +42 -46
  28. data/lib/gamefic/plot/snapshot.rb +14 -214
  29. data/lib/gamefic/query.rb +15 -17
  30. data/lib/gamefic/query/base.rb +51 -42
  31. data/lib/gamefic/query/children.rb +0 -0
  32. data/lib/gamefic/query/descendants.rb +2 -2
  33. data/lib/gamefic/query/external.rb +18 -0
  34. data/lib/gamefic/query/family.rb +3 -7
  35. data/lib/gamefic/query/matches.rb +75 -67
  36. data/lib/gamefic/query/parent.rb +0 -0
  37. data/lib/gamefic/query/siblings.rb +0 -0
  38. data/lib/gamefic/query/text.rb +12 -12
  39. data/lib/gamefic/query/tree.rb +17 -0
  40. data/lib/gamefic/scene.rb +1 -5
  41. data/lib/gamefic/scene/{active.rb → activity.rb} +4 -6
  42. data/lib/gamefic/scene/base.rb +77 -13
  43. data/lib/gamefic/scene/conclusion.rb +0 -2
  44. data/lib/gamefic/scene/custom.rb +0 -2
  45. data/lib/gamefic/scene/multiple_choice.rb +18 -16
  46. data/lib/gamefic/scene/multiple_scene.rb +29 -20
  47. data/lib/gamefic/scene/pause.rb +7 -2
  48. data/lib/gamefic/scene/yes_or_no.rb +21 -9
  49. data/lib/gamefic/scriptable.rb +88 -0
  50. data/lib/gamefic/serialize.rb +223 -0
  51. data/lib/gamefic/subplot.rb +47 -51
  52. data/lib/gamefic/syntax.rb +15 -13
  53. data/lib/gamefic/version.rb +3 -3
  54. data/lib/gamefic/world.rb +18 -0
  55. data/lib/gamefic/world/callbacks.rb +135 -0
  56. data/lib/gamefic/world/commands.rb +184 -0
  57. data/lib/gamefic/world/entities.rb +98 -0
  58. data/lib/gamefic/{plot → world}/playbook.rb +245 -236
  59. data/lib/gamefic/world/players.rb +37 -0
  60. data/lib/gamefic/world/scenes.rb +226 -0
  61. metadata +40 -108
  62. data/bin/gamefic +0 -9
  63. data/lib/gamefic/character.rb +0 -232
  64. data/lib/gamefic/character/state.rb +0 -12
  65. data/lib/gamefic/engine.rb +0 -7
  66. data/lib/gamefic/engine/base.rb +0 -66
  67. data/lib/gamefic/engine/tty.rb +0 -24
  68. data/lib/gamefic/grammar.rb +0 -13
  69. data/lib/gamefic/grammar/conjugator.rb +0 -20
  70. data/lib/gamefic/grammar/gender.rb +0 -11
  71. data/lib/gamefic/grammar/person.rb +0 -10
  72. data/lib/gamefic/grammar/plural.rb +0 -13
  73. data/lib/gamefic/grammar/pronouns.rb +0 -105
  74. data/lib/gamefic/grammar/tense.rb +0 -6
  75. data/lib/gamefic/grammar/verb_set.rb +0 -43
  76. data/lib/gamefic/grammar/verbs.rb +0 -26
  77. data/lib/gamefic/grammar/word_adapter.rb +0 -49
  78. data/lib/gamefic/plot/articles.rb +0 -22
  79. data/lib/gamefic/plot/callbacks.rb +0 -127
  80. data/lib/gamefic/plot/commands.rb +0 -121
  81. data/lib/gamefic/plot/entities.rb +0 -88
  82. data/lib/gamefic/plot/players.rb +0 -15
  83. data/lib/gamefic/plot/scenes.rb +0 -149
  84. data/lib/gamefic/plot/theater.rb +0 -73
  85. data/lib/gamefic/plot/you_mount.rb +0 -22
  86. data/lib/gamefic/script.rb +0 -13
  87. data/lib/gamefic/script/base.rb +0 -42
  88. data/lib/gamefic/script/file.rb +0 -14
  89. data/lib/gamefic/script/text.rb +0 -14
  90. data/lib/gamefic/shell.rb +0 -76
  91. data/lib/gamefic/source.rb +0 -14
  92. data/lib/gamefic/source/base.rb +0 -12
  93. data/lib/gamefic/source/file.rb +0 -23
  94. data/lib/gamefic/source/text.rb +0 -16
  95. data/lib/gamefic/tester.rb +0 -19
  96. data/lib/gamefic/text.rb +0 -8
  97. data/lib/gamefic/text/ansi.rb +0 -53
  98. data/lib/gamefic/text/html.rb +0 -68
  99. data/lib/gamefic/text/html/conversions.rb +0 -250
  100. data/lib/gamefic/text/html/entities.rb +0 -9
  101. data/lib/gamefic/tty.rb +0 -10
  102. data/lib/gamefic/user.rb +0 -8
  103. data/lib/gamefic/user/base.rb +0 -15
  104. data/lib/gamefic/user/buffer.rb +0 -32
  105. data/lib/gamefic/user/tty.rb +0 -54
@@ -1,23 +0,0 @@
1
- module Gamefic
2
-
3
- class Source::File < Source::Base
4
- @@extensions = ['.plot.rb', '.plot', '.rb']
5
- attr_reader :directories
6
- attr_accessor :main_dir
7
- def initialize(*directories)
8
- @directories = directories || []
9
- end
10
- def export path
11
- @directories.each { |directory|
12
- @@extensions.each { |ext|
13
- abs_file = File.join(directory, path + ext)
14
- if File.file?(abs_file)
15
- return Script::File.new(abs_file, path)
16
- end
17
- }
18
- }
19
- raise LoadError.new("cannot load script -- #{path}")
20
- end
21
- end
22
-
23
- end
@@ -1,16 +0,0 @@
1
- module Gamefic
2
-
3
- class Source::Text < Source::Base
4
- def initialize scripts = {}
5
- @scripts = scripts
6
- end
7
- def export path
8
- if @scripts.has_key?(path)
9
- Script::Text.new(path, @scripts[path])
10
- else
11
- raise "Script #{path} not found"
12
- end
13
- end
14
- end
15
-
16
- end
@@ -1,19 +0,0 @@
1
- module Gamefic
2
-
3
- module Tester
4
- def test_procs
5
- @test_procs ||= Hash.new
6
- end
7
- def on_test name = :me, &block
8
- test_procs[name] = block
9
- end
10
- def run_test name, actor
11
- queue = []
12
- stage actor, queue, &test_procs[name]
13
- actor.queue.push *queue
14
- actor[:test_queue_length] = queue.length
15
- actor[:test_queue_scene] = actor.scene
16
- end
17
- end
18
-
19
- end
@@ -1,8 +0,0 @@
1
- module Gamefic
2
-
3
- module Text
4
- autoload :Ansi, 'gamefic/text/ansi'
5
- autoload :Html, 'gamefic/text/html'
6
- end
7
-
8
- end
@@ -1,53 +0,0 @@
1
- module Gamefic
2
-
3
- # Constants for ANSI codes, plus ExtraCodes for custom formatting.
4
- module Text::Ansi
5
- module Code
6
- module Attribute
7
- NORMAL = 0
8
- BOLD = 1
9
- UNDERSCORE = 4
10
- BLINK = 5
11
- REVERSE = 7
12
- CONCEALED = 8
13
- end
14
- module Foreground
15
- BLACK = 30
16
- RED = 31
17
- GREEN = 32
18
- YELLOW = 33
19
- BLUE = 34
20
- MAGENTA = 35
21
- CYAN = 36
22
- WHITE = 37
23
- end
24
- module Background
25
- BLACK = 40
26
- RED = 41
27
- GREEN = 42
28
- YELLOW = 43
29
- BLUE = 44
30
- MAGENTA = 45
31
- CYAN = 46
32
- WHITE = 47
33
- end
34
- module Extra
35
- BLOCK = :block
36
- PRE = :pre
37
- HREF = :href
38
- IMAGE = :image
39
- SRC = :src
40
- UPPERCASE = :uppercase
41
- COMMAND = :command
42
- IGNORED = :ignored
43
- LINE = :line
44
- end
45
- end
46
- def self.graphics_mode(*settings)
47
- ansi = settings.flatten.that_are(Fixnum)
48
- return '' if ansi.length == 0
49
- "\e[#{ansi.join(';')}m"
50
- end
51
- end
52
-
53
- end
@@ -1,68 +0,0 @@
1
- require 'rexml/document'
2
- require 'gamefic/text/html/entities'
3
-
4
- module Gamefic
5
- module Text
6
- module Html
7
- autoload :Conversions, 'gamefic/text/html/conversions'
8
-
9
- # Convert ampersands to &amp;
10
- #
11
- # @param text [String]
12
- # @return [String]
13
- def self.fix_ampersands(text)
14
- codes = []
15
- ENTITIES.keys.each { |e|
16
- codes.push e[1..-1]
17
- }
18
- piped = codes.join('|')
19
- re = Regexp.new("&(?!(#{piped}))")
20
- text.gsub(re, '&amp;\1')
21
- end
22
-
23
- # Encode a String with HTML entities
24
- #
25
- # @param text [String]
26
- # @return [String]
27
- def self.encode(text)
28
- encoded = text
29
- ENTITIES.each { |k, v|
30
- encoded = encoded.gsub(v, k)
31
- }
32
- encoded
33
- end
34
-
35
- # Decode a String's HTML entities
36
- #
37
- # @param text [String]
38
- # @return [String]
39
- def self.decode(text)
40
- ENTITIES.each { |k, v|
41
- text = text.gsub(k, v)
42
- }
43
- text
44
- end
45
-
46
- # Parse a String into an XML document
47
- #
48
- # @param code [String]
49
- # @return [REXML::Document]
50
- def self.parse(code)
51
- code = fix_ampersands(code).strip
52
- last = nil
53
- begin
54
- doc = REXML::Document.new code
55
- rescue REXML::ParseException => e
56
- # Convert invalid < characters to &lt;
57
- if e.source.buffer != last and e.source.buffer[0,1] == '<'
58
- code = code[0,(code.length - e.source.buffer.length)] + '&lt;' + e.source.buffer[1..-1]
59
- last = e.source.buffer
60
- retry
61
- end
62
- raise e
63
- end
64
- end
65
- end
66
- end
67
-
68
- end
@@ -1,250 +0,0 @@
1
- require 'gamefic/text/ansi'
2
- require 'gamefic/text/html'
3
- require 'io/console'
4
-
5
- module Gamefic
6
-
7
- module Text::Html::Conversions
8
- include Gamefic::Text
9
-
10
- def self.html_to_ansi text, wrap: true, width: nil
11
- return '' if text.strip == ''
12
- output = ''
13
- begin
14
- doc = Html.parse("<body>#{text.gsub(/\r/, '').strip}</body>")
15
- output = AnsiFormatter.new.format(doc) + Ansi.graphics_mode(Ansi::Code::Attribute::NORMAL)
16
- output = Html.decode(output)
17
- rescue REXML::ParseException => e
18
- output = text.strip
19
- end
20
- calc_width = width || size[0]
21
- if calc_width.nil? or !wrap
22
- output
23
- else
24
- terminalize(output, calc_width - 1)
25
- end
26
- end
27
-
28
- def self.html_to_text text, wrap: true, width: nil
29
- text = html_to_ansi text, wrap: wrap, width: width
30
- text.gsub(/\e\[([;\d]+)?m/, '').gsub(/\n +\n/, "\n\n")
31
- end
32
-
33
- class AnsiNode
34
- include Gamefic::Text::Ansi::Code
35
- attr_accessor :parent
36
-
37
- def render
38
- end
39
-
40
- def in_block?
41
- p = parent
42
- while !p.nil?
43
- return true if p.kind_of?(BlockNode)
44
- p = p.parent
45
- end
46
- false
47
- end
48
- end
49
- private_constant :AnsiNode
50
-
51
- class TextNode < AnsiNode
52
- @@prev_format = nil
53
- attr_reader :text, :format
54
- def initialize text, format
55
- @text = text
56
- @format = format
57
- end
58
- def render
59
- return @text if format.include?(Extra::PRE)
60
- index = parent.children.index(self)
61
- if index > 0
62
- prev = parent.children[index - 1]
63
- if prev.kind_of?(TextNode) and prev.format == format
64
- if prev.text.match(/ $/)
65
- return @text.lstrip
66
- else
67
- return @text
68
- end
69
- end
70
- end
71
- if @@prev_format == format
72
- @text
73
- else
74
- @prev_format = format
75
- Gamefic::Text::Ansi.graphics_mode(*format) + @text
76
- end
77
- end
78
- end
79
- private_constant :TextNode
80
-
81
- class ElementNode < AnsiNode
82
- def children
83
- @children ||= []
84
- end
85
- def append child
86
- children.push child
87
- child.parent = self
88
- end
89
- end
90
- private_constant :ElementNode
91
-
92
- class BlockNode < ElementNode
93
- def render
94
- output = ''
95
- children.each { |c|
96
- output += c.render
97
- }
98
- output = "\n" + output.strip unless in_block?
99
- output
100
- end
101
- end
102
- private_constant :BlockNode
103
-
104
- class InlineNode < ElementNode
105
- def render
106
- output = ''
107
- children.each { |c|
108
- output += c.render
109
- output += "\n" if c.kind_of?(BlockNode)
110
- }
111
- output
112
- end
113
- end
114
- private_constant :InlineNode
115
-
116
- class BreakNode < ElementNode
117
- def render
118
- output = ''
119
- children.each { |c|
120
- output += c.render
121
- }
122
- output + "\n"
123
- end
124
- end
125
- private_constant :BreakNode
126
-
127
- class AnsiFormatter
128
- include Gamefic::Text::Ansi::Code
129
- def format document
130
- @document = document
131
- @ansi_root = InlineNode.new
132
- @list_index = []
133
- format_recursively @document.root, @ansi_root, [Attribute::NORMAL]
134
- output = @ansi_root.render
135
- output += (@ansi_root.children.last.kind_of?(BlockNode) ? "\n" : "")
136
- end
137
-
138
- def format_recursively element, ansi_node, stack
139
- if element.is_a?(REXML::Text)
140
- append_text element, ansi_node, stack
141
- else
142
- current = []
143
- case element.name
144
- when 'b', 'strong', 'em'
145
- current.push Attribute::BOLD
146
- format_children element, ansi_node, stack + current
147
- when 'i', 'u'
148
- current.push Attribute::UNDERSCORE
149
- format_children element, ansi_node, stack + current
150
- when 'h1', 'h2', 'h3', 'h4', 'h5'
151
- current.push Attribute::BOLD, Extra::UPPERCASE
152
- format_paragraph element, ansi_node, stack + current
153
- when 'p'
154
- format_paragraph element, ansi_node, stack
155
- when 'ol', 'ul'
156
- @list_index.push 0
157
- format_paragraph element, ansi_node, stack
158
- @list_index.pop
159
- when 'li'
160
- format_list_item element, ansi_node, stack
161
- when 'pre'
162
- current.push Extra::PRE
163
- format_children element, ansi_node, stack + current
164
- when 'br'
165
- ansi_node.append TextNode.new("\n", stack + [Extra::PRE])
166
- else
167
- format_children element, ansi_node, stack
168
- end
169
- end
170
- end
171
-
172
- def append_text element, ansi_node, stack
173
- text = element.to_s
174
- text.gsub!(/[\s]+/, ' ') unless stack.include?(Extra::PRE)
175
- text.upcase! if stack.include?(Extra::UPPERCASE)
176
- ansi_node.append TextNode.new(text, stack)
177
- end
178
-
179
- def format_children element, node, stack
180
- element.each { |e|
181
- format_recursively e, node, stack
182
- }
183
- end
184
-
185
- def format_paragraph element, node, stack
186
- paragraph = BlockNode.new
187
- node.append paragraph
188
- format_children element, paragraph, stack
189
- end
190
-
191
- def format_list_item element, node, stack
192
- i = 0
193
- unless @list_index.empty?
194
- @list_index[-1] = @list_index[-1] + 1
195
- i = @list_index[-1]
196
- end
197
- b = BreakNode.new
198
- node.append b
199
- if element.parent.name == 'ol'
200
- b.append TextNode.new("#{i}. ", stack)
201
- else
202
- b.append TextNode.new("* ", stack)
203
- end
204
- format_children element, b, stack
205
- end
206
- end
207
- private_constant :AnsiFormatter
208
-
209
- def self.terminalize string, max_length
210
- i = 0
211
- output = ''
212
- line_length = 0
213
- while i < string.length
214
- line_length += 1
215
- char = string[i,1]
216
- if char == "\e"
217
- # Right now, graphics modes are the only supported ANSI sequences.
218
- end_of_seq = string.index("m", i)
219
- output += string[i..end_of_seq]
220
- i = end_of_seq + 1
221
- elsif char == " "
222
- next_space = string.index(/[\s]/, i + 1)
223
- if !next_space.nil? and line_length + (next_space - i) > max_length
224
- output += "\n"
225
- line_length = 0
226
- else
227
- output += char
228
- end
229
- i += 1
230
- else
231
- if char == "\n"
232
- line_length = 0
233
- end
234
- output += char
235
- i += 1
236
- end
237
- end
238
- output
239
- end
240
-
241
- def self.size
242
- begin
243
- return STDOUT.winsize.reverse
244
- rescue
245
- return [nil,nil]
246
- end
247
- end
248
- end
249
-
250
- end
@@ -1,9 +0,0 @@
1
- module Gamefic
2
-
3
- module Text
4
- module Html
5
- ENTITIES = { "&quot;" => "\"", "&amp;" => "&", "&lt;" => "<", "&gt;" => ">", "&nbsp;" => " ", "&iexcl;" => "¡", "&cent;" => "¢", "&pound;" => "£", "&curren;" => "¤", "&yen;" => "¥", "&brvbar;" => "¦", "&sect;" => "§", "&uml;" => "¨", "&copy;" => "©", "&ordf;" => "ª", "&laquo;" => "«", "&not;" => "¬", "&shy;" => "­", "&reg;" => "®", "&macr;" => "¯", "&deg;" => "°", "&plusmn;" => "±", "&sup2;" => "²", "&sup3;" => "³", "&acute;" => "´", "&micro;" => "µ", "&para;" => "¶", "&middot;" => "·", "&cedil;" => "¸", "&sup1;" => "¹", "&ordm;" => "º", "&raquo;" => "»", "&frac14;" => "¼", "&frac12;" => "½", "&frac34;" => "¾", "&iquest;" => "¿", "&Agrave;" => "À", "&Aacute;" => "Á", "&Acirc;" => "Â", "&Atilde;" => "Ã", "&Auml;" => "Ä", "&Aring;" => "Å", "&AElig;" => "Æ", "&Ccedil;" => "Ç", "&Egrave;" => "È", "&Eacute;" => "É", "&Ecirc;" => "Ê", "&Euml;" => "Ë", "&Igrave;" => "Ì", "&Iacute;" => "Í", "&Icirc;" => "Î", "&Iuml;" => "Ï", "&ETH;" => "Ð", "&Ntilde;" => "Ñ", "&Ograve;" => "Ò", "&Oacute;" => "Ó", "&Ocirc;" => "Ô", "&Otilde;" => "Õ", "&Ouml;" => "Ö", "&times;" => "×", "&Oslash;" => "Ø", "&Ugrave;" => "Ù", "&Uacute;" => "Ú", "&Ucirc;" => "Û", "&Uuml;" => "Ü", "&Yacute;" => "Ý", "&THORN;" => "Þ", "&szlig;" => "ß", "&agrave;" => "à", "&aacute;" => "á", "&acirc;" => "â", "&atilde;" => "ã", "&auml;" => "ä", "&aring;" => "å", "&aelig;" => "æ", "&ccedil;" => "ç", "&egrave;" => "è", "&eacute;" => "é", "&ecirc;" => "ê", "&euml;" => "ë", "&igrave;" => "ì", "&iacute;" => "í", "&icirc;" => "î", "&iuml;" => "ï", "&eth;" => "ð", "&ntilde;" => "ñ", "&ograve;" => "ò", "&oacute;" => "ó", "&ocirc;" => "ô", "&otilde;" => "õ", "&ouml;" => "ö", "&divide;" => "÷", "&oslash;" => "ø", "&ugrave;" => "ù", "&uacute;" => "ú", "&ucirc;" => "û", "&uuml;" => "ü", "&yacute;" => "ý", "&thorn;" => "þ", "&yuml;" => "ÿ", "&OElig;" => "Œ", "&oelig;" => "œ", "&Scaron;" => "Š", "&scaron;" => "š", "&Yuml;" => "Ÿ", "&fnof;" => "ƒ", "&circ;" => "ˆ", "&tilde;" => "˜", "&Alpha;" => "Α", "&Beta;" => "Β", "&Gamma;" => "Γ", "&Delta;" => "Δ", "&Epsilon;" => "Ε", "&Zeta;" => "Ζ", "&Eta;" => "Η", "&Theta;" => "Θ", "&Iota;" => "Ι", "&Kappa;" => "Κ", "&Lambda;" => "Λ", "&Mu;" => "Μ", "&Nu;" => "Ν", "&Xi;" => "Ξ", "&Omicron;" => "Ο", "&Pi;" => "Π", "&Rho;" => "Ρ", "&Sigma;" => "Σ", "&Tau;" => "Τ", "&Upsilon;" => "Υ", "&Phi;" => "Φ", "&Chi;" => "Χ", "&Psi;" => "Ψ", "&Omega;" => "Ω", "&alpha;" => "α", "&beta;" => "β", "&gamma;" => "γ", "&delta;" => "δ", "&epsilon;" => "ε", "&zeta;" => "ζ", "&eta;" => "η", "&theta;" => "θ", "&iota;" => "ι", "&kappa;" => "κ", "&lambda;" => "λ", "&mu;" => "μ", "&nu;" => "ν", "&xi;" => "ξ", "&omicron;" => "ο", "&pi;" => "π", "&rho;" => "ρ", "&sigmaf;" => "ς", "&sigma;" => "σ", "&tau;" => "τ", "&upsilon;" => "υ", "&phi;" => "φ", "&chi;" => "χ", "&psi;" => "ψ", "&omega;" => "ω", "&thetasym;" => "ϑ", "&upsih;" => "ϒ", "&piv;" => "ϖ", "&ensp;" => " ", "&emsp;" => " ", "&thinsp;" => " ", "&zwnj;" => "‌", "&zwj;" => "‍", "&lrm;" => "‎", "&rlm;" => "‏", "&ndash;" => "–", "&mdash;" => "—", "&lsquo;" => "‘", "&rsquo;" => "’", "&sbquo;" => "‚", "&ldquo;" => "“", "&rdquo;" => "”", "&bdquo;" => "„", "&dagger;" => "†", "&Dagger;" => "‡", "&bull;" => "•", "&hellip;" => "…", "&permil;" => "‰", "&prime;" => "′", "&Prime;" => "″", "&lsaquo;" => "‹", "&rsaquo;" => "›", "&oline;" => "‾", "&frasl;" => "⁄", "&euro;" => "€", "&image;" => "ℑ", "&weierp;" => "℘", "&real;" => "ℜ", "&trade;" => "™", "&alefsym;" => "ℵ", "&larr;" => "←", "&uarr;" => "↑", "&rarr;" => "→", "&darr;" => "↓", "&harr;" => "↔", "&crarr;" => "↵", "&lArr;" => "⇐", "&uArr;" => "⇑", "&rArr;" => "⇒", "&dArr;" => "⇓", "&hArr;" => "⇔", "&forall;" => "∀", "&part;" => "∂", "&exist;" => "∃", "&empty;" => "∅", "&nabla;" => "∇", "&isin;" => "∈", "&notin;" => "∉", "&ni;" => "∋", "&prod;" => "∏", "&sum;" => "∑", "&minus;" => "−", "&lowast;" => "∗", "&radic;" => "√", "&prop;" => "∝", "&infin;" => "∞", "&ang;" => "∠", "&and;" => "∧", "&or;" => "∨", "&cap;" => "∩", "&cup;" => "∪", "&int;" => "∫", "&there4;" => "∴", "&sim;" => "∼", "&cong;" => "≅", "&asymp;" => "≈", "&ne;" => "≠", "&equiv;" => "≡", "&le;" => "≤", "&ge;" => "≥", "&sub;" => "⊂", "&sup;" => "⊃", "&nsub;" => "⊄", "&sube;" => "⊆", "&supe;" => "⊇", "&oplus;" => "⊕", "&otimes;" => "⊗", "&perp;" => "⊥", "&sdot;" => "⋅", "&lceil;" => "⌈", "&rceil;" => "⌉", "&lfloor;" => "⌊", "&rfloor;" => "⌋", "&lang;" => "〈", "&rang;" => "〉", "&loz;" => "◊", "&spades;" => "♠", "&clubs;" => "♣", "&hearts;" => "♥", "&diams;" => "♦" }
6
- end
7
- end
8
-
9
- end