instiki 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/CHANGELOG +174 -165
  2. data/README +68 -68
  3. data/app/controllers/admin_controller.rb +94 -94
  4. data/app/controllers/application.rb +135 -131
  5. data/app/controllers/file_controller.rb +129 -129
  6. data/app/controllers/wiki_controller.rb +354 -354
  7. data/app/helpers/application_helper.rb +68 -68
  8. data/app/models/author.rb +3 -3
  9. data/app/models/chunks/category.rb +33 -33
  10. data/app/models/chunks/chunk.rb +86 -86
  11. data/app/models/chunks/engines.rb +61 -54
  12. data/app/models/chunks/include.rb +41 -41
  13. data/app/models/chunks/literal.rb +31 -31
  14. data/app/models/chunks/nowiki.rb +28 -28
  15. data/app/models/chunks/test.rb +18 -18
  16. data/app/models/chunks/uri.rb +182 -182
  17. data/app/models/chunks/wiki.rb +141 -141
  18. data/app/models/file_yard.rb +58 -58
  19. data/app/models/page.rb +112 -112
  20. data/app/models/page_lock.rb +22 -22
  21. data/app/models/page_set.rb +89 -89
  22. data/app/models/revision.rb +123 -123
  23. data/app/models/web.rb +182 -176
  24. data/app/models/wiki_content.rb +207 -207
  25. data/app/models/wiki_service.rb +233 -233
  26. data/app/models/wiki_words.rb +23 -23
  27. data/app/views/admin/create_system.rhtml +83 -83
  28. data/app/views/admin/create_web.rhtml +69 -69
  29. data/app/views/admin/edit_web.rhtml +137 -136
  30. data/app/views/file/file.rhtml +18 -18
  31. data/app/views/file/import.rhtml +22 -22
  32. data/app/views/layouts/default.rhtml +86 -85
  33. data/app/views/markdown_help.rhtml +12 -12
  34. data/app/views/mixed_help.rhtml +6 -6
  35. data/app/views/navigation.rhtml +30 -30
  36. data/app/views/rdoc_help.rhtml +12 -12
  37. data/app/views/textile_help.rhtml +24 -24
  38. data/app/views/wiki/authors.rhtml +11 -11
  39. data/app/views/wiki/edit.rhtml +39 -39
  40. data/app/views/wiki/export.rhtml +12 -12
  41. data/app/views/wiki/feeds.rhtml +14 -14
  42. data/app/views/wiki/list.rhtml +64 -64
  43. data/app/views/wiki/locked.rhtml +23 -23
  44. data/app/views/wiki/login.rhtml +14 -14
  45. data/app/views/wiki/new.rhtml +31 -31
  46. data/app/views/wiki/page.rhtml +115 -115
  47. data/app/views/wiki/print.rhtml +14 -14
  48. data/app/views/wiki/published.rhtml +9 -9
  49. data/app/views/wiki/recently_revised.rhtml +26 -26
  50. data/app/views/wiki/revision.rhtml +103 -103
  51. data/app/views/wiki/rollback.rhtml +36 -36
  52. data/app/views/wiki/rss_feed.rhtml +22 -22
  53. data/app/views/wiki/search.rhtml +38 -38
  54. data/app/views/wiki/tex.rhtml +22 -22
  55. data/app/views/wiki/tex_web.rhtml +34 -34
  56. data/app/views/wiki/web_list.rhtml +18 -18
  57. data/app/views/wiki_words_help.rhtml +9 -9
  58. data/config/environment.rb +82 -82
  59. data/config/environments/development.rb +5 -5
  60. data/config/environments/production.rb +4 -4
  61. data/config/environments/test.rb +17 -17
  62. data/config/routes.rb +18 -18
  63. data/lib/active_record_stub.rb +31 -31
  64. data/lib/bluecloth_tweaked.rb +1127 -0
  65. data/lib/diff.rb +444 -444
  66. data/lib/instiki_errors.rb +14 -14
  67. data/lib/rdocsupport.rb +151 -151
  68. data/lib/redcloth_for_tex.rb +736 -736
  69. data/natives/osx/desktop_launcher/AppDelegate.h +18 -18
  70. data/natives/osx/desktop_launcher/AppDelegate.mm +109 -109
  71. data/natives/osx/desktop_launcher/Credits.html +15 -15
  72. data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/classes.nib +12 -12
  73. data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/info.nib +24 -24
  74. data/natives/osx/desktop_launcher/Info.plist +12 -12
  75. data/natives/osx/desktop_launcher/Instiki.xcode/project.pbxproj +592 -592
  76. data/natives/osx/desktop_launcher/Instiki_Prefix.pch +7 -7
  77. data/natives/osx/desktop_launcher/MakeDMG.sh +9 -9
  78. data/natives/osx/desktop_launcher/main.mm +14 -14
  79. data/natives/osx/desktop_launcher/version.plist +16 -16
  80. data/public/404.html +5 -5
  81. data/public/500.html +5 -5
  82. data/public/dispatch.rb +9 -9
  83. data/public/javascripts/edit_web.js +52 -52
  84. data/public/javascripts/prototype.js +336 -336
  85. data/public/stylesheets/instiki.css +222 -222
  86. data/script/breakpointer +4 -4
  87. data/script/server +93 -93
  88. metadata +4 -3
@@ -1,15 +1,15 @@
1
- # Model methods that want to rollback transactions gracefully
2
- # (i.e, returning the user back to the form from which the request was posted)
3
- # should raise Instiki::ValidationError.
4
- #
5
- # E.g. if a model object does
6
- # raise "Foo: '#{foo}' is not equal to Bar: '#{bar}'" if (foo != bar)
7
- #
8
- # then the operation is not committed; Rails returns the user to the page
9
- # where s/he was entering foo and bar, and the error message will be displayed
10
- # on the page
11
-
12
- module Instiki
13
- class ValidationError < StandardError
14
- end
1
+ # Model methods that want to rollback transactions gracefully
2
+ # (i.e, returning the user back to the form from which the request was posted)
3
+ # should raise Instiki::ValidationError.
4
+ #
5
+ # E.g. if a model object does
6
+ # raise "Foo: '#{foo}' is not equal to Bar: '#{bar}'" if (foo != bar)
7
+ #
8
+ # then the operation is not committed; Rails returns the user to the page
9
+ # where s/he was entering foo and bar, and the error message will be displayed
10
+ # on the page
11
+
12
+ module Instiki
13
+ class ValidationError < StandardError
14
+ end
15
15
  end
