Commit f54fa6c18a8530a66f5c4cf2ceed27c9c17a17b8

Authored by JoenioCosta
1 parent cc17d60a

ActionItem192: rewritten filter with an modified version of xss_terminate

git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@1717 3f533792-8f58-4932-b0fe-aaf55b0a4547
Showing 37 changed files with 2881 additions and 92 deletions   Show diff stats
app/controllers/application.rb
... ... @@ -45,9 +45,6 @@ class ApplicationController < ActionController::Base
45 45 verify :method => :post, :only => actions, :redirect_to => redirect
46 46 end
47 47  
48   - # to sanitize params[...] add method sanitize to controller
49   - before_filter :sanitize
50   -
51 48 protected
52 49  
53 50 # TODO: move this logic somewhere else (Domain class?)
... ... @@ -120,10 +117,4 @@ class ApplicationController < ActionController::Base
120 117 end
121 118 end
122 119  
123   - private
124   -
125   - def sanitize
126   - # dont sanitize anything for default
127   - end
128   -
129 120 end
... ...
app/controllers/my_profile/consumed_products_controller.rb
... ... @@ -30,14 +30,4 @@ class ConsumedProductsController < ApplicationController
30 30 redirect_back_or_default :action => 'index'
31 31 end
32 32  
33   - private
34   -
35   - require 'erb'
36   - include ERB::Util
37   - def sanitize
38   - if params[:consumption]
39   - params[:consumption][:aditional_specifications] = html_escape(params[:consumption][:aditional_specifications]) if params[:consumption][:aditional_specifications]
40   - end
41   - end
42   -
43 33 end
... ...
app/controllers/my_profile/enterprise_validation_controller.rb
... ... @@ -60,15 +60,4 @@ class EnterpriseValidationController < MyProfileController
60 60 end
61 61 end
62 62  
63   - private
64   -
65   - require 'erb'
66   - include ERB::Util
67   - def sanitize
68   - if params[:info]
69   - params[:info][:validation_methodology] = html_escape(params[:info][:validation_methodology]) if params[:info][:validation_methodology]
70   - params[:info][:restrictions] = html_escape(params[:info][:restrictions]) if params[:info][:restrictions]
71   - end
72   - end
73   -
74 63 end
... ...
app/controllers/my_profile/manage_products_controller.rb
... ... @@ -56,16 +56,5 @@ class ManageProductsController < ApplicationController
56 56 @categories = @current_category.children
57 57 render :partial => 'subcategories'
58 58 end
59   -
60   - private
61   -
62   - require 'erb'
63   - include ERB::Util
64   - def sanitize
65   - if params[:product]
66   - params[:product][:name] = html_escape(params[:product][:name]) if params[:product][:name]
67   - params[:product][:description] = html_escape(params[:product][:description]) if params[:product][:description]
68   - end
69   - end
70 59  
71 60 end
... ...
app/controllers/my_profile/memberships_controller.rb
... ... @@ -24,15 +24,4 @@ class MembershipsController < MyProfileController
24 24 end
25 25 end
26 26  
27   - private
28   -
29   - require 'erb'
30   - include ERB::Util
31   - def sanitize
32   - if params[:community]
33   - params[:community][:name] = html_escape(params[:community][:name]) if params[:community][:name]
34   - params[:community][:description] = html_escape(params[:community][:description]) if params[:community][:description]
35   - end
36   - end
37   -
38 27 end
... ...
app/controllers/my_profile/profile_editor_controller.rb
... ... @@ -42,20 +42,5 @@ class ProfileEditorController < MyProfileController
42 42 end
43 43 end
44 44  
45   - private
46   -
47   - require 'erb'
48   - include ERB::Util
49   - def sanitize
50   - if params[:info]
51   - params[:info][:name] = html_escape(params[:info][:name]) if params[:info][:name]
52   - params[:info][:contact_person] = html_escape(params[:info][:contact_person]) if params[:info][:contact_person]
53   - params[:info][:acronym] = html_escape(params[:info][:acronym]) if params[:info][:acronym]
54   - params[:info][:legal_form] = html_escape(params[:info][:legal_form]) if params[:info][:legal_form]
55   - params[:info][:economic_activity] = html_escape(params[:info][:economic_activity]) if params[:info][:economic_activity]
56   - params[:info][:management_information] = html_escape(params[:info][:management_information]) if params[:info][:management_information]
57   - end
58   - end
59   -
60 45 end
61 46  
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -67,15 +67,4 @@ class ContentViewerController < PublicController
67 67 redirect_to :action => 'view_page'
68 68 end
69 69  
70   - private
71   -
72   - require 'erb'
73   - include ERB::Util
74   - def sanitize
75   - if params[:comment]
76   - params[:comment][:body] = html_escape(params[:comment][:body]) if params[:comment][:body]
77   - params[:comment][:title] = html_escape(params[:comment][:title]) if params[:comment][:title]
78   - end
79   - end
80   -
81 70 end
... ...
app/controllers/public/enterprise_registration_controller.rb
... ... @@ -51,16 +51,4 @@ class EnterpriseRegistrationController < ApplicationController
51 51 @create_enterprise.save!
52 52 end
53 53  
54   - private
55   -
56   - require 'erb'
57   - include ERB::Util
58   - def sanitize
59   - if params[:create_enterprise]
60   - %w[name address contact_phone contact_person acronym foundation_year legal_form economic_activity management_information].each{ |i|
61   - params[:create_enterprise][i] = html_escape(params[:create_enterprise][i]) if params[:create_enterprise][i]
62   - }
63   - end
64   - end
65   -
66 54 end
... ...
app/models/comment.rb
... ... @@ -19,6 +19,8 @@ class Comment < ActiveRecord::Base
19 19 end
20 20 end
21 21  
  22 + xss_terminate :only => [ :body, :title ]
  23 +
22 24 def author_name
23 25 if author
24 26 author.name
... ...
app/models/community.rb
... ... @@ -3,6 +3,8 @@ class Community < Organization
3 3  
4 4 settings_items :description
5 5  
  6 + xss_terminate :only => [ :description ]
  7 +
6 8 def name=(value)
7 9 super(value)
8 10 self.identifier = value.to_slug
... ...
app/models/consumption.rb
... ... @@ -3,4 +3,7 @@ class Consumption < ActiveRecord::Base
3 3 belongs_to :product_category
4 4  
5 5 validates_uniqueness_of :product_category_id, :scope => :profile_id
  6 +
  7 + xss_terminate :only => [ :aditional_specifications ]
  8 +
6 9 end
... ...
app/models/create_enterprise.rb
... ... @@ -40,6 +40,8 @@ class CreateEnterprise < Task
40 40 # check for explanation when rejecting
41 41 validates_presence_of :reject_explanation, :if => (lambda { |record| record.status == Task::Status::CANCELLED } )
42 42  
  43 + xss_terminate :only => [ :acronym, :address, :contact_person, :contact_phone, :economic_activity, :foundation_year, :legal_form, :management_information, :name ], :on => 'validation'
  44 +
43 45 def validate
44 46 if self.region && self.target
45 47 unless self.region.validators.include?(self.target)
... ...
app/models/enterprise.rb
1 1 # An enterprise is a kind of organization. According to the system concept,
2 2 # only enterprises can offer products and services.
3 3 class Enterprise < Organization
  4 +
4 5 N_('Enterprise')
5 6  
6 7 has_many :products, :dependent => :destroy
7   -
  8 +
8 9 end
... ...
app/models/organization_info.rb
... ... @@ -4,6 +4,10 @@ class OrganizationInfo &lt; ActiveRecord::Base
4 4 validates_numericality_of :foundation_year, :only_integer => true, :allow_nil => true
5 5  
6 6 validates_format_of :contact_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |info| ! info.contact_email.nil? })
  7 +
  8 + xss_terminate :only => [ :acronym, :contact_person, :contact_email, :foundation_year, :legal_form, :economic_activity, :management_information ]
  9 +
  10 + #xss_terminate :only => [ :acronym, :contact_person, :contact_phone, :economic_activity, :foundation_year, :legal_form, :management_information, :address, :name ]
7 11  
8 12 def summary
9 13 # FIXME diplays too few fields
... ...
app/models/person_info.rb
... ... @@ -2,6 +2,8 @@ class PersonInfo &lt; ActiveRecord::Base
2 2  
3 3 belongs_to :person
4 4  
  5 + xss_terminate :only => [ :name ]
  6 +
5 7 def summary
6 8 ['name', 'contact_information', 'sex', 'birth_date', 'address', 'city', 'state', 'country'].map do |col|
7 9 [ PersonInfo.columns_hash[col] && PersonInfo.columns_hash[col].human_name, self.send(col) ]
... ...
app/models/product.rb
... ... @@ -11,6 +11,8 @@ class Product &lt; ActiveRecord::Base
11 11 after_update :save_image
12 12  
13 13 acts_as_searchable :fields => [ :name, :description, :category_full_name ]
  14 +
  15 + xss_terminate :only => [ :name, :description ]
14 16  
15 17 def category_full_name
16 18 product_category.full_name(" ")
... ...
app/models/profile.rb
... ... @@ -117,6 +117,8 @@ class Profile &lt; ActiveRecord::Base
117 117 true
118 118 end
119 119  
  120 + xss_terminate :only => [ :address, :contact_phone ]
  121 +
120 122 # Returns information about the profile's owner that was made public by
121 123 # him/her.
122 124 #
... ...
app/models/validation_info.rb
... ... @@ -2,4 +2,6 @@ class ValidationInfo &lt; ActiveRecord::Base
2 2 validates_presence_of :validation_methodology
3 3  
4 4 belongs_to :organization
  5 +
  6 + xss_terminate :only => [ :validation_methodology, :restrictions ]
5 7 end
... ...
test/functional/enterprise_validation_test.rb
... ... @@ -135,7 +135,7 @@ class EnterpriseValidationControllerTest &lt; Test::Unit::TestCase
135 135 assert_sanitized assigns(:info).validation_methodology
136 136 end
137 137  
138   - should 'filter html from restriction of the validation info' do
  138 + should 'filter html from restrictions of the validation info' do
139 139 info = ValidationInfo.new(:validation_methodology => 'none')
140 140 @org.expects(:validation_info).returns(info)
141 141 post :edit_validation_info, :profile => 'myorg', :info => {:restrictions => 'new <b>methodology</b>'}
... ...
vendor/plugins/xss_terminate/MIT-LICENSE 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +Copyright (c) 2008 Luke Francl
  2 +
  3 +Permission is hereby granted, free of charge, to any person obtaining
  4 +a copy of this software and associated documentation files (the
  5 +"Software"), to deal in the Software without restriction, including
  6 +without limitation the rights to use, copy, modify, merge, publish,
  7 +distribute, sublicense, and/or sell copies of the Software, and to
  8 +permit persons to whom the Software is furnished to do so, subject to
  9 +the following conditions:
  10 +
  11 +The above copyright notice and this permission notice shall be
  12 +included in all copies or substantial portions of the Software.
  13 +
  14 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