data/lib/rdocsupport.rb CHANGED
@@ -1,152 +1,152 @@
1
- begin
2
- require "rdoc/markup/simple_markup"
3
- require 'rdoc/markup/simple_markup/to_html'
4
- rescue LoadError
5
- # use old version if available
6
- require 'markup/simple_markup'
7
- require 'markup/simple_markup/to_html'
8
- end
9
-
10
- module RDocSupport
11
-
12
- # A simple +rdoc+ markup class which recognizes some additional
13
- # formatting commands suitable for Wiki use.
14
- class RDocMarkup < SM::SimpleMarkup
15
- def initialize
16
- super()
17
-
18
- pre = '(?:\\s|^|\\\\)'
19
-
20
- # links of the form
21
- # [[<url> description with spaces]]
22
- add_special(/((\\)?\[\[\S+?\s+.+?\]\])/,:TIDYLINK)
23
-
24
- # and external references
25
- add_special(/((\\)?(link:|anchor:|http:|mailto:|ftp:|img:|www\.)\S+\w\/?)/,
26
- :HYPERLINK)
27
-
28
- # <br/>
29
- add_special(%r{(#{pre}<br/>)}, :BR)
30
-
31
- # and <center> ... </center>
32
- add_html("center", :CENTER)
33
- end
34
-
35
- def convert(text, handler)
36
- super.sub(/^<p>\n/, '').sub(/<\/p>$/, '')
37
- end
38
- end
39
-
40
- # Handle special hyperlinking requirments for RDoc formatted
41
- # entries. Requires RDoc
42
-
43
- class HyperLinkHtml < SM::ToHtml
44
-
45
- # Initialize the HyperLinkHtml object.
46
- # [path] location of the node
47
- # [site] object representing the whole site (typically of class
48
- # +Site+)
49
- def initialize
50
- super()
51
- add_tag(:CENTER, "<center>", "</center>")
52
- end
53
-
54
- # handle <br/>
55
- def handle_special_BR(special)
56
- return "&lt;br/&gt" if special.text[0,1] == '\\'
57
- special.text
58
- end
59
-
60
- # We're invoked with a potential external hyperlink.
61
- # [mailto:] just gets inserted.
62
- # [http:] links are checked to see if they
63
- # reference an image. If so, that image gets inserted
64
- # using an <img> tag. Otherwise a conventional <a href>
65
- # is used.
66
- # [img:] insert a <tt><img></tt> tag
67
- # [link:] used to insert arbitrary <tt><a></tt> references
68
- # [anchor:] used to create an anchor
69
- def handle_special_HYPERLINK(special)
70
- text = special.text.strip
71
- return text[1..-1] if text[0,1] == '\\'
72
- url = special.text.strip
73
- if url =~ /([A-Za-z]+):(.*)/
74
- type = $1
75
- path = $2
76
- else
77
- type = "http"
78
- path = url
79
- url = "http://#{url}"
80
- end
81
-
82
- case type
83
- when "http"
84
- if url =~ /\.(gif|png|jpg|jpeg|bmp)$/
85
- "<img src=\"#{url}\"/>"
86
- else
87
- "<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
88
- end
89
- when "img"
90
- "<img src=\"#{path}\"/>"
91
- when "link"
92
- "<a href=\"#{path}\">#{path}</a>"
93
- when "anchor"
94
- "<a name=\"#{path}\"></a>"
95
- else
96
- "<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
97
- end
98
- end
99
-
100
- # Here's a hyperlink where the label is different to the URL
101
- # [[url label that may contain spaces]]
102
- #
103
-
104
- def handle_special_TIDYLINK(special)
105
- text = special.text.strip
106
- return text[1..-1] if text[0,1] == '\\'
107
- unless text =~ /\[\[(\S+?)\s+(.+?)\]\]/
108
- return text
109
- end
110
- url = $1
111
- label = $2
112
- label = RDocFormatter.new(label).to_html
113
- label = label.split.select{|x| x =~ /\S/}.
114
- map{|x| x.chomp}.join(' ')
115
-
116
- case url
117
- when /link:(\S+)/
118
- return %{<a href="#{$1}">#{label}</a>}
119
- when /img:(\S+)/
120
- return %{<img src="http://#{$1}" alt="#{label}" />}
121
- when /rubytalk:(\S+)/
122
- return %{<a href="http://ruby-talk.org/blade/#{$1}">#{label}</a>}
123
- when /rubygarden:(\S+)/
124
- return %{<a href="http://www.rubygarden.org/ruby?#{$1}">#{label}</a>}
125
- when /c2:(\S+)/
126
- return %{<a href="http://c2.com/cgi/wiki?#{$1}">#{label}</a>}
127
- when /isbn:(\S+)/
128
- return %{<a href="http://search.barnesandnoble.com/bookSearch/} +
129
- %{isbnInquiry.asp?isbn=#{$1}">#{label}</a>}
130
- end
131
-
132
- unless url =~ /\w+?:/
133
- url = "http://#{url}"
134
- end
135
-
136
- "<a href=\"#{url}\">#{label}</a>"
137
- end
138
- end
139
-
140
- class RDocFormatter
141
- def initialize(text)
142
- @text = text
143
- end
144
-
145
- def to_html
146
- markup = RDocMarkup.new
147
- h = HyperLinkHtml.new
148
- markup.convert(@text, h)
149
- end
150
- end
151
-
1
+ begin
2
+ require "rdoc/markup/simple_markup"
3
+ require 'rdoc/markup/simple_markup/to_html'
4
+ rescue LoadError
5
+ # use old version if available
6
+ require 'markup/simple_markup'
7
+ require 'markup/simple_markup/to_html'
8
+ end
9
+
10
+ module RDocSupport
11
+
12
+ # A simple +rdoc+ markup class which recognizes some additional
13
+ # formatting commands suitable for Wiki use.
14
+ class RDocMarkup < SM::SimpleMarkup
15
+ def initialize
16
+ super()
17
+
18
+ pre = '(?:\\s|^|\\\\)'
19
+
20
+ # links of the form
21
+ # [[<url> description with spaces]]
22
+ add_special(/((\\)?\[\[\S+?\s+.+?\]\])/,:TIDYLINK)
23
+
24
+ # and external references
25
+ add_special(/((\\)?(link:|anchor:|http:|mailto:|ftp:|img:|www\.)\S+\w\/?)/,
26
+ :HYPERLINK)
27
+
28
+ # <br/>
29
+ add_special(%r{(#{pre}<br/>)}, :BR)
30
+
31
+ # and <center> ... </center>
32
+ add_html("center", :CENTER)
33
+ end
34
+
35
+ def convert(text, handler)
36
+ super.sub(/^<p>\n/, '').sub(/<\/p>$/, '')
37
+ end
38
+ end
39
+
40
+ # Handle special hyperlinking requirments for RDoc formatted
41
+ # entries. Requires RDoc
42
+
43
+ class HyperLinkHtml < SM::ToHtml
44
+
45
+ # Initialize the HyperLinkHtml object.
46
+ # [path] location of the node
47
+ # [site] object representing the whole site (typically of class
48
+ # +Site+)
49
+ def initialize
50
+ super()
51
+ add_tag(:CENTER, "<center>", "</center>")
52
+ end
53
+
54
+ # handle <br/>
55
+ def handle_special_BR(special)
56
+ return "&lt;br/&gt" if special.text[0,1] == '\\'
57
+ special.text
58
+ end
59
+
60
+ # We're invoked with a potential external hyperlink.
61
+ # [mailto:] just gets inserted.
62
+ # [http:] links are checked to see if they
63
+ # reference an image. If so, that image gets inserted
64
+ # using an <img> tag. Otherwise a conventional <a href>
65
+ # is used.
66
+ # [img:] insert a <tt><img></tt> tag
67
+ # [link:] used to insert arbitrary <tt><a></tt> references
68
+ # [anchor:] used to create an anchor
69
+ def handle_special_HYPERLINK(special)
70
+ text = special.text.strip
71
+ return text[1..-1] if text[0,1] == '\\'
72
+ url = special.text.strip
73
+ if url =~ /([A-Za-z]+):(.*)/
74
+ type = $1
75
+ path = $2
76
+ else
77
+ type = "http"
78
+ path = url
79
+ url = "http://#{url}"
80
+ end
81
+
82
+ case type
83
+ when "http"
84
+ if url =~ /\.(gif|png|jpg|jpeg|bmp)$/
85
+ "<img src=\"#{url}\"/>"
86
+ else
87
+ "<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
88
+ end
89
+ when "img"
90
+ "<img src=\"#{path}\"/>"
91
+ when "link"
92
+ "<a href=\"#{path}\">#{path}</a>"
93
+ when "anchor"
94
+ "<a name=\"#{path}\"></a>"
95
+ else
96
+ "<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
97
+ end
98
+ end
99
+
100
+ # Here's a hyperlink where the label is different to the URL
101
+ # [[url label that may contain spaces]]
102
+ #
103
+
104
+ def handle_special_TIDYLINK(special)
105
+ text = special.text.strip
106
+ return text[1..-1] if text[0,1] == '\\'
107
+ unless text =~ /\[\[(\S+?)\s+(.+?)\]\]/
108
+ return text
109
+ end
110
+ url = $1
111
+ label = $2
112
+ label = RDocFormatter.new(label).to_html
113
+ label = label.split.select{|x| x =~ /\S/}.
114
+ map{|x| x.chomp}.join(' ')
115
+
116
+ case url
117
+ when /link:(\S+)/
118
+ return %{<a href="#{$1}">#{label}</a>}
119
+ when /img:(\S+)/
120
+ return %{<img src="http://#{$1}" alt="#{label}" />}
121
+ when /rubytalk:(\S+)/
122
+ return %{<a href="http://ruby-talk.org/blade/#{$1}">#{label}</a>}
123
+ when /rubygarden:(\S+)/
124
+ return %{<a href="http://www.rubygarden.org/ruby?#{$1}">#{label}</a>}
125
+ when /c2:(\S+)/
126
+ return %{<a href="http://c2.com/cgi/wiki?#{$1}">#{label}</a>}
127
+ when /isbn:(\S+)/
128
+ return %{<a href="http://search.barnesandnoble.com/bookSearch/} +
129
+ %{isbnInquiry.asp?isbn=#{$1}">#{label}</a>}
130
+ end
131
+
132
+ unless url =~ /\w+?:/
133
+ url = "http://#{url}"
134
+ end
135
+
136
+ "<a href=\"#{url}\">#{label}</a>"
137
+ end
138
+ end
139
+
140
+ class RDocFormatter
141
+ def initialize(text)
142
+ @text = text
143
+ end
144
+
145
+ def to_html
146
+ markup = RDocMarkup.new
147
+ h = HyperLinkHtml.new
148
+ markup.convert(@text, h)
149
+ end
150
+ end
151
+
152
152
  end
@@ -1,736 +1,736 @@
1
- # This is RedCloth (http://www.whytheluckystiff.net/ruby/redcloth/)
2
- # converted by David Heinemeier Hansson to emit Tex
3
-
4
- class String
5
- # Flexible HTML escaping
6
- def texesc!( mode )
7
- gsub!( '&', '\\\\&' )
8
- gsub!( '%', '\%' )
9
- gsub!( '$', '\$' )
10
- gsub!( '~', '$\sim$' )
11
- end
12
- end
13
-
14
-
15
- def table_of_contents(text, pages)
16
- text.gsub( /^([#*]+? .*?)$(?![^#*])/m ) do |match|
17
- lines = match.split( /\n/ )
18
- last_line = -1
19
- depth = []
20
- lines.each_with_index do |line, line_id|
21
- if line =~ /^([#*]+) (.*)$/m
22
- tl,content = $~[1..2]
23
- content.gsub! /[\[\]]/, ""
24
- content.strip!
25
-
26
- if depth.last
27
- if depth.last.length > tl.length
28
- (depth.length - 1).downto(0) do |i|
29
- break if depth[i].length == tl.length
30
- lines[line_id - 1] << "" # "\n\t\\end{#{ lT( depth[i] ) }}\n\t"
31
- depth.pop
32
- end
33
- end
34
- if !depth.last.nil? && !tl.length.nil? && depth.last.length == tl.length
35
- lines[line_id - 1] << ''
36
- end
37
- end
38
-
39
- depth << tl unless depth.last == tl
40
-
41
- subsection_depth = [depth.length - 1, 2].min
42
-
43
- lines[line_id] = "\n\\#{ "sub" * subsection_depth }section{#{ content }}"
44
- lines[line_id] += "\n#{pages[content]}" if pages.keys.include?(content)
45
-
46
- lines[line_id] = "\\pagebreak\n#{lines[line_id]}" if subsection_depth == 0
47
-
48
- last_line = line_id
49
-
50
- elsif line =~ /^\s+\S/
51
- last_line = line_id
52
- elsif line_id - last_line < 2 and line =~ /^\S/
53
- last_line = line_id
54
- end
55
- if line_id - last_line > 1 or line_id == lines.length - 1
56
- depth.delete_if do |v|
57
- lines[last_line] << "" # "\n\t\\end{#{ lT( v ) }}"
58
- end
59
- end
60
- end
61
- lines.join( "\n" )
62
- end
63
- end
64
-
65
- class RedClothForTex < String
66
-
67
- VERSION = '2.0.7'
68
-
69
- #
70
- # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents.
71
- # (from PyTextile)
72
- #
73
- TEXTILE_TAGS =
74
-
75
- [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230],
76
- [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249],
77
- [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217],
78
- [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732],
79
- [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]].
80
-
81
- collect! do |a, b|
82
- [a.chr, ( b.zero? and "" or "&#{ b };" )]
83
- end
84
-
85
- #
86
- # Regular expressions to convert to HTML.
87
- #
88
- A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/
89
- A_VLGN = /[\-^~]/
90
- C_CLAS = '(?:\([^)]+\))'
91
- C_LNGE = '(?:\[[^\]]+\])'
92
- C_STYL = '(?:\{[^}]+\})'
93
- S_CSPN = '(?:\\\\\d+)'
94
- S_RSPN = '(?:/\d+)'
95
- A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)"
96
- S = "(?:#{S_CSPN}?#{S_RSPN}|#{S_RSPN}?#{S_CSPN}?)"
97
- C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)"
98
- # PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' )
99
- PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' )
100
- HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(\s|$)'
101
-
102
- GLYPHS = [
103
- # [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
104
- [ /([^\s\[{(>])\'/, '\1&#8217;' ], # single closing
105
- [ /\'(?=\s|s\b|[#{PUNCT}])/, '&#8217;' ], # single closing
106
- [ /\'/, '&#8216;' ], # single opening
107
- # [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
108
- [ /([^\s\[{(>])"/, '\1&#8221;' ], # double closing
109
- [ /"(?=\s|[#{PUNCT}])/, '&#8221;' ], # double closing
110
- [ /"/, '&#8220;' ], # double opening
111
- [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
112
- [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
113
- [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]{2,})([^<a-z0-9]|$)/, '\1<span class="caps">\2</span>\3' ], # 3+ uppercase caps
114
- [ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
115
- [ /\s->\s/, ' &rarr; ' ], # en dash
116
- [ /\s-\s/, ' &#8211; ' ], # en dash
117
- [ /(\d+) ?x ?(\d+)/, '\1&#215;\2' ], # dimension sign
118
- [ /\b ?[(\[]TM[\])]/i, '&#8482;' ], # trademark
119
- [ /\b ?[(\[]R[\])]/i, '&#174;' ], # registered
120
- [ /\b ?[(\[]C[\])]/i, '&#169;' ] # copyright
121
- ]
122
-
123
- I_ALGN_VALS = {
124
- '<' => 'left',
125
- '=' => 'center',
126
- '>' => 'right'
127
- }
128
-
129
- H_ALGN_VALS = {
130
- '<' => 'left',
131
- '=' => 'center',
132
- '>' => 'right',
133
- '<>' => 'justify'
134
- }
135
-
136
- V_ALGN_VALS = {
137
- '^' => 'top',
138
- '-' => 'middle',
139
- '~' => 'bottom'
140
- }
141
-
142
- QTAGS = [
143
- ['**', 'bf'],
144
- ['*', 'bf'],
145
- ['??', 'cite'],
146
- ['-', 'del'],
147
- ['__', 'underline'],
148
- ['_', 'em'],
149
- ['%', 'span'],
150
- ['+', 'ins'],
151
- ['^', 'sup'],
152
- ['~', 'sub']
153
- ]
154
-
155
- def self.available?
156
- if not defined? @@available
157
- begin
158
- @@available = system "pdflatex -version"
159
- rescue Errno::ENOENT
160
- @@available = false
161
- end
162
- end
163
- @@available
164
- end
165
-
166
- #
167
- # Two accessor for setting security restrictions.
168
- #
169
- # This is a nice thing if you're using RedCloth for
170
- # formatting in public places (e.g. Wikis) where you
171
- # don't want users to abuse HTML for bad things.
172
- #
173
- # If +:filter_html+ is set, HTML which wasn't
174
- # created by the Textile processor will be escaped.
175
- #
176
- # If +:filter_styles+ is set, it will also disable
177
- # the style markup specifier. ('{color: red}')
178
- #
179
- attr_accessor :filter_html, :filter_styles
180
-
181
- #
182
- # Accessor for toggling line folding.
183
- #
184
- # If +:fold_lines+ is set, single newlines will
185
- # not be converted to break tags.
186
- #
187
- attr_accessor :fold_lines
188
-
189
- def initialize( string, restrictions = [] )
190
- restrictions.each { |r| method( "#{ r }=" ).call( true ) }
191
- super( string )
192
- end
193
-
194
- #
195
- # Generate tex.
196
- #
197
- def to_tex( lite = false )
198
-
199
- # make our working copy
200
- text = self.dup
201
-
202
- @urlrefs = {}
203
- @shelf = []
204
-
205
- # incoming_entities text
206
- fix_entities text
207
- clean_white_space text
208
-
209
- get_refs text
210
-
211
- no_textile text
212
-
213
- unless lite
214
- lists text
215
- table text
216
- end
217
-
218
- glyphs text
219
-
220
- unless lite
221
- fold text
222
- block text
223
- end
224
-
225
- retrieve text
226
- encode_entities text
227
-
228
- text.gsub!(/\[\[(.*?)\]\]/, "\\1")
229
- text.gsub!(/_/, "\\_")
230
- text.gsub!( /<\/?notextile>/, '' )
231
- # text.gsub!( /x%x%/, '&#38;' )
232
- # text.gsub!( /<br \/>/, "<br />\n" )
233
- text.strip!
234
- text
235
-
236
- end
237
-
238
- def pgl( text )
239
- GLYPHS.each do |re, resub|
240
- text.gsub! re, resub
241
- end
242
- end
243
-
244
- def pba( text_in, element = "" )
245
-
246
- return '' unless text_in
247
-
248
- style = []
249
- text = text_in.dup
250
- if element == 'td'
251
- colspan = $1 if text =~ /\\(\d+)/
252
- rowspan = $1 if text =~ /\/(\d+)/
253
- style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
254
- end
255
-
256
- style << "#{ $1 };" if not @filter_styles and
257
- text.sub!( /\{([^}]*)\}/, '' )
258
-
259
- lang = $1 if
260
- text.sub!( /\[([^)]+?)\]/, '' )
261
-
262
- cls = $1 if
263
- text.sub!( /\(([^()]+?)\)/, '' )
264
-
265
- style << "padding-left:#{ $1.length }em;" if
266
- text.sub!( /([(]+)/, '' )
267
-
268
- style << "padding-right:#{ $1.length }em;" if text.sub!( /([)]+)/, '' )
269
-
270
- style << "text-align:#{ h_align( $& ) };" if text =~ A_HLGN
271
-
272
- cls, id = $1, $2 if cls =~ /^(.*?)#(.*)$/
273
-
274
- atts = ''
275
- atts << " style=\"#{ style.join }\"" unless style.empty?
276
- atts << " class=\"#{ cls }\"" unless cls.to_s.empty?
277
- atts << " lang=\"#{ lang }\"" if lang
278
- atts << " id=\"#{ id }\"" if id
279
- atts << " colspan=\"#{ colspan }\"" if colspan
280
- atts << " rowspan=\"#{ rowspan }\"" if rowspan
281
-
282
- atts
283
- end
284
-
285
- def table( text )
286
- text << "\n\n"
287
- text.gsub!( /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)\n\n/m ) do |matches|
288
-
289
- tatts, fullrow = $~[1..2]
290
- tatts = pba( tatts, 'table' )
291
- rows = []
292
-
293
- fullrow.
294
- split( /\|$/m ).
295
- delete_if { |x| x.empty? }.
296
- each do |row|
297
-
298
- ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m
299
-
300
- cells = []
301
- row.split( '|' ).each do |cell|
302
- ctyp = 'd'
303
- ctyp = 'h' if cell =~ /^_/
304
-
305
- catts = ''
306
- catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. )(.*)/
307
-
308
- unless cell.strip.empty?
309
- cells << "\t\t\t<t#{ ctyp }#{ catts }>#{ cell }</t#{ ctyp }>"
310
- end
311
- end
312
- rows << "\t\t<tr#{ ratts }>\n#{ cells.join( "\n" ) }\n\t\t</tr>"
313
- end
314
- "\t<table#{ tatts }>\n#{ rows.join( "\n" ) }\n\t</table>\n\n"
315
- end
316
- end
317
-
318
- def lists( text )
319
- text.gsub!( /^([#*]+?#{C} .*?)$(?![^#*])/m ) do |match|
320
- lines = match.split( /\n/ )
321
- last_line = -1
322
- depth = []
323
- lines.each_with_index do |line, line_id|
324
- if line =~ /^([#*]+)(#{A}#{C}) (.*)$/m
325
- tl,atts,content = $~[1..3]
326
- if depth.last
327
- if depth.last.length > tl.length
328
- (depth.length - 1).downto(0) do |i|
329
- break if depth[i].length == tl.length
330
- lines[line_id - 1] << "\n\t\\end{#{ lT( depth[i] ) }}\n\t"
331
- depth.pop
332
- end
333
- end
334
- if !depth.last.nil? && !tl.length.nil? && depth.last.length == tl.length
335
- lines[line_id - 1] << ''
336
- end
337
- end
338
- unless depth.last == tl
339
- depth << tl
340
- atts = pba( atts )
341
- lines[line_id] = "\t\\begin{#{ lT(tl) }}\n\t\\item #{ content }"
342
- else
343
- lines[line_id] = "\t\t\\item #{ content }"
344
- end
345
- last_line = line_id
346
-
347
- elsif line =~ /^\s+\S/
348
- last_line = line_id
349
- elsif line_id - last_line < 2 and line =~ /^\S/
350
- last_line = line_id
351
- end
352
- if line_id - last_line > 1 or line_id == lines.length - 1
353
- depth.delete_if do |v|
354
- lines[last_line] << "\n\t\\end{#{ lT( v ) }}"
355
- end
356
- end
357
- end
358
- lines.join( "\n" )
359
- end
360
- end
361
-
362
- def lT( text )
363
- text =~ /\#$/ ? 'enumerate' : 'itemize'
364
- end
365
-
366
- def fold( text )
367
- text.gsub!( /(.+)\n(?![#*\s|])/, "\\1\\\\\\\\" )
368
- # text.gsub!( /(.+)\n(?![#*\s|])/, "\\1#{ @fold_lines ? ' ' : '<br />' }" )
369
- end
370
-
371
- def block( text )
372
- pre = false
373
- find = ['bq','h[1-6]','fn\d+']
374
-
375
- regexp_cue = []
376
-
377
- lines = text.split( /\n/ ) + [' ']
378
- new_text =
379
- lines.collect do |line|
380
- pre = true if line =~ /<(pre|notextile)>/i
381
- find.each do |tag|
382
- line.gsub!( /^(#{ tag })(#{A}#{C})\.(?::(\S+))? (.*)$/ ) do |m|
383
- tag,atts,cite,content = $~[1..4]
384
-
385
- atts = pba( atts )
386
-
387
- if tag =~ /fn(\d+)/
388
- # tag = 'p';
389
- # atts << " id=\"fn#{ $1 }\""
390
- regexp_cue << [ /footnote\{#{$1}}/, "footnote{#{content}}" ]
391
- content = ""
392
- end
393
-
394
- if tag =~ /h([1-6])/
395
- section_type = "sub" * [$1.to_i - 1, 2].min
396
- start = "\t\\#{section_type}section*{"
397
- tend = "}"
398
- end
399
-
400
- if tag == "bq"
401
- cite = check_refs( cite )
402
- cite = " cite=\"#{ cite }\"" if cite
403
- start = "\t\\begin{quotation}\n\\noindent {\\em ";
404
- tend = "}\n\t\\end{quotation}";
405
- end
406
-
407
- "#{ start }#{ content }#{ tend }"
408
- end unless pre
409
- end
410
-
411
- #line.gsub!( /^(?!\t|<\/?pre|<\/?notextile|<\/?code|$| )(.*)/, "\t<p>\\1</p>" )
412
-
413
- #line.gsub!( "<br />", "\n" ) if pre
414
- # pre = false if line =~ /<\/(pre|notextile)>/i
415
-
416
- line
417
- end.join( "\n" )
418
- text.replace( new_text )
419
- regexp_cue.each { |pair| text.gsub!(pair.first, pair.last) }
420
- end
421
-
422
- def span( text )
423
- QTAGS.each do |tt, ht|
424
- ttr = Regexp::quote( tt )
425
- text.gsub!(
426
-
427
- /(^|\s|\>|[#{PUNCT}{(\[])
428
- #{ttr}
429
- (#{C})
430
- (?::(\S+?))?
431
- ([^\s#{ttr}]+?(?:[^\n]|\n(?!\n))*?)
432
- ([#{PUNCT}]*?)
433
- #{ttr}
434
- (?=[\])}]|[#{PUNCT}]+?|<|\s|$)/xm
435
-
436
- ) do |m|
437
-
438
- start,atts,cite,content,tend = $~[1..5]
439
- atts = pba( atts )
440
- atts << " cite=\"#{ cite }\"" if cite
441
-
442
- "#{ start }{\\#{ ht } #{ content }#{ tend }}"
443
-
444
- end
445
- end
446
- end
447
-
448
- def links( text )
449
- text.gsub!( /
450
- ([\s\[{(]|[#{PUNCT}])? # $pre
451
- " # start
452
- (#{C}) # $atts
453
- ([^"]+?) # $text
454
- \s?
455
- (?:\(([^)]+?)\)(?="))? # $title
456
- ":
457
- (\S+?) # $url
458
- (\/)? # $slash
459
- ([^\w\/;]*?) # $post
460
- (?=\s|$)
461
- /x ) do |m|
462
- pre,atts,text,title,url,slash,post = $~[1..7]
463
-
464
- url.gsub!(/(\\)(.)/, '\2')
465
- url = check_refs( url )
466
-
467
- atts = pba( atts )
468
- atts << " title=\"#{ title }\"" if title
469
- atts = shelve( atts ) if atts
470
-
471
- "#{ pre }\\textit{#{ text }} \\footnote{\\texttt{\\textless #{ url }#{ slash }" +
472
- "\\textgreater}#{ post }}"
473
- end
474
- end
475
-
476
- def get_refs( text )
477
- text.gsub!( /(^|\s)\[(.+?)\]((?:http:\/\/|javascript:|ftp:\/\/|\/)\S+?)(?=\s|$)/ ) do |m|
478
- flag, url = $~[1..2]
479
- @urlrefs[flag] = url
480
- end
481
- end
482
-
483
- def check_refs( text )
484
- @urlrefs[text] || text
485
- end
486
-
487
- def image( text )
488
- text.gsub!( /
489
- \! # opening
490
- (\<|\=|\>)? # optional alignment atts
491
- (#{C}) # optional style,class atts
492
- (?:\. )? # optional dot-space
493
- ([^\s(!]+?) # presume this is the src
494
- \s? # optional space
495
- (?:\(((?:[^\(\)]|\([^\)]+\))+?)\))? # optional title
496
- \! # closing
497
- (?::#{ HYPERLINK })? # optional href
498
- /x ) do |m|
499
- algn,atts,url,title,href,href_a1,href_a2 = $~[1..7]
500
- atts = pba( atts )
501
- atts << " align=\"#{ i_align( algn ) }\"" if algn
502
- atts << " title=\"#{ title }\"" if title
503
- atts << " alt=\"#{ title }\""
504
- # size = @getimagesize($url);
505
- # if($size) $atts.= " $size[3]";
506
-
507
- href = check_refs( href ) if href
508
- url = check_refs( url )
509
-
510
- out = ''
511
- out << "<a href=\"#{ href }\">" if href
512
- out << "<img src=\"#{ url }\"#{ atts } />"
513
- out << "</a>#{ href_a1 }#{ href_a2 }" if href
514
-
515
- out
516
- end
517
- end
518
-
519
- def code( text )
520
- text.gsub!( /
521
- (?:^|([\s\(\[{])) # 1 open bracket?
522
- @ # opening
523
- (?:\|(\w+?)\|)? # 2 language
524
- (\S(?:[^\n]|\n(?!\n))*?) # 3 code
525
- @ # closing
526
- (?:$|([\]})])|
527
- (?=[#{PUNCT}]{1,2}|
528
- \s)) # 4 closing bracket?
529
- /x ) do |m|
530
- before,lang,code,after = $~[1..4]
531
- lang = " language=\"#{ lang }\"" if lang
532
- "#{ before }<code#{ lang }>#{ code }</code>#{ after }"
533
- end
534
- end
535
-
536
- def shelve( val )
537
- @shelf << val
538
- " <#{ @shelf.length }>"
539
- end
540
-
541
- def retrieve( text )
542
- @shelf.each_with_index do |r, i|
543
- text.gsub!( " <#{ i + 1 }>", r )
544
- end
545
- end
546
-
547
- def incoming_entities( text )
548
- ## turn any incoming ampersands into a dummy character for now.
549
- ## This uses a negative lookahead for alphanumerics followed by a semicolon,
550
- ## implying an incoming html entity, to be skipped
551
-
552
- text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" )
553
- end
554
-
555
- def encode_entities( text )
556
- ## Convert high and low ascii to entities.
557
- # if $-K == "UTF-8"
558
- # encode_high( text )
559
- # else
560
- text.texesc!( :NoQuotes )
561
- # end
562
- end
563
-
564
- def fix_entities( text )
565
- ## de-entify any remaining angle brackets or ampersands
566
- text.gsub!( "\&", "&" )
567
- text.gsub!( "\%", "%" )
568
- end
569
-
570
- def clean_white_space( text )
571
- text.gsub!( /\r\n/, "\n" )
572
- text.gsub!( /\t/, '' )
573
- text.gsub!( /\n{3,}/, "\n\n" )
574
- text.gsub!( /\n *\n/, "\n\n" )
575
- text.gsub!( /"$/, "\" " )
576
- end
577
-
578
- def no_textile( text )
579
- text.gsub!( /(^|\s)==(.*?)==(\s|$)?/,
580
- '\1<notextile>\2</notextile>\3' )
581
- end
582
-
583
- def footnote_ref( text )
584
- text.gsub!( /\[([0-9]+?)\](\s)?/,
585
- '\footnote{\1}\2')
586
- #'<sup><a href="#fn\1">\1</a></sup>\2' )
587
- end
588
-
589
- def inline( text )
590
- image text
591
- links text
592
- code text
593
- span text
594
- end
595
-
596
- def glyphs_deep( text )
597
- codepre = 0
598
- offtags = /(?:code|pre|kbd|notextile)/
599
- if text !~ /<.*>/
600
- # pgl text
601
- footnote_ref text
602
- else
603
- used_offtags = {}
604
- text.gsub!( /(?:[^<].*?(?=<[^\n]*?>|$)|<[^\n]*?>+)/m ) do |line|
605
- tagline = ( line =~ /^<.*>/ )
606
-
607
- ## matches are off if we're between <code>, <pre> etc.
608
- if tagline
609
- if line =~ /<(#{ offtags })>/i
610
- codepre += 1
611
- used_offtags[$1] = true
612
- line.texesc!( :NoQuotes ) if codepre - used_offtags.length > 0
613
- elsif line =~ /<\/(#{ offtags })>/i
614
- line.texesc!( :NoQuotes ) if codepre - used_offtags.length > 0
615
- codepre -= 1 unless codepre.zero?
616
- used_offtags = {} if codepre.zero?
617
- elsif @filter_html or codepre > 0
618
- line.texesc!( :NoQuotes )
619
- ## line.gsub!( /&lt;(\/?#{ offtags })&gt;/, '<\1>' )
620
- end
621
- ## do htmlspecial if between <code>
622
- elsif codepre > 0
623
- line.texesc!( :NoQuotes )
624
- ## line.gsub!( /&lt;(\/?#{ offtags })&gt;/, '<\1>' )
625
- elsif not tagline
626
- inline line
627
- glyphs_deep line
628
- end
629
-
630
- line
631
- end
632
- end
633
- end
634
-
635
- def glyphs( text )
636
- text.gsub!( /"\z/, "\" " )
637
- ## if no html, do a simple search and replace...
638
- if text !~ /<.*>/
639
- inline text
640
- end
641
- glyphs_deep text
642
- end
643
-
644
- def i_align( text )
645
- I_ALGN_VALS[text]
646
- end
647
-
648
- def h_align( text )
649
- H_ALGN_VALS[text]
650
- end
651
-
652
- def v_align( text )
653
- V_ALGN_VALS[text]
654
- end
655
-
656
- def encode_high( text )
657
- ## mb_encode_numericentity($text, $cmap, $charset);
658
- end
659
-
660
- def decode_high( text )
661
- ## mb_decode_numericentity($text, $cmap, $charset);
662
- end
663
-
664
- def textile_popup_help( name, helpvar, windowW, windowH )
665
- ' <a target="_blank" href="http://www.textpattern.com/help/?item=' + helpvar + '" onclick="window.open(this.href, \'popupwindow\', \'width=' + windowW + ',height=' + windowH + ',scrollbars,resizable\'); return false;">' + name + '</a><br />'
666
- end
667
-
668
- CMAP = [
669
- 160, 255, 0, 0xffff,
670
- 402, 402, 0, 0xffff,
671
- 913, 929, 0, 0xffff,
672
- 931, 937, 0, 0xffff,
673
- 945, 969, 0, 0xffff,
674
- 977, 978, 0, 0xffff,
675
- 982, 982, 0, 0xffff,
676
- 8226, 8226, 0, 0xffff,
677
- 8230, 8230, 0, 0xffff,
678
- 8242, 8243, 0, 0xffff,
679
- 8254, 8254, 0, 0xffff,
680
- 8260, 8260, 0, 0xffff,
681
- 8465, 8465, 0, 0xffff,
682
- 8472, 8472, 0, 0xffff,
683
- 8476, 8476, 0, 0xffff,
684
- 8482, 8482, 0, 0xffff,
685
- 8501, 8501, 0, 0xffff,
686
- 8592, 8596, 0, 0xffff,
687
- 8629, 8629, 0, 0xffff,
688
- 8656, 8660, 0, 0xffff,
689
- 8704, 8704, 0, 0xffff,
690
- 8706, 8707, 0, 0xffff,
691
- 8709, 8709, 0, 0xffff,
692
- 8711, 8713, 0, 0xffff,
693
- 8715, 8715, 0, 0xffff,
694
- 8719, 8719, 0, 0xffff,
695
- 8721, 8722, 0, 0xffff,
696
- 8727, 8727, 0, 0xffff,
697
- 8730, 8730, 0, 0xffff,
698
- 8733, 8734, 0, 0xffff,
699
- 8736, 8736, 0, 0xffff,
700
- 8743, 8747, 0, 0xffff,
701
- 8756, 8756, 0, 0xffff,
702
- 8764, 8764, 0, 0xffff,
703
- 8773, 8773, 0, 0xffff,
704
- 8776, 8776, 0, 0xffff,
705
- 8800, 8801, 0, 0xffff,
706
- 8804, 8805, 0, 0xffff,
707
- 8834, 8836, 0, 0xffff,
708
- 8838, 8839, 0, 0xffff,
709
- 8853, 8853, 0, 0xffff,
710
- 8855, 8855, 0, 0xffff,
711
- 8869, 8869, 0, 0xffff,
712
- 8901, 8901, 0, 0xffff,
713
- 8968, 8971, 0, 0xffff,
714
- 9001, 9002, 0, 0xffff,
715
- 9674, 9674, 0, 0xffff,
716
- 9824, 9824, 0, 0xffff,
717
- 9827, 9827, 0, 0xffff,
718
- 9829, 9830, 0, 0xffff,
719
- 338, 339, 0, 0xffff,
720
- 352, 353, 0, 0xffff,
721
- 376, 376, 0, 0xffff,
722
- 710, 710, 0, 0xffff,
723
- 732, 732, 0, 0xffff,
724
- 8194, 8195, 0, 0xffff,
725
- 8201, 8201, 0, 0xffff,
726
- 8204, 8207, 0, 0xffff,
727
- 8211, 8212, 0, 0xffff,
728
- 8216, 8218, 0, 0xffff,
729
- 8218, 8218, 0, 0xffff,
730
- 8220, 8222, 0, 0xffff,
731
- 8224, 8225, 0, 0xffff,
732
- 8240, 8240, 0, 0xffff,
733
- 8249, 8250, 0, 0xffff,
734
- 8364, 8364, 0, 0xffff
735
- ]
736
- end
1
+ # This is RedCloth (http://www.whytheluckystiff.net/ruby/redcloth/)
2
+ # converted by David Heinemeier Hansson to emit Tex
3
+
4
+ class String
5
+ # Flexible HTML escaping
6
+ def texesc!( mode )
7
+ gsub!( '&', '\\\\&' )
8
+ gsub!( '%', '\%' )
9
+ gsub!( '$', '\$' )
10
+ gsub!( '~', '$\sim$' )
11
+ end
12
+ end
13
+
14
+
15
+ def table_of_contents(text, pages)
16
+ text.gsub( /^([#*]+? .*?)$(?![^#*])/m ) do |match|
17
+ lines = match.split( /\n/ )
18
+ last_line = -1
19
+ depth = []
20
+ lines.each_with_index do |line, line_id|
21
+ if line =~ /^([#*]+) (.*)$/m
22
+ tl,content = $~[1..2]
23
+ content.gsub! /[\[\]]/, ""
24
+ content.strip!
25
+
26
+ if depth.last
27
+ if depth.last.length > tl.length
28
+ (depth.length - 1).downto(0) do |i|
29
+ break if depth[i].length == tl.length
30
+ lines[line_id - 1] << "" # "\n\t\\end{#{ lT( depth[i] ) }}\n\t"
31
+ depth.pop
32
+ end
33
+ end
34
+ if !depth.last.nil? && !tl.length.nil? && depth.last.length == tl.length
35
+ lines[line_id - 1] << ''
36
+ end
37
+ end
38
+
39
+ depth << tl unless depth.last == tl
40
+
41
+ subsection_depth = [depth.length - 1, 2].min
42
+
43
+ lines[line_id] = "\n\\#{ "sub" * subsection_depth }section{#{ content }}"
44
+ lines[line_id] += "\n#{pages[content]}" if pages.keys.include?(content)
45
+
46
+ lines[line_id] = "\\pagebreak\n#{lines[line_id]}" if subsection_depth == 0
47
+
48
+ last_line = line_id
49
+
50
+ elsif line =~ /^\s+\S/
51
+ last_line = line_id
52
+ elsif line_id - last_line < 2 and line =~ /^\S/
53
+ last_line = line_id
54
+ end
55
+ if line_id - last_line > 1 or line_id == lines.length - 1
56
+ depth.delete_if do |v|
57
+ lines[last_line] << "" # "\n\t\\end{#{ lT( v ) }}"
58
+ end
59
+ end
60
+ end
61
+ lines.join( "\n" )
62
+ end
63
+ end
64
+
65
+ class RedClothForTex < String
66
+
67
+ VERSION = '2.0.7'
68
+
69
+ #
70
+ # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents.
71
+ # (from PyTextile)
72
+ #
73
+ TEXTILE_TAGS =
74
+
75
+ [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230],
76
+ [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249],
77
+ [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217],
78
+ [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732],
79
+ [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]].
80
+
81
+ collect! do |a, b|
82
+ [a.chr, ( b.zero? and "" or "&#{ b };" )]
83
+ end
84
+
85
+ #
86
+ # Regular expressions to convert to HTML.
87
+ #
88
+ A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/
89
+ A_VLGN = /[\-^~]/
90
+ C_CLAS = '(?:\([^)]+\))'
91
+ C_LNGE = '(?:\[[^\]]+\])'
92
+ C_STYL = '(?:\{[^}]+\})'
93
+ S_CSPN = '(?:\\\\\d+)'
94
+ S_RSPN = '(?:/\d+)'
95
+ A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)"
96
+ S = "(?:#{S_CSPN}?#{S_RSPN}|#{S_RSPN}?#{S_CSPN}?)"
97
+ C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)"
98
+ # PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' )
99
+ PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' )
100
+ HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(\s|$)'
101
+
102
+ GLYPHS = [
103
+ # [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1&#8217;\2' ], # single closing
104
+ [ /([^\s\[{(>])\'/, '\1&#8217;' ], # single closing
105
+ [ /\'(?=\s|s\b|[#{PUNCT}])/, '&#8217;' ], # single closing
106
+ [ /\'/, '&#8216;' ], # single opening
107
+ # [ /([^\s\[{(])?"(\s|:|$)/, '\1&#8221;\2' ], # double closing
108
+ [ /([^\s\[{(>])"/, '\1&#8221;' ], # double closing
109
+ [ /"(?=\s|[#{PUNCT}])/, '&#8221;' ], # double closing
110
+ [ /"/, '&#8220;' ], # double opening
111
+ [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
112
+ [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
113
+ [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]{2,})([^<a-z0-9]|$)/, '\1<span class="caps">\2</span>\3' ], # 3+ uppercase caps
114
+ [ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
115
+ [ /\s->\s/, ' &rarr; ' ], # en dash
116
+ [ /\s-\s/, ' &#8211; ' ], # en dash
117
+ [ /(\d+) ?x ?(\d+)/, '\1&#215;\2' ], # dimension sign
118
+ [ /\b ?[(\[]TM[\])]/i, '&#8482;' ], # trademark
119
+ [ /\b ?[(\[]R[\])]/i, '&#174;' ], # registered
120
+ [ /\b ?[(\[]C[\])]/i, '&#169;' ] # copyright
121
+ ]
122
+
123
+ I_ALGN_VALS = {
124
+ '<' => 'left',
125
+ '=' => 'center',
126
+ '>' => 'right'
127
+ }
128
+
129
+ H_ALGN_VALS = {
130
+ '<' => 'left',
131
+ '=' => 'center',
132
+ '>' => 'right',
133
+ '<>' => 'justify'
134
+ }
135
+
136
+ V_ALGN_VALS = {
137
+ '^' => 'top',
138
+ '-' => 'middle',
139
+ '~' => 'bottom'
140
+ }
141
+
142
+ QTAGS = [
143
+ ['**', 'bf'],
144
+ ['*', 'bf'],
145
+ ['??', 'cite'],
146
+ ['-', 'del'],
147
+ ['__', 'underline'],
148
+ ['_', 'em'],
149
+ ['%', 'span'],
150
+ ['+', 'ins'],
151
+ ['^', 'sup'],
152
+ ['~', 'sub']
153
+ ]
154
+
155
+ def self.available?
156
+ if not defined? @@available
157
+ begin
158
+ @@available = system "pdflatex -version"
159
+ rescue Errno::ENOENT
160
+ @@available = false
161
+ end
162
+ end
163
+ @@available
164
+ end
165
+
166
+ #
167
+ # Two accessor for setting security restrictions.
168
+ #
169
+ # This is a nice thing if you're using RedCloth for
170
+ # formatting in public places (e.g. Wikis) where you
171
+ # don't want users to abuse HTML for bad things.
172
+ #
173
+ # If +:filter_html+ is set, HTML which wasn't
174
+ # created by the Textile processor will be escaped.
175
+ #
176
+ # If +:filter_styles+ is set, it will also disable
177
+ # the style markup specifier. ('{color: red}')
178
+ #
179
+ attr_accessor :filter_html, :filter_styles
180
+
181
+ #
182
+ # Accessor for toggling line folding.
183
+ #
184
+ # If +:fold_lines+ is set, single newlines will
185
+ # not be converted to break tags.
186
+ #
187
+ attr_accessor :fold_lines
188
+
189
+ def initialize( string, restrictions = [] )
190
+ restrictions.each { |r| method( "#{ r }=" ).call( true ) }
191
+ super( string )
192
+ end
193
+
194
+ #
195
+ # Generate tex.
196
+ #
197
+ def to_tex( lite = false )
198
+
199
+ # make our working copy
200
+ text = self.dup
201
+
202
+ @urlrefs = {}
203
+ @shelf = []
204
+
205
+ # incoming_entities text
206
+ fix_entities text
207
+ clean_white_space text
208
+
209
+ get_refs text
210
+
211
+ no_textile text
212
+
213
+ unless lite
214
+ lists text
215
+ table text
216
+ end
217
+
218
+ glyphs text
219
+
220
+ unless lite
221
+ fold text
222
+ block text
223
+ end
224
+
225
+ retrieve text
226
+ encode_entities text
227
+
228
+ text.gsub!(/\[\[(.*?)\]\]/, "\\1")
229
+ text.gsub!(/_/, "\\_")
230
+ text.gsub!( /<\/?notextile>/, '' )
231
+ # text.gsub!( /x%x%/, '&#38;' )
232
+ # text.gsub!( /<br \/>/, "<br />\n" )
233
+ text.strip!
234
+ text
235
+
236
+ end
237
+
238
+ def pgl( text )
239
+ GLYPHS.each do |re, resub|
240
+ text.gsub! re, resub
241
+ end
242
+ end
243
+
244
+ def pba( text_in, element = "" )
245
+
246
+ return '' unless text_in
247
+
248
+ style = []
249
+ text = text_in.dup
250
+ if element == 'td'
251
+ colspan = $1 if text =~ /\\(\d+)/
252
+ rowspan = $1 if text =~ /\/(\d+)/
253
+ style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
254
+ end
255
+
256
+ style << "#{ $1 };" if not @filter_styles and
257
+ text.sub!( /\{([^}]*)\}/, '' )
258
+
259
+ lang = $1 if
260
+ text.sub!( /\[([^)]+?)\]/, '' )
261
+
262
+ cls = $1 if
263
+ text.sub!( /\(([^()]+?)\)/, '' )
264
+
265
+ style << "padding-left:#{ $1.length }em;" if
266
+ text.sub!( /([(]+)/, '' )
267
+
268
+ style << "padding-right:#{ $1.length }em;" if text.sub!( /([)]+)/, '' )
269
+
270
+ style << "text-align:#{ h_align( $& ) };" if text =~ A_HLGN
271
+
272
+ cls, id = $1, $2 if cls =~ /^(.*?)#(.*)$/
273
+
274
+ atts = ''
275
+ atts << " style=\"#{ style.join }\"" unless style.empty?
276
+ atts << " class=\"#{ cls }\"" unless cls.to_s.empty?
277
+ atts << " lang=\"#{ lang }\"" if lang
278
+ atts << " id=\"#{ id }\"" if id
279
+ atts << " colspan=\"#{ colspan }\"" if colspan
280
+ atts << " rowspan=\"#{ rowspan }\"" if rowspan
281
+
282
+ atts
283
+ end
284
+
285
+ def table( text )
286
+ text << "\n\n"
287
+ text.gsub!( /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)\n\n/m ) do |matches|
288
+
289
+ tatts, fullrow = $~[1..2]
290
+ tatts = pba( tatts, 'table' )
291
+ rows = []
292
+
293
+ fullrow.
294
+ split( /\|$/m ).
295
+ delete_if { |x| x.empty? }.
296
+ each do |row|
297
+
298
+ ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m
299
+
300
+ cells = []
301
+ row.split( '|' ).each do |cell|
302
+ ctyp = 'd'
303
+ ctyp = 'h' if cell =~ /^_/
304
+
305
+ catts = ''
306
+ catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. )(.*)/
307
+
308
+ unless cell.strip.empty?
309
+ cells << "\t\t\t<t#{ ctyp }#{ catts }>#{ cell }</t#{ ctyp }>"
310
+ end
311
+ end
312
+ rows << "\t\t<tr#{ ratts }>\n#{ cells.join( "\n" ) }\n\t\t</tr>"
313
+ end
314
+ "\t<table#{ tatts }>\n#{ rows.join( "\n" ) }\n\t</table>\n\n"
315
+ end
316
+ end
317
+
318
+ def lists( text )
319
+ text.gsub!( /^([#*]+?#{C} .*?)$(?![^#*])/m ) do |match|
320
+ lines = match.split( /\n/ )
321
+ last_line = -1
322
+ depth = []
323
+ lines.each_with_index do |line, line_id|
324
+ if line =~ /^([#*]+)(#{A}#{C}) (.*)$/m
325
+ tl,atts,content = $~[1..3]
326
+ if depth.last
327
+ if depth.last.length > tl.length
328
+ (depth.length - 1).downto(0) do |i|
329
+ break if depth[i].length == tl.length
330
+ lines[line_id - 1] << "\n\t\\end{#{ lT( depth[i] ) }}\n\t"
331
+ depth.pop
332
+ end
333
+ end
334
+ if !depth.last.nil? && !tl.length.nil? && depth.last.length == tl.length
335
+ lines[line_id - 1] << ''
336
+ end
337
+ end
338
+ unless depth.last == tl
339
+ depth << tl
340
+ atts = pba( atts )
341
+ lines[line_id] = "\t\\begin{#{ lT(tl) }}\n\t\\item #{ content }"
342
+ else
343
+ lines[line_id] = "\t\t\\item #{ content }"
344
+ end
345
+ last_line = line_id
346
+
347
+ elsif line =~ /^\s+\S/
348
+ last_line = line_id
349
+ elsif line_id - last_line < 2 and line =~ /^\S/
350
+ last_line = line_id
351
+ end
352
+ if line_id - last_line > 1 or line_id == lines.length - 1
353
+ depth.delete_if do |v|
354
+ lines[last_line] << "\n\t\\end{#{ lT( v ) }}"
355
+ end
356
+ end
357
+ end
358
+ lines.join( "\n" )
359
+ end
360
+ end
361
+
362
+ def lT( text )
363
+ text =~ /\#$/ ? 'enumerate' : 'itemize'
364
+ end
365
+
366
+ def fold( text )
367
+ text.gsub!( /(.+)\n(?![#*\s|])/, "\\1\\\\\\\\" )
368
+ # text.gsub!( /(.+)\n(?![#*\s|])/, "\\1#{ @fold_lines ? ' ' : '<br />' }" )
369
+ end
370
+
371
+ def block( text )
372
+ pre = false
373
+ find = ['bq','h[1-6]','fn\d+']
374
+
375
+ regexp_cue = []
376
+
377
+ lines = text.split( /\n/ ) + [' ']
378
+ new_text =
379
+ lines.collect do |line|
380
+ pre = true if line =~ /<(pre|notextile)>/i
381
+ find.each do |tag|
382
+ line.gsub!( /^(#{ tag })(#{A}#{C})\.(?::(\S+))? (.*)$/ ) do |m|
383
+ tag,atts,cite,content = $~[1..4]
384
+
385
+ atts = pba( atts )
386
+
387
+ if tag =~ /fn(\d+)/
388
+ # tag = 'p';
389
+ # atts << " id=\"fn#{ $1 }\""
390
+ regexp_cue << [ /footnote\{#{$1}}/, "footnote{#{content}}" ]
391
+ content = ""
392
+ end
393
+
394
+ if tag =~ /h([1-6])/
395
+ section_type = "sub" * [$1.to_i - 1, 2].min
396
+ start = "\t\\#{section_type}section*{"
397
+ tend = "}"
398
+ end
399
+
400
+ if tag == "bq"
401
+ cite = check_refs( cite )
402
+ cite = " cite=\"#{ cite }\"" if cite
403
+ start = "\t\\begin{quotation}\n\\noindent {\\em ";
404
+ tend = "}\n\t\\end{quotation}";
405
+ end
406
+
407
+ "#{ start }#{ content }#{ tend }"
408
+ end unless pre
409
+ end
410
+
411
+ #line.gsub!( /^(?!\t|<\/?pre|<\/?notextile|<\/?code|$| )(.*)/, "\t<p>\\1</p>" )
412
+
413
+ #line.gsub!( "<br />", "\n" ) if pre
414
+ # pre = false if line =~ /<\/(pre|notextile)>/i
415
+
416
+ line
417
+ end.join( "\n" )
418
+ text.replace( new_text )
419
+ regexp_cue.each { |pair| text.gsub!(pair.first, pair.last) }
420
+ end
421
+
422
+ def span( text )
423
+ QTAGS.each do |tt, ht|
424
+ ttr = Regexp::quote( tt )
425
+ text.gsub!(
426
+
427
+ /(^|\s|\>|[#{PUNCT}{(\[])
428
+ #{ttr}
429
+ (#{C})
430
+ (?::(\S+?))?
431
+ ([^\s#{ttr}]+?(?:[^\n]|\n(?!\n))*?)
432
+ ([#{PUNCT}]*?)
433
+ #{ttr}
434
+ (?=[\])}]|[#{PUNCT}]+?|<|\s|$)/xm
435
+
436
+ ) do |m|
437
+
438
+ start,atts,cite,content,tend = $~[1..5]
439
+ atts = pba( atts )
440
+ atts << " cite=\"#{ cite }\"" if cite
441
+
442
+ "#{ start }{\\#{ ht } #{ content }#{ tend }}"
443
+
444
+ end
445
+ end
446
+ end
447
+
448
+ def links( text )
449
+ text.gsub!( /
450
+ ([\s\[{(]|[#{PUNCT}])? # $pre
451
+ " # start
452
+ (#{C}) # $atts
453
+ ([^"]+?) # $text
454
+ \s?
455
+ (?:\(([^)]+?)\)(?="))? # $title
456
+ ":
457
+ (\S+?) # $url
458
+ (\/)? # $slash
459
+ ([^\w\/;]*?) # $post
460
+ (?=\s|$)
461
+ /x ) do |m|
462
+ pre,atts,text,title,url,slash,post = $~[1..7]
463
+
464
+ url.gsub!(/(\\)(.)/, '\2')
465
+ url = check_refs( url )
466
+
467
+ atts = pba( atts )
468
+ atts << " title=\"#{ title }\"" if title
469
+ atts = shelve( atts ) if atts
470
+
471
+ "#{ pre }\\textit{#{ text }} \\footnote{\\texttt{\\textless #{ url }#{ slash }" +
472
+ "\\textgreater}#{ post }}"
473
+ end
474
+ end
475
+
476
+ def get_refs( text )
477
+ text.gsub!( /(^|\s)\[(.+?)\]((?:http:\/\/|javascript:|ftp:\/\/|\/)\S+?)(?=\s|$)/ ) do |m|
478
+ flag, url = $~[1..2]
479
+ @urlrefs[flag] = url
480
+ end
481
+ end
482
+
483
+ def check_refs( text )
484
+ @urlrefs[text] || text
485
+ end
486
+
487
+ def image( text )
488
+ text.gsub!( /
489
+ \! # opening
490
+ (\<|\=|\>)? # optional alignment atts
491
+ (#{C}) # optional style,class atts
492
+ (?:\. )? # optional dot-space
493
+ ([^\s(!]+?) # presume this is the src
494
+ \s? # optional space
495
+ (?:\(((?:[^\(\)]|\([^\)]+\))+?)\))? # optional title
496
+ \! # closing
497
+ (?::#{ HYPERLINK })? # optional href
498
+ /x ) do |m|
499
+ algn,atts,url,title,href,href_a1,href_a2 = $~[1..7]
500
+ atts = pba( atts )
501
+ atts << " align=\"#{ i_align( algn ) }\"" if algn
502
+ atts << " title=\"#{ title }\"" if title
503
+ atts << " alt=\"#{ title }\""
504
+ # size = @getimagesize($url);
505
+ # if($size) $atts.= " $size[3]";
506
+
507
+ href = check_refs( href ) if href
508
+ url = check_refs( url )
509
+
510
+ out = ''
511
+ out << "<a href=\"#{ href }\">" if href
512
+ out << "<img src=\"#{ url }\"#{ atts } />"
513
+ out << "</a>#{ href_a1 }#{ href_a2 }" if href
514
+
515
+ out
516
+ end
517
+ end
518
+
519
+ def code( text )
520
+ text.gsub!( /
521
+ (?:^|([\s\(\[{])) # 1 open bracket?
522
+ @ # opening
523
+ (?:\|(\w+?)\|)? # 2 language
524
+ (\S(?:[^\n]|\n(?!\n))*?) # 3 code
525
+ @ # closing
526
+ (?:$|([\]})])|
527
+ (?=[#{PUNCT}]{1,2}|
528
+ \s)) # 4 closing bracket?
529
+ /x ) do |m|
530
+ before,lang,code,after = $~[1..4]
531
+ lang = " language=\"#{ lang }\"" if lang
532
+ "#{ before }<code#{ lang }>#{ code }</code>#{ after }"
533
+ end
534
+ end
535
+
536
+ def shelve( val )
537
+ @shelf << val
538
+ " <#{ @shelf.length }>"
539
+ end
540
+
541
+ def retrieve( text )
542
+ @shelf.each_with_index do |r, i|
543
+ text.gsub!( " <#{ i + 1 }>", r )
544
+ end
545
+ end
546
+
547
+ def incoming_entities( text )
548
+ ## turn any incoming ampersands into a dummy character for now.
549
+ ## This uses a negative lookahead for alphanumerics followed by a semicolon,
550
+ ## implying an incoming html entity, to be skipped
551
+
552
+ text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" )
553
+ end
554
+
555
+ def encode_entities( text )
556
+ ## Convert high and low ascii to entities.
557
+ # if $-K == "UTF-8"
558
+ # encode_high( text )
559
+ # else
560
+ text.texesc!( :NoQuotes )
561
+ # end
562
+ end
563
+
564
+ def fix_entities( text )
565
+ ## de-entify any remaining angle brackets or ampersands
566
+ text.gsub!( "\&", "&" )
567
+ text.gsub!( "\%", "%" )
568
+ end
569
+
570
+ def clean_white_space( text )
571
+ text.gsub!( /\r\n/, "\n" )
572
+ text.gsub!( /\t/, '' )
573
+ text.gsub!( /\n{3,}/, "\n\n" )
574
+ text.gsub!( /\n *\n/, "\n\n" )
575
+ text.gsub!( /"$/, "\" " )
576
+ end
577
+
578
+ def no_textile( text )
579
+ text.gsub!( /(^|\s)==(.*?)==(\s|$)?/,
580
+ '\1<notextile>\2</notextile>\3' )
581
+ end
582
+
583
+ def footnote_ref( text )
584
+ text.gsub!( /\[([0-9]+?)\](\s)?/,
585
+ '\footnote{\1}\2')
586
+ #'<sup><a href="#fn\1">\1</a></sup>\2' )
587
+ end
588
+
589
+ def inline( text )
590
+ image text
591
+ links text
592
+ code text
593
+ span text
594
+ end
595
+
596
+ def glyphs_deep( text )
597
+ codepre = 0
598
+ offtags = /(?:code|pre|kbd|notextile)/
599
+ if text !~ /<.*>/
600
+ # pgl text
601
+ footnote_ref text
602
+ else
603
+ used_offtags = {}
604
+ text.gsub!( /(?:[^<].*?(?=<[^\n]*?>|$)|<[^\n]*?>+)/m ) do |line|
605
+ tagline = ( line =~ /^<.*>/ )
606
+
607
+ ## matches are off if we're between <code>, <pre> etc.
608
+ if tagline
609
+ if line =~ /<(#{ offtags })>/i
610
+ codepre += 1
611
+ used_offtags[$1] = true
612
+ line.texesc!( :NoQuotes ) if codepre - used_offtags.length > 0
613
+ elsif line =~ /<\/(#{ offtags })>/i
614
+ line.texesc!( :NoQuotes ) if codepre - used_offtags.length > 0
615
+ codepre -= 1 unless codepre.zero?
616
+ used_offtags = {} if codepre.zero?
617
+ elsif @filter_html or codepre > 0
618
+ line.texesc!( :NoQuotes )
619
+ ## line.gsub!( /&lt;(\/?#{ offtags })&gt;/, '<\1>' )
620
+ end
621
+ ## do htmlspecial if between <code>
622
+ elsif codepre > 0
623
+ line.texesc!( :NoQuotes )
624
+ ## line.gsub!( /&lt;(\/?#{ offtags })&gt;/, '<\1>' )
625
+ elsif not tagline
626
+ inline line
627
+ glyphs_deep line
628
+ end
629
+
630
+ line
631
+ end
632
+ end
633
+ end
634
+
635
+ def glyphs( text )
636
+ text.gsub!( /"\z/, "\" " )
637
+ ## if no html, do a simple search and replace...
638
+ if text !~ /<.*>/
639
+ inline text
640
+ end
641
+ glyphs_deep text
642
+ end
643
+
644
+ def i_align( text )
645
+ I_ALGN_VALS[text]
646
+ end
647
+
648
+ def h_align( text )
649
+ H_ALGN_VALS[text]
650
+ end
651
+
652
+ def v_align( text )
653
+ V_ALGN_VALS[text]
654
+ end
655
+
656
+ def encode_high( text )
657
+ ## mb_encode_numericentity($text, $cmap, $charset);
658
+ end
659
+
660
+ def decode_high( text )
661
+ ## mb_decode_numericentity($text, $cmap, $charset);
662
+ end
663
+
664
+ def textile_popup_help( name, helpvar, windowW, windowH )
665
+ ' <a target="_blank" href="http://www.textpattern.com/help/?item=' + helpvar + '" onclick="window.open(this.href, \'popupwindow\', \'width=' + windowW + ',height=' + windowH + ',scrollbars,resizable\'); return false;">' + name + '</a><br />'
666
+ end
667
+
668
+ CMAP = [
669
+ 160, 255, 0, 0xffff,
670
+ 402, 402, 0, 0xffff,
671
+ 913, 929, 0, 0xffff,
672
+ 931, 937, 0, 0xffff,
673
+ 945, 969, 0, 0xffff,
674
+ 977, 978, 0, 0xffff,
675
+ 982, 982, 0, 0xffff,
676
+ 8226, 8226, 0, 0xffff,
677
+ 8230, 8230, 0, 0xffff,
678
+ 8242, 8243, 0, 0xffff,
679
+ 8254, 8254, 0, 0xffff,
680
+ 8260, 8260, 0, 0xffff,
681
+ 8465, 8465, 0, 0xffff,
682
+ 8472, 8472, 0, 0xffff,
683
+ 8476, 8476, 0, 0xffff,
684
+ 8482, 8482, 0, 0xffff,
685
+ 8501, 8501, 0, 0xffff,
686
+ 8592, 8596, 0, 0xffff,
687
+ 8629, 8629, 0, 0xffff,
688
+ 8656, 8660, 0, 0xffff,
689
+ 8704, 8704, 0, 0xffff,
690
+ 8706, 8707, 0, 0xffff,
691
+ 8709, 8709, 0, 0xffff,
692
+ 8711, 8713, 0, 0xffff,
693
+ 8715, 8715, 0, 0xffff,
694
+ 8719, 8719, 0, 0xffff,
695
+ 8721, 8722, 0, 0xffff,
696
+ 8727, 8727, 0, 0xffff,
697
+ 8730, 8730, 0, 0xffff,
698
+ 8733, 8734, 0, 0xffff,
699
+ 8736, 8736, 0, 0xffff,
700
+ 8743, 8747, 0, 0xffff,
701
+ 8756, 8756, 0, 0xffff,
702
+ 8764, 8764, 0, 0xffff,
703
+ 8773, 8773, 0, 0xffff,
704
+ 8776, 8776, 0, 0xffff,
705
+ 8800, 8801, 0, 0xffff,
706
+ 8804, 8805, 0, 0xffff,
707
+ 8834, 8836, 0, 0xffff,
708
+ 8838, 8839, 0, 0xffff,
709
+ 8853, 8853, 0, 0xffff,
710
+ 8855, 8855, 0, 0xffff,
711
+ 8869, 8869, 0, 0xffff,
712
+ 8901, 8901, 0, 0xffff,
713
+ 8968, 8971, 0, 0xffff,
714
+ 9001, 9002, 0, 0xffff,
715
+ 9674, 9674, 0, 0xffff,
716
+ 9824, 9824, 0, 0xffff,
717
+ 9827, 9827, 0, 0xffff,
718
+ 9829, 9830, 0, 0xffff,
719
+ 338, 339, 0, 0xffff,
720
+ 352, 353, 0, 0xffff,
721
+ 376, 376, 0, 0xffff,
722
+ 710, 710, 0, 0xffff,
723
+ 732, 732, 0, 0xffff,
724
+ 8194, 8195, 0, 0xffff,
725
+ 8201, 8201, 0, 0xffff,
726
+ 8204, 8207, 0, 0xffff,
727
+ 8211, 8212, 0, 0xffff,
728
+ 8216, 8218, 0, 0xffff,
729
+ 8218, 8218, 0, 0xffff,
730
+ 8220, 8222, 0, 0xffff,
731
+ 8224, 8225, 0, 0xffff,
732
+ 8240, 8240, 0, 0xffff,
733
+ 8249, 8250, 0, 0xffff,
734
+ 8364, 8364, 0, 0xffff
735
+ ]
736
+ end