... ...
vendor/plugins/xss_terminate/README 0 → 100644
... ... @@ -0,0 +1,118 @@
  1 += xss_terminate
  2 +
  3 +*this version is changed by joenio and should be re-documented*
  4 +
  5 ++xss_terminate+ is a plugin in that makes stripping and sanitizing HTML
  6 +stupid-simple. Install and forget. And forget about forgetting to <tt>h()</tt>
  7 +your output, because you won't need to anymore.
  8 +
  9 +But +xss_terminate+ is also flexible. By default, it will strip all HTML tags
  10 +from user input. This is usually what you want, but sometimes you need users to be
  11 +able to enter HTML. The plugin allows you remove bad HTML with your choice
  12 +of two whitelist-based sanitizers, or to skip HTML sanitization entirely on
  13 +a per-field basis.
  14 +
  15 +To install, do:
  16 +
  17 + script/plugin install http://xssterminate.googlecode.com/svn/trunk/xss_terminate
  18 +
  19 +== HTML sanitization
  20 +
  21 +A note on your choices.
  22 +
  23 +* Strip tags: removes all HTML using Rails's built-in +strip_tags+ method. Tags are removed, but their content is not.
  24 +* Rails sanitization: Removes bad HTML with Rails's built-in sanitize method. Bad tags are removed completely, including their content.
  25 +* HTML5lib sanitization: Removes bad HTML after parsing it with {HTML5lib}[http://code.google.com/p/html5lib/], a library that parses HTML like browsers do. It should be very tolerant of invalid HTML. Bad tags are escaped, not removed.
  26 +* Do nothing. You can chose not to process given fields.
  27 +
  28 +== Usage
  29 +
  30 +Installing the plugin creates a +before_save+ hook that will strip HTML tags
  31 +from all string and text fields. No further configuration is necessary if this
  32 +is what you want. To customize the behavior, you use the +xss_terminate+ class
  33 +method.
  34 +
  35 +To exempt some fields from sanitization, use the <tt>:except</tt> option
  36 +with a list of fields not to process:
  37 +
  38 + class Comment < ActiveRecord::Base
  39 + xss_terminate :except => [ :body ]
  40 + end
  41 +
  42 +To sanitize only fields, use the <tt>:only</tt> option:
  43 +
  44 + class Person < ActiveRecord::Base
  45 + xss_sanitize :only => [ :email, :name ]
  46 + end
  47 +
  48 +
  49 +By default sanitization use HTML sanitize Rails's built-in, to use other add <tt>:with</tt> option.
  50 +
  51 +To sanitize using Rails white list use:
  52 +
  53 + class Review < ActiveRecord::Base
  54 + xss_sanitize :only => [ :body, :author_name ], :with => 'white_list'
  55 + end
  56 +
  57 +To sanitize HTML with {HTML5Lib}[http://code.google.com/p/html5lib/]
  58 +(<tt>gem install html5</tt> to get it), use the <tt>:with => 'html5lib'</tt> option:
  59 +
  60 + class Entry < ActiveRecord::Base
  61 + xss_terminate :only => [ :body, :author_name ], :with => 'html5lib'
  62 + end
  63 +
  64 +You can redefine when sanitize/filter will be executed with option <tt>:on</tt>. By default
  65 +sanitization is on before_save, but if you need to sanitize on before_validation use:
  66 +
  67 + class Message < ActiveRecord::Base
  68 + xss_terminate :executed => [ :body ], :on => 'validation'
  69 + end
  70 +
  71 +== Configuration
  72 +
  73 +By default all fields in all models will be sanitized after install this plugin.
  74 +
  75 +To change it add in our environment.rb:
  76 +
  77 + XssTerminate.sanitize_by_default = false
  78 +
  79 +== Sanitizing existing records (FIXME tests this)
  80 +
  81 +After installing +xss_terminate+ and configuring it to your liking, you can
  82 +run <tt>rake xss_terminate MODELS=Foo,Bar,Baz</tt> to execute it against your
  83 +existing records. This will load each model found and save it again to invoke
  84 +the before_save hook.
  85 +
  86 +== Unique features
  87 +
  88 ++xss_terminate+ is based on +acts_as_sanitized+. Here is what's different:
  89 +
  90 +* Rails 2.0-ready.
  91 +* Automatic. It is included with default options in <tt>ActiveReord::Base</tt> so all your models are sanitized.
  92 +* It works with migrations. Columns are fetched when model is saved, not when the class is loaded.
  93 +* You can decide whether to sanitize or strip tags on a field-by-field basis instead of model-by-model.
  94 +* HTML5lib support.
  95 +
  96 +== TODO
  97 +
  98 +* Performance tests
  99 +* Test suites with "real world" HTML
  100 +* Test/make work with Rails 1.2.x (Rails 1.2 sanitization is crap, so you'd want to use HTML5lib)
  101 +* Add Tests to HTML5lib to new API (changed by joenio)
  102 +* Add tests to new API
  103 +* Adapt to keep compatibility with old API
  104 +* Create tests to serializable fields
  105 +* Document new API and changes
  106 +* Create and send path to author
  107 +
  108 +== Credits
  109 +
  110 +Written by {Luke Francl}[http://railspikes.com] and based on acts_as_sanitized by
  111 +{Alex Payne}[http://www.al3x.net].
  112 +
  113 +HTML5Lib sanitization by {Jacques Distler}[http://golem.ph.utexas.edu/~distler].
  114 +
  115 +== License
  116 +
  117 +MIT License, except for lib/html5lib_sanitize.rb which is under the
  118 +Ruby license and copyright to Jacques Distler.
... ...
vendor/plugins/xss_terminate/Rakefile 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +require 'rake'
  2 +require 'rake/testtask'
  3 +require 'rake/rdoctask'
  4 +
  5 +desc 'Default: run unit tests.'
  6 +task :default => :test
  7 +
  8 +desc 'Test the xss_terminate plugin.'
  9 +Rake::TestTask.new(:test) do |t|
  10 + t.libs << 'lib'
  11 + t.pattern = 'test/**/*_test.rb'
  12 + t.verbose = true
  13 +end
  14 +
  15 +desc 'Generate documentation for the xss_terminate plugin.'
  16 +Rake::RDocTask.new(:rdoc) do |rdoc|
  17 + rdoc.rdoc_dir = 'rdoc'
  18 + rdoc.title = 'xss_terminate'
  19 + rdoc.options << '--line-numbers' << '--inline-source'
  20 + rdoc.rdoc_files.include('README')
  21 + rdoc.rdoc_files.include('lib/**/*.rb')
  22 +end
... ...
vendor/plugins/xss_terminate/init.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +ActiveRecord::Base.send(:include, XssTerminate)
... ...
vendor/plugins/xss_terminate/install.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +# Install hook code here
... ...
vendor/plugins/xss_terminate/lib/html5lib_sanitize.rb 0 → 100644
... ... @@ -0,0 +1,2454 @@
  1 +# == Introduction
  2 +#
  3 +# This module provides sanitization of XHTML+MathML+SVG
  4 +# and of inline style attributes. Its genesis is {described here}[http://golem.ph.utexas.edu/~distler/blog/archives/001181.html].
  5 +#
  6 +# Uses the {HTML5lib parser}[http://code.google.com/p/html5lib/], so that the parsing behaviour should
  7 +# resemble that of browsers.
  8 +#
  9 +# sanitize_xhtml() is a case-sensitive sanitizer, suitable for XHTML
  10 +# sanitize_html() is a case-insensitive sanitizer suitable for HTML
  11 +# sanitize_rexml() sanitizes a REXML tree, returning a string
  12 +#
  13 +# == Files
  14 +#
  15 +# {sanitize.rb}[http://golem.ph.utexas.edu/~distler/code/instiki/svn/lib/sanitize.rb],
  16 +# {HTML5lib}[http://golem.ph.utexas.edu/~distler/code/instiki/svn/vendor/plugins/HTML5lib/]
  17 +#
  18 +# == Author
  19 +#
  20 +# {Jacques Distler}[http://golem.ph.utexas.edu/~distler/]
  21 +#
  22 +# == License
  23 +#
  24 +# Ruby License
  25 +
  26 +class HTML5libSanitize
  27 +
  28 + require 'html5/html5parser'
  29 + require 'html5/liberalxmlparser'
  30 + require 'html5/treewalkers'
  31 + require 'html5/treebuilders'
  32 + require 'html5/serializer'
  33 + require 'html5/sanitizer'
  34 +
  35 + include HTML5
  36 +
  37 +# Sanitize a string, parsed using XHTML parsing rules.
  38 +#
  39 +# :call-seq:
  40 +# sanitize_xhtml(string) -> string
  41 +# sanitize_xhtml(string, {:encoding => 'iso-8859-1', :to_tree => true}) -> REXML::Document
  42 +#
  43 +# Unless otherwise specified, the string is assumed to be utf-8 encoded.
  44 +# By default, the output is a string. But, optionally, you can return a REXML tree.
  45 +#
  46 +# The string returned is utf-8 encoded. If you want, you can use iconv to convert it to some other encoding.
  47 +# (REXML trees are always utf-8 encoded.)
  48 + def sanitize_xhtml(html, options = {})
  49 + @encoding = 'utf-8'
  50 + @treebuilder = TreeBuilders::REXML::TreeBuilder
  51 + @to_tree = false
  52 + options.each do |name, value|
  53 + next unless %w(encoding treebuilder to_tree).include? name.to_s
  54 + if name.to_s == 'treebuilder'
  55 + @treebuilder = HTML5lib::TreeBuilders.get_tree_builder(value)
  56 + else
  57 + instance_variable_set("@#{name}", value)
  58 + end
  59 + end
  60 + if @encoding == 'utf-8'
  61 + parsed = XHTMLParser.parse_fragment(html.to_utf8, {:tokenizer => HTMLSanitizer,
  62 + :lowercase_element_name => false, :lowercase_attr_name => false,
  63 + :encoding => @encoding, :tree => @treebuilder })
  64 + else
  65 + parsed = XHTMLParser.parse_fragment(html.to_ncr, {:tokenizer => HTMLSanitizer,
  66 + :lowercase_element_name => false, :lowercase_attr_name => false,
  67 + :encoding => @encoding, :tree => @treebuilder })
  68 + end
  69 + return parsed if @to_tree
  70 + return parsed.to_s
  71 + end
  72 +
  73 +# Sanitize a string, parsed using HTML parsing rules.
  74 +#
  75 +# :call-seq:
  76 +# sanitize_html( string ) -> string
  77 +# sanitize_html( string, {:encoding => 'iso-8859-1', :to_tree => true} ) -> REXML::Document
  78 +#
  79 +# Unless otherwise specified, the string is assumed to be utf-8 encoded.
  80 +# By default, the output is a string. But, optionally, you can return a REXML tree.
  81 +#
  82 +# The string returned is utf-8 encoded. If you want, you can use iconv to convert it to some other encoding.
  83 +# (REXML trees are always utf-8 encoded.)
  84 + alias :sanitize :sanitize_html
  85 + def sanitize_html(html, options = {})
  86 + @encoding = 'utf-8'
  87 + @treebuilder = TreeBuilders::REXML::TreeBuilder
  88 + @to_tree = false
  89 + options.each do |name, value|
  90 + next unless %w(encoding treebuilder to_tree).include? name.to_s
  91 + if name.to_s == 'treebuilder'
  92 + @treebuilder = HTML5lib::TreeBuilders.get_tree_builder(value)
  93 + else
  94 + instance_variable_set("@#{name}", value)
  95 + end
  96 + end
  97 + if @encoding == 'utf-8'
  98 + parsed = HTMLParser.parse_fragment(html.to_utf8, {:tokenizer => HTMLSanitizer,
  99 + :encoding => @encoding, :tree => @treebuilder })
  100 + else
  101 + parsed = HTMLParser.parse_fragment(html.to_ncr, {:tokenizer => HTMLSanitizer,
  102 + :encoding => @encoding, :tree => @treebuilder })
  103 + end
  104 + return parsed if @to_tree
  105 + return parsed.to_s
  106 + end
  107 +
  108 +# Sanitize a REXML tree. The output is a string.
  109 +#
  110 +# :call-seq:
  111 +# sanitize_rexml(tree) -> string
  112 +#
  113 + def sanitize_rexml(tree)
  114 + tokens = TreeWalkers.get_tree_walker('rexml2').new(tree)
  115 + XHTMLSerializer.serialize(tokens, {:encoding=>'utf-8',
  116 + :space_before_trailing_solidus => true,
  117 + :inject_meta_charset => false,
  118 + :sanitize => true})
  119 + end
  120 +end
  121 +
  122 +# Some useful additions to the String class
  123 +
  124 +class String
  125 +
  126 +# Check whether a string is valid utf-8
  127 +#
  128 +# :call-seq:
  129 +# string.is_utf8? -> boolean
  130 +#
  131 +# returns true if the sequence of bytes in string is valid utf-8
  132 +#--
  133 + def is_utf8?
  134 + #expand NCRs to utf-8
  135 + text = self.gsub(/&#x([a-fA-F0-9]+);/) {|m| [$1.hex].pack('U*') }
  136 + text.gsub!(/&#(\d+);/) {|m| [$1.to_i].pack('U*') }
  137 + #ensure the resulting string of bytes is valid utf-8
  138 + text =~ /\A(
  139 + [\x09\x0A\x0D\x20-\x7E] # ASCII
  140 + | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
  141 + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
  142 + | [\xE1-\xEC\xEE][\x80-\xBF]{2} # straight 3-byte
  143 + | \xEF[\x80-\xBE]{2} #
  144 + | \xEF\xBF[\x80-\xBD] # excluding U+fffe and U+ffff
  145 + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
  146 + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
  147 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
  148 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
  149 + )*\Z/x;
  150 + end
  151 +#++
  152 +
  153 +#:stopdoc:
  154 + MATHML_ENTITIES = {
  155 + 'Alpha' => '&#x0391;',
  156 + 'Beta' => '&#x0392;',
  157 + 'Epsilon' => '&#x0395;',
  158 + 'Zeta' => '&#x0396;',
  159 + 'Eta' => '&#x0397;',
  160 + 'Iota' => '&#x0399;',
  161 + 'Kappa' => '&#x039A;',
  162 + 'Mu' => '&#x039C;',
  163 + 'Nu' => '&#x039D;',
  164 + 'Omicron' => '&#x039F;',
  165 + 'Rho' => '&#x03A1;',
  166 + 'Tau' => '&#x03A4;',
  167 + 'Chi' => '&#x03A7;',
  168 + 'epsilon' => '&#x03B5;',
  169 + 'zeta' => '&#x03B6;',
  170 + 'omicron' => '&#x03BF;',
  171 + 'sigmaf' => '&#x03C2;',
  172 + 'thetasym' => '&#x03D1;',
  173 + 'upsih' => '&#x03D2;',
  174 + 'oline' => '&#x203E;',
  175 + 'frasl' => '&#x2044;',
  176 + 'alefsym' => '&#x2135;',
  177 + 'crarr' => '&#x21B5;',
  178 + 'empty' => '&#x2205;',
  179 + 'amp' => '&#x0026;',
  180 + 'lt' => '&#x003C;',
  181 + 'zwnj' => '&#x200C;',
  182 + 'zwj' => '&#x200D;',
  183 + 'lrm' => '&#x200E;',
  184 + 'rlm' => '&#x200F;',
  185 + 'sbquo' => '&#x201A;',
  186 + 'bdquo' => '&#x201E;',
  187 + 'lsaquo' => '&#x2039;',
  188 + 'rsaquo' => '&#x203A;',
  189 + 'euro' => '&#x20AC;',
  190 + 'angzarr' => '&#x0237C;',
  191 + 'cirmid' => '&#x02AEF;',
  192 + 'cudarrl' => '&#x02938;',
  193 + 'cudarrr' => '&#x02935;',
  194 + 'cularr' => '&#x021B6;',
  195 + 'cularrp' => '&#x0293D;',
  196 + 'curarr' => '&#x021B7;',
  197 + 'curarrm' => '&#x0293C;',
  198 + 'Darr' => '&#x021A1;',
  199 + 'dArr' => '&#x021D3;',
  200 + 'ddarr' => '&#x021CA;',
  201 + 'DDotrahd' => '&#x02911;',
  202 + 'dfisht' => '&#x0297F;',
  203 + 'dHar' => '&#x02965;',
  204 + 'dharl' => '&#x021C3;',
  205 + 'dharr' => '&#x021C2;',
  206 + 'duarr' => '&#x021F5;',
  207 + 'duhar' => '&#x0296F;',
  208 + 'dzigrarr' => '&#x027FF;',
  209 + 'erarr' => '&#x02971;',
  210 + 'hArr' => '&#x021D4;',
  211 + 'harr' => '&#x02194;',
  212 + 'harrcir' => '&#x02948;',
  213 + 'harrw' => '&#x021AD;',
  214 + 'hoarr' => '&#x021FF;',
  215 + 'imof' => '&#x022B7;',
  216 + 'lAarr' => '&#x021DA;',
  217 + 'Larr' => '&#x0219E;',
  218 + 'larrbfs' => '&#x0291F;',
  219 + 'larrfs' => '&#x0291D;',
  220 + 'larrhk' => '&#x021A9;',
  221 + 'larrlp' => '&#x021AB;',
  222 + 'larrpl' => '&#x02939;',
  223 + 'larrsim' => '&#x02973;',
  224 + 'larrtl' => '&#x021A2;',
  225 + 'lAtail' => '&#x0291B;',
  226 + 'latail' => '&#x02919;',
  227 + 'lBarr' => '&#x0290E;',
  228 + 'lbarr' => '&#x0290C;',
  229 + 'ldca' => '&#x02936;',
  230 + 'ldrdhar' => '&#x02967;',
  231 + 'ldrushar' => '&#x0294B;',
  232 + 'ldsh' => '&#x021B2;',
  233 + 'lfisht' => '&#x0297C;',
  234 + 'lHar' => '&#x02962;',
  235 + 'lhard' => '&#x021BD;',
  236 + 'lharu' => '&#x021BC;',
  237 + 'lharul' => '&#x0296A;',
  238 + 'llarr' => '&#x021C7;',
  239 + 'llhard' => '&#x0296B;',
  240 + 'loarr' => '&#x021FD;',
  241 + 'lrarr' => '&#x021C6;',
  242 + 'lrhar' => '&#x021CB;',
  243 + 'lrhard' => '&#x0296D;',
  244 + 'lsh' => '&#x021B0;',
  245 + 'lurdshar' => '&#x0294A;',
  246 + 'luruhar' => '&#x02966;',
  247 + 'Map' => '&#x02905;',
  248 + 'map' => '&#x021A6;',
  249 + 'midcir' => '&#x02AF0;',
  250 + 'mumap' => '&#x022B8;',
  251 + 'nearhk' => '&#x02924;',
  252 + 'neArr' => '&#x021D7;',
  253 + 'nearr' => '&#x02197;',
  254 + 'nesear' => '&#x02928;',
  255 + 'nhArr' => '&#x021CE;',
  256 + 'nharr' => '&#x021AE;',
  257 + 'nlArr' => '&#x021CD;',
  258 + 'nlarr' => '&#x0219A;',
  259 + 'nrArr' => '&#x021CF;',
  260 + 'nrarr' => '&#x0219B;',
  261 + 'nrarrc' => '&#x02933;&#x00338;',
  262 + 'nrarrw' => '&#x0219D;&#x00338;',
  263 + 'nvHarr' => '&#x02904;',
  264 + 'nvlArr' => '&#x02902;',
  265 + 'nvrArr' => '&#x02903;',
  266 + 'nwarhk' => '&#x02923;',
  267 + 'nwArr' => '&#x021D6;',
  268 + 'nwarr' => '&#x02196;',
  269 + 'nwnear' => '&#x02927;',
  270 + 'olarr' => '&#x021BA;',
  271 + 'orarr' => '&#x021BB;',
  272 + 'origof' => '&#x022B6;',
  273 + 'rAarr' => '&#x021DB;',
  274 + 'Rarr' => '&#x021A0;',
  275 + 'rarrap' => '&#x02975;',
  276 + 'rarrbfs' => '&#x02920;',
  277 + 'rarrc' => '&#x02933;',
  278 + 'rarrfs' => '&#x0291E;',
  279 + 'rarrhk' => '&#x021AA;',
  280 + 'rarrlp' => '&#x021AC;',
  281 + 'rarrpl' => '&#x02945;',
  282 + 'rarrsim' => '&#x02974;',
  283 + 'Rarrtl' => '&#x02916;',
  284 + 'rarrtl' => '&#x021A3;',
  285 + 'rarrw' => '&#x0219D;',
  286 + 'rAtail' => '&#x0291C;',
  287 + 'ratail' => '&#x0291A;',
  288 + 'RBarr' => '&#x02910;',
  289 + 'rBarr' => '&#x0290F;',
  290 + 'rbarr' => '&#x0290D;',
  291 + 'rdca' => '&#x02937;',
  292 + 'rdldhar' => '&#x02969;',
  293 + 'rdsh' => '&#x021B3;',
  294 + 'rfisht' => '&#x0297D;',
  295 + 'rHar' => '&#x02964;',
  296 + 'rhard' => '&#x021C1;',
  297 + 'rharu' => '&#x021C0;',
  298 + 'rharul' => '&#x0296C;',
  299 + 'rlarr' => '&#x021C4;',
  300 + 'rlhar' => '&#x021CC;',
  301 + 'roarr' => '&#x021FE;',
  302 + 'rrarr' => '&#x021C9;',
  303 + 'rsh' => '&#x021B1;',
  304 + 'ruluhar' => '&#x02968;',
  305 + 'searhk' => '&#x02925;',
  306 + 'seArr' => '&#x021D8;',
  307 + 'searr' => '&#x02198;',
  308 + 'seswar' => '&#x02929;',
  309 + 'simrarr' => '&#x02972;',
  310 + 'slarr' => '&#x02190;',
  311 + 'srarr' => '&#x02192;',
  312 + 'swarhk' => '&#x02926;',
  313 + 'swArr' => '&#x021D9;',
  314 + 'swarr' => '&#x02199;',
  315 + 'swnwar' => '&#x0292A;',
  316 + 'Uarr' => '&#x0219F;',
  317 + 'uArr' => '&#x021D1;',
  318 + 'Uarrocir' => '&#x02949;',
  319 + 'udarr' => '&#x021C5;',
  320 + 'udhar' => '&#x0296E;',
  321 + 'ufisht' => '&#x0297E;',
  322 + 'uHar' => '&#x02963;',
  323 + 'uharl' => '&#x021BF;',
  324 + 'uharr' => '&#x021BE;',
  325 + 'uuarr' => '&#x021C8;',
  326 + 'vArr' => '&#x021D5;',
  327 + 'varr' => '&#x02195;',
  328 + 'xhArr' => '&#x027FA;',
  329 + 'xharr' => '&#x027F7;',
  330 + 'xlArr' => '&#x027F8;',
  331 + 'xlarr' => '&#x027F5;',
  332 + 'xmap' => '&#x027FC;',
  333 + 'xrArr' => '&#x027F9;',
  334 + 'xrarr' => '&#x027F6;',
  335 + 'zigrarr' => '&#x021DD;',
  336 + 'ac' => '&#x0223E;',
  337 + 'acE' => '&#x0223E;&#x00333;',
  338 + 'amalg' => '&#x02A3F;',
  339 + 'barvee' => '&#x022BD;',
  340 + 'Barwed' => '&#x02306;',
  341 + 'barwed' => '&#x02305;',
  342 + 'bsolb' => '&#x029C5;',
  343 + 'Cap' => '&#x022D2;',
  344 + 'capand' => '&#x02A44;',
  345 + 'capbrcup' => '&#x02A49;',
  346 + 'capcap' => '&#x02A4B;',
  347 + 'capcup' => '&#x02A47;',
  348 + 'capdot' => '&#x02A40;',
  349 + 'caps' => '&#x02229;&#x0FE00;',
  350 + 'ccaps' => '&#x02A4D;',
  351 + 'ccups' => '&#x02A4C;',
  352 + 'ccupssm' => '&#x02A50;',
  353 + 'coprod' => '&#x02210;',
  354 + 'Cup' => '&#x022D3;',
  355 + 'cupbrcap' => '&#x02A48;',
  356 + 'cupcap' => '&#x02A46;',
  357 + 'cupcup' => '&#x02A4A;',
  358 + 'cupdot' => '&#x0228D;',
  359 + 'cupor' => '&#x02A45;',
  360 + 'cups' => '&#x0222A;&#x0FE00;',
  361 + 'cuvee' => '&#x022CE;',
  362 + 'cuwed' => '&#x022CF;',
  363 + 'Dagger' => '&#x02021;',
  364 + 'dagger' => '&#x02020;',
  365 + 'diam' => '&#x022C4;',
  366 + 'divonx' => '&#x022C7;',
  367 + 'eplus' => '&#x02A71;',
  368 + 'hercon' => '&#x022B9;',
  369 + 'intcal' => '&#x022BA;',
  370 + 'iprod' => '&#x02A3C;',
  371 + 'loplus' => '&#x02A2D;',
  372 + 'lotimes' => '&#x02A34;',
  373 + 'lthree' => '&#x022CB;',
  374 + 'ltimes' => '&#x022C9;',
  375 + 'midast' => '&#x0002A;',
  376 + 'minusb' => '&#x0229F;',
  377 + 'minusd' => '&#x02238;',
  378 + 'minusdu' => '&#x02A2A;',
  379 + 'ncap' => '&#x02A43;',
  380 + 'ncup' => '&#x02A42;',
  381 + 'oast' => '&#x0229B;',
  382 + 'ocir' => '&#x0229A;',
  383 + 'odash' => '&#x0229D;',
  384 + 'odiv' => '&#x02A38;',
  385 + 'odot' => '&#x02299;',
  386 + 'odsold' => '&#x029BC;',
  387 + 'ofcir' => '&#x029BF;',
  388 + 'ogt' => '&#x029C1;',
  389 + 'ohbar' => '&#x029B5;',
  390 + 'olcir' => '&#x029BE;',
  391 + 'olt' => '&#x029C0;',
  392 + 'omid' => '&#x029B6;',
  393 + 'ominus' => '&#x02296;',
  394 + 'opar' => '&#x029B7;',
  395 + 'operp' => '&#x029B9;',
  396 + 'oplus' => '&#x02295;',
  397 + 'osol' => '&#x02298;',
  398 + 'Otimes' => '&#x02A37;',
  399 + 'otimes' => '&#x02297;',
  400 + 'otimesas' => '&#x02A36;',
  401 + 'ovbar' => '&#x0233D;',
  402 + 'plusacir' => '&#x02A23;',
  403 + 'plusb' => '&#x0229E;',
  404 + 'pluscir' => '&#x02A22;',
  405 + 'plusdo' => '&#x02214;',
  406 + 'plusdu' => '&#x02A25;',
  407 + 'pluse' => '&#x02A72;',
  408 + 'plussim' => '&#x02A26;',
  409 + 'plustwo' => '&#x02A27;',
  410 + 'prod' => '&#x0220F;',
  411 + 'race' => '&#x029DA;',
  412 + 'roplus' => '&#x02A2E;',
  413 + 'rotimes' => '&#x02A35;',
  414 + 'rthree' => '&#x022CC;',
  415 + 'rtimes' => '&#x022CA;',
  416 + 'sdot' => '&#x022C5;',
  417 + 'sdotb' => '&#x022A1;',
  418 + 'setmn' => '&#x02216;',
  419 + 'simplus' => '&#x02A24;',
  420 + 'smashp' => '&#x02A33;',
  421 + 'solb' => '&#x029C4;',
  422 + 'sqcap' => '&#x02293;',
  423 + 'sqcaps' => '&#x02293;&#x0FE00;',
  424 + 'sqcup' => '&#x02294;',
  425 + 'sqcups' => '&#x02294;&#x0FE00;',
  426 + 'ssetmn' => '&#x02216;',
  427 + 'sstarf' => '&#x022C6;',
  428 + 'subdot' => '&#x02ABD;',
  429 + 'sum' => '&#x02211;',
  430 + 'supdot' => '&#x02ABE;',
  431 + 'timesb' => '&#x022A0;',
  432 + 'timesbar' => '&#x02A31;',
  433 + 'timesd' => '&#x02A30;',
  434 + 'tridot' => '&#x025EC;',
  435 + 'triminus' => '&#x02A3A;',
  436 + 'triplus' => '&#x02A39;',
  437 + 'trisb' => '&#x029CD;',
  438 + 'tritime' => '&#x02A3B;',
  439 + 'uplus' => '&#x0228E;',
  440 + 'veebar' => '&#x022BB;',
  441 + 'wedbar' => '&#x02A5F;',
  442 + 'wreath' => '&#x02240;',
  443 + 'xcap' => '&#x022C2;',
  444 + 'xcirc' => '&#x025EF;',
  445 + 'xcup' => '&#x022C3;',
  446 + 'xdtri' => '&#x025BD;',
  447 + 'xodot' => '&#x02A00;',
  448 + 'xoplus' => '&#x02A01;',
  449 + 'xotime' => '&#x02A02;',
  450 + 'xsqcup' => '&#x02A06;',
  451 + 'xuplus' => '&#x02A04;',
  452 + 'xutri' => '&#x025B3;',
  453 + 'xvee' => '&#x022C1;',
  454 + 'xwedge' => '&#x022C0;',
  455 + 'dlcorn' => '&#x0231E;',
  456 + 'drcorn' => '&#x0231F;',
  457 + 'gtlPar' => '&#x02995;',
  458 + 'langd' => '&#x02991;',
  459 + 'lbrke' => '&#x0298B;',
  460 + 'lbrksld' => '&#x0298F;',
  461 + 'lbrkslu' => '&#x0298D;',
  462 + 'lceil' => '&#x02308;',
  463 + 'lfloor' => '&#x0230A;',
  464 + 'lmoust' => '&#x023B0;',
  465 + 'lparlt' => '&#x02993;',
  466 + 'ltrPar' => '&#x02996;',
  467 + 'rangd' => '&#x02992;',
  468 + 'rbrke' => '&#x0298C;',
  469 + 'rbrksld' => '&#x0298E;',
  470 + 'rbrkslu' => '&#x02990;',
  471 + 'rceil' => '&#x02309;',
  472 + 'rfloor' => '&#x0230B;',
  473 + 'rmoust' => '&#x023B1;',
  474 + 'rpargt' => '&#x02994;',
  475 + 'ulcorn' => '&#x0231C;',
  476 + 'urcorn' => '&#x0231D;',
  477 + 'gnap' => '&#x02A8A;',
  478 + 'gnE' => '&#x02269;',
  479 + 'gne' => '&#x02A88;',
  480 + 'gnsim' => '&#x022E7;',
  481 + 'gvnE' => '&#x02269;&#x0FE00;',
  482 + 'lnap' => '&#x02A89;',
  483 + 'lnE' => '&#x02268;',
  484 + 'lne' => '&#x02A87;',
  485 + 'lnsim' => '&#x022E6;',
  486 + 'lvnE' => '&#x02268;&#x0FE00;',
  487 + 'nap' => '&#x02249;',
  488 + 'napE' => '&#x02A70;&#x00338;',
  489 + 'napid' => '&#x0224B;&#x00338;',
  490 + 'ncong' => '&#x02247;',
  491 + 'ncongdot' => '&#x02A6D;&#x00338;',
  492 + 'nequiv' => '&#x02262;',
  493 + 'ngE' => '&#x02267;&#x00338;',
  494 + 'nge' => '&#x02271;',
  495 + 'nges' => '&#x02A7E;&#x00338;',
  496 + 'nGg' => '&#x022D9;&#x00338;',
  497 + 'ngsim' => '&#x02275;',
  498 + 'nGt' => '&#x0226B;&#x020D2;',
  499 + 'ngt' => '&#x0226F;',
  500 + 'nGtv' => '&#x0226B;&#x00338;',
  501 + 'nlE' => '&#x02266;&#x00338;',
  502 + 'nle' => '&#x02270;',
  503 + 'nles' => '&#x02A7D;&#x00338;',
  504 + 'nLl' => '&#x022D8;&#x00338;',
  505 + 'nlsim' => '&#x02274;',
  506 + 'nLt' => '&#x0226A;&#x020D2;',
  507 + 'nlt' => '&#x0226E;',
  508 + 'nltri' => '&#x022EA;',
  509 + 'nltrie' => '&#x022EC;',
  510 + 'nLtv' => '&#x0226A;&#x00338;',
  511 + 'nmid' => '&#x02224;',
  512 + 'npar' => '&#x02226;',
  513 + 'npr' => '&#x02280;',
  514 + 'nprcue' => '&#x022E0;',
  515 + 'npre' => '&#x02AAF;&#x00338;',
  516 + 'nrtri' => '&#x022EB;',
  517 + 'nrtrie' => '&#x022ED;',
  518 + 'nsc' => '&#x02281;',
  519 + 'nsccue' => '&#x022E1;',
  520 + 'nsce' => '&#x02AB0;&#x00338;',
  521 + 'nsim' => '&#x02241;',
  522 + 'nsime' => '&#x02244;',
  523 + 'nsmid' => '&#x02224;',
  524 + 'nspar' => '&#x02226;',
  525 + 'nsqsube' => '&#x022E2;',
  526 + 'nsqsupe' => '&#x022E3;',
  527 + 'nsub' => '&#x02284;',
  528 + 'nsubE' => '&#x02AC5;&#x00338;',
  529 + 'nsube' => '&#x02288;',
  530 + 'nsup' => '&#x02285;',
  531 + 'nsupE' => '&#x02AC6;&#x00338;',
  532 + 'nsupe' => '&#x02289;',
  533 + 'ntgl' => '&#x02279;',
  534 + 'ntlg' => '&#x02278;',
  535 + 'nvap' => '&#x0224D;&#x020D2;',
  536 + 'nVDash' => '&#x022AF;',
  537 + 'nVdash' => '&#x022AE;',
  538 + 'nvDash' => '&#x022AD;',
  539 + 'nvdash' => '&#x022AC;',
  540 + 'nvge' => '&#x02265;&#x020D2;',
  541 + 'nvgt' => '&#x0003E;&#x020D2;',
  542 + 'nvle' => '&#x02264;&#x020D2;',
  543 + 'nvltrie' => '&#x022B4;&#x020D2;',
  544 + 'nvrtrie' => '&#x022B5;&#x020D2;',
  545 + 'nvsim' => '&#x0223C;&#x020D2;',
  546 + 'parsim' => '&#x02AF3;',
  547 + 'prnap' => '&#x02AB9;',
  548 + 'prnE' => '&#x02AB5;',
  549 + 'prnsim' => '&#x022E8;',
  550 + 'rnmid' => '&#x02AEE;',
  551 + 'scnap' => '&#x02ABA;',
  552 + 'scnE' => '&#x02AB6;',
  553 + 'scnsim' => '&#x022E9;',
  554 + 'simne' => '&#x02246;',
  555 + 'solbar' => '&#x0233F;',
  556 + 'subnE' => '&#x02ACB;',
  557 + 'subne' => '&#x0228A;',
  558 + 'supnE' => '&#x02ACC;',
  559 + 'supne' => '&#x0228B;',
  560 + 'vnsub' => '&#x02282;&#x020D2;',
  561 + 'vnsup' => '&#x02283;&#x020D2;',
  562 + 'vsubnE' => '&#x02ACB;&#x0FE00;',
  563 + 'vsubne' => '&#x0228A;&#x0FE00;',
  564 + 'vsupnE' => '&#x02ACC;&#x0FE00;',
  565 + 'vsupne' => '&#x0228B;&#x0FE00;',
  566 + 'ang' => '&#x02220;',
  567 + 'ange' => '&#x029A4;',
  568 + 'angmsd' => '&#x02221;',
  569 + 'angmsdaa' => '&#x029A8;',
  570 + 'angmsdab' => '&#x029A9;',
  571 + 'angmsdac' => '&#x029AA;',
  572 + 'angmsdad' => '&#x029AB;',
  573 + 'angmsdae' => '&#x029AC;',
  574 + 'angmsdaf' => '&#x029AD;',
  575 + 'angmsdag' => '&#x029AE;',
  576 + 'angmsdah' => '&#x029AF;',
  577 + 'angrtvb' => '&#x022BE;',
  578 + 'angrtvbd' => '&#x0299D;',
  579 + 'bbrk' => '&#x023B5;',
  580 + 'bbrktbrk' => '&#x023B6;',
  581 + 'bemptyv' => '&#x029B0;',
  582 + 'beth' => '&#x02136;',
  583 + 'boxbox' => '&#x029C9;',
  584 + 'bprime' => '&#x02035;',
  585 + 'bsemi' => '&#x0204F;',
  586 + 'cemptyv' => '&#x029B2;',
  587 + 'cirE' => '&#x029C3;',
  588 + 'cirscir' => '&#x029C2;',
  589 + 'comp' => '&#x02201;',
  590 + 'daleth' => '&#x02138;',
  591 + 'demptyv' => '&#x029B1;',
  592 + 'ell' => '&#x02113;',
  593 + 'empty' => '&#x02205;',
  594 + 'emptyv' => '&#x02205;',
  595 + 'gimel' => '&#x02137;',
  596 + 'iiota' => '&#x02129;',
  597 + 'image' => '&#x02111;',
  598 + 'imath' => '&#x00131;',
  599 + 'jmath' => '&#x0006A;',
  600 + 'laemptyv' => '&#x029B4;',
  601 + 'lltri' => '&#x025FA;',
  602 + 'lrtri' => '&#x022BF;',
  603 + 'mho' => '&#x02127;',
  604 + 'nang' => '&#x02220;&#x020D2;',
  605 + 'nexist' => '&#x02204;',
  606 + 'oS' => '&#x024C8;',
  607 + 'planck' => '&#x0210F;',
  608 + 'plankv' => '&#x0210F;',
  609 + 'raemptyv' => '&#x029B3;',
  610 + 'range' => '&#x029A5;',
  611 + 'real' => '&#x0211C;',
  612 + 'tbrk' => '&#x023B4;',
  613 + 'trpezium' => '&#x0FFFD;',
  614 + 'ultri' => '&#x025F8;',
  615 + 'urtri' => '&#x025F9;',
  616 + 'vzigzag' => '&#x0299A;',
  617 + 'weierp' => '&#x02118;',
  618 + 'apE' => '&#x02A70;',
  619 + 'ape' => '&#x0224A;',
  620 + 'apid' => '&#x0224B;',
  621 + 'asymp' => '&#x02248;',
  622 + 'Barv' => '&#x02AE7;',
  623 + 'bcong' => '&#x0224C;',
  624 + 'bepsi' => '&#x003F6;',
  625 + 'bowtie' => '&#x022C8;',
  626 + 'bsim' => '&#x0223D;',
  627 + 'bsime' => '&#x022CD;',
  628 + 'bsolhsub' => '&#x0005C;&#x02282;',
  629 + 'bump' => '&#x0224E;',
  630 + 'bumpE' => '&#x02AAE;',
  631 + 'bumpe' => '&#x0224F;',
  632 + 'cire' => '&#x02257;',
  633 + 'Colon' => '&#x02237;',
  634 + 'Colone' => '&#x02A74;',
  635 + 'colone' => '&#x02254;',
  636 + 'congdot' => '&#x02A6D;',
  637 + 'csub' => '&#x02ACF;',
  638 + 'csube' => '&#x02AD1;',
  639 + 'csup' => '&#x02AD0;',
  640 + 'csupe' => '&#x02AD2;',
  641 + 'cuepr' => '&#x022DE;',
  642 + 'cuesc' => '&#x022DF;',
  643 + 'Dashv' => '&#x02AE4;',
  644 + 'dashv' => '&#x022A3;',
  645 + 'easter' => '&#x02A6E;',
  646 + 'ecir' => '&#x02256;',
  647 + 'ecolon' => '&#x02255;',
  648 + 'eDDot' => '&#x02A77;',
  649 + 'eDot' => '&#x02251;',
  650 + 'efDot' => '&#x02252;',
  651 + 'eg' => '&#x02A9A;',
  652 + 'egs' => '&#x02A96;',
  653 + 'egsdot' => '&#x02A98;',
  654 + 'el' => '&#x02A99;',
  655 + 'els' => '&#x02A95;',
  656 + 'elsdot' => '&#x02A97;',
  657 + 'equest' => '&#x0225F;',
  658 + 'equivDD' => '&#x02A78;',
  659 + 'erDot' => '&#x02253;',
  660 + 'esdot' => '&#x02250;',
  661 + 'Esim' => '&#x02A73;',
  662 + 'esim' => '&#x02242;',
  663 + 'fork' => '&#x022D4;',
  664 + 'forkv' => '&#x02AD9;',
  665 + 'frown' => '&#x02322;',
  666 + 'gap' => '&#x02A86;',
  667 + 'gE' => '&#x02267;',
  668 + 'gEl' => '&#x02A8C;',
  669 + 'gel' => '&#x022DB;',
  670 + 'ges' => '&#x02A7E;',
  671 + 'gescc' => '&#x02AA9;',
  672 + 'gesdot' => '&#x02A80;',
  673 + 'gesdoto' => '&#x02A82;',
  674 + 'gesdotol' => '&#x02A84;',
  675 + 'gesl' => '&#x022DB;&#x0FE00;',
  676 + 'gesles' => '&#x02A94;',
  677 + 'Gg' => '&#x022D9;',
  678 + 'gl' => '&#x02277;',
  679 + 'gla' => '&#x02AA5;',
  680 + 'glE' => '&#x02A92;',
  681 + 'glj' => '&#x02AA4;',
  682 + 'gsim' => '&#x02273;',
  683 + 'gsime' => '&#x02A8E;',
  684 + 'gsiml' => '&#x02A90;',
  685 + 'Gt' => '&#x0226B;',
  686 + 'gtcc' => '&#x02AA7;',
  687 + 'gtcir' => '&#x02A7A;',
  688 + 'gtdot' => '&#x022D7;',
  689 + 'gtquest' => '&#x02A7C;',
  690 + 'gtrarr' => '&#x02978;',
  691 + 'homtht' => '&#x0223B;',
  692 + 'lap' => '&#x02A85;',
  693 + 'lat' => '&#x02AAB;',
  694 + 'late' => '&#x02AAD;',
  695 + 'lates' => '&#x02AAD;&#x0FE00;',
  696 + 'lE' => '&#x02266;',
  697 + 'lEg' => '&#x02A8B;',
  698 + 'leg' => '&#x022DA;',
  699 + 'les' => '&#x02A7D;',
  700 + 'lescc' => '&#x02AA8;',
  701 + 'lesdot' => '&#x02A7F;',
  702 + 'lesdoto' => '&#x02A81;',
  703 + 'lesdotor' => '&#x02A83;',
  704 + 'lesg' => '&#x022DA;&#x0FE00;',
  705 + 'lesges' => '&#x02A93;',
  706 + 'lg' => '&#x02276;',
  707 + 'lgE' => '&#x02A91;',
  708 + 'Ll' => '&#x022D8;',
  709 + 'lsim' => '&#x02272;',
  710 + 'lsime' => '&#x02A8D;',
  711 + 'lsimg' => '&#x02A8F;',
  712 + 'Lt' => '&#x0226A;',
  713 + 'ltcc' => '&#x02AA6;',
  714 + 'ltcir' => '&#x02A79;',
  715 + 'ltdot' => '&#x022D6;',
  716 + 'ltlarr' => '&#x02976;',
  717 + 'ltquest' => '&#x02A7B;',
  718 + 'ltrie' => '&#x022B4;',
  719 + 'mcomma' => '&#x02A29;',
  720 + 'mDDot' => '&#x0223A;',
  721 + 'mid' => '&#x02223;',
  722 + 'mlcp' => '&#x02ADB;',
  723 + 'models' => '&#x022A7;',
  724 + 'mstpos' => '&#x0223E;',
  725 + 'Pr' => '&#x02ABB;',
  726 + 'pr' => '&#x0227A;',
  727 + 'prap' => '&#x02AB7;',
  728 + 'prcue' => '&#x0227C;',
  729 + 'prE' => '&#x02AB3;',
  730 + 'pre' => '&#x02AAF;',
  731 + 'prsim' => '&#x0227E;',
  732 + 'prurel' => '&#x022B0;',
  733 + 'ratio' => '&#x02236;',
  734 + 'rtrie' => '&#x022B5;',
  735 + 'rtriltri' => '&#x029CE;',
  736 + 'Sc' => '&#x02ABC;',
  737 + 'sc' => '&#x0227B;',
  738 + 'scap' => '&#x02AB8;',
  739 + 'sccue' => '&#x0227D;',
  740 + 'scE' => '&#x02AB4;',
  741 + 'sce' => '&#x02AB0;',
  742 + 'scsim' => '&#x0227F;',
  743 + 'sdote' => '&#x02A66;',
  744 + 'sfrown' => '&#x02322;',
  745 + 'simg' => '&#x02A9E;',
  746 + 'simgE' => '&#x02AA0;',
  747 + 'siml' => '&#x02A9D;',
  748 + 'simlE' => '&#x02A9F;',
  749 + 'smid' => '&#x02223;',
  750 + 'smile' => '&#x02323;',
  751 + 'smt' => '&#x02AAA;',
  752 + 'smte' => '&#x02AAC;',
  753 + 'smtes' => '&#x02AAC;&#x0FE00;',
  754 + 'spar' => '&#x02225;',
  755 + 'sqsub' => '&#x0228F;',
  756 + 'sqsube' => '&#x02291;',
  757 + 'sqsup' => '&#x02290;',
  758 + 'sqsupe' => '&#x02292;',
  759 + 'ssmile' => '&#x02323;',
  760 + 'Sub' => '&#x022D0;',
  761 + 'subE' => '&#x02AC5;',
  762 + 'subedot' => '&#x02AC3;',
  763 + 'submult' => '&#x02AC1;',
  764 + 'subplus' => '&#x02ABF;',
  765 + 'subrarr' => '&#x02979;',
  766 + 'subsim' => '&#x02AC7;',
  767 + 'subsub' => '&#x02AD5;',
  768 + 'subsup' => '&#x02AD3;',
  769 + 'Sup' => '&#x022D1;',
  770 + 'supdsub' => '&#x02AD8;',
  771 + 'supE' => '&#x02AC6;',
  772 + 'supedot' => '&#x02AC4;',
  773 + 'suphsol' => '&#x02283;&#x0002F;',
  774 + 'suphsub' => '&#x02AD7;',
  775 + 'suplarr' => '&#x0297B;',
  776 + 'supmult' => '&#x02AC2;',
  777 + 'supplus' => '&#x02AC0;',
  778 + 'supsim' => '&#x02AC8;',
  779 + 'supsub' => '&#x02AD4;',
  780 + 'supsup' => '&#x02AD6;',
  781 + 'thkap' => '&#x02248;',
  782 + 'thksim' => '&#x0223C;',
  783 + 'topfork' => '&#x02ADA;',
  784 + 'trie' => '&#x0225C;',
  785 + 'twixt' => '&#x0226C;',
  786 + 'Vbar' => '&#x02AEB;',
  787 + 'vBar' => '&#x02AE8;',
  788 + 'vBarv' => '&#x02AE9;',
  789 + 'VDash' => '&#x022AB;',
  790 + 'Vdash' => '&#x022A9;',
  791 + 'vDash' => '&#x022A8;',
  792 + 'vdash' => '&#x022A2;',
  793 + 'Vdashl' => '&#x02AE6;',
  794 + 'vltri' => '&#x022B2;',
  795 + 'vprop' => '&#x0221D;',
  796 + 'vrtri' => '&#x022B3;',
  797 + 'Vvdash' => '&#x022AA;',
  798 + 'alpha' => '&#x003B1;',
  799 + 'beta' => '&#x003B2;',
  800 + 'chi' => '&#x003C7;',
  801 + 'Delta' => '&#x00394;',
  802 + 'delta' => '&#x003B4;',
  803 + 'epsi' => '&#x003F5;',
  804 + 'epsiv' => '&#x003B5;',
  805 + 'eta' => '&#x003B7;',
  806 + 'Gamma' => '&#x00393;',
  807 + 'gamma' => '&#x003B3;',
  808 + 'Gammad' => '&#x003DC;',
  809 + 'gammad' => '&#x003DD;',
  810 + 'iota' => '&#x003B9;',
  811 + 'kappa' => '&#x003BA;',
  812 + 'kappav' => '&#x003F0;',
  813 + 'Lambda' => '&#x0039B;',
  814 + 'lambda' => '&#x003BB;',
  815 + 'mu' => '&#x003BC;',
  816 + 'nu' => '&#x003BD;',
  817 + 'Omega' => '&#x003A9;',
  818 + 'omega' => '&#x003C9;',
  819 + 'Phi' => '&#x003A6;',
  820 + 'phi' => '&#x003D5;',
  821 + 'phiv' => '&#x003C6;',
  822 + 'Pi' => '&#x003A0;',
  823 + 'pi' => '&#x003C0;',
  824 + 'piv' => '&#x003D6;',
  825 + 'Psi' => '&#x003A8;',
  826 + 'psi' => '&#x003C8;',
  827 + 'rho' => '&#x003C1;',
  828 + 'rhov' => '&#x003F1;',
  829 + 'Sigma' => '&#x003A3;',
  830 + 'sigma' => '&#x003C3;',
  831 + 'sigmav' => '&#x003C2;',
  832 + 'tau' => '&#x003C4;',
  833 + 'Theta' => '&#x00398;',
  834 + 'theta' => '&#x003B8;',
  835 + 'thetav' => '&#x003D1;',
  836 + 'Upsi' => '&#x003D2;',
  837 + 'upsi' => '&#x003C5;',
  838 + 'Xi' => '&#x0039E;',
  839 + 'xi' => '&#x003BE;',
  840 + 'zeta' => '&#x003B6;',
  841 + 'Afr' => '&#x1D504;',
  842 + 'afr' => '&#x1D51E;',
  843 + 'Bfr' => '&#x1D505;',
  844 + 'bfr' => '&#x1D51F;',
  845 + 'Cfr' => '&#x0212D;',
  846 + 'cfr' => '&#x1D520;',
  847 + 'Dfr' => '&#x1D507;',
  848 + 'dfr' => '&#x1D521;',
  849 + 'Efr' => '&#x1D508;',
  850 + 'efr' => '&#x1D522;',
  851 + 'Ffr' => '&#x1D509;',
  852 + 'ffr' => '&#x1D523;',
  853 + 'Gfr' => '&#x1D50A;',
  854 + 'gfr' => '&#x1D524;',
  855 + 'Hfr' => '&#x0210C;',
  856 + 'hfr' => '&#x1D525;',
  857 + 'Ifr' => '&#x02111;',
  858 + 'ifr' => '&#x1D526;',
  859 + 'Jfr' => '&#x1D50D;',
  860 + 'jfr' => '&#x1D527;',
  861 + 'Kfr' => '&#x1D50E;',
  862 + 'kfr' => '&#x1D528;',
  863 + 'Lfr' => '&#x1D50F;',
  864 + 'lfr' => '&#x1D529;',
  865 + 'Mfr' => '&#x1D510;',
  866 + 'mfr' => '&#x1D52A;',
  867 + 'Nfr' => '&#x1D511;',
  868 + 'nfr' => '&#x1D52B;',
  869 + 'Ofr' => '&#x1D512;',
  870 + 'ofr' => '&#x1D52C;',
  871 + 'Pfr' => '&#x1D513;',
  872 + 'pfr' => '&#x1D52D;',
  873 + 'Qfr' => '&#x1D514;',
  874 + 'qfr' => '&#x1D52E;',
  875 + 'Rfr' => '&#x0211C;',
  876 + 'rfr' => '&#x1D52F;',
  877 + 'Sfr' => '&#x1D516;',
  878 + 'sfr' => '&#x1D530;',
  879 + 'Tfr' => '&#x1D517;',
  880 + 'tfr' => '&#x1D531;',
  881 + 'Ufr' => '&#x1D518;',
  882 + 'ufr' => '&#x1D532;',
  883 + 'Vfr' => '&#x1D519;',
  884 + 'vfr' => '&#x1D533;',
  885 + 'Wfr' => '&#x1D51A;',
  886 + 'wfr' => '&#x1D534;',
  887 + 'Xfr' => '&#x1D51B;',
  888 + 'xfr' => '&#x1D535;',
  889 + 'Yfr' => '&#x1D51C;',
  890 + 'yfr' => '&#x1D536;',
  891 + 'Zfr' => '&#x02128;',
  892 + 'zfr' => '&#x1D537;',
  893 + 'Aopf' => '&#x1D538;',
  894 + 'Bopf' => '&#x1D539;',
  895 + 'Copf' => '&#x02102;',
  896 + 'Dopf' => '&#x1D53B;',
  897 + 'Eopf' => '&#x1D53C;',
  898 + 'Fopf' => '&#x1D53D;',
  899 + 'Gopf' => '&#x1D53E;',
  900 + 'Hopf' => '&#x0210D;',
  901 + 'Iopf' => '&#x1D540;',
  902 + 'Jopf' => '&#x1D541;',
  903 + 'Kopf' => '&#x1D542;',
  904 + 'Lopf' => '&#x1D543;',
  905 + 'Mopf' => '&#x1D544;',
  906 + 'Nopf' => '&#x02115;',
  907 + 'Oopf' => '&#x1D546;',
  908 + 'Popf' => '&#x02119;',
  909 + 'Qopf' => '&#x0211A;',
  910 + 'Ropf' => '&#x0211D;',
  911 + 'Sopf' => '&#x1D54A;',
  912 + 'Topf' => '&#x1D54B;',
  913 + 'Uopf' => '&#x1D54C;',
  914 + 'Vopf' => '&#x1D54D;',
  915 + 'Wopf' => '&#x1D54E;',
  916 + 'Xopf' => '&#x1D54F;',
  917 + 'Yopf' => '&#x1D550;',
  918 + 'Zopf' => '&#x02124;',
  919 + 'Ascr' => '&#x1D49C;',
  920 + 'ascr' => '&#x1D4B6;',
  921 + 'Bscr' => '&#x0212C;',
  922 + 'bscr' => '&#x1D4B7;',
  923 + 'Cscr' => '&#x1D49E;',
  924 + 'cscr' => '&#x1D4B8;',
  925 + 'Dscr' => '&#x1D49F;',
  926 + 'dscr' => '&#x1D4B9;',
  927 + 'Escr' => '&#x02130;',
  928 + 'escr' => '&#x0212F;',
  929 + 'Fscr' => '&#x02131;',
  930 + 'fscr' => '&#x1D4BB;',
  931 + 'Gscr' => '&#x1D4A2;',
  932 + 'gscr' => '&#x0210A;',
  933 + 'Hscr' => '&#x0210B;',
  934 + 'hscr' => '&#x1D4BD;',
  935 + 'Iscr' => '&#x02110;',
  936 + 'iscr' => '&#x1D4BE;',
  937 + 'Jscr' => '&#x1D4A5;',
  938 + 'jscr' => '&#x1D4BF;',
  939 + 'Kscr' => '&#x1D4A6;',
  940 + 'kscr' => '&#x1D4C0;',
  941 + 'Lscr' => '&#x02112;',
  942 + 'lscr' => '&#x1D4C1;',
  943 + 'Mscr' => '&#x02133;',
  944 + 'mscr' => '&#x1D4C2;',
  945 + 'Nscr' => '&#x1D4A9;',
  946 + 'nscr' => '&#x1D4C3;',
  947 + 'Oscr' => '&#x1D4AA;',
  948 + 'oscr' => '&#x02134;',
  949 + 'Pscr' => '&#x1D4AB;',
  950 + 'pscr' => '&#x1D4C5;',
  951 + 'Qscr' => '&#x1D4AC;',
  952 + 'qscr' => '&#x1D4C6;',
  953 + 'Rscr' => '&#x0211B;',
  954 + 'rscr' => '&#x1D4C7;',
  955 + 'Sscr' => '&#x1D4AE;',
  956 + 'sscr' => '&#x1D4C8;',
  957 + 'Tscr' => '&#x1D4AF;',
  958 + 'tscr' => '&#x1D4C9;',
  959 + 'Uscr' => '&#x1D4B0;',
  960 + 'uscr' => '&#x1D4CA;',
  961 + 'Vscr' => '&#x1D4B1;',
  962 + 'vscr' => '&#x1D4CB;',
  963 + 'Wscr' => '&#x1D4B2;',
  964 + 'wscr' => '&#x1D4CC;',
  965 + 'Xscr' => '&#x1D4B3;',
  966 + 'xscr' => '&#x1D4CD;',
  967 + 'Yscr' => '&#x1D4B4;',
  968 + 'yscr' => '&#x1D4CE;',
  969 + 'Zscr' => '&#x1D4B5;',
  970 + 'zscr' => '&#x1D4CF;',
  971 + 'acd' => '&#x0223F;',
  972 + 'aleph' => '&#x02135;',
  973 + 'And' => '&#x02A53;',
  974 + 'and' => '&#x02227;',
  975 + 'andand' => '&#x02A55;',
  976 + 'andd' => '&#x02A5C;',
  977 + 'andslope' => '&#x02A58;',
  978 + 'andv' => '&#x02A5A;',
  979 + 'angrt' => '&#x0221F;',
  980 + 'angsph' => '&#x02222;',
  981 + 'angst' => '&#x0212B;',
  982 + 'ap' => '&#x02248;',
  983 + 'apacir' => '&#x02A6F;',
  984 + 'awconint' => '&#x02233;',
  985 + 'awint' => '&#x02A11;',
  986 + 'becaus' => '&#x02235;',
  987 + 'bernou' => '&#x0212C;',
  988 + 'bne' => '&#x0003D;&#x020E5;',
  989 + 'bnequiv' => '&#x02261;&#x020E5;',
  990 + 'bNot' => '&#x02AED;',
  991 + 'bnot' => '&#x02310;',
  992 + 'bottom' => '&#x022A5;',
  993 + 'cap' => '&#x02229;',
  994 + 'Cconint' => '&#x02230;',
  995 + 'cirfnint' => '&#x02A10;',
  996 + 'compfn' => '&#x02218;',
  997 + 'cong' => '&#x02245;',
  998 + 'Conint' => '&#x0222F;',
  999 + 'conint' => '&#x0222E;',
  1000 + 'ctdot' => '&#x022EF;',
  1001 + 'cup' => '&#x0222A;',
  1002 + 'cwconint' => '&#x02232;',
  1003 + 'cwint' => '&#x02231;',
  1004 + 'cylcty' => '&#x0232D;',
  1005 + 'disin' => '&#x022F2;',
  1006 + 'Dot' => '&#x000A8;',
  1007 + 'DotDot' => '&#x020DC;',
  1008 + 'dsol' => '&#x029F6;',
  1009 + 'dtdot' => '&#x022F1;',
  1010 + 'dwangle' => '&#x029A6;',
  1011 + 'elinters' => '&#x0FFFD;',
  1012 + 'epar' => '&#x022D5;',
  1013 + 'eparsl' => '&#x029E3;',
  1014 + 'equiv' => '&#x02261;',
  1015 + 'eqvparsl' => '&#x029E5;',
  1016 + 'exist' => '&#x02203;',
  1017 + 'fltns' => '&#x025B1;',
  1018 + 'fnof' => '&#x00192;',
  1019 + 'forall' => '&#x02200;',
  1020 + 'fpartint' => '&#x02A0D;',
  1021 + 'ge' => '&#x02265;',
  1022 + 'hamilt' => '&#x0210B;',
  1023 + 'iff' => '&#x021D4;',
  1024 + 'iinfin' => '&#x029DC;',
  1025 + 'imped' => '&#x001B5;',
  1026 + 'infin' => '&#x0221E;',
  1027 + 'infintie' => '&#x029DD;',
  1028 + 'Int' => '&#x0222C;',
  1029 + 'int' => '&#x0222B;',
  1030 + 'intlarhk' => '&#x02A17;',
  1031 + 'isin' => '&#x02208;',
  1032 + 'isindot' => '&#x022F5;',
  1033 + 'isinE' => '&#x022F9;',
  1034 + 'isins' => '&#x022F4;',
  1035 + 'isinsv' => '&#x022F3;',
  1036 + 'isinv' => '&#x02208;',
  1037 + 'lagran' => '&#x02112;',
  1038 + 'Lang' => '&#x0300A;',
  1039 + 'lang' => '&#x02329;',
  1040 + 'lArr' => '&#x021D0;',
  1041 + 'lbbrk' => '&#x03014;',
  1042 + 'le' => '&#x02264;',
  1043 + 'loang' => '&#x03018;',
  1044 + 'lobrk' => '&#x0301A;',
  1045 + 'lopar' => '&#x02985;',
  1046 + 'lowast' => '&#x02217;',
  1047 + 'minus' => '&#x02212;',
  1048 + 'mnplus' => '&#x02213;',
  1049 + 'nabla' => '&#x02207;',
  1050 + 'ne' => '&#x02260;',
  1051 + 'nedot' => '&#x02250;&#x00338;',
  1052 + 'nhpar' => '&#x02AF2;',
  1053 + 'ni' => '&#x0220B;',
  1054 + 'nis' => '&#x022FC;',
  1055 + 'nisd' => '&#x022FA;',
  1056 + 'niv' => '&#x0220B;',
  1057 + 'Not' => '&#x02AEC;',
  1058 + 'notin' => '&#x02209;',
  1059 + 'notindot' => '&#x022F5;&#x00338;',
  1060 + 'notinE' => '&#x022F9;&#x00338;',
  1061 + 'notinva' => '&#x02209;',
  1062 + 'notinvb' => '&#x022F7;',
  1063 + 'notinvc' => '&#x022F6;',
  1064 + 'notni' => '&#x0220C;',
  1065 + 'notniva' => '&#x0220C;',
  1066 + 'notnivb' => '&#x022FE;',
  1067 + 'notnivc' => '&#x022FD;',
  1068 + 'nparsl' => '&#x02AFD;&#x020E5;',
  1069 + 'npart' => '&#x02202;&#x00338;',
  1070 + 'npolint' => '&#x02A14;',
  1071 + 'nvinfin' => '&#x029DE;',
  1072 + 'olcross' => '&#x029BB;',
  1073 + 'Or' => '&#x02A54;',
  1074 + 'or' => '&#x02228;',
  1075 + 'ord' => '&#x02A5D;',
  1076 + 'order' => '&#x02134;',
  1077 + 'oror' => '&#x02A56;',
  1078 + 'orslope' => '&#x02A57;',
  1079 + 'orv' => '&#x02A5B;',
  1080 + 'par' => '&#x02225;',
  1081 + 'parsl' => '&#x02AFD;',
  1082 + 'part' => '&#x02202;',
  1083 + 'permil' => '&#x02030;',
  1084 + 'perp' => '&#x022A5;',
  1085 + 'pertenk' => '&#x02031;',
  1086 + 'phmmat' => '&#x02133;',
  1087 + 'pointint' => '&#x02A15;',
  1088 + 'Prime' => '&#x02033;',
  1089 + 'prime' => '&#x02032;',
  1090 + 'profalar' => '&#x0232E;',
  1091 + 'profline' => '&#x02312;',
  1092 + 'profsurf' => '&#x02313;',
  1093 + 'prop' => '&#x0221D;',
  1094 + 'qint' => '&#x02A0C;',
  1095 + 'qprime' => '&#x02057;',
  1096 + 'quatint' => '&#x02A16;',
  1097 + 'radic' => '&#x0221A;',
  1098 + 'Rang' => '&#x0300B;',
  1099 + 'rang' => '&#x0232A;',
  1100 + 'rArr' => '&#x021D2;',
  1101 + 'rbbrk' => '&#x03015;',
  1102 + 'roang' => '&#x03019;',
  1103 + 'robrk' => '&#x0301B;',
  1104 + 'ropar' => '&#x02986;',
  1105 + 'rppolint' => '&#x02A12;',
  1106 + 'scpolint' => '&#x02A13;',
  1107 + 'sim' => '&#x0223C;',
  1108 + 'simdot' => '&#x02A6A;',
  1109 + 'sime' => '&#x02243;',
  1110 + 'smeparsl' => '&#x029E4;',
  1111 + 'square' => '&#x025A1;',
  1112 + 'squarf' => '&#x025AA;',
  1113 + 'strns' => '&#x000AF;',
  1114 + 'sub' => '&#x02282;',
  1115 + 'sube' => '&#x02286;',
  1116 + 'sup' => '&#x02283;',
  1117 + 'supe' => '&#x02287;',
  1118 + 'tdot' => '&#x020DB;',
  1119 + 'there4' => '&#x02234;',
  1120 + 'tint' => '&#x0222D;',
  1121 + 'top' => '&#x022A4;',
  1122 + 'topbot' => '&#x02336;',
  1123 + 'topcir' => '&#x02AF1;',
  1124 + 'tprime' => '&#x02034;',
  1125 + 'utdot' => '&#x022F0;',
  1126 + 'uwangle' => '&#x029A7;',
  1127 + 'vangrt' => '&#x0299C;',
  1128 + 'veeeq' => '&#x0225A;',
  1129 + 'Verbar' => '&#x02016;',
  1130 + 'wedgeq' => '&#x02259;',
  1131 + 'xnis' => '&#x022FB;',
  1132 + 'boxDL' => '&#x02557;',
  1133 + 'boxDl' => '&#x02556;',
  1134 + 'boxdL' => '&#x02555;',
  1135 + 'boxdl' => '&#x02510;',
  1136 + 'boxDR' => '&#x02554;',
  1137 + 'boxDr' => '&#x02553;',
  1138 + 'boxdR' => '&#x02552;',
  1139 + 'boxdr' => '&#x0250C;',
  1140 + 'boxH' => '&#x02550;',
  1141 + 'boxh' => '&#x02500;',
  1142 + 'boxHD' => '&#x02566;',
  1143 + 'boxHd' => '&#x02564;',
  1144 + 'boxhD' => '&#x02565;',
  1145 + 'boxhd' => '&#x0252C;',
  1146 + 'boxHU' => '&#x02569;',
  1147 + 'boxHu' => '&#x02567;',
  1148 + 'boxhU' => '&#x02568;',
  1149 + 'boxhu' => '&#x02534;',
  1150 + 'boxUL' => '&#x0255D;',
  1151 + 'boxUl' => '&#x0255C;',
  1152 + 'boxuL' => '&#x0255B;',
  1153 + 'boxul' => '&#x02518;',
  1154 + 'boxUR' => '&#x0255A;',
  1155 + 'boxUr' => '&#x02559;',
  1156 + 'boxuR' => '&#x02558;',
  1157 + 'boxur' => '&#x02514;',
  1158 + 'boxV' => '&#x02551;',
  1159 + 'boxv' => '&#x02502;',
  1160 + 'boxVH' => '&#x0256C;',
  1161 + 'boxVh' => '&#x0256B;',
  1162 + 'boxvH' => '&#x0256A;',
  1163 + 'boxvh' => '&#x0253C;',
  1164 + 'boxVL' => '&#x02563;',
  1165 + 'boxVl' => '&#x02562;',
  1166 + 'boxvL' => '&#x02561;',
  1167 + 'boxvl' => '&#x02524;',
  1168 + 'boxVR' => '&#x02560;',
  1169 + 'boxVr' => '&#x0255F;',
  1170 + 'boxvR' => '&#x0255E;',
  1171 + 'boxvr' => '&#x0251C;',
  1172 + 'Acy' => '&#x00410;',
  1173 + 'acy' => '&#x00430;',
  1174 + 'Bcy' => '&#x00411;',
  1175 + 'bcy' => '&#x00431;',
  1176 + 'CHcy' => '&#x00427;',
  1177 + 'chcy' => '&#x00447;',
  1178 + 'Dcy' => '&#x00414;',
  1179 + 'dcy' => '&#x00434;',
  1180 + 'Ecy' => '&#x0042D;',
  1181 + 'ecy' => '&#x0044D;',
  1182 + 'Fcy' => '&#x00424;',
  1183 + 'fcy' => '&#x00444;',
  1184 + 'Gcy' => '&#x00413;',
  1185 + 'gcy' => '&#x00433;',
  1186 + 'HARDcy' => '&#x0042A;',
  1187 + 'hardcy' => '&#x0044A;',
  1188 + 'Icy' => '&#x00418;',
  1189 + 'icy' => '&#x00438;',
  1190 + 'IEcy' => '&#x00415;',
  1191 + 'iecy' => '&#x00435;',
  1192 + 'IOcy' => '&#x00401;',
  1193 + 'iocy' => '&#x00451;',
  1194 + 'Jcy' => '&#x00419;',
  1195 + 'jcy' => '&#x00439;',
  1196 + 'Kcy' => '&#x0041A;',
  1197 + 'kcy' => '&#x0043A;',
  1198 + 'KHcy' => '&#x00425;',
  1199 + 'khcy' => '&#x00445;',
  1200 + 'Lcy' => '&#x0041B;',
  1201 + 'lcy' => '&#x0043B;',
  1202 + 'Mcy' => '&#x0041C;',
  1203 + 'mcy' => '&#x0043C;',
  1204 + 'Ncy' => '&#x0041D;',
  1205 + 'ncy' => '&#x0043D;',
  1206 + 'numero' => '&#x02116;',
  1207 + 'Ocy' => '&#x0041E;',
  1208 + 'ocy' => '&#x0043E;',
  1209 + 'Pcy' => '&#x0041F;',
  1210 + 'pcy' => '&#x0043F;',
  1211 + 'Rcy' => '&#x00420;',
  1212 + 'rcy' => '&#x00440;',
  1213 + 'Scy' => '&#x00421;',
  1214 + 'scy' => '&#x00441;',
  1215 + 'SHCHcy' => '&#x00429;',
  1216 + 'shchcy' => '&#x00449;',
  1217 + 'SHcy' => '&#x00428;',
  1218 + 'shcy' => '&#x00448;',
  1219 + 'SOFTcy' => '&#x0042C;',
  1220 + 'softcy' => '&#x0044C;',
  1221 + 'Tcy' => '&#x00422;',
  1222 + 'tcy' => '&#x00442;',
  1223 + 'TScy' => '&#x00426;',
  1224 + 'tscy' => '&#x00446;',
  1225 + 'Ucy' => '&#x00423;',
  1226 + 'ucy' => '&#x00443;',
  1227 + 'Vcy' => '&#x00412;',
  1228 + 'vcy' => '&#x00432;',
  1229 + 'YAcy' => '&#x0042F;',
  1230 + 'yacy' => '&#x0044F;',
  1231 + 'Ycy' => '&#x0042B;',
  1232 + 'ycy' => '&#x0044B;',
  1233 + 'YUcy' => '&#x0042E;',
  1234 + 'yucy' => '&#x0044E;',
  1235 + 'Zcy' => '&#x00417;',
  1236 + 'zcy' => '&#x00437;',
  1237 + 'ZHcy' => '&#x00416;',
  1238 + 'zhcy' => '&#x00436;',
  1239 + 'DJcy' => '&#x00402;',
  1240 + 'djcy' => '&#x00452;',
  1241 + 'DScy' => '&#x00405;',
  1242 + 'dscy' => '&#x00455;',
  1243 + 'DZcy' => '&#x0040F;',
  1244 + 'dzcy' => '&#x0045F;',
  1245 + 'GJcy' => '&#x00403;',
  1246 + 'gjcy' => '&#x00453;',
  1247 + 'Iukcy' => '&#x00406;',
  1248 + 'iukcy' => '&#x00456;',
  1249 + 'Jsercy' => '&#x00408;',
  1250 + 'jsercy' => '&#x00458;',
  1251 + 'Jukcy' => '&#x00404;',
  1252 + 'jukcy' => '&#x00454;',
  1253 + 'KJcy' => '&#x0040C;',
  1254 + 'kjcy' => '&#x0045C;',
  1255 + 'LJcy' => '&#x00409;',
  1256 + 'ljcy' => '&#x00459;',
  1257 + 'NJcy' => '&#x0040A;',
  1258 + 'njcy' => '&#x0045A;',
  1259 + 'TSHcy' => '&#x0040B;',
  1260 + 'tshcy' => '&#x0045B;',
  1261 + 'Ubrcy' => '&#x0040E;',
  1262 + 'ubrcy' => '&#x0045E;',
  1263 + 'YIcy' => '&#x00407;',
  1264 + 'yicy' => '&#x00457;',
  1265 + 'acute' => '&#x000B4;',
  1266 + 'breve' => '&#x002D8;',
  1267 + 'caron' => '&#x002C7;',
  1268 + 'cedil' => '&#x000B8;',
  1269 + 'circ' => '&#x002C6;',
  1270 + 'dblac' => '&#x002DD;',
  1271 + 'die' => '&#x000A8;',
  1272 + 'dot' => '&#x002D9;',
  1273 + 'grave' => '&#x00060;',
  1274 + 'macr' => '&#x000AF;',
  1275 + 'ogon' => '&#x002DB;',
  1276 + 'ring' => '&#x002DA;',
  1277 + 'tilde' => '&#x002DC;',
  1278 + 'uml' => '&#x000A8;',
  1279 + 'Aacute' => '&#x000C1;',
  1280 + 'aacute' => '&#x000E1;',
  1281 + 'Acirc' => '&#x000C2;',
  1282 + 'acirc' => '&#x000E2;',
  1283 + 'AElig' => '&#x000C6;',
  1284 + 'aelig' => '&#x000E6;',
  1285 + 'Agrave' => '&#x000C0;',
  1286 + 'agrave' => '&#x000E0;',
  1287 + 'Aring' => '&#x000C5;',
  1288 + 'aring' => '&#x000E5;',
  1289 + 'Atilde' => '&#x000C3;',
  1290 + 'atilde' => '&#x000E3;',
  1291 + 'Auml' => '&#x000C4;',
  1292 + 'auml' => '&#x000E4;',
  1293 + 'Ccedil' => '&#x000C7;',
  1294 + 'ccedil' => '&#x000E7;',
  1295 + 'Eacute' => '&#x000C9;',
  1296 + 'eacute' => '&#x000E9;',
  1297 + 'Ecirc' => '&#x000CA;',
  1298 + 'ecirc' => '&#x000EA;',
  1299 + 'Egrave' => '&#x000C8;',
  1300 + 'egrave' => '&#x000E8;',
  1301 + 'ETH' => '&#x000D0;',
  1302 + 'eth' => '&#x000F0;',
  1303 + 'Euml' => '&#x000CB;',
  1304 + 'euml' => '&#x000EB;',
  1305 + 'Iacute' => '&#x000CD;',
  1306 + 'iacute' => '&#x000ED;',
  1307 + 'Icirc' => '&#x000CE;',
  1308 + 'icirc' => '&#x000EE;',
  1309 + 'Igrave' => '&#x000CC;',
  1310 + 'igrave' => '&#x000EC;',
  1311 + 'Iuml' => '&#x000CF;',
  1312 + 'iuml' => '&#x000EF;',
  1313 + 'Ntilde' => '&#x000D1;',
  1314 + 'ntilde' => '&#x000F1;',
  1315 + 'Oacute' => '&#x000D3;',
  1316 + 'oacute' => '&#x000F3;',
  1317 + 'Ocirc' => '&#x000D4;',
  1318 + 'ocirc' => '&#x000F4;',
  1319 + 'Ograve' => '&#x000D2;',
  1320 + 'ograve' => '&#x000F2;',
  1321 + 'Oslash' => '&#x000D8;',
  1322 + 'oslash' => '&#x000F8;',
  1323 + 'Otilde' => '&#x000D5;',
  1324 + 'otilde' => '&#x000F5;',
  1325 + 'Ouml' => '&#x000D6;',
  1326 + 'ouml' => '&#x000F6;',
  1327 + 'szlig' => '&#x000DF;',
  1328 + 'THORN' => '&#x000DE;',
  1329 + 'thorn' => '&#x000FE;',
  1330 + 'Uacute' => '&#x000DA;',
  1331 + 'uacute' => '&#x000FA;',
  1332 + 'Ucirc' => '&#x000DB;',
  1333 + 'ucirc' => '&#x000FB;',
  1334 + 'Ugrave' => '&#x000D9;',
  1335 + 'ugrave' => '&#x000F9;',
  1336 + 'Uuml' => '&#x000DC;',
  1337 + 'uuml' => '&#x000FC;',
  1338 + 'Yacute' => '&#x000DD;',
  1339 + 'yacute' => '&#x000FD;',
  1340 + 'yuml' => '&#x000FF;',
  1341 + 'Abreve' => '&#x00102;',
  1342 + 'abreve' => '&#x00103;',
  1343 + 'Amacr' => '&#x00100;',
  1344 + 'amacr' => '&#x00101;',
  1345 + 'Aogon' => '&#x00104;',
  1346 + 'aogon' => '&#x00105;',
  1347 + 'Cacute' => '&#x00106;',
  1348 + 'cacute' => '&#x00107;',
  1349 + 'Ccaron' => '&#x0010C;',
  1350 + 'ccaron' => '&#x0010D;',
  1351 + 'Ccirc' => '&#x00108;',
  1352 + 'ccirc' => '&#x00109;',
  1353 + 'Cdot' => '&#x0010A;',
  1354 + 'cdot' => '&#x0010B;',
  1355 + 'Dcaron' => '&#x0010E;',
  1356 + 'dcaron' => '&#x0010F;',
  1357 + 'Dstrok' => '&#x00110;',
  1358 + 'dstrok' => '&#x00111;',
  1359 + 'Ecaron' => '&#x0011A;',
  1360 + 'ecaron' => '&#x0011B;',
  1361 + 'Edot' => '&#x00116;',
  1362 + 'edot' => '&#x00117;',
  1363 + 'Emacr' => '&#x00112;',
  1364 + 'emacr' => '&#x00113;',
  1365 + 'ENG' => '&#x0014A;',
  1366 + 'eng' => '&#x0014B;',
  1367 + 'Eogon' => '&#x00118;',
  1368 + 'eogon' => '&#x00119;',
  1369 + 'gacute' => '&#x001F5;',
  1370 + 'Gbreve' => '&#x0011E;',
  1371 + 'gbreve' => '&#x0011F;',
  1372 + 'Gcedil' => '&#x00122;',
  1373 + 'Gcirc' => '&#x0011C;',
  1374 + 'gcirc' => '&#x0011D;',
  1375 + 'Gdot' => '&#x00120;',
  1376 + 'gdot' => '&#x00121;',
  1377 + 'Hcirc' => '&#x00124;',
  1378 + 'hcirc' => '&#x00125;',
  1379 + 'Hstrok' => '&#x00126;',
  1380 + 'hstrok' => '&#x00127;',
  1381 + 'Idot' => '&#x00130;',
  1382 + 'IJlig' => '&#x00132;',
  1383 + 'ijlig' => '&#x00133;',
  1384 + 'Imacr' => '&#x0012A;',
  1385 + 'imacr' => '&#x0012B;',
  1386 + 'inodot' => '&#x00131;',
  1387 + 'Iogon' => '&#x0012E;',
  1388 + 'iogon' => '&#x0012F;',
  1389 + 'Itilde' => '&#x00128;',
  1390 + 'itilde' => '&#x00129;',
  1391 + 'Jcirc' => '&#x00134;',
  1392 + 'jcirc' => '&#x00135;',
  1393 + 'Kcedil' => '&#x00136;',
  1394 + 'kcedil' => '&#x00137;',
  1395 + 'kgreen' => '&#x00138;',
  1396 + 'Lacute' => '&#x00139;',
  1397 + 'lacute' => '&#x0013A;',
  1398 + 'Lcaron' => '&#x0013D;',
  1399 + 'lcaron' => '&#x0013E;',
  1400 + 'Lcedil' => '&#x0013B;',
  1401 + 'lcedil' => '&#x0013C;',
  1402 + 'Lmidot' => '&#x0013F;',
  1403 + 'lmidot' => '&#x00140;',
  1404 + 'Lstrok' => '&#x00141;',
  1405 + 'lstrok' => '&#x00142;',
  1406 + 'Nacute' => '&#x00143;',
  1407 + 'nacute' => '&#x00144;',
  1408 + 'napos' => '&#x00149;',
  1409 + 'Ncaron' => '&#x00147;',
  1410 + 'ncaron' => '&#x00148;',
  1411 + 'Ncedil' => '&#x00145;',
  1412 + 'ncedil' => '&#x00146;',
  1413 + 'Odblac' => '&#x00150;',
  1414 + 'odblac' => '&#x00151;',
  1415 + 'OElig' => '&#x00152;',
  1416 + 'oelig' => '&#x00153;',
  1417 + 'Omacr' => '&#x0014C;',
  1418 + 'omacr' => '&#x0014D;',
  1419 + 'Racute' => '&#x00154;',
  1420 + 'racute' => '&#x00155;',
  1421 + 'Rcaron' => '&#x00158;',
  1422 + 'rcaron' => '&#x00159;',
  1423 + 'Rcedil' => '&#x00156;',
  1424 + 'rcedil' => '&#x00157;',
  1425 + 'Sacute' => '&#x0015A;',
  1426 + 'sacute' => '&#x0015B;',
  1427 + 'Scaron' => '&#x00160;',
  1428 + 'scaron' => '&#x00161;',
  1429 + 'Scedil' => '&#x0015E;',
  1430 + 'scedil' => '&#x0015F;',
  1431 + 'Scirc' => '&#x0015C;',
  1432 + 'scirc' => '&#x0015D;',
  1433 + 'Tcaron' => '&#x00164;',
  1434 + 'tcaron' => '&#x00165;',
  1435 + 'Tcedil' => '&#x00162;',
  1436 + 'tcedil' => '&#x00163;',
  1437 + 'Tstrok' => '&#x00166;',
  1438 + 'tstrok' => '&#x00167;',
  1439 + 'Ubreve' => '&#x0016C;',
  1440 + 'ubreve' => '&#x0016D;',
  1441 + 'Udblac' => '&#x00170;',
  1442 + 'udblac' => '&#x00171;',
  1443 + 'Umacr' => '&#x0016A;',
  1444 + 'umacr' => '&#x0016B;',
  1445 + 'Uogon' => '&#x00172;',
  1446 + 'uogon' => '&#x00173;',
  1447 + 'Uring' => '&#x0016E;',
  1448 + 'uring' => '&#x0016F;',
  1449 + 'Utilde' => '&#x00168;',
  1450 + 'utilde' => '&#x00169;',
  1451 + 'Wcirc' => '&#x00174;',
  1452 + 'wcirc' => '&#x00175;',
  1453 + 'Ycirc' => '&#x00176;',
  1454 + 'ycirc' => '&#x00177;',
  1455 + 'Yuml' => '&#x00178;',
  1456 + 'Zacute' => '&#x00179;',
  1457 + 'zacute' => '&#x0017A;',
  1458 + 'Zcaron' => '&#x0017D;',
  1459 + 'zcaron' => '&#x0017E;',
  1460 + 'Zdot' => '&#x0017B;',
  1461 + 'zdot' => '&#x0017C;',
  1462 + 'apos' => '&#x00027;',
  1463 + 'ast' => '&#x0002A;',
  1464 + 'brvbar' => '&#x000A6;',
  1465 + 'bsol' => '&#x0005C;',
  1466 + 'cent' => '&#x000A2;',
  1467 + 'colon' => '&#x0003A;',
  1468 + 'comma' => '&#x0002C;',
  1469 + 'commat' => '&#x00040;',
  1470 + 'copy' => '&#x000A9;',
  1471 + 'curren' => '&#x000A4;',
  1472 + 'darr' => '&#x02193;',
  1473 + 'deg' => '&#x000B0;',
  1474 + 'divide' => '&#x000F7;',
  1475 + 'dollar' => '&#x00024;',
  1476 + 'equals' => '&#x0003D;',
  1477 + 'excl' => '&#x00021;',
  1478 + 'frac12' => '&#x000BD;',
  1479 + 'frac14' => '&#x000BC;',
  1480 + 'frac18' => '&#x0215B;',
  1481 + 'frac34' => '&#x000BE;',
  1482 + 'frac38' => '&#x0215C;',
  1483 + 'frac58' => '&#x0215D;',
  1484 + 'frac78' => '&#x0215E;',
  1485 + 'gt' => '&#x0003E;',
  1486 + 'half' => '&#x000BD;',
  1487 + 'horbar' => '&#x02015;',
  1488 + 'hyphen' => '&#x02010;',
  1489 + 'iexcl' => '&#x000A1;',
  1490 + 'iquest' => '&#x000BF;',
  1491 + 'laquo' => '&#x000AB;',
  1492 + 'larr' => '&#x02190;',
  1493 + 'lcub' => '&#x0007B;',
  1494 + 'ldquo' => '&#x0201C;',
  1495 + 'lowbar' => '&#x0005F;',
  1496 + 'lpar' => '&#x00028;',
  1497 + 'lsqb' => '&#x0005B;',
  1498 + 'lsquo' => '&#x02018;',
  1499 + 'micro' => '&#x000B5;',
  1500 + 'middot' => '&#x000B7;',
  1501 + 'nbsp' => '&#x000A0;',
  1502 + 'not' => '&#x000AC;',
  1503 + 'num' => '&#x00023;',
  1504 + 'ohm' => '&#x02126;',
  1505 + 'ordf' => '&#x000AA;',
  1506 + 'ordm' => '&#x000BA;',
  1507 + 'para' => '&#x000B6;',
  1508 + 'percnt' => '&#x00025;',
  1509 + 'period' => '&#x0002E;',
  1510 + 'plus' => '&#x0002B;',
  1511 + 'plusmn' => '&#x000B1;',
  1512 + 'pound' => '&#x000A3;',
  1513 + 'quest' => '&#x0003F;',
  1514 + 'quot' => '&#x00022;',
  1515 + 'raquo' => '&#x000BB;',
  1516 + 'rarr' => '&#x02192;',
  1517 + 'rcub' => '&#x0007D;',
  1518 + 'rdquo' => '&#x0201D;',
  1519 + 'reg' => '&#x000AE;',
  1520 + 'rpar' => '&#x00029;',
  1521 + 'rsqb' => '&#x0005D;',
  1522 + 'rsquo' => '&#x02019;',
  1523 + 'sect' => '&#x000A7;',
  1524 + 'semi' => '&#x0003B;',
  1525 + 'shy' => '&#x000AD;',
  1526 + 'sol' => '&#x0002F;',
  1527 + 'sung' => '&#x0266A;',
  1528 + 'sup1' => '&#x000B9;',
  1529 + 'sup2' => '&#x000B2;',
  1530 + 'sup3' => '&#x000B3;',
  1531 + 'times' => '&#x000D7;',
  1532 + 'trade' => '&#x02122;',
  1533 + 'uarr' => '&#x02191;',
  1534 + 'verbar' => '&#x0007C;',
  1535 + 'yen' => '&#x000A5;',
  1536 + 'blank' => '&#x02423;',
  1537 + 'blk12' => '&#x02592;',
  1538 + 'blk14' => '&#x02591;',
  1539 + 'blk34' => '&#x02593;',
  1540 + 'block' => '&#x02588;',
  1541 + 'bull' => '&#x02022;',
  1542 + 'caret' => '&#x02041;',
  1543 + 'check' => '&#x02713;',
  1544 + 'cir' => '&#x025CB;',
  1545 + 'clubs' => '&#x02663;',
  1546 + 'copysr' => '&#x02117;',
  1547 + 'cross' => '&#x02717;',
  1548 + 'Dagger' => '&#x02021;',
  1549 + 'dagger' => '&#x02020;',
  1550 + 'dash' => '&#x02010;',
  1551 + 'diams' => '&#x02666;',
  1552 + 'dlcrop' => '&#x0230D;',
  1553 + 'drcrop' => '&#x0230C;',
  1554 + 'dtri' => '&#x025BF;',
  1555 + 'dtrif' => '&#x025BE;',
  1556 + 'emsp' => '&#x02003;',
  1557 + 'emsp13' => '&#x02004;',
  1558 + 'emsp14' => '&#x02005;',
  1559 + 'ensp' => '&#x02002;',
  1560 + 'female' => '&#x02640;',
  1561 + 'ffilig' => '&#x0FB03;',
  1562 + 'fflig' => '&#x0FB00;',
  1563 + 'ffllig' => '&#x0FB04;',
  1564 + 'filig' => '&#x0FB01;',
  1565 + 'flat' => '&#x0266D;',
  1566 + 'fllig' => '&#x0FB02;',
  1567 + 'frac13' => '&#x02153;',
  1568 + 'frac15' => '&#x02155;',
  1569 + 'frac16' => '&#x02159;',
  1570 + 'frac23' => '&#x02154;',
  1571 + 'frac25' => '&#x02156;',
  1572 + 'frac35' => '&#x02157;',
  1573 + 'frac45' => '&#x02158;',
  1574 + 'frac56' => '&#x0215A;',
  1575 + 'hairsp' => '&#x0200A;',
  1576 + 'hearts' => '&#x02665;',
  1577 + 'hellip' => '&#x02026;',
  1578 + 'hybull' => '&#x02043;',
  1579 + 'incare' => '&#x02105;',
  1580 + 'ldquor' => '&#x0201E;',
  1581 + 'lhblk' => '&#x02584;',
  1582 + 'loz' => '&#x025CA;',
  1583 + 'lozf' => '&#x029EB;',
  1584 + 'lsquor' => '&#x0201A;',
  1585 + 'ltri' => '&#x025C3;',
  1586 + 'ltrif' => '&#x025C2;',
  1587 + 'male' => '&#x02642;',
  1588 + 'malt' => '&#x02720;',
  1589 + 'marker' => '&#x025AE;',
  1590 + 'mdash' => '&#x02014;',
  1591 + 'mldr' => '&#x02026;',
  1592 + 'natur' => '&#x0266E;',
  1593 + 'ndash' => '&#x02013;',
  1594 + 'nldr' => '&#x02025;',
  1595 + 'numsp' => '&#x02007;',
  1596 + 'phone' => '&#x0260E;',
  1597 + 'puncsp' => '&#x02008;',
  1598 + 'rdquor' => '&#x0201D;',
  1599 + 'rect' => '&#x025AD;',
  1600 + 'rsquor' => '&#x02019;',
  1601 + 'rtri' => '&#x025B9;',
  1602 + 'rtrif' => '&#x025B8;',
  1603 + 'rx' => '&#x0211E;',
  1604 + 'sext' => '&#x02736;',
  1605 + 'sharp' => '&#x0266F;',
  1606 + 'spades' => '&#x02660;',
  1607 + 'squ' => '&#x025A1;',
  1608 + 'squf' => '&#x025AA;',
  1609 + 'star' => '&#x02606;',
  1610 + 'starf' => '&#x02605;',
  1611 + 'target' => '&#x02316;',
  1612 + 'telrec' => '&#x02315;',
  1613 + 'thinsp' => '&#x02009;',
  1614 + 'uhblk' => '&#x02580;',
  1615 + 'ulcrop' => '&#x0230F;',
  1616 + 'urcrop' => '&#x0230E;',
  1617 + 'utri' => '&#x025B5;',
  1618 + 'utrif' => '&#x025B4;',
  1619 + 'vellip' => '&#x022EE;',
  1620 + 'af' => '&#x02061;',
  1621 + 'aopf' => '&#x1D552;',
  1622 + 'asympeq' => '&#x0224D;',
  1623 + 'bopf' => '&#x1D553;',
  1624 + 'copf' => '&#x1D554;',
  1625 + 'Cross' => '&#x02A2F;',
  1626 + 'DD' => '&#x02145;',
  1627 + 'dd' => '&#x02146;',
  1628 + 'dopf' => '&#x1D555;',
  1629 + 'DownArrowBar' => '&#x02913;',
  1630 + 'DownBreve' => '&#x00311;',
  1631 + 'DownLeftRightVector' => '&#x02950;',
  1632 + 'DownLeftTeeVector' => '&#x0295E;',
  1633 + 'DownLeftVectorBar' => '&#x02956;',
  1634 + 'DownRightTeeVector' => '&#x0295F;',
  1635 + 'DownRightVectorBar' => '&#x02957;',
  1636 + 'ee' => '&#x02147;',
  1637 + 'EmptySmallSquare' => '&#x025FB;',
  1638 + 'EmptyVerySmallSquare' => '&#x025AB;',
  1639 + 'eopf' => '&#x1D556;',
  1640 + 'Equal' => '&#x02A75;',
  1641 + 'FilledSmallSquare' => '&#x025FC;',
  1642 + 'FilledVerySmallSquare' => '&#x025AA;',
  1643 + 'fopf' => '&#x1D557;',
  1644 + 'gopf' => '&#x1D558;',
  1645 + 'GreaterGreater' => '&#x02AA2;',
  1646 + 'Hat' => '&#x0005E;',
  1647 + 'hopf' => '&#x1D559;',
  1648 + 'HorizontalLine' => '&#x02500;',
  1649 + 'ic' => '&#x02063;',
  1650 + 'ii' => '&#x02148;',
  1651 + 'iopf' => '&#x1D55A;',
  1652 + 'it' => '&#x02062;',
  1653 + 'jopf' => '&#x1D55B;',
  1654 + 'kopf' => '&#x1D55C;',
  1655 + 'larrb' => '&#x021E4;',
  1656 + 'LeftDownTeeVector' => '&#x02961;',
  1657 + 'LeftDownVectorBar' => '&#x02959;',
  1658 + 'LeftRightVector' => '&#x0294E;',
  1659 + 'LeftTeeVector' => '&#x0295A;',
  1660 + 'LeftTriangleBar' => '&#x029CF;',
  1661 + 'LeftUpDownVector' => '&#x02951;',
  1662 + 'LeftUpTeeVector' => '&#x02960;',
  1663 + 'LeftUpVectorBar' => '&#x02958;',
  1664 + 'LeftVectorBar' => '&#x02952;',
  1665 + 'LessLess' => '&#x02AA1;',
  1666 + 'lopf' => '&#x1D55D;',
  1667 + 'mapstodown' => '&#x021A7;',
  1668 + 'mapstoleft' => '&#x021A4;',
  1669 + 'mapstoup' => '&#x021A5;',
  1670 + 'MediumSpace' => '&#x0205F;',
  1671 + 'mopf' => '&#x1D55E;',
  1672 + 'nbump' => '&#x0224E;&#x00338;',
  1673 + 'nbumpe' => '&#x0224F;&#x00338;',
  1674 + 'nesim' => '&#x02242;&#x00338;',
  1675 + 'NewLine' => '&#x0000A;',
  1676 + 'NoBreak' => '&#x02060;',
  1677 + 'nopf' => '&#x1D55F;',
  1678 + 'NotCupCap' => '&#x0226D;',
  1679 + 'NotHumpEqual' => '&#x0224F;&#x00338;',
  1680 + 'NotLeftTriangleBar' => '&#x029CF;&#x00338;',
  1681 + 'NotNestedGreaterGreater' => '&#x02AA2;&#x00338;',
  1682 + 'NotNestedLessLess' => '&#x02AA1;&#x00338;',
  1683 + 'NotRightTriangleBar' => '&#x029D0;&#x00338;',
  1684 + 'NotSquareSubset' => '&#x0228F;&#x00338;',
  1685 + 'NotSquareSuperset' => '&#x02290;&#x00338;',
  1686 + 'NotSucceedsTilde' => '&#x0227F;&#x00338;',
  1687 + 'oopf' => '&#x1D560;',
  1688 + 'OverBar' => '&#x000AF;',
  1689 + 'OverBrace' => '&#x0FE37;',
  1690 + 'OverBracket' => '&#x023B4;',
  1691 + 'OverParenthesis' => '&#x0FE35;',
  1692 + 'planckh' => '&#x0210E;',
  1693 + 'popf' => '&#x1D561;',
  1694 + 'Product' => '&#x0220F;',
  1695 + 'qopf' => '&#x1D562;',
  1696 + 'rarrb' => '&#x021E5;',
  1697 + 'RightDownTeeVector' => '&#x0295D;',
  1698 + 'RightDownVectorBar' => '&#x02955;',
  1699 + 'RightTeeVector' => '&#x0295B;',
  1700 + 'RightTriangleBar' => '&#x029D0;',
  1701 + 'RightUpDownVector' => '&#x0294F;',
  1702 + 'RightUpTeeVector' => '&#x0295C;',
  1703 + 'RightUpVectorBar' => '&#x02954;',
  1704 + 'RightVectorBar' => '&#x02953;',
  1705 + 'ropf' => '&#x1D563;',
  1706 + 'RoundImplies' => '&#x02970;',
  1707 + 'RuleDelayed' => '&#x029F4;',
  1708 + 'sopf' => '&#x1D564;',
  1709 + 'Tab' => '&#x00009;',
  1710 + 'ThickSpace' => '&#x02009;&#x0200A;&#x0200A;',
  1711 + 'topf' => '&#x1D565;',
  1712 + 'UnderBar' => '&#x00332;',
  1713 + 'UnderBrace' => '&#x0FE38;',
  1714 + 'UnderBracket' => '&#x023B5;',
  1715 + 'UnderParenthesis' => '&#x0FE36;',
  1716 + 'uopf' => '&#x1D566;',
  1717 + 'UpArrowBar' => '&#x02912;',
  1718 + 'Upsilon' => '&#x003A5;',
  1719 + 'VerticalLine' => '&#x0007C;',
  1720 + 'VerticalSeparator' => '&#x02758;',
  1721 + 'vopf' => '&#x1D567;',
  1722 + 'wopf' => '&#x1D568;',
  1723 + 'xopf' => '&#x1D569;',
  1724 + 'yopf' => '&#x1D56A;',
  1725 + 'ZeroWidthSpace' => '&#x0200B;',
  1726 + 'zopf' => '&#x1D56B;',
  1727 + 'angle' => '&#x02220;',
  1728 + 'ApplyFunction' => '&#x02061;',
  1729 + 'approx' => '&#x02248;',
  1730 + 'approxeq' => '&#x0224A;',
  1731 + 'Assign' => '&#x02254;',
  1732 + 'backcong' => '&#x0224C;',
  1733 + 'backepsilon' => '&#x003F6;',
  1734 + 'backprime' => '&#x02035;',
  1735 + 'backsim' => '&#x0223D;',
  1736 + 'backsimeq' => '&#x022CD;',
  1737 + 'Backslash' => '&#x02216;',
  1738 + 'barwedge' => '&#x02305;',
  1739 + 'Because' => '&#x02235;',
  1740 + 'because' => '&#x02235;',
  1741 + 'Bernoullis' => '&#x0212C;',
  1742 + 'between' => '&#x0226C;',
  1743 + 'bigcap' => '&#x022C2;',
  1744 + 'bigcirc' => '&#x025EF;',
  1745 + 'bigcup' => '&#x022C3;',
  1746 + 'bigodot' => '&#x02A00;',
  1747 + 'bigoplus' => '&#x02A01;',
  1748 + 'bigotimes' => '&#x02A02;',
  1749 + 'bigsqcup' => '&#x02A06;',
  1750 + 'bigstar' => '&#x02605;',
  1751 + 'bigtriangledown' => '&#x025BD;',
  1752 + 'bigtriangleup' => '&#x025B3;',
  1753 + 'biguplus' => '&#x02A04;',
  1754 + 'bigvee' => '&#x022C1;',
  1755 + 'bigwedge' => '&#x022C0;',
  1756 + 'bkarow' => '&#x0290D;',
  1757 + 'blacklozenge' => '&#x029EB;',
  1758 + 'blacksquare' => '&#x025AA;',
  1759 + 'blacktriangle' => '&#x025B4;',
  1760 + 'blacktriangledown' => '&#x025BE;',
  1761 + 'blacktriangleleft' => '&#x025C2;',
  1762 + 'blacktriangleright' => '&#x025B8;',
  1763 + 'bot' => '&#x022A5;',
  1764 + 'boxminus' => '&#x0229F;',
  1765 + 'boxplus' => '&#x0229E;',
  1766 + 'boxtimes' => '&#x022A0;',
  1767 + 'Breve' => '&#x002D8;',
  1768 + 'bullet' => '&#x02022;',
  1769 + 'Bumpeq' => '&#x0224E;',
  1770 + 'bumpeq' => '&#x0224F;',
  1771 + 'CapitalDifferentialD' => '&#x02145;',
  1772 + 'Cayleys' => '&#x0212D;',
  1773 + 'Cedilla' => '&#x000B8;',
  1774 + 'CenterDot' => '&#x000B7;',
  1775 + 'centerdot' => '&#x000B7;',
  1776 + 'checkmark' => '&#x02713;',
  1777 + 'circeq' => '&#x02257;',
  1778 + 'circlearrowleft' => '&#x021BA;',
  1779 + 'circlearrowright' => '&#x021BB;',
  1780 + 'circledast' => '&#x0229B;',
  1781 + 'circledcirc' => '&#x0229A;',
  1782 + 'circleddash' => '&#x0229D;',
  1783 + 'CircleDot' => '&#x02299;',
  1784 + 'circledR' => '&#x000AE;',
  1785 + 'circledS' => '&#x024C8;',
  1786 + 'CircleMinus' => '&#x02296;',
  1787 + 'CirclePlus' => '&#x02295;',
  1788 + 'CircleTimes' => '&#x02297;',
  1789 + 'ClockwiseContourIntegral' => '&#x02232;',
  1790 + 'CloseCurlyDoubleQuote' => '&#x0201D;',
  1791 + 'CloseCurlyQuote' => '&#x02019;',
  1792 + 'clubsuit' => '&#x02663;',
  1793 + 'coloneq' => '&#x02254;',
  1794 + 'complement' => '&#x02201;',
  1795 + 'complexes' => '&#x02102;',
  1796 + 'Congruent' => '&#x02261;',
  1797 + 'ContourIntegral' => '&#x0222E;',
  1798 + 'Coproduct' => '&#x02210;',
  1799 + 'CounterClockwiseContourIntegral' => '&#x02233;',
  1800 + 'CupCap' => '&#x0224D;',
  1801 + 'curlyeqprec' => '&#x022DE;',
  1802 + 'curlyeqsucc' => '&#x022DF;',
  1803 + 'curlyvee' => '&#x022CE;',
  1804 + 'curlywedge' => '&#x022CF;',
  1805 + 'curvearrowleft' => '&#x021B6;',
  1806 + 'curvearrowright' => '&#x021B7;',
  1807 + 'dbkarow' => '&#x0290F;',
  1808 + 'ddagger' => '&#x02021;',
  1809 + 'ddotseq' => '&#x02A77;',
  1810 + 'Del' => '&#x02207;',
  1811 + 'DiacriticalAcute' => '&#x000B4;',
  1812 + 'DiacriticalDot' => '&#x002D9;',
  1813 + 'DiacriticalDoubleAcute' => '&#x002DD;',
  1814 + 'DiacriticalGrave' => '&#x00060;',
  1815 + 'DiacriticalTilde' => '&#x002DC;',
  1816 + 'Diamond' => '&#x022C4;',
  1817 + 'diamond' => '&#x022C4;',
  1818 + 'diamondsuit' => '&#x02666;',
  1819 + 'DifferentialD' => '&#x02146;',
  1820 + 'digamma' => '&#x003DD;',
  1821 + 'div' => '&#x000F7;',
  1822 + 'divideontimes' => '&#x022C7;',
  1823 + 'doteq' => '&#x02250;',
  1824 + 'doteqdot' => '&#x02251;',
  1825 + 'DotEqual' => '&#x02250;',
  1826 + 'dotminus' => '&#x02238;',
  1827 + 'dotplus' => '&#x02214;',
  1828 + 'dotsquare' => '&#x022A1;',
  1829 + 'doublebarwedge' => '&#x02306;',
  1830 + 'DoubleContourIntegral' => '&#x0222F;',
  1831 + 'DoubleDot' => '&#x000A8;',
  1832 + 'DoubleDownArrow' => '&#x021D3;',
  1833 + 'DoubleLeftArrow' => '&#x021D0;',
  1834 + 'DoubleLeftRightArrow' => '&#x021D4;',
  1835 + 'DoubleLeftTee' => '&#x02AE4;',
  1836 + 'DoubleLongLeftArrow' => '&#x027F8;',
  1837 + 'DoubleLongLeftRightArrow' => '&#x027FA;',
  1838 + 'DoubleLongRightArrow' => '&#x027F9;',
  1839 + 'DoubleRightArrow' => '&#x021D2;',
  1840 + 'DoubleRightTee' => '&#x022A8;',
  1841 + 'DoubleUpArrow' => '&#x021D1;',
  1842 + 'DoubleUpDownArrow' => '&#x021D5;',
  1843 + 'DoubleVerticalBar' => '&#x02225;',
  1844 + 'DownArrow' => '&#x02193;',
  1845 + 'Downarrow' => '&#x021D3;',
  1846 + 'downarrow' => '&#x02193;',
  1847 + 'DownArrowUpArrow' => '&#x021F5;',
  1848 + 'downdownarrows' => '&#x021CA;',
  1849 + 'downharpoonleft' => '&#x021C3;',
  1850 + 'downharpoonright' => '&#x021C2;',
  1851 + 'DownLeftVector' => '&#x021BD;',
  1852 + 'DownRightVector' => '&#x021C1;',
  1853 + 'DownTee' => '&#x022A4;',
  1854 + 'DownTeeArrow' => '&#x021A7;',
  1855 + 'drbkarow' => '&#x02910;',
  1856 + 'Element' => '&#x02208;',
  1857 + 'emptyset' => '&#x02205;',
  1858 + 'eqcirc' => '&#x02256;',
  1859 + 'eqcolon' => '&#x02255;',
  1860 + 'eqsim' => '&#x02242;',
  1861 + 'eqslantgtr' => '&#x02A96;',
  1862 + 'eqslantless' => '&#x02A95;',
  1863 + 'EqualTilde' => '&#x02242;',
  1864 + 'Equilibrium' => '&#x021CC;',
  1865 + 'Exists' => '&#x02203;',
  1866 + 'expectation' => '&#x02130;',
  1867 + 'ExponentialE' => '&#x02147;',
  1868 + 'exponentiale' => '&#x02147;',
  1869 + 'fallingdotseq' => '&#x02252;',
  1870 + 'ForAll' => '&#x02200;',
  1871 + 'Fouriertrf' => '&#x02131;',
  1872 + 'geq' => '&#x02265;',
  1873 + 'geqq' => '&#x02267;',
  1874 + 'geqslant' => '&#x02A7E;',
  1875 + 'gg' => '&#x0226B;',
  1876 + 'ggg' => '&#x022D9;',
  1877 + 'gnapprox' => '&#x02A8A;',
  1878 + 'gneq' => '&#x02A88;',
  1879 + 'gneqq' => '&#x02269;',
  1880 + 'GreaterEqual' => '&#x02265;',
  1881 + 'GreaterEqualLess' => '&#x022DB;',
  1882 + 'GreaterFullEqual' => '&#x02267;',
  1883 + 'GreaterLess' => '&#x02277;',
  1884 + 'GreaterSlantEqual' => '&#x02A7E;',
  1885 + 'GreaterTilde' => '&#x02273;',
  1886 + 'gtrapprox' => '&#x02A86;',
  1887 + 'gtrdot' => '&#x022D7;',
  1888 + 'gtreqless' => '&#x022DB;',
  1889 + 'gtreqqless' => '&#x02A8C;',
  1890 + 'gtrless' => '&#x02277;',
  1891 + 'gtrsim' => '&#x02273;',
  1892 + 'gvertneqq' => '&#x02269;&#x0FE00;',
  1893 + 'Hacek' => '&#x002C7;',
  1894 + 'hbar' => '&#x0210F;',
  1895 + 'heartsuit' => '&#x02665;',
  1896 + 'HilbertSpace' => '&#x0210B;',
  1897 + 'hksearow' => '&#x02925;',
  1898 + 'hkswarow' => '&#x02926;',
  1899 + 'hookleftarrow' => '&#x021A9;',
  1900 + 'hookrightarrow' => '&#x021AA;',
  1901 + 'hslash' => '&#x0210F;',
  1902 + 'HumpDownHump' => '&#x0224E;',
  1903 + 'HumpEqual' => '&#x0224F;',
  1904 + 'iiiint' => '&#x02A0C;',
  1905 + 'iiint' => '&#x0222D;',
  1906 + 'Im' => '&#x02111;',
  1907 + 'ImaginaryI' => '&#x02148;',
  1908 + 'imagline' => '&#x02110;',
  1909 + 'imagpart' => '&#x02111;',
  1910 + 'Implies' => '&#x021D2;',
  1911 + 'in' => '&#x02208;',
  1912 + 'integers' => '&#x02124;',
  1913 + 'Integral' => '&#x0222B;',
  1914 + 'intercal' => '&#x022BA;',
  1915 + 'Intersection' => '&#x022C2;',
  1916 + 'intprod' => '&#x02A3C;',
  1917 + 'InvisibleComma' => '&#x02063;',
  1918 + 'InvisibleTimes' => '&#x02062;',
  1919 + 'langle' => '&#x02329;',
  1920 + 'Laplacetrf' => '&#x02112;',
  1921 + 'lbrace' => '&#x0007B;',
  1922 + 'lbrack' => '&#x0005B;',
  1923 + 'LeftAngleBracket' => '&#x02329;',
  1924 + 'LeftArrow' => '&#x02190;',
  1925 + 'Leftarrow' => '&#x021D0;',
  1926 + 'leftarrow' => '&#x02190;',
  1927 + 'LeftArrowBar' => '&#x021E4;',
  1928 + 'LeftArrowRightArrow' => '&#x021C6;',
  1929 + 'leftarrowtail' => '&#x021A2;',
  1930 + 'LeftCeiling' => '&#x02308;',
  1931 + 'LeftDoubleBracket' => '&#x0301A;',
  1932 + 'LeftDownVector' => '&#x021C3;',
  1933 + 'LeftFloor' => '&#x0230A;',
  1934 + 'leftharpoondown' => '&#x021BD;',
  1935 + 'leftharpoonup' => '&#x021BC;',
  1936 + 'leftleftarrows' => '&#x021C7;',
  1937 + 'LeftRightArrow' => '&#x02194;',
  1938 + 'Leftrightarrow' => '&#x021D4;',
  1939 + 'leftrightarrow' => '&#x02194;',
  1940 + 'leftrightarrows' => '&#x021C6;',
  1941 + 'leftrightharpoons' => '&#x021CB;',
  1942 + 'leftrightsquigarrow' => '&#x021AD;',
  1943 + 'LeftTee' => '&#x022A3;',
  1944 + 'LeftTeeArrow' => '&#x021A4;',
  1945 + 'leftthreetimes' => '&#x022CB;',
  1946 + 'LeftTriangle' => '&#x022B2;',
  1947 + 'LeftTriangleEqual' => '&#x022B4;',
  1948 + 'LeftUpVector' => '&#x021BF;',
  1949 + 'LeftVector' => '&#x021BC;',
  1950 + 'leq' => '&#x02264;',
  1951 + 'leqq' => '&#x02266;',
  1952 + 'leqslant' => '&#x02A7D;',
  1953 + 'lessapprox' => '&#x02A85;',
  1954 + 'lessdot' => '&#x022D6;',
  1955 + 'lesseqgtr' => '&#x022DA;',
  1956 + 'lesseqqgtr' => '&#x02A8B;',
  1957 + 'LessEqualGreater' => '&#x022DA;',
  1958 + 'LessFullEqual' => '&#x02266;',
  1959 + 'LessGreater' => '&#x02276;',
  1960 + 'lessgtr' => '&#x02276;',
  1961 + 'lesssim' => '&#x02272;',
  1962 + 'LessSlantEqual' => '&#x02A7D;',
  1963 + 'LessTilde' => '&#x02272;',
  1964 + 'll' => '&#x0226A;',
  1965 + 'llcorner' => '&#x0231E;',
  1966 + 'Lleftarrow' => '&#x021DA;',
  1967 + 'lmoustache' => '&#x023B0;',
  1968 + 'lnapprox' => '&#x02A89;',
  1969 + 'lneq' => '&#x02A87;',
  1970 + 'lneqq' => '&#x02268;',
  1971 + 'LongLeftArrow' => '&#x027F5;',
  1972 + 'Longleftarrow' => '&#x027F8;',
  1973 + 'longleftarrow' => '&#x027F5;',
  1974 + 'LongLeftRightArrow' => '&#x027F7;',
  1975 + 'Longleftrightarrow' => '&#x027FA;',
  1976 + 'longleftrightarrow' => '&#x027F7;',
  1977 + 'longmapsto' => '&#x027FC;',
  1978 + 'LongRightArrow' => '&#x027F6;',
  1979 + 'Longrightarrow' => '&#x027F9;',
  1980 + 'longrightarrow' => '&#x027F6;',
  1981 + 'looparrowleft' => '&#x021AB;',
  1982 + 'looparrowright' => '&#x021AC;',
  1983 + 'LowerLeftArrow' => '&#x02199;',
  1984 + 'LowerRightArrow' => '&#x02198;',
  1985 + 'lozenge' => '&#x025CA;',
  1986 + 'lrcorner' => '&#x0231F;',
  1987 + 'Lsh' => '&#x021B0;',
  1988 + 'lvertneqq' => '&#x02268;&#x0FE00;',
  1989 + 'maltese' => '&#x02720;',
  1990 + 'mapsto' => '&#x021A6;',
  1991 + 'measuredangle' => '&#x02221;',
  1992 + 'Mellintrf' => '&#x02133;',
  1993 + 'MinusPlus' => '&#x02213;',
  1994 + 'mp' => '&#x02213;',
  1995 + 'multimap' => '&#x022B8;',
  1996 + 'napprox' => '&#x02249;',
  1997 + 'natural' => '&#x0266E;',
  1998 + 'naturals' => '&#x02115;',
  1999 + 'nearrow' => '&#x02197;',
  2000 + 'NegativeMediumSpace' => '&#x0200B;',
  2001 + 'NegativeThickSpace' => '&#x0200B;',
  2002 + 'NegativeThinSpace' => '&#x0200B;',
  2003 + 'NegativeVeryThinSpace' => '&#x0200B;',
  2004 + 'NestedGreaterGreater' => '&#x0226B;',
  2005 + 'NestedLessLess' => '&#x0226A;',
  2006 + 'nexists' => '&#x02204;',
  2007 + 'ngeq' => '&#x02271;',
  2008 + 'ngeqq' => '&#x02267;&#x00338;',
  2009 + 'ngeqslant' => '&#x02A7E;&#x00338;',
  2010 + 'ngtr' => '&#x0226F;',
  2011 + 'nLeftarrow' => '&#x021CD;',
  2012 + 'nleftarrow' => '&#x0219A;',
  2013 + 'nLeftrightarrow' => '&#x021CE;',
  2014 + 'nleftrightarrow' => '&#x021AE;',
  2015 + 'nleq' => '&#x02270;',
  2016 + 'nleqq' => '&#x02266;&#x00338;',
  2017 + 'nleqslant' => '&#x02A7D;&#x00338;',
  2018 + 'nless' => '&#x0226E;',
  2019 + 'NonBreakingSpace' => '&#x000A0;',
  2020 + 'NotCongruent' => '&#x02262;',
  2021 + 'NotDoubleVerticalBar' => '&#x02226;',
  2022 + 'NotElement' => '&#x02209;',
  2023 + 'NotEqual' => '&#x02260;',
  2024 + 'NotEqualTilde' => '&#x02242;&#x00338;',
  2025 + 'NotExists' => '&#x02204;',
  2026 + 'NotGreater' => '&#x0226F;',
  2027 + 'NotGreaterEqual' => '&#x02271;',
  2028 + 'NotGreaterFullEqual' => '&#x02266;&#x00338;',
  2029 + 'NotGreaterGreater' => '&#x0226B;&#x00338;',
  2030 + 'NotGreaterLess' => '&#x02279;',
  2031 + 'NotGreaterSlantEqual' => '&#x02A7E;&#x00338;',
  2032 + 'NotGreaterTilde' => '&#x02275;',
  2033 + 'NotHumpDownHump' => '&#x0224E;&#x00338;',
  2034 + 'NotLeftTriangle' => '&#x022EA;',
  2035 + 'NotLeftTriangleEqual' => '&#x022EC;',
  2036 + 'NotLess' => '&#x0226E;',
  2037 + 'NotLessEqual' => '&#x02270;',
  2038 + 'NotLessGreater' => '&#x02278;',
  2039 + 'NotLessLess' => '&#x0226A;&#x00338;',
  2040 + 'NotLessSlantEqual' => '&#x02A7D;&#x00338;',
  2041 + 'NotLessTilde' => '&#x02274;',
  2042 + 'NotPrecedes' => '&#x02280;',
  2043 + 'NotPrecedesEqual' => '&#x02AAF;&#x00338;',
  2044 + 'NotPrecedesSlantEqual' => '&#x022E0;',
  2045 + 'NotReverseElement' => '&#x0220C;',
  2046 + 'NotRightTriangle' => '&#x022EB;',
  2047 + 'NotRightTriangleEqual' => '&#x022ED;',
  2048 + 'NotSquareSubsetEqual' => '&#x022E2;',
  2049 + 'NotSquareSupersetEqual' => '&#x022E3;',
  2050 + 'NotSubset' => '&#x02282;&#x020D2;',
  2051 + 'NotSubsetEqual' => '&#x02288;',
  2052 + 'NotSucceeds' => '&#x02281;',
  2053 + 'NotSucceedsEqual' => '&#x02AB0;&#x00338;',
  2054 + 'NotSucceedsSlantEqual' => '&#x022E1;',
  2055 + 'NotSuperset' => '&#x02283;&#x020D2;',
  2056 + 'NotSupersetEqual' => '&#x02289;',
  2057 + 'NotTilde' => '&#x02241;',
  2058 + 'NotTildeEqual' => '&#x02244;',
  2059 + 'NotTildeFullEqual' => '&#x02247;',
  2060 + 'NotTildeTilde' => '&#x02249;',
  2061 + 'NotVerticalBar' => '&#x02224;',
  2062 + 'nparallel' => '&#x02226;',
  2063 + 'nprec' => '&#x02280;',
  2064 + 'npreceq' => '&#x02AAF;&#x00338;',
  2065 + 'nRightarrow' => '&#x021CF;',
  2066 + 'nrightarrow' => '&#x0219B;',
  2067 + 'nshortmid' => '&#x02224;',
  2068 + 'nshortparallel' => '&#x02226;',
  2069 + 'nsimeq' => '&#x02244;',
  2070 + 'nsubset' => '&#x02282;&#x020D2;',
  2071 + 'nsubseteq' => '&#x02288;',
  2072 + 'nsubseteqq' => '&#x02AC5;&#x00338;',
  2073 + 'nsucc' => '&#x02281;',
  2074 + 'nsucceq' => '&#x02AB0;&#x00338;',
  2075 + 'nsupset' => '&#x02283;&#x020D2;',
  2076 + 'nsupseteq' => '&#x02289;',
  2077 + 'nsupseteqq' => '&#x02AC6;&#x00338;',
  2078 + 'ntriangleleft' => '&#x022EA;',
  2079 + 'ntrianglelefteq' => '&#x022EC;',
  2080 + 'ntriangleright' => '&#x022EB;',
  2081 + 'ntrianglerighteq' => '&#x022ED;',
  2082 + 'nwarrow' => '&#x02196;',
  2083 + 'oint' => '&#x0222E;',
  2084 + 'OpenCurlyDoubleQuote' => '&#x0201C;',
  2085 + 'OpenCurlyQuote' => '&#x02018;',
  2086 + 'orderof' => '&#x02134;',
  2087 + 'parallel' => '&#x02225;',
  2088 + 'PartialD' => '&#x02202;',
  2089 + 'pitchfork' => '&#x022D4;',
  2090 + 'PlusMinus' => '&#x000B1;',
  2091 + 'pm' => '&#x000B1;',
  2092 + 'Poincareplane' => '&#x0210C;',
  2093 + 'prec' => '&#x0227A;',
  2094 + 'precapprox' => '&#x02AB7;',
  2095 + 'preccurlyeq' => '&#x0227C;',
  2096 + 'Precedes' => '&#x0227A;',
  2097 + 'PrecedesEqual' => '&#x02AAF;',
  2098 + 'PrecedesSlantEqual' => '&#x0227C;',
  2099 + 'PrecedesTilde' => '&#x0227E;',
  2100 + 'preceq' => '&#x02AAF;',
  2101 + 'precnapprox' => '&#x02AB9;',
  2102 + 'precneqq' => '&#x02AB5;',
  2103 + 'precnsim' => '&#x022E8;',
  2104 + 'precsim' => '&#x0227E;',
  2105 + 'primes' => '&#x02119;',
  2106 + 'Proportion' => '&#x02237;',
  2107 + 'Proportional' => '&#x0221D;',
  2108 + 'propto' => '&#x0221D;',
  2109 + 'quaternions' => '&#x0210D;',
  2110 + 'questeq' => '&#x0225F;',
  2111 + 'rangle' => '&#x0232A;',
  2112 + 'rationals' => '&#x0211A;',
  2113 + 'rbrace' => '&#x0007D;',
  2114 + 'rbrack' => '&#x0005D;',
  2115 + 'Re' => '&#x0211C;',
  2116 + 'realine' => '&#x0211B;',
  2117 + 'realpart' => '&#x0211C;',
  2118 + 'reals' => '&#x0211D;',
  2119 + 'ReverseElement' => '&#x0220B;',
  2120 + 'ReverseEquilibrium' => '&#x021CB;',
  2121 + 'ReverseUpEquilibrium' => '&#x0296F;',
  2122 + 'RightAngleBracket' => '&#x0232A;',
  2123 + 'RightArrow' => '&#x02192;',
  2124 + 'Rightarrow' => '&#x021D2;',
  2125 + 'rightarrow' => '&#x02192;',
  2126 + 'RightArrowBar' => '&#x021E5;',
  2127 + 'RightArrowLeftArrow' => '&#x021C4;',
  2128 + 'rightarrowtail' => '&#x021A3;',
  2129 + 'RightCeiling' => '&#x02309;',
  2130 + 'RightDoubleBracket' => '&#x0301B;',
  2131 + 'RightDownVector' => '&#x021C2;',
  2132 + 'RightFloor' => '&#x0230B;',
  2133 + 'rightharpoondown' => '&#x021C1;',
  2134 + 'rightharpoonup' => '&#x021C0;',
  2135 + 'rightleftarrows' => '&#x021C4;',
  2136 + 'rightleftharpoons' => '&#x021CC;',
  2137 + 'rightrightarrows' => '&#x021C9;',
  2138 + 'rightsquigarrow' => '&#x0219D;',
  2139 + 'RightTee' => '&#x022A2;',
  2140 + 'RightTeeArrow' => '&#x021A6;',
  2141 + 'rightthreetimes' => '&#x022CC;',
  2142 + 'RightTriangle' => '&#x022B3;',
  2143 + 'RightTriangleEqual' => '&#x022B5;',
  2144 + 'RightUpVector' => '&#x021BE;',
  2145 + 'RightVector' => '&#x021C0;',
  2146 + 'risingdotseq' => '&#x02253;',
  2147 + 'rmoustache' => '&#x023B1;',
  2148 + 'Rrightarrow' => '&#x021DB;',
  2149 + 'Rsh' => '&#x021B1;',
  2150 + 'searrow' => '&#x02198;',
  2151 + 'setminus' => '&#x02216;',
  2152 + 'ShortDownArrow' => '&#x02193;',
  2153 + 'ShortLeftArrow' => '&#x02190;',
  2154 + 'shortmid' => '&#x02223;',
  2155 + 'shortparallel' => '&#x02225;',
  2156 + 'ShortRightArrow' => '&#x02192;',
  2157 + 'ShortUpArrow' => '&#x02191;',
  2158 + 'simeq' => '&#x02243;',
  2159 + 'SmallCircle' => '&#x02218;',
  2160 + 'smallsetminus' => '&#x02216;',
  2161 + 'spadesuit' => '&#x02660;',
  2162 + 'Sqrt' => '&#x0221A;',
  2163 + 'sqsubset' => '&#x0228F;',
  2164 + 'sqsubseteq' => '&#x02291;',
  2165 + 'sqsupset' => '&#x02290;',
  2166 + 'sqsupseteq' => '&#x02292;',
  2167 + 'Square' => '&#x025A1;',
  2168 + 'SquareIntersection' => '&#x02293;',
  2169 + 'SquareSubset' => '&#x0228F;',
  2170 + 'SquareSubsetEqual' => '&#x02291;',
  2171 + 'SquareSuperset' => '&#x02290;',
  2172 + 'SquareSupersetEqual' => '&#x02292;',
  2173 + 'SquareUnion' => '&#x02294;',
  2174 + 'Star' => '&#x022C6;',
  2175 + 'straightepsilon' => '&#x003F5;',
  2176 + 'straightphi' => '&#x003D5;',
  2177 + 'Subset' => '&#x022D0;',
  2178 + 'subset' => '&#x02282;',
  2179 + 'subseteq' => '&#x02286;',
  2180 + 'subseteqq' => '&#x02AC5;',
  2181 + 'SubsetEqual' => '&#x02286;',
  2182 + 'subsetneq' => '&#x0228A;',
  2183 + 'subsetneqq' => '&#x02ACB;',
  2184 + 'succ' => '&#x0227B;',
  2185 + 'succapprox' => '&#x02AB8;',
  2186 + 'succcurlyeq' => '&#x0227D;',
  2187 + 'Succeeds' => '&#x0227B;',
  2188 + 'SucceedsEqual' => '&#x02AB0;',
  2189 + 'SucceedsSlantEqual' => '&#x0227D;',
  2190 + 'SucceedsTilde' => '&#x0227F;',
  2191 + 'succeq' => '&#x02AB0;',
  2192 + 'succnapprox' => '&#x02ABA;',
  2193 + 'succneqq' => '&#x02AB6;',
  2194 + 'succnsim' => '&#x022E9;',
  2195 + 'succsim' => '&#x0227F;',
  2196 + 'SuchThat' => '&#x0220B;',
  2197 + 'Sum' => '&#x02211;',
  2198 + 'Superset' => '&#x02283;',
  2199 + 'SupersetEqual' => '&#x02287;',
  2200 + 'Supset' => '&#x022D1;',
  2201 + 'supset' => '&#x02283;',
  2202 + 'supseteq' => '&#x02287;',
  2203 + 'supseteqq' => '&#x02AC6;',
  2204 + 'supsetneq' => '&#x0228B;',
  2205 + 'supsetneqq' => '&#x02ACC;',
  2206 + 'swarrow' => '&#x02199;',
  2207 + 'Therefore' => '&#x02234;',
  2208 + 'therefore' => '&#x02234;',
  2209 + 'thickapprox' => '&#x02248;',
  2210 + 'thicksim' => '&#x0223C;',
  2211 + 'ThinSpace' => '&#x02009;',
  2212 + 'Tilde' => '&#x0223C;',
  2213 + 'TildeEqual' => '&#x02243;',
  2214 + 'TildeFullEqual' => '&#x02245;',
  2215 + 'TildeTilde' => '&#x02248;',
  2216 + 'toea' => '&#x02928;',
  2217 + 'tosa' => '&#x02929;',
  2218 + 'triangle' => '&#x025B5;',
  2219 + 'triangledown' => '&#x025BF;',
  2220 + 'triangleleft' => '&#x025C3;',
  2221 + 'trianglelefteq' => '&#x022B4;',
  2222 + 'triangleq' => '&#x0225C;',
  2223 + 'triangleright' => '&#x025B9;',
  2224 + 'trianglerighteq' => '&#x022B5;',
  2225 + 'TripleDot' => '&#x020DB;',
  2226 + 'twoheadleftarrow' => '&#x0219E;',
  2227 + 'twoheadrightarrow' => '&#x021A0;',
  2228 + 'ulcorner' => '&#x0231C;',
  2229 + 'Union' => '&#x022C3;',
  2230 + 'UnionPlus' => '&#x0228E;',
  2231 + 'UpArrow' => '&#x02191;',
  2232 + 'Uparrow' => '&#x021D1;',
  2233 + 'uparrow' => '&#x02191;',
  2234 + 'UpArrowDownArrow' => '&#x021C5;',
  2235 + 'UpDownArrow' => '&#x02195;',
  2236 + 'Updownarrow' => '&#x021D5;',
  2237 + 'updownarrow' => '&#x02195;',
  2238 + 'UpEquilibrium' => '&#x0296E;',
  2239 + 'upharpoonleft' => '&#x021BF;',
  2240 + 'upharpoonright' => '&#x021BE;',
  2241 + 'UpperLeftArrow' => '&#x02196;',
  2242 + 'UpperRightArrow' => '&#x02197;',
  2243 + 'upsilon' => '&#x003C5;',
  2244 + 'UpTee' => '&#x022A5;',
  2245 + 'UpTeeArrow' => '&#x021A5;',
  2246 + 'upuparrows' => '&#x021C8;',
  2247 + 'urcorner' => '&#x0231D;',
  2248 + 'varepsilon' => '&#x003B5;',
  2249 + 'varkappa' => '&#x003F0;',
  2250 + 'varnothing' => '&#x02205;',
  2251 + 'varphi' => '&#x003C6;',
  2252 + 'varpi' => '&#x003D6;',
  2253 + 'varpropto' => '&#x0221D;',
  2254 + 'varrho' => '&#x003F1;',
  2255 + 'varsigma' => '&#x003C2;',
  2256 + 'varsubsetneq' => '&#x0228A;&#x0FE00;',
  2257 + 'varsubsetneqq' => '&#x02ACB;&#x0FE00;',
  2258 + 'varsupsetneq' => '&#x0228B;&#x0FE00;',
  2259 + 'varsupsetneqq' => '&#x02ACC;&#x0FE00;',
  2260 + 'vartheta' => '&#x003D1;',
  2261 + 'vartriangleleft' => '&#x022B2;',
  2262 + 'vartriangleright' => '&#x022B3;',
  2263 + 'Vee' => '&#x022C1;',
  2264 + 'vee' => '&#x02228;',
  2265 + 'Vert' => '&#x02016;',
  2266 + 'vert' => '&#x0007C;',
  2267 + 'VerticalBar' => '&#x02223;',
  2268 + 'VerticalTilde' => '&#x02240;',
  2269 + 'VeryThinSpace' => '&#x0200A;',
  2270 + 'Wedge' => '&#x022C0;',
  2271 + 'wedge' => '&#x02227;',
  2272 + 'wp' => '&#x02118;',
  2273 + 'wr' => '&#x02240;',
  2274 + 'zeetrf' => '&#x02128;'
  2275 + }
  2276 +#:startdoc:
  2277 +
  2278 +# Converts XHTML+MathML named entities in string to Numeric Character References
  2279 +#
  2280 +# :call-seq:
  2281 +# string.to_ncr -> string
  2282 +#
  2283 + def to_ncr
  2284 + self.gsub(/&(?:(lt|gt|amp|quot|apos)|[a-zA-Z0-9]+);/){|s| $1 ? s : s.convert_to_ncr}
  2285 + end
  2286 +
  2287 +# Converts XHTML+MathML named entities in string to Numeric Character References
  2288 +#
  2289 +# :call-seq:
  2290 +# string.to_ncr! -> str or nil
  2291 +#
  2292 +# Substitution is done in-place.
  2293 +#
  2294 + def to_ncr!
  2295 + self.gsub!(/&(?:(lt|gt|amp|quot|apos)|[a-zA-Z0-9]+);/){|s| $1 ? s : s.convert_to_ncr}
  2296 + end
  2297 +
  2298 +# Converts XHTML+MathML named entities in string to UTF-8
  2299 +#
  2300 +# :call-seq:
  2301 +# string.to_utf8 -> string
  2302 +#
  2303 + def to_utf8
  2304 + self.gsub(/&(?:(lt|gt|amp|quot|apos)|[a-zA-Z0-9]+);/){|s| $1 ? s : s.convert_to_utf8}
  2305 + end
  2306 +
  2307 +# Converts XHTML+MathML named entities in string to UTF-8
  2308 +#
  2309 +# :call-seq:
  2310 +# string.to_ncr! -> str or nil
  2311 +#
  2312 +# Substitution is done in-place.
  2313 +#
  2314 + def to_utf8!
  2315 + self.gsub!(/&(?:(lt|gt|amp|quot|apos)|[a-zA-Z0-9]+);/){|s| $1 ? s : s.convert_to_utf8}
  2316 + end
  2317 +
  2318 + protected
  2319 +
  2320 + def convert_to_ncr #:nodoc:
  2321 + self =~ /^&([a-zA-Z0-9]+);$/
  2322 + name = $1
  2323 + return MATHML_ENTITIES.has_key?(name) ? MATHML_ENTITIES[name] : "&amp;" + name + ";"
  2324 + end
  2325 +
  2326 + def convert_to_utf8 #:nodoc:
  2327 + self =~ /^&([a-zA-Z0-9]+);$/
  2328 + name = $1
  2329 + return MATHML_ENTITIES.has_key?(name) ? MATHML_ENTITIES[name].split(';').collect {|s| s.gsub(/^&#x([A-F0-9]+)$/, '\1').hex }.pack('U*') : "&amp;" + name + ";"
  2330 + end
  2331 +
  2332 +
  2333 +end
  2334 +
  2335 +require 'rexml/element'
  2336 +module REXML #:nodoc:
  2337 + class Element
  2338 +
  2339 +# Convert XHTML+MathML Named Entities in a REXML::Element to Numeric Character References
  2340 +#
  2341 +# :call-seq:
  2342 +# tree.to_ncr -> REXML::Element
  2343 +#
  2344 +# REXML, typically, converts NCRs to utf-8 characters, which is what you'll see when you
  2345 +# access the resulting REXML document.
  2346 +#
  2347 +# Note that this method needs to traverse the entire tree, converting text nodes and attributes
  2348 +# for each element. This can be SLOW. It will often be faster to serialize to a string and then
  2349 +# use String.to_ncr instead.
  2350 +#
  2351 + def to_ncr
  2352 + self.each_element { |el|
  2353 + el.texts.each_index {|i|
  2354 + el.texts[i].value = el.texts[i].to_s.to_ncr
  2355 + }
  2356 + el.attributes.each { |name,val|
  2357 + el.attributes[name] = val.to_ncr
  2358 + }
  2359 + el.to_ncr if el.has_elements?
  2360 + }
  2361 + return self
  2362 + end
  2363 +
  2364 +# Convert XHTML+MathML Named Entities in a REXML::Element to UTF-8
  2365 +#
  2366 +# :call-seq:
  2367 +# tree.to_utf8 -> REXML::Element
  2368 +#
  2369 +# Note that this method needs to traverse the entire tree, converting text nodes and attributes
  2370 +# for each element. This can be SLOW. It will often be faster to serialize to a string and then
  2371 +# use String.to_utf8 instead.
  2372 +#
  2373 + def to_utf8
  2374 + self.each_element { |el|
  2375 + el.texts.each_index {|i|
  2376 + el.texts[i].value = el.texts[i].to_s.to_utf8
  2377 + }
  2378 + el.attributes.each { |name,val|
  2379 + el.attributes[name] = val.to_utf8
  2380 + }
  2381 + el.to_utf8 if el.has_elements?
  2382 + }
  2383 + return self
  2384 + end
  2385 +
  2386 + end
  2387 +end
  2388 +
  2389 +module HTML5 #:nodoc: all
  2390 + module TreeWalkers
  2391 +
  2392 + private
  2393 +
  2394 + class << self
  2395 + def [](name)
  2396 + case name.to_s.downcase
  2397 + when 'rexml'
  2398 + require 'html5/treewalkers/rexml'
  2399 + REXML::TreeWalker
  2400 + when 'rexml2'
  2401 + REXML2::TreeWalker
  2402 + else
  2403 + raise "Unknown TreeWalker #{name}"
  2404 + end
  2405 + end
  2406 +
  2407 + alias :get_tree_walker :[]
  2408 + end
  2409 +
  2410 + module REXML2
  2411 + class TreeWalker < HTML5::TreeWalkers::NonRecursiveTreeWalker
  2412 +
  2413 + private
  2414 +
  2415 + def node_details(node)
  2416 + case node
  2417 + when ::REXML::Document
  2418 + [:DOCUMENT]
  2419 + when ::REXML::Element
  2420 + if !node.name
  2421 + [:DOCUMENT_FRAGMENT]
  2422 + else
  2423 + [:ELEMENT, node.name,
  2424 + node.attributes.map {|name,value| [name,value.to_utf8]},
  2425 + node.has_elements? || node.has_text?]
  2426 + end
  2427 + when ::REXML::Text
  2428 + [:TEXT, node.value.to_utf8]
  2429 + when ::REXML::Comment
  2430 + [:COMMENT, node.string]
  2431 + when ::REXML::DocType
  2432 + [:DOCTYPE, node.name, node.public, node.system]
  2433 + when ::REXML::XMLDecl
  2434 + [nil]
  2435 + else
  2436 + [:UNKNOWN, node.class.inspect]
  2437 + end
  2438 + end
  2439 +
  2440 + def first_child(node)
  2441 + node.children.first
  2442 + end
  2443 +
  2444 + def next_sibling(node)
  2445 + node.next_sibling
  2446 + end
  2447 +
  2448 + def parent(node)
  2449 + node.parent
  2450 + end
  2451 + end
  2452 + end
  2453 + end
  2454 +end
... ...
vendor/plugins/xss_terminate/lib/rails_sanitize.rb 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +# This class exists so including the Rails HTML sanitization helpers doesn't polute your models.
  2 +class RailsSanitize
  3 + include ActionView::Helpers::SanitizeHelper
  4 +end
0 5 \ No newline at end of file
... ...
vendor/plugins/xss_terminate/lib/xss_terminate.rb 0 → 100644
... ... @@ -0,0 +1,81 @@
  1 +module XssTerminate
  2 +
  3 + def self.sanitize_by_default=(value)
  4 + @@sanitize_by_default = value
  5 + end
  6 +
  7 + def self.included(base)
  8 + base.extend(ClassMethods)
  9 + # sets up default of stripping tags for all fields
  10 + # FIXME read value from environment.rb
  11 + @@sanitize_by_default = false
  12 + base.send(:xss_terminate) if @@sanitize_by_default
  13 + end
  14 +
  15 + module ClassMethods
  16 +
  17 + def xss_terminate(options = {})
  18 + # :on is util when before_filter dont work for model
  19 + case options[:on]
  20 + when 'create'
  21 + before_create :sanitize_fields
  22 + when 'validation'
  23 + before_validation :sanitize_fields
  24 + else
  25 + before_save :sanitize_fields
  26 + end
  27 +
  28 + sanitizer = case options[:with]
  29 + when 'html5lib'
  30 + HTML5libSanitize.new
  31 + when 'white_list'
  32 + RailsSanitize.white_list_sanitizer
  33 + else
  34 + RailsSanitize.full_sanitizer
  35 + end
  36 +
  37 + write_inheritable_attribute(:xss_terminate_options, {
  38 + :except => (options[:except] || []),
  39 + :only => (options[:only] || options[:sanitize] || []),
  40 + :sanitizer => sanitizer,
  41 +
  42 + :html5lib_sanitize => (options[:html5lib_sanitize] || [])
  43 + })
  44 +
  45 + class_inheritable_reader :xss_terminate_options
  46 +
  47 + include XssTerminate::InstanceMethods
  48 + end
  49 + end
  50 +
  51 + module InstanceMethods
  52 +
  53 + def sanitize_fields
  54 +
  55 + columns = self.class.columns.select{ |i| i.type == :string || i.type == :text }.map{ |i| i.name }
  56 + columns_serialized = self.class.serialized_attributes.keys
  57 +
  58 + if !xss_terminate_options[:only].empty?
  59 + columns.select{ |i| xss_terminate_options[:only].include?( i ) }
  60 + elsif !xss_terminate_options[:except].empty?
  61 + columns.delete_if{ |i| xss_terminate_options[:except].include?( i.to_sym ) }
  62 + end
  63 +
  64 + columns.each do |column|
  65 + field = column.to_sym
  66 + if columns_serialized.include?(column)
  67 + next unless self[field]
  68 + self[field].each_key { |key|
  69 + key = key.to_sym
  70 + self[field][key] = xss_terminate_options[:sanitizer].sanitize(self[field][key].to_s)
  71 + }
  72 + else
  73 + self[field] = xss_terminate_options[:sanitizer].sanitize(self[field])
  74 + end
  75 + end
  76 +
  77 + end
  78 +
  79 + end
  80 +
  81 +end
... ...
vendor/plugins/xss_terminate/tasks/xss_terminate_tasks.rake 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +desc "Given MODELS=Foo,Bar,Baz find all instances in the DB and save to sanitize existing records"
  2 +task :xss_terminate => :environment do
  3 + models = ENV['MODELS'].split(',')
  4 + models.each do |model|
  5 + model.constantize.find(:all).map(&:save)
  6 + end
  7 +end
... ...
vendor/plugins/xss_terminate/test/models/comment.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +# Commet uses the default: stripping tags fro all fields.
  2 +class Comment < ActiveRecord::Base
  3 + belongs_to :entry
  4 + belongs_to :person
  5 +end
... ...
vendor/plugins/xss_terminate/test/models/entry.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +# Rails HTML sanitization on some fields
  2 +class Entry < ActiveRecord::Base
  3 + belongs_to :person
  4 + has_many :comments
  5 +
  6 + xss_terminate :sanitize => [:body, :extended]
  7 +end
... ...
vendor/plugins/xss_terminate/test/models/message.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +class Message < ActiveRecord::Base
  2 + belongs_to :person
  3 +
  4 + xss_terminate :only => [ :body ]
  5 +end
... ...
vendor/plugins/xss_terminate/test/models/person.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +# This model excepts HTML sanitization on the name
  2 +class Person < ActiveRecord::Base
  3 + has_many :entries
  4 + xss_terminate :except => [ :name ]
  5 +end
... ...
vendor/plugins/xss_terminate/test/models/review.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +class Review < ActiveRecord::Base
  2 + belongs_to :person
  3 +
  4 + xss_terminate :html5lib_sanitize => [:body, :extended]
  5 +end
... ...
vendor/plugins/xss_terminate/test/schema.rb 0 → 100644
... ... @@ -0,0 +1,34 @@
  1 +ActiveRecord::Schema.define(:version => 0) do
  2 + create_table :people, :force => true do |t|
  3 + t.column :name, :string
  4 + end
  5 +
  6 + create_table :entries, :force => true do |t|
  7 + t.column :title, :string
  8 + t.column :body, :text
  9 + t.column :extended, :text
  10 + t.column :person_id, :integer
  11 + t.column :created_on, :datetime
  12 + end
  13 +
  14 + create_table :comments, :force => true do |t|
  15 + t.column :person_id, :integer
  16 + t.column :title, :string
  17 + t.column :body, :text
  18 + t.column :created_on, :datetime
  19 + end
  20 +
  21 + create_table :messages, :force => true do |t|
  22 + t.column :person_id, :integer
  23 + t.column :recipient_id, :integer
  24 + t.column :body, :text
  25 + end
  26 +
  27 + create_table :reviews, :force => true do |t|
  28 + t.column :title, :string
  29 + t.column :body, :text
  30 + t.column :extended, :text
  31 + t.column :person_id, :integer
  32 + t.column :created_on, :datetime
  33 + end
  34 +end
... ...
vendor/plugins/xss_terminate/test/setup_test.rb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +# borrowed from err who borrowed from topfunky who borrowed from...
  2 +
  3 +# set up test environment
  4 +RAILS_ENV = 'test'
  5 +require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
  6 +require 'test/unit'
  7 +
  8 +# load test schema
  9 +load(File.dirname(__FILE__) + "/schema.rb")
  10 +
  11 +# load test models
  12 +require File.join(File.dirname(__FILE__), 'models/person')
  13 +require File.join(File.dirname(__FILE__), 'models/entry')
  14 +require File.join(File.dirname(__FILE__), 'models/comment')
  15 +require File.join(File.dirname(__FILE__), 'models/message')
  16 +require File.join(File.dirname(__FILE__), 'models/review')
0 17 \ No newline at end of file
... ...
vendor/plugins/xss_terminate/test/xss_terminate_test.rb 0 → 100644
... ... @@ -0,0 +1,71 @@
  1 +require File.join(File.dirname(__FILE__), 'setup_test')
  2 +
  3 +class XssTerminateTest < Test::Unit::TestCase
  4 +
  5 + XssTerminate.sanitize_by_default = true
  6 +
  7 + def test_sanitize_by_default_is_true
  8 + assert XssTerminate.sanitize_by_default
  9 + end
  10 +
  11 +
  12 + def test_strip_tags_on_discovered_fields
  13 + c = Comment.create!(:title => "<script>alert('xss in title')</script>",
  14 + :body => "<script>alert('xss in body')</script>")
  15 +
  16 + assert_equal "alert('xss in title')", c.title
  17 +
  18 + assert_equal "alert('xss in body')", c.body
  19 + end
  20 +
  21 + def test_rails_sanitization_on_specified_fields
  22 + e = Entry.create!(:title => "<script>alert('xss in title')</script>",
  23 + :body => "<script>alert('xss in body')</script>",
  24 + :extended => "<script>alert('xss in extended')</script>",
  25 + :person_id => 1)
  26 +
  27 + assert_equal [:body, :extended], e.xss_terminate_options[:only]
  28 +
  29 + assert_equal "alert('xss in title')", e.title
  30 +
  31 + assert_equal "", e.body
  32 +
  33 + assert_equal "", e.extended
  34 + end
  35 +
  36 + def test_excepting_specified_fields
  37 + p = Person.create!(:name => "<strong>Mallory</strong>")
  38 +
  39 + assert_equal [:name], p.xss_terminate_options[:except]
  40 +
  41 + assert_equal "<strong>Mallory</strong>", p.name
  42 + end
  43 +
  44 +
  45 + def test_html5lib_sanitization_on_specified_fields
  46 + r = Review.create!(:title => "<script>alert('xss in title')</script>",
  47 + :body => "<script>alert('xss in body')</script>",
  48 + :extended => "<script>alert('xss in extended')</script>",
  49 + :person_id => 1)
  50 +
  51 + assert_equal [:body, :extended], r.xss_terminate_options[:html5lib_sanitize]
  52 +
  53 + assert_equal "alert('xss in title')", r.title
  54 +
  55 + assert_equal "&lt;script&gt;alert('xss in body')&lt;/script&gt;", r.body
  56 +
  57 + assert_equal "&lt;script&gt;alert('xss in extended')&lt;/script&gt;", r.extended
  58 + end
  59 +
  60 +
  61 + ### Tests for new features (the API rewriten)
  62 +
  63 + def test_onlying_specified_fields
  64 + p = Message.create!(:body => "<strong>Mallory</strong>")
  65 +
  66 + assert_equal [:body], p.xss_terminate_options[:only]
  67 +
  68 + assert_equal "Mallory", p.body
  69 + end
  70 +
  71 +end
... ...
vendor/plugins/xss_terminate/uninstall.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +# Uninstall hook code here
... ...