diff --git a/app/controllers/application.rb b/app/controllers/application.rb
index 306a6e2..ca2fb69 100644
--- a/app/controllers/application.rb
+++ b/app/controllers/application.rb
@@ -45,9 +45,6 @@ class ApplicationController < ActionController::Base
verify :method => :post, :only => actions, :redirect_to => redirect
end
- # to sanitize params[...] add method sanitize to controller
- before_filter :sanitize
-
protected
# TODO: move this logic somewhere else (Domain class?)
@@ -120,10 +117,4 @@ class ApplicationController < ActionController::Base
end
end
- private
-
- def sanitize
- # dont sanitize anything for default
- end
-
end
diff --git a/app/controllers/my_profile/consumed_products_controller.rb b/app/controllers/my_profile/consumed_products_controller.rb
index 4652cfc..8f3e8cc 100644
--- a/app/controllers/my_profile/consumed_products_controller.rb
+++ b/app/controllers/my_profile/consumed_products_controller.rb
@@ -30,14 +30,4 @@ class ConsumedProductsController < ApplicationController
redirect_back_or_default :action => 'index'
end
- private
-
- require 'erb'
- include ERB::Util
- def sanitize
- if params[:consumption]
- params[:consumption][:aditional_specifications] = html_escape(params[:consumption][:aditional_specifications]) if params[:consumption][:aditional_specifications]
- end
- end
-
end
diff --git a/app/controllers/my_profile/enterprise_validation_controller.rb b/app/controllers/my_profile/enterprise_validation_controller.rb
index 70ff146..c34a6d0 100644
--- a/app/controllers/my_profile/enterprise_validation_controller.rb
+++ b/app/controllers/my_profile/enterprise_validation_controller.rb
@@ -60,15 +60,4 @@ class EnterpriseValidationController < MyProfileController
end
end
- private
-
- require 'erb'
- include ERB::Util
- def sanitize
- if params[:info]
- params[:info][:validation_methodology] = html_escape(params[:info][:validation_methodology]) if params[:info][:validation_methodology]
- params[:info][:restrictions] = html_escape(params[:info][:restrictions]) if params[:info][:restrictions]
- end
- end
-
end
diff --git a/app/controllers/my_profile/manage_products_controller.rb b/app/controllers/my_profile/manage_products_controller.rb
index 7fd68ee..99cdaa6 100644
--- a/app/controllers/my_profile/manage_products_controller.rb
+++ b/app/controllers/my_profile/manage_products_controller.rb
@@ -56,16 +56,5 @@ class ManageProductsController < ApplicationController
@categories = @current_category.children
render :partial => 'subcategories'
end
-
- private
-
- require 'erb'
- include ERB::Util
- def sanitize
- if params[:product]
- params[:product][:name] = html_escape(params[:product][:name]) if params[:product][:name]
- params[:product][:description] = html_escape(params[:product][:description]) if params[:product][:description]
- end
- end
end
diff --git a/app/controllers/my_profile/memberships_controller.rb b/app/controllers/my_profile/memberships_controller.rb
index 4a7bee1..47589e5 100644
--- a/app/controllers/my_profile/memberships_controller.rb
+++ b/app/controllers/my_profile/memberships_controller.rb
@@ -24,15 +24,4 @@ class MembershipsController < MyProfileController
end
end
- private
-
- require 'erb'
- include ERB::Util
- def sanitize
- if params[:community]
- params[:community][:name] = html_escape(params[:community][:name]) if params[:community][:name]
- params[:community][:description] = html_escape(params[:community][:description]) if params[:community][:description]
- end
- end
-
end
diff --git a/app/controllers/my_profile/profile_editor_controller.rb b/app/controllers/my_profile/profile_editor_controller.rb
index 2fa55c0..3af170f 100644
--- a/app/controllers/my_profile/profile_editor_controller.rb
+++ b/app/controllers/my_profile/profile_editor_controller.rb
@@ -42,20 +42,5 @@ class ProfileEditorController < MyProfileController
end
end
- private
-
- require 'erb'
- include ERB::Util
- def sanitize
- if params[:info]
- params[:info][:name] = html_escape(params[:info][:name]) if params[:info][:name]
- params[:info][:contact_person] = html_escape(params[:info][:contact_person]) if params[:info][:contact_person]
- params[:info][:acronym] = html_escape(params[:info][:acronym]) if params[:info][:acronym]
- params[:info][:legal_form] = html_escape(params[:info][:legal_form]) if params[:info][:legal_form]
- params[:info][:economic_activity] = html_escape(params[:info][:economic_activity]) if params[:info][:economic_activity]
- params[:info][:management_information] = html_escape(params[:info][:management_information]) if params[:info][:management_information]
- end
- end
-
end
diff --git a/app/controllers/public/content_viewer_controller.rb b/app/controllers/public/content_viewer_controller.rb
index 6920ca4..f6dc9ea 100644
--- a/app/controllers/public/content_viewer_controller.rb
+++ b/app/controllers/public/content_viewer_controller.rb
@@ -67,15 +67,4 @@ class ContentViewerController < PublicController
redirect_to :action => 'view_page'
end
- private
-
- require 'erb'
- include ERB::Util
- def sanitize
- if params[:comment]
- params[:comment][:body] = html_escape(params[:comment][:body]) if params[:comment][:body]
- params[:comment][:title] = html_escape(params[:comment][:title]) if params[:comment][:title]
- end
- end
-
end
diff --git a/app/controllers/public/enterprise_registration_controller.rb b/app/controllers/public/enterprise_registration_controller.rb
index b3a071b..7977982 100644
--- a/app/controllers/public/enterprise_registration_controller.rb
+++ b/app/controllers/public/enterprise_registration_controller.rb
@@ -51,16 +51,4 @@ class EnterpriseRegistrationController < ApplicationController
@create_enterprise.save!
end
- private
-
- require 'erb'
- include ERB::Util
- def sanitize
- if params[:create_enterprise]
- %w[name address contact_phone contact_person acronym foundation_year legal_form economic_activity management_information].each{ |i|
- params[:create_enterprise][i] = html_escape(params[:create_enterprise][i]) if params[:create_enterprise][i]
- }
- end
- end
-
end
diff --git a/app/models/comment.rb b/app/models/comment.rb
index 3694574..a5d0f1f 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -19,6 +19,8 @@ class Comment < ActiveRecord::Base
end
end
+ xss_terminate :only => [ :body, :title ]
+
def author_name
if author
author.name
diff --git a/app/models/community.rb b/app/models/community.rb
index 8f5ccfb..600baf1 100644
--- a/app/models/community.rb
+++ b/app/models/community.rb
@@ -3,6 +3,8 @@ class Community < Organization
settings_items :description
+ xss_terminate :only => [ :description ]
+
def name=(value)
super(value)
self.identifier = value.to_slug
diff --git a/app/models/consumption.rb b/app/models/consumption.rb
index 5dd4a22..f2d0778 100644
--- a/app/models/consumption.rb
+++ b/app/models/consumption.rb
@@ -3,4 +3,7 @@ class Consumption < ActiveRecord::Base
belongs_to :product_category
validates_uniqueness_of :product_category_id, :scope => :profile_id
+
+ xss_terminate :only => [ :aditional_specifications ]
+
end
diff --git a/app/models/create_enterprise.rb b/app/models/create_enterprise.rb
index 21c2e6e..1865ffe 100644
--- a/app/models/create_enterprise.rb
+++ b/app/models/create_enterprise.rb
@@ -40,6 +40,8 @@ class CreateEnterprise < Task
# check for explanation when rejecting
validates_presence_of :reject_explanation, :if => (lambda { |record| record.status == Task::Status::CANCELLED } )
+ xss_terminate :only => [ :acronym, :address, :contact_person, :contact_phone, :economic_activity, :foundation_year, :legal_form, :management_information, :name ], :on => 'validation'
+
def validate
if self.region && self.target
unless self.region.validators.include?(self.target)
diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb
index 1406417..7ae25db 100644
--- a/app/models/enterprise.rb
+++ b/app/models/enterprise.rb
@@ -1,8 +1,9 @@
# An enterprise is a kind of organization. According to the system concept,
# only enterprises can offer products and services.
class Enterprise < Organization
+
N_('Enterprise')
has_many :products, :dependent => :destroy
-
+
end
diff --git a/app/models/organization_info.rb b/app/models/organization_info.rb
index 6c74b43..2d67225 100644
--- a/app/models/organization_info.rb
+++ b/app/models/organization_info.rb
@@ -4,6 +4,10 @@ class OrganizationInfo < ActiveRecord::Base
validates_numericality_of :foundation_year, :only_integer => true, :allow_nil => true
validates_format_of :contact_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |info| ! info.contact_email.nil? })
+
+ xss_terminate :only => [ :acronym, :contact_person, :contact_email, :foundation_year, :legal_form, :economic_activity, :management_information ]
+
+ #xss_terminate :only => [ :acronym, :contact_person, :contact_phone, :economic_activity, :foundation_year, :legal_form, :management_information, :address, :name ]
def summary
# FIXME diplays too few fields
diff --git a/app/models/person_info.rb b/app/models/person_info.rb
index cd1aa0f..437def3 100644
--- a/app/models/person_info.rb
+++ b/app/models/person_info.rb
@@ -2,6 +2,8 @@ class PersonInfo < ActiveRecord::Base
belongs_to :person
+ xss_terminate :only => [ :name ]
+
def summary
['name', 'contact_information', 'sex', 'birth_date', 'address', 'city', 'state', 'country'].map do |col|
[ PersonInfo.columns_hash[col] && PersonInfo.columns_hash[col].human_name, self.send(col) ]
diff --git a/app/models/product.rb b/app/models/product.rb
index e138582..cbf8b8d 100644
--- a/app/models/product.rb
+++ b/app/models/product.rb
@@ -11,6 +11,8 @@ class Product < ActiveRecord::Base
after_update :save_image
acts_as_searchable :fields => [ :name, :description, :category_full_name ]
+
+ xss_terminate :only => [ :name, :description ]
def category_full_name
product_category.full_name(" ")
diff --git a/app/models/profile.rb b/app/models/profile.rb
index d2336b2..66b9c1b 100644
--- a/app/models/profile.rb
+++ b/app/models/profile.rb
@@ -117,6 +117,8 @@ class Profile < ActiveRecord::Base
true
end
+ xss_terminate :only => [ :address, :contact_phone ]
+
# Returns information about the profile's owner that was made public by
# him/her.
#
diff --git a/app/models/validation_info.rb b/app/models/validation_info.rb
index 04c132a..890cd69 100644
--- a/app/models/validation_info.rb
+++ b/app/models/validation_info.rb
@@ -2,4 +2,6 @@ class ValidationInfo < ActiveRecord::Base
validates_presence_of :validation_methodology
belongs_to :organization
+
+ xss_terminate :only => [ :validation_methodology, :restrictions ]
end
diff --git a/test/functional/enterprise_validation_test.rb b/test/functional/enterprise_validation_test.rb
index 829aba3..c9db894 100644
--- a/test/functional/enterprise_validation_test.rb
+++ b/test/functional/enterprise_validation_test.rb
@@ -135,7 +135,7 @@ class EnterpriseValidationControllerTest < Test::Unit::TestCase
assert_sanitized assigns(:info).validation_methodology
end
- should 'filter html from restriction of the validation info' do
+ should 'filter html from restrictions of the validation info' do
info = ValidationInfo.new(:validation_methodology => 'none')
@org.expects(:validation_info).returns(info)
post :edit_validation_info, :profile => 'myorg', :info => {:restrictions => 'new methodology'}
diff --git a/vendor/plugins/xss_terminate/MIT-LICENSE b/vendor/plugins/xss_terminate/MIT-LICENSE
new file mode 100644
index 0000000..9c4c822
--- /dev/null
+++ b/vendor/plugins/xss_terminate/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008 Luke Francl
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/plugins/xss_terminate/README b/vendor/plugins/xss_terminate/README
new file mode 100644
index 0000000..659184f
--- /dev/null
+++ b/vendor/plugins/xss_terminate/README
@@ -0,0 +1,118 @@
+= xss_terminate
+
+*this version is changed by joenio and should be re-documented*
+
++xss_terminate+ is a plugin in that makes stripping and sanitizing HTML
+stupid-simple. Install and forget. And forget about forgetting to h()
+your output, because you won't need to anymore.
+
+But +xss_terminate+ is also flexible. By default, it will strip all HTML tags
+from user input. This is usually what you want, but sometimes you need users to be
+able to enter HTML. The plugin allows you remove bad HTML with your choice
+of two whitelist-based sanitizers, or to skip HTML sanitization entirely on
+a per-field basis.
+
+To install, do:
+
+ script/plugin install http://xssterminate.googlecode.com/svn/trunk/xss_terminate
+
+== HTML sanitization
+
+A note on your choices.
+
+* Strip tags: removes all HTML using Rails's built-in +strip_tags+ method. Tags are removed, but their content is not.
+* Rails sanitization: Removes bad HTML with Rails's built-in sanitize method. Bad tags are removed completely, including their content.
+* 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.
+* Do nothing. You can chose not to process given fields.
+
+== Usage
+
+Installing the plugin creates a +before_save+ hook that will strip HTML tags
+from all string and text fields. No further configuration is necessary if this
+is what you want. To customize the behavior, you use the +xss_terminate+ class
+method.
+
+To exempt some fields from sanitization, use the :except option
+with a list of fields not to process:
+
+ class Comment < ActiveRecord::Base
+ xss_terminate :except => [ :body ]
+ end
+
+To sanitize only fields, use the :only option:
+
+ class Person < ActiveRecord::Base
+ xss_sanitize :only => [ :email, :name ]
+ end
+
+
+By default sanitization use HTML sanitize Rails's built-in, to use other add :with option.
+
+To sanitize using Rails white list use:
+
+ class Review < ActiveRecord::Base
+ xss_sanitize :only => [ :body, :author_name ], :with => 'white_list'
+ end
+
+To sanitize HTML with {HTML5Lib}[http://code.google.com/p/html5lib/]
+(gem install html5 to get it), use the :with => 'html5lib' option:
+
+ class Entry < ActiveRecord::Base
+ xss_terminate :only => [ :body, :author_name ], :with => 'html5lib'
+ end
+
+You can redefine when sanitize/filter will be executed with option :on. By default
+sanitization is on before_save, but if you need to sanitize on before_validation use:
+
+ class Message < ActiveRecord::Base
+ xss_terminate :executed => [ :body ], :on => 'validation'
+ end
+
+== Configuration
+
+By default all fields in all models will be sanitized after install this plugin.
+
+To change it add in our environment.rb:
+
+ XssTerminate.sanitize_by_default = false
+
+== Sanitizing existing records (FIXME tests this)
+
+After installing +xss_terminate+ and configuring it to your liking, you can
+run rake xss_terminate MODELS=Foo,Bar,Baz to execute it against your
+existing records. This will load each model found and save it again to invoke
+the before_save hook.
+
+== Unique features
+
++xss_terminate+ is based on +acts_as_sanitized+. Here is what's different:
+
+* Rails 2.0-ready.
+* Automatic. It is included with default options in ActiveReord::Base so all your models are sanitized.
+* It works with migrations. Columns are fetched when model is saved, not when the class is loaded.
+* You can decide whether to sanitize or strip tags on a field-by-field basis instead of model-by-model.
+* HTML5lib support.
+
+== TODO
+
+* Performance tests
+* Test suites with "real world" HTML
+* Test/make work with Rails 1.2.x (Rails 1.2 sanitization is crap, so you'd want to use HTML5lib)
+* Add Tests to HTML5lib to new API (changed by joenio)
+* Add tests to new API
+* Adapt to keep compatibility with old API
+* Create tests to serializable fields
+* Document new API and changes
+* Create and send path to author
+
+== Credits
+
+Written by {Luke Francl}[http://railspikes.com] and based on acts_as_sanitized by
+{Alex Payne}[http://www.al3x.net].
+
+HTML5Lib sanitization by {Jacques Distler}[http://golem.ph.utexas.edu/~distler].
+
+== License
+
+MIT License, except for lib/html5lib_sanitize.rb which is under the
+Ruby license and copyright to Jacques Distler.
diff --git a/vendor/plugins/xss_terminate/Rakefile b/vendor/plugins/xss_terminate/Rakefile
new file mode 100644
index 0000000..d3646c2
--- /dev/null
+++ b/vendor/plugins/xss_terminate/Rakefile
@@ -0,0 +1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the xss_terminate plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the xss_terminate plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'xss_terminate'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
diff --git a/vendor/plugins/xss_terminate/init.rb b/vendor/plugins/xss_terminate/init.rb
new file mode 100644
index 0000000..2719727
--- /dev/null
+++ b/vendor/plugins/xss_terminate/init.rb
@@ -0,0 +1 @@
+ActiveRecord::Base.send(:include, XssTerminate)
diff --git a/vendor/plugins/xss_terminate/install.rb b/vendor/plugins/xss_terminate/install.rb
new file mode 100644
index 0000000..f7732d3
--- /dev/null
+++ b/vendor/plugins/xss_terminate/install.rb
@@ -0,0 +1 @@
+# Install hook code here
diff --git a/vendor/plugins/xss_terminate/lib/html5lib_sanitize.rb b/vendor/plugins/xss_terminate/lib/html5lib_sanitize.rb
new file mode 100644
index 0000000..f39f854
--- /dev/null
+++ b/vendor/plugins/xss_terminate/lib/html5lib_sanitize.rb
@@ -0,0 +1,2454 @@
+# == Introduction
+#
+# This module provides sanitization of XHTML+MathML+SVG
+# and of inline style attributes. Its genesis is {described here}[http://golem.ph.utexas.edu/~distler/blog/archives/001181.html].
+#
+# Uses the {HTML5lib parser}[http://code.google.com/p/html5lib/], so that the parsing behaviour should
+# resemble that of browsers.
+#
+# sanitize_xhtml() is a case-sensitive sanitizer, suitable for XHTML
+# sanitize_html() is a case-insensitive sanitizer suitable for HTML
+# sanitize_rexml() sanitizes a REXML tree, returning a string
+#
+# == Files
+#
+# {sanitize.rb}[http://golem.ph.utexas.edu/~distler/code/instiki/svn/lib/sanitize.rb],
+# {HTML5lib}[http://golem.ph.utexas.edu/~distler/code/instiki/svn/vendor/plugins/HTML5lib/]
+#
+# == Author
+#
+# {Jacques Distler}[http://golem.ph.utexas.edu/~distler/]
+#
+# == License
+#
+# Ruby License
+
+class HTML5libSanitize
+
+ require 'html5/html5parser'
+ require 'html5/liberalxmlparser'
+ require 'html5/treewalkers'
+ require 'html5/treebuilders'
+ require 'html5/serializer'
+ require 'html5/sanitizer'
+
+ include HTML5
+
+# Sanitize a string, parsed using XHTML parsing rules.
+#
+# :call-seq:
+# sanitize_xhtml(string) -> string
+# sanitize_xhtml(string, {:encoding => 'iso-8859-1', :to_tree => true}) -> REXML::Document
+#
+# Unless otherwise specified, the string is assumed to be utf-8 encoded.
+# By default, the output is a string. But, optionally, you can return a REXML tree.
+#
+# The string returned is utf-8 encoded. If you want, you can use iconv to convert it to some other encoding.
+# (REXML trees are always utf-8 encoded.)
+ def sanitize_xhtml(html, options = {})
+ @encoding = 'utf-8'
+ @treebuilder = TreeBuilders::REXML::TreeBuilder
+ @to_tree = false
+ options.each do |name, value|
+ next unless %w(encoding treebuilder to_tree).include? name.to_s
+ if name.to_s == 'treebuilder'
+ @treebuilder = HTML5lib::TreeBuilders.get_tree_builder(value)
+ else
+ instance_variable_set("@#{name}", value)
+ end
+ end
+ if @encoding == 'utf-8'
+ parsed = XHTMLParser.parse_fragment(html.to_utf8, {:tokenizer => HTMLSanitizer,
+ :lowercase_element_name => false, :lowercase_attr_name => false,
+ :encoding => @encoding, :tree => @treebuilder })
+ else
+ parsed = XHTMLParser.parse_fragment(html.to_ncr, {:tokenizer => HTMLSanitizer,
+ :lowercase_element_name => false, :lowercase_attr_name => false,
+ :encoding => @encoding, :tree => @treebuilder })
+ end
+ return parsed if @to_tree
+ return parsed.to_s
+ end
+
+# Sanitize a string, parsed using HTML parsing rules.
+#
+# :call-seq:
+# sanitize_html( string ) -> string
+# sanitize_html( string, {:encoding => 'iso-8859-1', :to_tree => true} ) -> REXML::Document
+#
+# Unless otherwise specified, the string is assumed to be utf-8 encoded.
+# By default, the output is a string. But, optionally, you can return a REXML tree.
+#
+# The string returned is utf-8 encoded. If you want, you can use iconv to convert it to some other encoding.
+# (REXML trees are always utf-8 encoded.)
+ alias :sanitize :sanitize_html
+ def sanitize_html(html, options = {})
+ @encoding = 'utf-8'
+ @treebuilder = TreeBuilders::REXML::TreeBuilder
+ @to_tree = false
+ options.each do |name, value|
+ next unless %w(encoding treebuilder to_tree).include? name.to_s
+ if name.to_s == 'treebuilder'
+ @treebuilder = HTML5lib::TreeBuilders.get_tree_builder(value)
+ else
+ instance_variable_set("@#{name}", value)
+ end
+ end
+ if @encoding == 'utf-8'
+ parsed = HTMLParser.parse_fragment(html.to_utf8, {:tokenizer => HTMLSanitizer,
+ :encoding => @encoding, :tree => @treebuilder })
+ else
+ parsed = HTMLParser.parse_fragment(html.to_ncr, {:tokenizer => HTMLSanitizer,
+ :encoding => @encoding, :tree => @treebuilder })
+ end
+ return parsed if @to_tree
+ return parsed.to_s
+ end
+
+# Sanitize a REXML tree. The output is a string.
+#
+# :call-seq:
+# sanitize_rexml(tree) -> string
+#
+ def sanitize_rexml(tree)
+ tokens = TreeWalkers.get_tree_walker('rexml2').new(tree)
+ XHTMLSerializer.serialize(tokens, {:encoding=>'utf-8',
+ :space_before_trailing_solidus => true,
+ :inject_meta_charset => false,
+ :sanitize => true})
+ end
+end
+
+# Some useful additions to the String class
+
+class String
+
+# Check whether a string is valid utf-8
+#
+# :call-seq:
+# string.is_utf8? -> boolean
+#
+# returns true if the sequence of bytes in string is valid utf-8
+#--
+ def is_utf8?
+ #expand NCRs to utf-8
+ text = self.gsub(/([a-fA-F0-9]+);/) {|m| [$1.hex].pack('U*') }
+ text.gsub!(/(\d+);/) {|m| [$1.to_i].pack('U*') }
+ #ensure the resulting string of bytes is valid utf-8
+ text =~ /\A(
+ [\x09\x0A\x0D\x20-\x7E] # ASCII
+ | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
+ | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
+ | [\xE1-\xEC\xEE][\x80-\xBF]{2} # straight 3-byte
+ | \xEF[\x80-\xBE]{2} #
+ | \xEF\xBF[\x80-\xBD] # excluding U+fffe and U+ffff
+ | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
+ | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
+ | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
+ | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
+ )*\Z/x;
+ end
+#++
+
+#:stopdoc:
+ MATHML_ENTITIES = {
+ 'Alpha' => 'Α',
+ 'Beta' => 'Β',
+ 'Epsilon' => 'Ε',
+ 'Zeta' => 'Ζ',
+ 'Eta' => 'Η',
+ 'Iota' => 'Ι',
+ 'Kappa' => 'Κ',
+ 'Mu' => 'Μ',
+ 'Nu' => 'Ν',
+ 'Omicron' => 'Ο',
+ 'Rho' => 'Ρ',
+ 'Tau' => 'Τ',
+ 'Chi' => 'Χ',
+ 'epsilon' => 'ε',
+ 'zeta' => 'ζ',
+ 'omicron' => 'ο',
+ 'sigmaf' => 'ς',
+ 'thetasym' => 'ϑ',
+ 'upsih' => 'ϒ',
+ 'oline' => '‾',
+ 'frasl' => '⁄',
+ 'alefsym' => 'ℵ',
+ 'crarr' => '↵',
+ 'empty' => '∅',
+ 'amp' => '&',
+ 'lt' => '<',
+ 'zwnj' => '',
+ 'zwj' => '',
+ 'lrm' => '',
+ 'rlm' => '',
+ 'sbquo' => '‚',
+ 'bdquo' => '„',
+ 'lsaquo' => '‹',
+ 'rsaquo' => '›',
+ 'euro' => '€',
+ 'angzarr' => '⍼',
+ 'cirmid' => '⫯',
+ 'cudarrl' => '⤸',
+ 'cudarrr' => '⤵',
+ 'cularr' => '↶',
+ 'cularrp' => '⤽',
+ 'curarr' => '↷',
+ 'curarrm' => '⤼',
+ 'Darr' => '↡',
+ 'dArr' => '⇓',
+ 'ddarr' => '⇊',
+ 'DDotrahd' => '⤑',
+ 'dfisht' => '⥿',
+ 'dHar' => '⥥',
+ 'dharl' => '⇃',
+ 'dharr' => '⇂',
+ 'duarr' => '⇵',
+ 'duhar' => '⥯',
+ 'dzigrarr' => '⟿',
+ 'erarr' => '⥱',
+ 'hArr' => '⇔',
+ 'harr' => '↔',
+ 'harrcir' => '⥈',
+ 'harrw' => '↭',
+ 'hoarr' => '⇿',
+ 'imof' => '⊷',
+ 'lAarr' => '⇚',
+ 'Larr' => '↞',
+ 'larrbfs' => '⤟',
+ 'larrfs' => '⤝',
+ 'larrhk' => '↩',
+ 'larrlp' => '↫',
+ 'larrpl' => '⤹',
+ 'larrsim' => '⥳',
+ 'larrtl' => '↢',
+ 'lAtail' => '⤛',
+ 'latail' => '⤙',
+ 'lBarr' => '⤎',
+ 'lbarr' => '⤌',
+ 'ldca' => '⤶',
+ 'ldrdhar' => '⥧',
+ 'ldrushar' => '⥋',
+ 'ldsh' => '↲',
+ 'lfisht' => '⥼',
+ 'lHar' => '⥢',
+ 'lhard' => '↽',
+ 'lharu' => '↼',
+ 'lharul' => '⥪',
+ 'llarr' => '⇇',
+ 'llhard' => '⥫',
+ 'loarr' => '⇽',
+ 'lrarr' => '⇆',
+ 'lrhar' => '⇋',
+ 'lrhard' => '⥭',
+ 'lsh' => '↰',
+ 'lurdshar' => '⥊',
+ 'luruhar' => '⥦',
+ 'Map' => '⤅',
+ 'map' => '↦',
+ 'midcir' => '⫰',
+ 'mumap' => '⊸',
+ 'nearhk' => '⤤',
+ 'neArr' => '⇗',
+ 'nearr' => '↗',
+ 'nesear' => '⤨',
+ 'nhArr' => '⇎',
+ 'nharr' => '↮',
+ 'nlArr' => '⇍',
+ 'nlarr' => '↚',
+ 'nrArr' => '⇏',
+ 'nrarr' => '↛',
+ 'nrarrc' => '⤳̸',
+ 'nrarrw' => '↝̸',
+ 'nvHarr' => '⤄',
+ 'nvlArr' => '⤂',
+ 'nvrArr' => '⤃',
+ 'nwarhk' => '⤣',
+ 'nwArr' => '⇖',
+ 'nwarr' => '↖',
+ 'nwnear' => '⤧',
+ 'olarr' => '↺',
+ 'orarr' => '↻',
+ 'origof' => '⊶',
+ 'rAarr' => '⇛',
+ 'Rarr' => '↠',
+ 'rarrap' => '⥵',
+ 'rarrbfs' => '⤠',
+ 'rarrc' => '⤳',
+ 'rarrfs' => '⤞',
+ 'rarrhk' => '↪',
+ 'rarrlp' => '↬',
+ 'rarrpl' => '⥅',
+ 'rarrsim' => '⥴',
+ 'Rarrtl' => '⤖',
+ 'rarrtl' => '↣',
+ 'rarrw' => '↝',
+ 'rAtail' => '⤜',
+ 'ratail' => '⤚',
+ 'RBarr' => '⤐',
+ 'rBarr' => '⤏',
+ 'rbarr' => '⤍',
+ 'rdca' => '⤷',
+ 'rdldhar' => '⥩',
+ 'rdsh' => '↳',
+ 'rfisht' => '⥽',
+ 'rHar' => '⥤',
+ 'rhard' => '⇁',
+ 'rharu' => '⇀',
+ 'rharul' => '⥬',
+ 'rlarr' => '⇄',
+ 'rlhar' => '⇌',
+ 'roarr' => '⇾',
+ 'rrarr' => '⇉',
+ 'rsh' => '↱',
+ 'ruluhar' => '⥨',
+ 'searhk' => '⤥',
+ 'seArr' => '⇘',
+ 'searr' => '↘',
+ 'seswar' => '⤩',
+ 'simrarr' => '⥲',
+ 'slarr' => '←',
+ 'srarr' => '→',
+ 'swarhk' => '⤦',
+ 'swArr' => '⇙',
+ 'swarr' => '↙',
+ 'swnwar' => '⤪',
+ 'Uarr' => '↟',
+ 'uArr' => '⇑',
+ 'Uarrocir' => '⥉',
+ 'udarr' => '⇅',
+ 'udhar' => '⥮',
+ 'ufisht' => '⥾',
+ 'uHar' => '⥣',
+ 'uharl' => '↿',
+ 'uharr' => '↾',
+ 'uuarr' => '⇈',
+ 'vArr' => '⇕',
+ 'varr' => '↕',
+ 'xhArr' => '⟺',
+ 'xharr' => '⟷',
+ 'xlArr' => '⟸',
+ 'xlarr' => '⟵',
+ 'xmap' => '⟼',
+ 'xrArr' => '⟹',
+ 'xrarr' => '⟶',
+ 'zigrarr' => '⇝',
+ 'ac' => '∾',
+ 'acE' => '∾̳',
+ 'amalg' => '⨿',
+ 'barvee' => '⊽',
+ 'Barwed' => '⌆',
+ 'barwed' => '⌅',
+ 'bsolb' => '⧅',
+ 'Cap' => '⋒',
+ 'capand' => '⩄',
+ 'capbrcup' => '⩉',
+ 'capcap' => '⩋',
+ 'capcup' => '⩇',
+ 'capdot' => '⩀',
+ 'caps' => '∩︀',
+ 'ccaps' => '⩍',
+ 'ccups' => '⩌',
+ 'ccupssm' => '⩐',
+ 'coprod' => '∐',
+ 'Cup' => '⋓',
+ 'cupbrcap' => '⩈',
+ 'cupcap' => '⩆',
+ 'cupcup' => '⩊',
+ 'cupdot' => '⊍',
+ 'cupor' => '⩅',
+ 'cups' => '∪︀',
+ 'cuvee' => '⋎',
+ 'cuwed' => '⋏',
+ 'Dagger' => '‡',
+ 'dagger' => '†',
+ 'diam' => '⋄',
+ 'divonx' => '⋇',
+ 'eplus' => '⩱',
+ 'hercon' => '⊹',
+ 'intcal' => '⊺',
+ 'iprod' => '⨼',
+ 'loplus' => '⨭',
+ 'lotimes' => '⨴',
+ 'lthree' => '⋋',
+ 'ltimes' => '⋉',
+ 'midast' => '*',
+ 'minusb' => '⊟',
+ 'minusd' => '∸',
+ 'minusdu' => '⨪',
+ 'ncap' => '⩃',
+ 'ncup' => '⩂',
+ 'oast' => '⊛',
+ 'ocir' => '⊚',
+ 'odash' => '⊝',
+ 'odiv' => '⨸',
+ 'odot' => '⊙',
+ 'odsold' => '⦼',
+ 'ofcir' => '⦿',
+ 'ogt' => '⧁',
+ 'ohbar' => '⦵',
+ 'olcir' => '⦾',
+ 'olt' => '⧀',
+ 'omid' => '⦶',
+ 'ominus' => '⊖',
+ 'opar' => '⦷',
+ 'operp' => '⦹',
+ 'oplus' => '⊕',
+ 'osol' => '⊘',
+ 'Otimes' => '⨷',
+ 'otimes' => '⊗',
+ 'otimesas' => '⨶',
+ 'ovbar' => '⌽',
+ 'plusacir' => '⨣',
+ 'plusb' => '⊞',
+ 'pluscir' => '⨢',
+ 'plusdo' => '∔',
+ 'plusdu' => '⨥',
+ 'pluse' => '⩲',
+ 'plussim' => '⨦',
+ 'plustwo' => '⨧',
+ 'prod' => '∏',
+ 'race' => '⧚',
+ 'roplus' => '⨮',
+ 'rotimes' => '⨵',
+ 'rthree' => '⋌',
+ 'rtimes' => '⋊',
+ 'sdot' => '⋅',
+ 'sdotb' => '⊡',
+ 'setmn' => '∖',
+ 'simplus' => '⨤',
+ 'smashp' => '⨳',
+ 'solb' => '⧄',
+ 'sqcap' => '⊓',
+ 'sqcaps' => '⊓︀',
+ 'sqcup' => '⊔',
+ 'sqcups' => '⊔︀',
+ 'ssetmn' => '∖',
+ 'sstarf' => '⋆',
+ 'subdot' => '⪽',
+ 'sum' => '∑',
+ 'supdot' => '⪾',
+ 'timesb' => '⊠',
+ 'timesbar' => '⨱',
+ 'timesd' => '⨰',
+ 'tridot' => '◬',
+ 'triminus' => '⨺',
+ 'triplus' => '⨹',
+ 'trisb' => '⧍',
+ 'tritime' => '⨻',
+ 'uplus' => '⊎',
+ 'veebar' => '⊻',
+ 'wedbar' => '⩟',
+ 'wreath' => '≀',
+ 'xcap' => '⋂',
+ 'xcirc' => '◯',
+ 'xcup' => '⋃',
+ 'xdtri' => '▽',
+ 'xodot' => '⨀',
+ 'xoplus' => '⨁',
+ 'xotime' => '⨂',
+ 'xsqcup' => '⨆',
+ 'xuplus' => '⨄',
+ 'xutri' => '△',
+ 'xvee' => '⋁',
+ 'xwedge' => '⋀',
+ 'dlcorn' => '⌞',
+ 'drcorn' => '⌟',
+ 'gtlPar' => '⦕',
+ 'langd' => '⦑',
+ 'lbrke' => '⦋',
+ 'lbrksld' => '⦏',
+ 'lbrkslu' => '⦍',
+ 'lceil' => '⌈',
+ 'lfloor' => '⌊',
+ 'lmoust' => '⎰',
+ 'lparlt' => '⦓',
+ 'ltrPar' => '⦖',
+ 'rangd' => '⦒',
+ 'rbrke' => '⦌',
+ 'rbrksld' => '⦎',
+ 'rbrkslu' => '⦐',
+ 'rceil' => '⌉',
+ 'rfloor' => '⌋',
+ 'rmoust' => '⎱',
+ 'rpargt' => '⦔',
+ 'ulcorn' => '⌜',
+ 'urcorn' => '⌝',
+ 'gnap' => '⪊',
+ 'gnE' => '≩',
+ 'gne' => '⪈',
+ 'gnsim' => '⋧',
+ 'gvnE' => '≩︀',
+ 'lnap' => '⪉',
+ 'lnE' => '≨',
+ 'lne' => '⪇',
+ 'lnsim' => '⋦',
+ 'lvnE' => '≨︀',
+ 'nap' => '≉',
+ 'napE' => '⩰̸',
+ 'napid' => '≋̸',
+ 'ncong' => '≇',
+ 'ncongdot' => '⩭̸',
+ 'nequiv' => '≢',
+ 'ngE' => '≧̸',
+ 'nge' => '≱',
+ 'nges' => '⩾̸',
+ 'nGg' => '⋙̸',
+ 'ngsim' => '≵',
+ 'nGt' => '≫⃒',
+ 'ngt' => '≯',
+ 'nGtv' => '≫̸',
+ 'nlE' => '≦̸',
+ 'nle' => '≰',
+ 'nles' => '⩽̸',
+ 'nLl' => '⋘̸',
+ 'nlsim' => '≴',
+ 'nLt' => '≪⃒',
+ 'nlt' => '≮',
+ 'nltri' => '⋪',
+ 'nltrie' => '⋬',
+ 'nLtv' => '≪̸',
+ 'nmid' => '∤',
+ 'npar' => '∦',
+ 'npr' => '⊀',
+ 'nprcue' => '⋠',
+ 'npre' => '⪯̸',
+ 'nrtri' => '⋫',
+ 'nrtrie' => '⋭',
+ 'nsc' => '⊁',
+ 'nsccue' => '⋡',
+ 'nsce' => '⪰̸',
+ 'nsim' => '≁',
+ 'nsime' => '≄',
+ 'nsmid' => '∤',
+ 'nspar' => '∦',
+ 'nsqsube' => '⋢',
+ 'nsqsupe' => '⋣',
+ 'nsub' => '⊄',
+ 'nsubE' => '⫅̸',
+ 'nsube' => '⊈',
+ 'nsup' => '⊅',
+ 'nsupE' => '⫆̸',
+ 'nsupe' => '⊉',
+ 'ntgl' => '≹',
+ 'ntlg' => '≸',
+ 'nvap' => '≍⃒',
+ 'nVDash' => '⊯',
+ 'nVdash' => '⊮',
+ 'nvDash' => '⊭',
+ 'nvdash' => '⊬',
+ 'nvge' => '≥⃒',
+ 'nvgt' => '>⃒',
+ 'nvle' => '≤⃒',
+ 'nvltrie' => '⊴⃒',
+ 'nvrtrie' => '⊵⃒',
+ 'nvsim' => '∼⃒',
+ 'parsim' => '⫳',
+ 'prnap' => '⪹',
+ 'prnE' => '⪵',
+ 'prnsim' => '⋨',
+ 'rnmid' => '⫮',
+ 'scnap' => '⪺',
+ 'scnE' => '⪶',
+ 'scnsim' => '⋩',
+ 'simne' => '≆',
+ 'solbar' => '⌿',
+ 'subnE' => '⫋',
+ 'subne' => '⊊',
+ 'supnE' => '⫌',
+ 'supne' => '⊋',
+ 'vnsub' => '⊂⃒',
+ 'vnsup' => '⊃⃒',
+ 'vsubnE' => '⫋︀',
+ 'vsubne' => '⊊︀',
+ 'vsupnE' => '⫌︀',
+ 'vsupne' => '⊋︀',
+ 'ang' => '∠',
+ 'ange' => '⦤',
+ 'angmsd' => '∡',
+ 'angmsdaa' => '⦨',
+ 'angmsdab' => '⦩',
+ 'angmsdac' => '⦪',
+ 'angmsdad' => '⦫',
+ 'angmsdae' => '⦬',
+ 'angmsdaf' => '⦭',
+ 'angmsdag' => '⦮',
+ 'angmsdah' => '⦯',
+ 'angrtvb' => '⊾',
+ 'angrtvbd' => '⦝',
+ 'bbrk' => '⎵',
+ 'bbrktbrk' => '⎶',
+ 'bemptyv' => '⦰',
+ 'beth' => 'ℶ',
+ 'boxbox' => '⧉',
+ 'bprime' => '‵',
+ 'bsemi' => '⁏',
+ 'cemptyv' => '⦲',
+ 'cirE' => '⧃',
+ 'cirscir' => '⧂',
+ 'comp' => '∁',
+ 'daleth' => 'ℸ',
+ 'demptyv' => '⦱',
+ 'ell' => 'ℓ',
+ 'empty' => '∅',
+ 'emptyv' => '∅',
+ 'gimel' => 'ℷ',
+ 'iiota' => '℩',
+ 'image' => 'ℑ',
+ 'imath' => 'ı',
+ 'jmath' => 'j',
+ 'laemptyv' => '⦴',
+ 'lltri' => '◺',
+ 'lrtri' => '⊿',
+ 'mho' => '℧',
+ 'nang' => '∠⃒',
+ 'nexist' => '∄',
+ 'oS' => 'Ⓢ',
+ 'planck' => 'ℏ',
+ 'plankv' => 'ℏ',
+ 'raemptyv' => '⦳',
+ 'range' => '⦥',
+ 'real' => 'ℜ',
+ 'tbrk' => '⎴',
+ 'trpezium' => '�',
+ 'ultri' => '◸',
+ 'urtri' => '◹',
+ 'vzigzag' => '⦚',
+ 'weierp' => '℘',
+ 'apE' => '⩰',
+ 'ape' => '≊',
+ 'apid' => '≋',
+ 'asymp' => '≈',
+ 'Barv' => '⫧',
+ 'bcong' => '≌',
+ 'bepsi' => '϶',
+ 'bowtie' => '⋈',
+ 'bsim' => '∽',
+ 'bsime' => '⋍',
+ 'bsolhsub' => '\⊂',
+ 'bump' => '≎',
+ 'bumpE' => '⪮',
+ 'bumpe' => '≏',
+ 'cire' => '≗',
+ 'Colon' => '∷',
+ 'Colone' => '⩴',
+ 'colone' => '≔',
+ 'congdot' => '⩭',
+ 'csub' => '⫏',
+ 'csube' => '⫑',
+ 'csup' => '⫐',
+ 'csupe' => '⫒',
+ 'cuepr' => '⋞',
+ 'cuesc' => '⋟',
+ 'Dashv' => '⫤',
+ 'dashv' => '⊣',
+ 'easter' => '⩮',
+ 'ecir' => '≖',
+ 'ecolon' => '≕',
+ 'eDDot' => '⩷',
+ 'eDot' => '≑',
+ 'efDot' => '≒',
+ 'eg' => '⪚',
+ 'egs' => '⪖',
+ 'egsdot' => '⪘',
+ 'el' => '⪙',
+ 'els' => '⪕',
+ 'elsdot' => '⪗',
+ 'equest' => '≟',
+ 'equivDD' => '⩸',
+ 'erDot' => '≓',
+ 'esdot' => '≐',
+ 'Esim' => '⩳',
+ 'esim' => '≂',
+ 'fork' => '⋔',
+ 'forkv' => '⫙',
+ 'frown' => '⌢',
+ 'gap' => '⪆',
+ 'gE' => '≧',
+ 'gEl' => '⪌',
+ 'gel' => '⋛',
+ 'ges' => '⩾',
+ 'gescc' => '⪩',
+ 'gesdot' => '⪀',
+ 'gesdoto' => '⪂',
+ 'gesdotol' => '⪄',
+ 'gesl' => '⋛︀',
+ 'gesles' => '⪔',
+ 'Gg' => '⋙',
+ 'gl' => '≷',
+ 'gla' => '⪥',
+ 'glE' => '⪒',
+ 'glj' => '⪤',
+ 'gsim' => '≳',
+ 'gsime' => '⪎',
+ 'gsiml' => '⪐',
+ 'Gt' => '≫',
+ 'gtcc' => '⪧',
+ 'gtcir' => '⩺',
+ 'gtdot' => '⋗',
+ 'gtquest' => '⩼',
+ 'gtrarr' => '⥸',
+ 'homtht' => '∻',
+ 'lap' => '⪅',
+ 'lat' => '⪫',
+ 'late' => '⪭',
+ 'lates' => '⪭︀',
+ 'lE' => '≦',
+ 'lEg' => '⪋',
+ 'leg' => '⋚',
+ 'les' => '⩽',
+ 'lescc' => '⪨',
+ 'lesdot' => '⩿',
+ 'lesdoto' => '⪁',
+ 'lesdotor' => '⪃',
+ 'lesg' => '⋚︀',
+ 'lesges' => '⪓',
+ 'lg' => '≶',
+ 'lgE' => '⪑',
+ 'Ll' => '⋘',
+ 'lsim' => '≲',
+ 'lsime' => '⪍',
+ 'lsimg' => '⪏',
+ 'Lt' => '≪',
+ 'ltcc' => '⪦',
+ 'ltcir' => '⩹',
+ 'ltdot' => '⋖',
+ 'ltlarr' => '⥶',
+ 'ltquest' => '⩻',
+ 'ltrie' => '⊴',
+ 'mcomma' => '⨩',
+ 'mDDot' => '∺',
+ 'mid' => '∣',
+ 'mlcp' => '⫛',
+ 'models' => '⊧',
+ 'mstpos' => '∾',
+ 'Pr' => '⪻',
+ 'pr' => '≺',
+ 'prap' => '⪷',
+ 'prcue' => '≼',
+ 'prE' => '⪳',
+ 'pre' => '⪯',
+ 'prsim' => '≾',
+ 'prurel' => '⊰',
+ 'ratio' => '∶',
+ 'rtrie' => '⊵',
+ 'rtriltri' => '⧎',
+ 'Sc' => '⪼',
+ 'sc' => '≻',
+ 'scap' => '⪸',
+ 'sccue' => '≽',
+ 'scE' => '⪴',
+ 'sce' => '⪰',
+ 'scsim' => '≿',
+ 'sdote' => '⩦',
+ 'sfrown' => '⌢',
+ 'simg' => '⪞',
+ 'simgE' => '⪠',
+ 'siml' => '⪝',
+ 'simlE' => '⪟',
+ 'smid' => '∣',
+ 'smile' => '⌣',
+ 'smt' => '⪪',
+ 'smte' => '⪬',
+ 'smtes' => '⪬︀',
+ 'spar' => '∥',
+ 'sqsub' => '⊏',
+ 'sqsube' => '⊑',
+ 'sqsup' => '⊐',
+ 'sqsupe' => '⊒',
+ 'ssmile' => '⌣',
+ 'Sub' => '⋐',
+ 'subE' => '⫅',
+ 'subedot' => '⫃',
+ 'submult' => '⫁',
+ 'subplus' => '⪿',
+ 'subrarr' => '⥹',
+ 'subsim' => '⫇',
+ 'subsub' => '⫕',
+ 'subsup' => '⫓',
+ 'Sup' => '⋑',
+ 'supdsub' => '⫘',
+ 'supE' => '⫆',
+ 'supedot' => '⫄',
+ 'suphsol' => '⊃/',
+ 'suphsub' => '⫗',
+ 'suplarr' => '⥻',
+ 'supmult' => '⫂',
+ 'supplus' => '⫀',
+ 'supsim' => '⫈',
+ 'supsub' => '⫔',
+ 'supsup' => '⫖',
+ 'thkap' => '≈',
+ 'thksim' => '∼',
+ 'topfork' => '⫚',
+ 'trie' => '≜',
+ 'twixt' => '≬',
+ 'Vbar' => '⫫',
+ 'vBar' => '⫨',
+ 'vBarv' => '⫩',
+ 'VDash' => '⊫',
+ 'Vdash' => '⊩',
+ 'vDash' => '⊨',
+ 'vdash' => '⊢',
+ 'Vdashl' => '⫦',
+ 'vltri' => '⊲',
+ 'vprop' => '∝',
+ 'vrtri' => '⊳',
+ 'Vvdash' => '⊪',
+ 'alpha' => 'α',
+ 'beta' => 'β',
+ 'chi' => 'χ',
+ 'Delta' => 'Δ',
+ 'delta' => 'δ',
+ 'epsi' => 'ϵ',
+ 'epsiv' => 'ε',
+ 'eta' => 'η',
+ 'Gamma' => 'Γ',
+ 'gamma' => 'γ',
+ 'Gammad' => 'Ϝ',
+ 'gammad' => 'ϝ',
+ 'iota' => 'ι',
+ 'kappa' => 'κ',
+ 'kappav' => 'ϰ',
+ 'Lambda' => 'Λ',
+ 'lambda' => 'λ',
+ 'mu' => 'μ',
+ 'nu' => 'ν',
+ 'Omega' => 'Ω',
+ 'omega' => 'ω',
+ 'Phi' => 'Φ',
+ 'phi' => 'ϕ',
+ 'phiv' => 'φ',
+ 'Pi' => 'Π',
+ 'pi' => 'π',
+ 'piv' => 'ϖ',
+ 'Psi' => 'Ψ',
+ 'psi' => 'ψ',
+ 'rho' => 'ρ',
+ 'rhov' => 'ϱ',
+ 'Sigma' => 'Σ',
+ 'sigma' => 'σ',
+ 'sigmav' => 'ς',
+ 'tau' => 'τ',
+ 'Theta' => 'Θ',
+ 'theta' => 'θ',
+ 'thetav' => 'ϑ',
+ 'Upsi' => 'ϒ',
+ 'upsi' => 'υ',
+ 'Xi' => 'Ξ',
+ 'xi' => 'ξ',
+ 'zeta' => 'ζ',
+ 'Afr' => '𝔄',
+ 'afr' => '𝔞',
+ 'Bfr' => '𝔅',
+ 'bfr' => '𝔟',
+ 'Cfr' => 'ℭ',
+ 'cfr' => '𝔠',
+ 'Dfr' => '𝔇',
+ 'dfr' => '𝔡',
+ 'Efr' => '𝔈',
+ 'efr' => '𝔢',
+ 'Ffr' => '𝔉',
+ 'ffr' => '𝔣',
+ 'Gfr' => '𝔊',
+ 'gfr' => '𝔤',
+ 'Hfr' => 'ℌ',
+ 'hfr' => '𝔥',
+ 'Ifr' => 'ℑ',
+ 'ifr' => '𝔦',
+ 'Jfr' => '𝔍',
+ 'jfr' => '𝔧',
+ 'Kfr' => '𝔎',
+ 'kfr' => '𝔨',
+ 'Lfr' => '𝔏',
+ 'lfr' => '𝔩',
+ 'Mfr' => '𝔐',
+ 'mfr' => '𝔪',
+ 'Nfr' => '𝔑',
+ 'nfr' => '𝔫',
+ 'Ofr' => '𝔒',
+ 'ofr' => '𝔬',
+ 'Pfr' => '𝔓',
+ 'pfr' => '𝔭',
+ 'Qfr' => '𝔔',
+ 'qfr' => '𝔮',
+ 'Rfr' => 'ℜ',
+ 'rfr' => '𝔯',
+ 'Sfr' => '𝔖',
+ 'sfr' => '𝔰',
+ 'Tfr' => '𝔗',
+ 'tfr' => '𝔱',
+ 'Ufr' => '𝔘',
+ 'ufr' => '𝔲',
+ 'Vfr' => '𝔙',
+ 'vfr' => '𝔳',
+ 'Wfr' => '𝔚',
+ 'wfr' => '𝔴',
+ 'Xfr' => '𝔛',
+ 'xfr' => '𝔵',
+ 'Yfr' => '𝔜',
+ 'yfr' => '𝔶',
+ 'Zfr' => 'ℨ',
+ 'zfr' => '𝔷',
+ 'Aopf' => '𝔸',
+ 'Bopf' => '𝔹',
+ 'Copf' => 'ℂ',
+ 'Dopf' => '𝔻',
+ 'Eopf' => '𝔼',
+ 'Fopf' => '𝔽',
+ 'Gopf' => '𝔾',
+ 'Hopf' => 'ℍ',
+ 'Iopf' => '𝕀',
+ 'Jopf' => '𝕁',
+ 'Kopf' => '𝕂',
+ 'Lopf' => '𝕃',
+ 'Mopf' => '𝕄',
+ 'Nopf' => 'ℕ',
+ 'Oopf' => '𝕆',
+ 'Popf' => 'ℙ',
+ 'Qopf' => 'ℚ',
+ 'Ropf' => 'ℝ',
+ 'Sopf' => '𝕊',
+ 'Topf' => '𝕋',
+ 'Uopf' => '𝕌',
+ 'Vopf' => '𝕍',
+ 'Wopf' => '𝕎',
+ 'Xopf' => '𝕏',
+ 'Yopf' => '𝕐',
+ 'Zopf' => 'ℤ',
+ 'Ascr' => '𝒜',
+ 'ascr' => '𝒶',
+ 'Bscr' => 'ℬ',
+ 'bscr' => '𝒷',
+ 'Cscr' => '𝒞',
+ 'cscr' => '𝒸',
+ 'Dscr' => '𝒟',
+ 'dscr' => '𝒹',
+ 'Escr' => 'ℰ',
+ 'escr' => 'ℯ',
+ 'Fscr' => 'ℱ',
+ 'fscr' => '𝒻',
+ 'Gscr' => '𝒢',
+ 'gscr' => 'ℊ',
+ 'Hscr' => 'ℋ',
+ 'hscr' => '𝒽',
+ 'Iscr' => 'ℐ',
+ 'iscr' => '𝒾',
+ 'Jscr' => '𝒥',
+ 'jscr' => '𝒿',
+ 'Kscr' => '𝒦',
+ 'kscr' => '𝓀',
+ 'Lscr' => 'ℒ',
+ 'lscr' => '𝓁',
+ 'Mscr' => 'ℳ',
+ 'mscr' => '𝓂',
+ 'Nscr' => '𝒩',
+ 'nscr' => '𝓃',
+ 'Oscr' => '𝒪',
+ 'oscr' => 'ℴ',
+ 'Pscr' => '𝒫',
+ 'pscr' => '𝓅',
+ 'Qscr' => '𝒬',
+ 'qscr' => '𝓆',
+ 'Rscr' => 'ℛ',
+ 'rscr' => '𝓇',
+ 'Sscr' => '𝒮',
+ 'sscr' => '𝓈',
+ 'Tscr' => '𝒯',
+ 'tscr' => '𝓉',
+ 'Uscr' => '𝒰',
+ 'uscr' => '𝓊',
+ 'Vscr' => '𝒱',
+ 'vscr' => '𝓋',
+ 'Wscr' => '𝒲',
+ 'wscr' => '𝓌',
+ 'Xscr' => '𝒳',
+ 'xscr' => '𝓍',
+ 'Yscr' => '𝒴',
+ 'yscr' => '𝓎',
+ 'Zscr' => '𝒵',
+ 'zscr' => '𝓏',
+ 'acd' => '∿',
+ 'aleph' => 'ℵ',
+ 'And' => '⩓',
+ 'and' => '∧',
+ 'andand' => '⩕',
+ 'andd' => '⩜',
+ 'andslope' => '⩘',
+ 'andv' => '⩚',
+ 'angrt' => '∟',
+ 'angsph' => '∢',
+ 'angst' => 'Å',
+ 'ap' => '≈',
+ 'apacir' => '⩯',
+ 'awconint' => '∳',
+ 'awint' => '⨑',
+ 'becaus' => '∵',
+ 'bernou' => 'ℬ',
+ 'bne' => '=⃥',
+ 'bnequiv' => '≡⃥',
+ 'bNot' => '⫭',
+ 'bnot' => '⌐',
+ 'bottom' => '⊥',
+ 'cap' => '∩',
+ 'Cconint' => '∰',
+ 'cirfnint' => '⨐',
+ 'compfn' => '∘',
+ 'cong' => '≅',
+ 'Conint' => '∯',
+ 'conint' => '∮',
+ 'ctdot' => '⋯',
+ 'cup' => '∪',
+ 'cwconint' => '∲',
+ 'cwint' => '∱',
+ 'cylcty' => '⌭',
+ 'disin' => '⋲',
+ 'Dot' => '¨',
+ 'DotDot' => '⃜',
+ 'dsol' => '⧶',
+ 'dtdot' => '⋱',
+ 'dwangle' => '⦦',
+ 'elinters' => '�',
+ 'epar' => '⋕',
+ 'eparsl' => '⧣',
+ 'equiv' => '≡',
+ 'eqvparsl' => '⧥',
+ 'exist' => '∃',
+ 'fltns' => '▱',
+ 'fnof' => 'ƒ',
+ 'forall' => '∀',
+ 'fpartint' => '⨍',
+ 'ge' => '≥',
+ 'hamilt' => 'ℋ',
+ 'iff' => '⇔',
+ 'iinfin' => '⧜',
+ 'imped' => 'Ƶ',
+ 'infin' => '∞',
+ 'infintie' => '⧝',
+ 'Int' => '∬',
+ 'int' => '∫',
+ 'intlarhk' => '⨗',
+ 'isin' => '∈',
+ 'isindot' => '⋵',
+ 'isinE' => '⋹',
+ 'isins' => '⋴',
+ 'isinsv' => '⋳',
+ 'isinv' => '∈',
+ 'lagran' => 'ℒ',
+ 'Lang' => '《',
+ 'lang' => '〈',
+ 'lArr' => '⇐',
+ 'lbbrk' => '〔',
+ 'le' => '≤',
+ 'loang' => '〘',
+ 'lobrk' => '〚',
+ 'lopar' => '⦅',
+ 'lowast' => '∗',
+ 'minus' => '−',
+ 'mnplus' => '∓',
+ 'nabla' => '∇',
+ 'ne' => '≠',
+ 'nedot' => '≐̸',
+ 'nhpar' => '⫲',
+ 'ni' => '∋',
+ 'nis' => '⋼',
+ 'nisd' => '⋺',
+ 'niv' => '∋',
+ 'Not' => '⫬',
+ 'notin' => '∉',
+ 'notindot' => '⋵̸',
+ 'notinE' => '⋹̸',
+ 'notinva' => '∉',
+ 'notinvb' => '⋷',
+ 'notinvc' => '⋶',
+ 'notni' => '∌',
+ 'notniva' => '∌',
+ 'notnivb' => '⋾',
+ 'notnivc' => '⋽',
+ 'nparsl' => '⫽⃥',
+ 'npart' => '∂̸',
+ 'npolint' => '⨔',
+ 'nvinfin' => '⧞',
+ 'olcross' => '⦻',
+ 'Or' => '⩔',
+ 'or' => '∨',
+ 'ord' => '⩝',
+ 'order' => 'ℴ',
+ 'oror' => '⩖',
+ 'orslope' => '⩗',
+ 'orv' => '⩛',
+ 'par' => '∥',
+ 'parsl' => '⫽',
+ 'part' => '∂',
+ 'permil' => '‰',
+ 'perp' => '⊥',
+ 'pertenk' => '‱',
+ 'phmmat' => 'ℳ',
+ 'pointint' => '⨕',
+ 'Prime' => '″',
+ 'prime' => '′',
+ 'profalar' => '⌮',
+ 'profline' => '⌒',
+ 'profsurf' => '⌓',
+ 'prop' => '∝',
+ 'qint' => '⨌',
+ 'qprime' => '⁗',
+ 'quatint' => '⨖',
+ 'radic' => '√',
+ 'Rang' => '》',
+ 'rang' => '〉',
+ 'rArr' => '⇒',
+ 'rbbrk' => '〕',
+ 'roang' => '〙',
+ 'robrk' => '〛',
+ 'ropar' => '⦆',
+ 'rppolint' => '⨒',
+ 'scpolint' => '⨓',
+ 'sim' => '∼',
+ 'simdot' => '⩪',
+ 'sime' => '≃',
+ 'smeparsl' => '⧤',
+ 'square' => '□',
+ 'squarf' => '▪',
+ 'strns' => '¯',
+ 'sub' => '⊂',
+ 'sube' => '⊆',
+ 'sup' => '⊃',
+ 'supe' => '⊇',
+ 'tdot' => '⃛',
+ 'there4' => '∴',
+ 'tint' => '∭',
+ 'top' => '⊤',
+ 'topbot' => '⌶',
+ 'topcir' => '⫱',
+ 'tprime' => '‴',
+ 'utdot' => '⋰',
+ 'uwangle' => '⦧',
+ 'vangrt' => '⦜',
+ 'veeeq' => '≚',
+ 'Verbar' => '‖',
+ 'wedgeq' => '≙',
+ 'xnis' => '⋻',
+ 'boxDL' => '╗',
+ 'boxDl' => '╖',
+ 'boxdL' => '╕',
+ 'boxdl' => '┐',
+ 'boxDR' => '╔',
+ 'boxDr' => '╓',
+ 'boxdR' => '╒',
+ 'boxdr' => '┌',
+ 'boxH' => '═',
+ 'boxh' => '─',
+ 'boxHD' => '╦',
+ 'boxHd' => '╤',
+ 'boxhD' => '╥',
+ 'boxhd' => '┬',
+ 'boxHU' => '╩',
+ 'boxHu' => '╧',
+ 'boxhU' => '╨',
+ 'boxhu' => '┴',
+ 'boxUL' => '╝',
+ 'boxUl' => '╜',
+ 'boxuL' => '╛',
+ 'boxul' => '┘',
+ 'boxUR' => '╚',
+ 'boxUr' => '╙',
+ 'boxuR' => '╘',
+ 'boxur' => '└',
+ 'boxV' => '║',
+ 'boxv' => '│',
+ 'boxVH' => '╬',
+ 'boxVh' => '╫',
+ 'boxvH' => '╪',
+ 'boxvh' => '┼',
+ 'boxVL' => '╣',
+ 'boxVl' => '╢',
+ 'boxvL' => '╡',
+ 'boxvl' => '┤',
+ 'boxVR' => '╠',
+ 'boxVr' => '╟',
+ 'boxvR' => '╞',
+ 'boxvr' => '├',
+ 'Acy' => 'А',
+ 'acy' => 'а',
+ 'Bcy' => 'Б',
+ 'bcy' => 'б',
+ 'CHcy' => 'Ч',
+ 'chcy' => 'ч',
+ 'Dcy' => 'Д',
+ 'dcy' => 'д',
+ 'Ecy' => 'Э',
+ 'ecy' => 'э',
+ 'Fcy' => 'Ф',
+ 'fcy' => 'ф',
+ 'Gcy' => 'Г',
+ 'gcy' => 'г',
+ 'HARDcy' => 'Ъ',
+ 'hardcy' => 'ъ',
+ 'Icy' => 'И',
+ 'icy' => 'и',
+ 'IEcy' => 'Е',
+ 'iecy' => 'е',
+ 'IOcy' => 'Ё',
+ 'iocy' => 'ё',
+ 'Jcy' => 'Й',
+ 'jcy' => 'й',
+ 'Kcy' => 'К',
+ 'kcy' => 'к',
+ 'KHcy' => 'Х',
+ 'khcy' => 'х',
+ 'Lcy' => 'Л',
+ 'lcy' => 'л',
+ 'Mcy' => 'М',
+ 'mcy' => 'м',
+ 'Ncy' => 'Н',
+ 'ncy' => 'н',
+ 'numero' => '№',
+ 'Ocy' => 'О',
+ 'ocy' => 'о',
+ 'Pcy' => 'П',
+ 'pcy' => 'п',
+ 'Rcy' => 'Р',
+ 'rcy' => 'р',
+ 'Scy' => 'С',
+ 'scy' => 'с',
+ 'SHCHcy' => 'Щ',
+ 'shchcy' => 'щ',
+ 'SHcy' => 'Ш',
+ 'shcy' => 'ш',
+ 'SOFTcy' => 'Ь',
+ 'softcy' => 'ь',
+ 'Tcy' => 'Т',
+ 'tcy' => 'т',
+ 'TScy' => 'Ц',
+ 'tscy' => 'ц',
+ 'Ucy' => 'У',
+ 'ucy' => 'у',
+ 'Vcy' => 'В',
+ 'vcy' => 'в',
+ 'YAcy' => 'Я',
+ 'yacy' => 'я',
+ 'Ycy' => 'Ы',
+ 'ycy' => 'ы',
+ 'YUcy' => 'Ю',
+ 'yucy' => 'ю',
+ 'Zcy' => 'З',
+ 'zcy' => 'з',
+ 'ZHcy' => 'Ж',
+ 'zhcy' => 'ж',
+ 'DJcy' => 'Ђ',
+ 'djcy' => 'ђ',
+ 'DScy' => 'Ѕ',
+ 'dscy' => 'ѕ',
+ 'DZcy' => 'Џ',
+ 'dzcy' => 'џ',
+ 'GJcy' => 'Ѓ',
+ 'gjcy' => 'ѓ',
+ 'Iukcy' => 'І',
+ 'iukcy' => 'і',
+ 'Jsercy' => 'Ј',
+ 'jsercy' => 'ј',
+ 'Jukcy' => 'Є',
+ 'jukcy' => 'є',
+ 'KJcy' => 'Ќ',
+ 'kjcy' => 'ќ',
+ 'LJcy' => 'Љ',
+ 'ljcy' => 'љ',
+ 'NJcy' => 'Њ',
+ 'njcy' => 'њ',
+ 'TSHcy' => 'Ћ',
+ 'tshcy' => 'ћ',
+ 'Ubrcy' => 'Ў',
+ 'ubrcy' => 'ў',
+ 'YIcy' => 'Ї',
+ 'yicy' => 'ї',
+ 'acute' => '´',
+ 'breve' => '˘',
+ 'caron' => 'ˇ',
+ 'cedil' => '¸',
+ 'circ' => 'ˆ',
+ 'dblac' => '˝',
+ 'die' => '¨',
+ 'dot' => '˙',
+ 'grave' => '`',
+ 'macr' => '¯',
+ 'ogon' => '˛',
+ 'ring' => '˚',
+ 'tilde' => '˜',
+ 'uml' => '¨',
+ 'Aacute' => 'Á',
+ 'aacute' => 'á',
+ 'Acirc' => 'Â',
+ 'acirc' => 'â',
+ 'AElig' => 'Æ',
+ 'aelig' => 'æ',
+ 'Agrave' => 'À',
+ 'agrave' => 'à',
+ 'Aring' => 'Å',
+ 'aring' => 'å',
+ 'Atilde' => 'Ã',
+ 'atilde' => 'ã',
+ 'Auml' => 'Ä',
+ 'auml' => 'ä',
+ 'Ccedil' => 'Ç',
+ 'ccedil' => 'ç',
+ 'Eacute' => 'É',
+ 'eacute' => 'é',
+ 'Ecirc' => 'Ê',
+ 'ecirc' => 'ê',
+ 'Egrave' => 'È',
+ 'egrave' => 'è',
+ 'ETH' => 'Ð',
+ 'eth' => 'ð',
+ 'Euml' => 'Ë',
+ 'euml' => 'ë',
+ 'Iacute' => 'Í',
+ 'iacute' => 'í',
+ 'Icirc' => 'Î',
+ 'icirc' => 'î',
+ 'Igrave' => 'Ì',
+ 'igrave' => 'ì',
+ 'Iuml' => 'Ï',
+ 'iuml' => 'ï',
+ 'Ntilde' => 'Ñ',
+ 'ntilde' => 'ñ',
+ 'Oacute' => 'Ó',
+ 'oacute' => 'ó',
+ 'Ocirc' => 'Ô',
+ 'ocirc' => 'ô',
+ 'Ograve' => 'Ò',
+ 'ograve' => 'ò',
+ 'Oslash' => 'Ø',
+ 'oslash' => 'ø',
+ 'Otilde' => 'Õ',
+ 'otilde' => 'õ',
+ 'Ouml' => 'Ö',
+ 'ouml' => 'ö',
+ 'szlig' => 'ß',
+ 'THORN' => 'Þ',
+ 'thorn' => 'þ',
+ 'Uacute' => 'Ú',
+ 'uacute' => 'ú',
+ 'Ucirc' => 'Û',
+ 'ucirc' => 'û',
+ 'Ugrave' => 'Ù',
+ 'ugrave' => 'ù',
+ 'Uuml' => 'Ü',
+ 'uuml' => 'ü',
+ 'Yacute' => 'Ý',
+ 'yacute' => 'ý',
+ 'yuml' => 'ÿ',
+ 'Abreve' => 'Ă',
+ 'abreve' => 'ă',
+ 'Amacr' => 'Ā',
+ 'amacr' => 'ā',
+ 'Aogon' => 'Ą',
+ 'aogon' => 'ą',
+ 'Cacute' => 'Ć',
+ 'cacute' => 'ć',
+ 'Ccaron' => 'Č',
+ 'ccaron' => 'č',
+ 'Ccirc' => 'Ĉ',
+ 'ccirc' => 'ĉ',
+ 'Cdot' => 'Ċ',
+ 'cdot' => 'ċ',
+ 'Dcaron' => 'Ď',
+ 'dcaron' => 'ď',
+ 'Dstrok' => 'Đ',
+ 'dstrok' => 'đ',
+ 'Ecaron' => 'Ě',
+ 'ecaron' => 'ě',
+ 'Edot' => 'Ė',
+ 'edot' => 'ė',
+ 'Emacr' => 'Ē',
+ 'emacr' => 'ē',
+ 'ENG' => 'Ŋ',
+ 'eng' => 'ŋ',
+ 'Eogon' => 'Ę',
+ 'eogon' => 'ę',
+ 'gacute' => 'ǵ',
+ 'Gbreve' => 'Ğ',
+ 'gbreve' => 'ğ',
+ 'Gcedil' => 'Ģ',
+ 'Gcirc' => 'Ĝ',
+ 'gcirc' => 'ĝ',
+ 'Gdot' => 'Ġ',
+ 'gdot' => 'ġ',
+ 'Hcirc' => 'Ĥ',
+ 'hcirc' => 'ĥ',
+ 'Hstrok' => 'Ħ',
+ 'hstrok' => 'ħ',
+ 'Idot' => 'İ',
+ 'IJlig' => 'IJ',
+ 'ijlig' => 'ij',
+ 'Imacr' => 'Ī',
+ 'imacr' => 'ī',
+ 'inodot' => 'ı',
+ 'Iogon' => 'Į',
+ 'iogon' => 'į',
+ 'Itilde' => 'Ĩ',
+ 'itilde' => 'ĩ',
+ 'Jcirc' => 'Ĵ',
+ 'jcirc' => 'ĵ',
+ 'Kcedil' => 'Ķ',
+ 'kcedil' => 'ķ',
+ 'kgreen' => 'ĸ',
+ 'Lacute' => 'Ĺ',
+ 'lacute' => 'ĺ',
+ 'Lcaron' => 'Ľ',
+ 'lcaron' => 'ľ',
+ 'Lcedil' => 'Ļ',
+ 'lcedil' => 'ļ',
+ 'Lmidot' => 'Ŀ',
+ 'lmidot' => 'ŀ',
+ 'Lstrok' => 'Ł',
+ 'lstrok' => 'ł',
+ 'Nacute' => 'Ń',
+ 'nacute' => 'ń',
+ 'napos' => 'ʼn',
+ 'Ncaron' => 'Ň',
+ 'ncaron' => 'ň',
+ 'Ncedil' => 'Ņ',
+ 'ncedil' => 'ņ',
+ 'Odblac' => 'Ő',
+ 'odblac' => 'ő',
+ 'OElig' => 'Œ',
+ 'oelig' => 'œ',
+ 'Omacr' => 'Ō',
+ 'omacr' => 'ō',
+ 'Racute' => 'Ŕ',
+ 'racute' => 'ŕ',
+ 'Rcaron' => 'Ř',
+ 'rcaron' => 'ř',
+ 'Rcedil' => 'Ŗ',
+ 'rcedil' => 'ŗ',
+ 'Sacute' => 'Ś',
+ 'sacute' => 'ś',
+ 'Scaron' => 'Š',
+ 'scaron' => 'š',
+ 'Scedil' => 'Ş',
+ 'scedil' => 'ş',
+ 'Scirc' => 'Ŝ',
+ 'scirc' => 'ŝ',
+ 'Tcaron' => 'Ť',
+ 'tcaron' => 'ť',
+ 'Tcedil' => 'Ţ',
+ 'tcedil' => 'ţ',
+ 'Tstrok' => 'Ŧ',
+ 'tstrok' => 'ŧ',
+ 'Ubreve' => 'Ŭ',
+ 'ubreve' => 'ŭ',
+ 'Udblac' => 'Ű',
+ 'udblac' => 'ű',
+ 'Umacr' => 'Ū',
+ 'umacr' => 'ū',
+ 'Uogon' => 'Ų',
+ 'uogon' => 'ų',
+ 'Uring' => 'Ů',
+ 'uring' => 'ů',
+ 'Utilde' => 'Ũ',
+ 'utilde' => 'ũ',
+ 'Wcirc' => 'Ŵ',
+ 'wcirc' => 'ŵ',
+ 'Ycirc' => 'Ŷ',
+ 'ycirc' => 'ŷ',
+ 'Yuml' => 'Ÿ',
+ 'Zacute' => 'Ź',
+ 'zacute' => 'ź',
+ 'Zcaron' => 'Ž',
+ 'zcaron' => 'ž',
+ 'Zdot' => 'Ż',
+ 'zdot' => 'ż',
+ 'apos' => ''',
+ 'ast' => '*',
+ 'brvbar' => '¦',
+ 'bsol' => '\',
+ 'cent' => '¢',
+ 'colon' => ':',
+ 'comma' => ',',
+ 'commat' => '@',
+ 'copy' => '©',
+ 'curren' => '¤',
+ 'darr' => '↓',
+ 'deg' => '°',
+ 'divide' => '÷',
+ 'dollar' => '$',
+ 'equals' => '=',
+ 'excl' => '!',
+ 'frac12' => '½',
+ 'frac14' => '¼',
+ 'frac18' => '⅛',
+ 'frac34' => '¾',
+ 'frac38' => '⅜',
+ 'frac58' => '⅝',
+ 'frac78' => '⅞',
+ 'gt' => '>',
+ 'half' => '½',
+ 'horbar' => '―',
+ 'hyphen' => '‐',
+ 'iexcl' => '¡',
+ 'iquest' => '¿',
+ 'laquo' => '«',
+ 'larr' => '←',
+ 'lcub' => '{',
+ 'ldquo' => '“',
+ 'lowbar' => '_',
+ 'lpar' => '(',
+ 'lsqb' => '[',
+ 'lsquo' => '‘',
+ 'micro' => 'µ',
+ 'middot' => '·',
+ 'nbsp' => ' ',
+ 'not' => '¬',
+ 'num' => '#',
+ 'ohm' => 'Ω',
+ 'ordf' => 'ª',
+ 'ordm' => 'º',
+ 'para' => '¶',
+ 'percnt' => '%',
+ 'period' => '.',
+ 'plus' => '+',
+ 'plusmn' => '±',
+ 'pound' => '£',
+ 'quest' => '?',
+ 'quot' => '"',
+ 'raquo' => '»',
+ 'rarr' => '→',
+ 'rcub' => '}',
+ 'rdquo' => '”',
+ 'reg' => '®',
+ 'rpar' => ')',
+ 'rsqb' => ']',
+ 'rsquo' => '’',
+ 'sect' => '§',
+ 'semi' => ';',
+ 'shy' => '',
+ 'sol' => '/',
+ 'sung' => '♪',
+ 'sup1' => '¹',
+ 'sup2' => '²',
+ 'sup3' => '³',
+ 'times' => '×',
+ 'trade' => '™',
+ 'uarr' => '↑',
+ 'verbar' => '|',
+ 'yen' => '¥',
+ 'blank' => '␣',
+ 'blk12' => '▒',
+ 'blk14' => '░',
+ 'blk34' => '▓',
+ 'block' => '█',
+ 'bull' => '•',
+ 'caret' => '⁁',
+ 'check' => '✓',
+ 'cir' => '○',
+ 'clubs' => '♣',
+ 'copysr' => '℗',
+ 'cross' => '✗',
+ 'Dagger' => '‡',
+ 'dagger' => '†',
+ 'dash' => '‐',
+ 'diams' => '♦',
+ 'dlcrop' => '⌍',
+ 'drcrop' => '⌌',
+ 'dtri' => '▿',
+ 'dtrif' => '▾',
+ 'emsp' => ' ',
+ 'emsp13' => ' ',
+ 'emsp14' => ' ',
+ 'ensp' => ' ',
+ 'female' => '♀',
+ 'ffilig' => 'ffi',
+ 'fflig' => 'ff',
+ 'ffllig' => 'ffl',
+ 'filig' => 'fi',
+ 'flat' => '♭',
+ 'fllig' => 'fl',
+ 'frac13' => '⅓',
+ 'frac15' => '⅕',
+ 'frac16' => '⅙',
+ 'frac23' => '⅔',
+ 'frac25' => '⅖',
+ 'frac35' => '⅗',
+ 'frac45' => '⅘',
+ 'frac56' => '⅚',
+ 'hairsp' => ' ',
+ 'hearts' => '♥',
+ 'hellip' => '…',
+ 'hybull' => '⁃',
+ 'incare' => '℅',
+ 'ldquor' => '„',
+ 'lhblk' => '▄',
+ 'loz' => '◊',
+ 'lozf' => '⧫',
+ 'lsquor' => '‚',
+ 'ltri' => '◃',
+ 'ltrif' => '◂',
+ 'male' => '♂',
+ 'malt' => '✠',
+ 'marker' => '▮',
+ 'mdash' => '—',
+ 'mldr' => '…',
+ 'natur' => '♮',
+ 'ndash' => '–',
+ 'nldr' => '‥',
+ 'numsp' => ' ',
+ 'phone' => '☎',
+ 'puncsp' => ' ',
+ 'rdquor' => '”',
+ 'rect' => '▭',
+ 'rsquor' => '’',
+ 'rtri' => '▹',
+ 'rtrif' => '▸',
+ 'rx' => '℞',
+ 'sext' => '✶',
+ 'sharp' => '♯',
+ 'spades' => '♠',
+ 'squ' => '□',
+ 'squf' => '▪',
+ 'star' => '☆',
+ 'starf' => '★',
+ 'target' => '⌖',
+ 'telrec' => '⌕',
+ 'thinsp' => ' ',
+ 'uhblk' => '▀',
+ 'ulcrop' => '⌏',
+ 'urcrop' => '⌎',
+ 'utri' => '▵',
+ 'utrif' => '▴',
+ 'vellip' => '⋮',
+ 'af' => '',
+ 'aopf' => '𝕒',
+ 'asympeq' => '≍',
+ 'bopf' => '𝕓',
+ 'copf' => '𝕔',
+ 'Cross' => '⨯',
+ 'DD' => 'ⅅ',
+ 'dd' => 'ⅆ',
+ 'dopf' => '𝕕',
+ 'DownArrowBar' => '⤓',
+ 'DownBreve' => '̑',
+ 'DownLeftRightVector' => '⥐',
+ 'DownLeftTeeVector' => '⥞',
+ 'DownLeftVectorBar' => '⥖',
+ 'DownRightTeeVector' => '⥟',
+ 'DownRightVectorBar' => '⥗',
+ 'ee' => 'ⅇ',
+ 'EmptySmallSquare' => '◻',
+ 'EmptyVerySmallSquare' => '▫',
+ 'eopf' => '𝕖',
+ 'Equal' => '⩵',
+ 'FilledSmallSquare' => '◼',
+ 'FilledVerySmallSquare' => '▪',
+ 'fopf' => '𝕗',
+ 'gopf' => '𝕘',
+ 'GreaterGreater' => '⪢',
+ 'Hat' => '^',
+ 'hopf' => '𝕙',
+ 'HorizontalLine' => '─',
+ 'ic' => '',
+ 'ii' => 'ⅈ',
+ 'iopf' => '𝕚',
+ 'it' => '',
+ 'jopf' => '𝕛',
+ 'kopf' => '𝕜',
+ 'larrb' => '⇤',
+ 'LeftDownTeeVector' => '⥡',
+ 'LeftDownVectorBar' => '⥙',
+ 'LeftRightVector' => '⥎',
+ 'LeftTeeVector' => '⥚',
+ 'LeftTriangleBar' => '⧏',
+ 'LeftUpDownVector' => '⥑',
+ 'LeftUpTeeVector' => '⥠',
+ 'LeftUpVectorBar' => '⥘',
+ 'LeftVectorBar' => '⥒',
+ 'LessLess' => '⪡',
+ 'lopf' => '𝕝',
+ 'mapstodown' => '↧',
+ 'mapstoleft' => '↤',
+ 'mapstoup' => '↥',
+ 'MediumSpace' => ' ',
+ 'mopf' => '𝕞',
+ 'nbump' => '≎̸',
+ 'nbumpe' => '≏̸',
+ 'nesim' => '≂̸',
+ 'NewLine' => '
',
+ 'NoBreak' => '',
+ 'nopf' => '𝕟',
+ 'NotCupCap' => '≭',
+ 'NotHumpEqual' => '≏̸',
+ 'NotLeftTriangleBar' => '⧏̸',
+ 'NotNestedGreaterGreater' => '⪢̸',
+ 'NotNestedLessLess' => '⪡̸',
+ 'NotRightTriangleBar' => '⧐̸',
+ 'NotSquareSubset' => '⊏̸',
+ 'NotSquareSuperset' => '⊐̸',
+ 'NotSucceedsTilde' => '≿̸',
+ 'oopf' => '𝕠',
+ 'OverBar' => '¯',
+ 'OverBrace' => '︷',
+ 'OverBracket' => '⎴',
+ 'OverParenthesis' => '︵',
+ 'planckh' => 'ℎ',
+ 'popf' => '𝕡',
+ 'Product' => '∏',
+ 'qopf' => '𝕢',
+ 'rarrb' => '⇥',
+ 'RightDownTeeVector' => '⥝',
+ 'RightDownVectorBar' => '⥕',
+ 'RightTeeVector' => '⥛',
+ 'RightTriangleBar' => '⧐',
+ 'RightUpDownVector' => '⥏',
+ 'RightUpTeeVector' => '⥜',
+ 'RightUpVectorBar' => '⥔',
+ 'RightVectorBar' => '⥓',
+ 'ropf' => '𝕣',
+ 'RoundImplies' => '⥰',
+ 'RuleDelayed' => '⧴',
+ 'sopf' => '𝕤',
+ 'Tab' => ' ',
+ 'ThickSpace' => ' ',
+ 'topf' => '𝕥',
+ 'UnderBar' => '̲',
+ 'UnderBrace' => '︸',
+ 'UnderBracket' => '⎵',
+ 'UnderParenthesis' => '︶',
+ 'uopf' => '𝕦',
+ 'UpArrowBar' => '⤒',
+ 'Upsilon' => 'Υ',
+ 'VerticalLine' => '|',
+ 'VerticalSeparator' => '❘',
+ 'vopf' => '𝕧',
+ 'wopf' => '𝕨',
+ 'xopf' => '𝕩',
+ 'yopf' => '𝕪',
+ 'ZeroWidthSpace' => '',
+ 'zopf' => '𝕫',
+ 'angle' => '∠',
+ 'ApplyFunction' => '',
+ 'approx' => '≈',
+ 'approxeq' => '≊',
+ 'Assign' => '≔',
+ 'backcong' => '≌',
+ 'backepsilon' => '϶',
+ 'backprime' => '‵',
+ 'backsim' => '∽',
+ 'backsimeq' => '⋍',
+ 'Backslash' => '∖',
+ 'barwedge' => '⌅',
+ 'Because' => '∵',
+ 'because' => '∵',
+ 'Bernoullis' => 'ℬ',
+ 'between' => '≬',
+ 'bigcap' => '⋂',
+ 'bigcirc' => '◯',
+ 'bigcup' => '⋃',
+ 'bigodot' => '⨀',
+ 'bigoplus' => '⨁',
+ 'bigotimes' => '⨂',
+ 'bigsqcup' => '⨆',
+ 'bigstar' => '★',
+ 'bigtriangledown' => '▽',
+ 'bigtriangleup' => '△',
+ 'biguplus' => '⨄',
+ 'bigvee' => '⋁',
+ 'bigwedge' => '⋀',
+ 'bkarow' => '⤍',
+ 'blacklozenge' => '⧫',
+ 'blacksquare' => '▪',
+ 'blacktriangle' => '▴',
+ 'blacktriangledown' => '▾',
+ 'blacktriangleleft' => '◂',
+ 'blacktriangleright' => '▸',
+ 'bot' => '⊥',
+ 'boxminus' => '⊟',
+ 'boxplus' => '⊞',
+ 'boxtimes' => '⊠',
+ 'Breve' => '˘',
+ 'bullet' => '•',
+ 'Bumpeq' => '≎',
+ 'bumpeq' => '≏',
+ 'CapitalDifferentialD' => 'ⅅ',
+ 'Cayleys' => 'ℭ',
+ 'Cedilla' => '¸',
+ 'CenterDot' => '·',
+ 'centerdot' => '·',
+ 'checkmark' => '✓',
+ 'circeq' => '≗',
+ 'circlearrowleft' => '↺',
+ 'circlearrowright' => '↻',
+ 'circledast' => '⊛',
+ 'circledcirc' => '⊚',
+ 'circleddash' => '⊝',
+ 'CircleDot' => '⊙',
+ 'circledR' => '®',
+ 'circledS' => 'Ⓢ',
+ 'CircleMinus' => '⊖',
+ 'CirclePlus' => '⊕',
+ 'CircleTimes' => '⊗',
+ 'ClockwiseContourIntegral' => '∲',
+ 'CloseCurlyDoubleQuote' => '”',
+ 'CloseCurlyQuote' => '’',
+ 'clubsuit' => '♣',
+ 'coloneq' => '≔',
+ 'complement' => '∁',
+ 'complexes' => 'ℂ',
+ 'Congruent' => '≡',
+ 'ContourIntegral' => '∮',
+ 'Coproduct' => '∐',
+ 'CounterClockwiseContourIntegral' => '∳',
+ 'CupCap' => '≍',
+ 'curlyeqprec' => '⋞',
+ 'curlyeqsucc' => '⋟',
+ 'curlyvee' => '⋎',
+ 'curlywedge' => '⋏',
+ 'curvearrowleft' => '↶',
+ 'curvearrowright' => '↷',
+ 'dbkarow' => '⤏',
+ 'ddagger' => '‡',
+ 'ddotseq' => '⩷',
+ 'Del' => '∇',
+ 'DiacriticalAcute' => '´',
+ 'DiacriticalDot' => '˙',
+ 'DiacriticalDoubleAcute' => '˝',
+ 'DiacriticalGrave' => '`',
+ 'DiacriticalTilde' => '˜',
+ 'Diamond' => '⋄',
+ 'diamond' => '⋄',
+ 'diamondsuit' => '♦',
+ 'DifferentialD' => 'ⅆ',
+ 'digamma' => 'ϝ',
+ 'div' => '÷',
+ 'divideontimes' => '⋇',
+ 'doteq' => '≐',
+ 'doteqdot' => '≑',
+ 'DotEqual' => '≐',
+ 'dotminus' => '∸',
+ 'dotplus' => '∔',
+ 'dotsquare' => '⊡',
+ 'doublebarwedge' => '⌆',
+ 'DoubleContourIntegral' => '∯',
+ 'DoubleDot' => '¨',
+ 'DoubleDownArrow' => '⇓',
+ 'DoubleLeftArrow' => '⇐',
+ 'DoubleLeftRightArrow' => '⇔',
+ 'DoubleLeftTee' => '⫤',
+ 'DoubleLongLeftArrow' => '⟸',
+ 'DoubleLongLeftRightArrow' => '⟺',
+ 'DoubleLongRightArrow' => '⟹',
+ 'DoubleRightArrow' => '⇒',
+ 'DoubleRightTee' => '⊨',
+ 'DoubleUpArrow' => '⇑',
+ 'DoubleUpDownArrow' => '⇕',
+ 'DoubleVerticalBar' => '∥',
+ 'DownArrow' => '↓',
+ 'Downarrow' => '⇓',
+ 'downarrow' => '↓',
+ 'DownArrowUpArrow' => '⇵',
+ 'downdownarrows' => '⇊',
+ 'downharpoonleft' => '⇃',
+ 'downharpoonright' => '⇂',
+ 'DownLeftVector' => '↽',
+ 'DownRightVector' => '⇁',
+ 'DownTee' => '⊤',
+ 'DownTeeArrow' => '↧',
+ 'drbkarow' => '⤐',
+ 'Element' => '∈',
+ 'emptyset' => '∅',
+ 'eqcirc' => '≖',
+ 'eqcolon' => '≕',
+ 'eqsim' => '≂',
+ 'eqslantgtr' => '⪖',
+ 'eqslantless' => '⪕',
+ 'EqualTilde' => '≂',
+ 'Equilibrium' => '⇌',
+ 'Exists' => '∃',
+ 'expectation' => 'ℰ',
+ 'ExponentialE' => 'ⅇ',
+ 'exponentiale' => 'ⅇ',
+ 'fallingdotseq' => '≒',
+ 'ForAll' => '∀',
+ 'Fouriertrf' => 'ℱ',
+ 'geq' => '≥',
+ 'geqq' => '≧',
+ 'geqslant' => '⩾',
+ 'gg' => '≫',
+ 'ggg' => '⋙',
+ 'gnapprox' => '⪊',
+ 'gneq' => '⪈',
+ 'gneqq' => '≩',
+ 'GreaterEqual' => '≥',
+ 'GreaterEqualLess' => '⋛',
+ 'GreaterFullEqual' => '≧',
+ 'GreaterLess' => '≷',
+ 'GreaterSlantEqual' => '⩾',
+ 'GreaterTilde' => '≳',
+ 'gtrapprox' => '⪆',
+ 'gtrdot' => '⋗',
+ 'gtreqless' => '⋛',
+ 'gtreqqless' => '⪌',
+ 'gtrless' => '≷',
+ 'gtrsim' => '≳',
+ 'gvertneqq' => '≩︀',
+ 'Hacek' => 'ˇ',
+ 'hbar' => 'ℏ',
+ 'heartsuit' => '♥',
+ 'HilbertSpace' => 'ℋ',
+ 'hksearow' => '⤥',
+ 'hkswarow' => '⤦',
+ 'hookleftarrow' => '↩',
+ 'hookrightarrow' => '↪',
+ 'hslash' => 'ℏ',
+ 'HumpDownHump' => '≎',
+ 'HumpEqual' => '≏',
+ 'iiiint' => '⨌',
+ 'iiint' => '∭',
+ 'Im' => 'ℑ',
+ 'ImaginaryI' => 'ⅈ',
+ 'imagline' => 'ℐ',
+ 'imagpart' => 'ℑ',
+ 'Implies' => '⇒',
+ 'in' => '∈',
+ 'integers' => 'ℤ',
+ 'Integral' => '∫',
+ 'intercal' => '⊺',
+ 'Intersection' => '⋂',
+ 'intprod' => '⨼',
+ 'InvisibleComma' => '',
+ 'InvisibleTimes' => '',
+ 'langle' => '〈',
+ 'Laplacetrf' => 'ℒ',
+ 'lbrace' => '{',
+ 'lbrack' => '[',
+ 'LeftAngleBracket' => '〈',
+ 'LeftArrow' => '←',
+ 'Leftarrow' => '⇐',
+ 'leftarrow' => '←',
+ 'LeftArrowBar' => '⇤',
+ 'LeftArrowRightArrow' => '⇆',
+ 'leftarrowtail' => '↢',
+ 'LeftCeiling' => '⌈',
+ 'LeftDoubleBracket' => '〚',
+ 'LeftDownVector' => '⇃',
+ 'LeftFloor' => '⌊',
+ 'leftharpoondown' => '↽',
+ 'leftharpoonup' => '↼',
+ 'leftleftarrows' => '⇇',
+ 'LeftRightArrow' => '↔',
+ 'Leftrightarrow' => '⇔',
+ 'leftrightarrow' => '↔',
+ 'leftrightarrows' => '⇆',
+ 'leftrightharpoons' => '⇋',
+ 'leftrightsquigarrow' => '↭',
+ 'LeftTee' => '⊣',
+ 'LeftTeeArrow' => '↤',
+ 'leftthreetimes' => '⋋',
+ 'LeftTriangle' => '⊲',
+ 'LeftTriangleEqual' => '⊴',
+ 'LeftUpVector' => '↿',
+ 'LeftVector' => '↼',
+ 'leq' => '≤',
+ 'leqq' => '≦',
+ 'leqslant' => '⩽',
+ 'lessapprox' => '⪅',
+ 'lessdot' => '⋖',
+ 'lesseqgtr' => '⋚',
+ 'lesseqqgtr' => '⪋',
+ 'LessEqualGreater' => '⋚',
+ 'LessFullEqual' => '≦',
+ 'LessGreater' => '≶',
+ 'lessgtr' => '≶',
+ 'lesssim' => '≲',
+ 'LessSlantEqual' => '⩽',
+ 'LessTilde' => '≲',
+ 'll' => '≪',
+ 'llcorner' => '⌞',
+ 'Lleftarrow' => '⇚',
+ 'lmoustache' => '⎰',
+ 'lnapprox' => '⪉',
+ 'lneq' => '⪇',
+ 'lneqq' => '≨',
+ 'LongLeftArrow' => '⟵',
+ 'Longleftarrow' => '⟸',
+ 'longleftarrow' => '⟵',
+ 'LongLeftRightArrow' => '⟷',
+ 'Longleftrightarrow' => '⟺',
+ 'longleftrightarrow' => '⟷',
+ 'longmapsto' => '⟼',
+ 'LongRightArrow' => '⟶',
+ 'Longrightarrow' => '⟹',
+ 'longrightarrow' => '⟶',
+ 'looparrowleft' => '↫',
+ 'looparrowright' => '↬',
+ 'LowerLeftArrow' => '↙',
+ 'LowerRightArrow' => '↘',
+ 'lozenge' => '◊',
+ 'lrcorner' => '⌟',
+ 'Lsh' => '↰',
+ 'lvertneqq' => '≨︀',
+ 'maltese' => '✠',
+ 'mapsto' => '↦',
+ 'measuredangle' => '∡',
+ 'Mellintrf' => 'ℳ',
+ 'MinusPlus' => '∓',
+ 'mp' => '∓',
+ 'multimap' => '⊸',
+ 'napprox' => '≉',
+ 'natural' => '♮',
+ 'naturals' => 'ℕ',
+ 'nearrow' => '↗',
+ 'NegativeMediumSpace' => '',
+ 'NegativeThickSpace' => '',
+ 'NegativeThinSpace' => '',
+ 'NegativeVeryThinSpace' => '',
+ 'NestedGreaterGreater' => '≫',
+ 'NestedLessLess' => '≪',
+ 'nexists' => '∄',
+ 'ngeq' => '≱',
+ 'ngeqq' => '≧̸',
+ 'ngeqslant' => '⩾̸',
+ 'ngtr' => '≯',
+ 'nLeftarrow' => '⇍',
+ 'nleftarrow' => '↚',
+ 'nLeftrightarrow' => '⇎',
+ 'nleftrightarrow' => '↮',
+ 'nleq' => '≰',
+ 'nleqq' => '≦̸',
+ 'nleqslant' => '⩽̸',
+ 'nless' => '≮',
+ 'NonBreakingSpace' => ' ',
+ 'NotCongruent' => '≢',
+ 'NotDoubleVerticalBar' => '∦',
+ 'NotElement' => '∉',
+ 'NotEqual' => '≠',
+ 'NotEqualTilde' => '≂̸',
+ 'NotExists' => '∄',
+ 'NotGreater' => '≯',
+ 'NotGreaterEqual' => '≱',
+ 'NotGreaterFullEqual' => '≦̸',
+ 'NotGreaterGreater' => '≫̸',
+ 'NotGreaterLess' => '≹',
+ 'NotGreaterSlantEqual' => '⩾̸',
+ 'NotGreaterTilde' => '≵',
+ 'NotHumpDownHump' => '≎̸',
+ 'NotLeftTriangle' => '⋪',
+ 'NotLeftTriangleEqual' => '⋬',
+ 'NotLess' => '≮',
+ 'NotLessEqual' => '≰',
+ 'NotLessGreater' => '≸',
+ 'NotLessLess' => '≪̸',
+ 'NotLessSlantEqual' => '⩽̸',
+ 'NotLessTilde' => '≴',
+ 'NotPrecedes' => '⊀',
+ 'NotPrecedesEqual' => '⪯̸',
+ 'NotPrecedesSlantEqual' => '⋠',
+ 'NotReverseElement' => '∌',
+ 'NotRightTriangle' => '⋫',
+ 'NotRightTriangleEqual' => '⋭',
+ 'NotSquareSubsetEqual' => '⋢',
+ 'NotSquareSupersetEqual' => '⋣',
+ 'NotSubset' => '⊂⃒',
+ 'NotSubsetEqual' => '⊈',
+ 'NotSucceeds' => '⊁',
+ 'NotSucceedsEqual' => '⪰̸',
+ 'NotSucceedsSlantEqual' => '⋡',
+ 'NotSuperset' => '⊃⃒',
+ 'NotSupersetEqual' => '⊉',
+ 'NotTilde' => '≁',
+ 'NotTildeEqual' => '≄',
+ 'NotTildeFullEqual' => '≇',
+ 'NotTildeTilde' => '≉',
+ 'NotVerticalBar' => '∤',
+ 'nparallel' => '∦',
+ 'nprec' => '⊀',
+ 'npreceq' => '⪯̸',
+ 'nRightarrow' => '⇏',
+ 'nrightarrow' => '↛',
+ 'nshortmid' => '∤',
+ 'nshortparallel' => '∦',
+ 'nsimeq' => '≄',
+ 'nsubset' => '⊂⃒',
+ 'nsubseteq' => '⊈',
+ 'nsubseteqq' => '⫅̸',
+ 'nsucc' => '⊁',
+ 'nsucceq' => '⪰̸',
+ 'nsupset' => '⊃⃒',
+ 'nsupseteq' => '⊉',
+ 'nsupseteqq' => '⫆̸',
+ 'ntriangleleft' => '⋪',
+ 'ntrianglelefteq' => '⋬',
+ 'ntriangleright' => '⋫',
+ 'ntrianglerighteq' => '⋭',
+ 'nwarrow' => '↖',
+ 'oint' => '∮',
+ 'OpenCurlyDoubleQuote' => '“',
+ 'OpenCurlyQuote' => '‘',
+ 'orderof' => 'ℴ',
+ 'parallel' => '∥',
+ 'PartialD' => '∂',
+ 'pitchfork' => '⋔',
+ 'PlusMinus' => '±',
+ 'pm' => '±',
+ 'Poincareplane' => 'ℌ',
+ 'prec' => '≺',
+ 'precapprox' => '⪷',
+ 'preccurlyeq' => '≼',
+ 'Precedes' => '≺',
+ 'PrecedesEqual' => '⪯',
+ 'PrecedesSlantEqual' => '≼',
+ 'PrecedesTilde' => '≾',
+ 'preceq' => '⪯',
+ 'precnapprox' => '⪹',
+ 'precneqq' => '⪵',
+ 'precnsim' => '⋨',
+ 'precsim' => '≾',
+ 'primes' => 'ℙ',
+ 'Proportion' => '∷',
+ 'Proportional' => '∝',
+ 'propto' => '∝',
+ 'quaternions' => 'ℍ',
+ 'questeq' => '≟',
+ 'rangle' => '〉',
+ 'rationals' => 'ℚ',
+ 'rbrace' => '}',
+ 'rbrack' => ']',
+ 'Re' => 'ℜ',
+ 'realine' => 'ℛ',
+ 'realpart' => 'ℜ',
+ 'reals' => 'ℝ',
+ 'ReverseElement' => '∋',
+ 'ReverseEquilibrium' => '⇋',
+ 'ReverseUpEquilibrium' => '⥯',
+ 'RightAngleBracket' => '〉',
+ 'RightArrow' => '→',
+ 'Rightarrow' => '⇒',
+ 'rightarrow' => '→',
+ 'RightArrowBar' => '⇥',
+ 'RightArrowLeftArrow' => '⇄',
+ 'rightarrowtail' => '↣',
+ 'RightCeiling' => '⌉',
+ 'RightDoubleBracket' => '〛',
+ 'RightDownVector' => '⇂',
+ 'RightFloor' => '⌋',
+ 'rightharpoondown' => '⇁',
+ 'rightharpoonup' => '⇀',
+ 'rightleftarrows' => '⇄',
+ 'rightleftharpoons' => '⇌',
+ 'rightrightarrows' => '⇉',
+ 'rightsquigarrow' => '↝',
+ 'RightTee' => '⊢',
+ 'RightTeeArrow' => '↦',
+ 'rightthreetimes' => '⋌',
+ 'RightTriangle' => '⊳',
+ 'RightTriangleEqual' => '⊵',
+ 'RightUpVector' => '↾',
+ 'RightVector' => '⇀',
+ 'risingdotseq' => '≓',
+ 'rmoustache' => '⎱',
+ 'Rrightarrow' => '⇛',
+ 'Rsh' => '↱',
+ 'searrow' => '↘',
+ 'setminus' => '∖',
+ 'ShortDownArrow' => '↓',
+ 'ShortLeftArrow' => '←',
+ 'shortmid' => '∣',
+ 'shortparallel' => '∥',
+ 'ShortRightArrow' => '→',
+ 'ShortUpArrow' => '↑',
+ 'simeq' => '≃',
+ 'SmallCircle' => '∘',
+ 'smallsetminus' => '∖',
+ 'spadesuit' => '♠',
+ 'Sqrt' => '√',
+ 'sqsubset' => '⊏',
+ 'sqsubseteq' => '⊑',
+ 'sqsupset' => '⊐',
+ 'sqsupseteq' => '⊒',
+ 'Square' => '□',
+ 'SquareIntersection' => '⊓',
+ 'SquareSubset' => '⊏',
+ 'SquareSubsetEqual' => '⊑',
+ 'SquareSuperset' => '⊐',
+ 'SquareSupersetEqual' => '⊒',
+ 'SquareUnion' => '⊔',
+ 'Star' => '⋆',
+ 'straightepsilon' => 'ϵ',
+ 'straightphi' => 'ϕ',
+ 'Subset' => '⋐',
+ 'subset' => '⊂',
+ 'subseteq' => '⊆',
+ 'subseteqq' => '⫅',
+ 'SubsetEqual' => '⊆',
+ 'subsetneq' => '⊊',
+ 'subsetneqq' => '⫋',
+ 'succ' => '≻',
+ 'succapprox' => '⪸',
+ 'succcurlyeq' => '≽',
+ 'Succeeds' => '≻',
+ 'SucceedsEqual' => '⪰',
+ 'SucceedsSlantEqual' => '≽',
+ 'SucceedsTilde' => '≿',
+ 'succeq' => '⪰',
+ 'succnapprox' => '⪺',
+ 'succneqq' => '⪶',
+ 'succnsim' => '⋩',
+ 'succsim' => '≿',
+ 'SuchThat' => '∋',
+ 'Sum' => '∑',
+ 'Superset' => '⊃',
+ 'SupersetEqual' => '⊇',
+ 'Supset' => '⋑',
+ 'supset' => '⊃',
+ 'supseteq' => '⊇',
+ 'supseteqq' => '⫆',
+ 'supsetneq' => '⊋',
+ 'supsetneqq' => '⫌',
+ 'swarrow' => '↙',
+ 'Therefore' => '∴',
+ 'therefore' => '∴',
+ 'thickapprox' => '≈',
+ 'thicksim' => '∼',
+ 'ThinSpace' => ' ',
+ 'Tilde' => '∼',
+ 'TildeEqual' => '≃',
+ 'TildeFullEqual' => '≅',
+ 'TildeTilde' => '≈',
+ 'toea' => '⤨',
+ 'tosa' => '⤩',
+ 'triangle' => '▵',
+ 'triangledown' => '▿',
+ 'triangleleft' => '◃',
+ 'trianglelefteq' => '⊴',
+ 'triangleq' => '≜',
+ 'triangleright' => '▹',
+ 'trianglerighteq' => '⊵',
+ 'TripleDot' => '⃛',
+ 'twoheadleftarrow' => '↞',
+ 'twoheadrightarrow' => '↠',
+ 'ulcorner' => '⌜',
+ 'Union' => '⋃',
+ 'UnionPlus' => '⊎',
+ 'UpArrow' => '↑',
+ 'Uparrow' => '⇑',
+ 'uparrow' => '↑',
+ 'UpArrowDownArrow' => '⇅',
+ 'UpDownArrow' => '↕',
+ 'Updownarrow' => '⇕',
+ 'updownarrow' => '↕',
+ 'UpEquilibrium' => '⥮',
+ 'upharpoonleft' => '↿',
+ 'upharpoonright' => '↾',
+ 'UpperLeftArrow' => '↖',
+ 'UpperRightArrow' => '↗',
+ 'upsilon' => 'υ',
+ 'UpTee' => '⊥',
+ 'UpTeeArrow' => '↥',
+ 'upuparrows' => '⇈',
+ 'urcorner' => '⌝',
+ 'varepsilon' => 'ε',
+ 'varkappa' => 'ϰ',
+ 'varnothing' => '∅',
+ 'varphi' => 'φ',
+ 'varpi' => 'ϖ',
+ 'varpropto' => '∝',
+ 'varrho' => 'ϱ',
+ 'varsigma' => 'ς',
+ 'varsubsetneq' => '⊊︀',
+ 'varsubsetneqq' => '⫋︀',
+ 'varsupsetneq' => '⊋︀',
+ 'varsupsetneqq' => '⫌︀',
+ 'vartheta' => 'ϑ',
+ 'vartriangleleft' => '⊲',
+ 'vartriangleright' => '⊳',
+ 'Vee' => '⋁',
+ 'vee' => '∨',
+ 'Vert' => '‖',
+ 'vert' => '|',
+ 'VerticalBar' => '∣',
+ 'VerticalTilde' => '≀',
+ 'VeryThinSpace' => ' ',
+ 'Wedge' => '⋀',
+ 'wedge' => '∧',
+ 'wp' => '℘',
+ 'wr' => '≀',
+ 'zeetrf' => 'ℨ'
+ }
+#:startdoc:
+
+# Converts XHTML+MathML named entities in string to Numeric Character References
+#
+# :call-seq:
+# string.to_ncr -> string
+#
+ def to_ncr
+ self.gsub(/&(?:(lt|gt|amp|quot|apos)|[a-zA-Z0-9]+);/){|s| $1 ? s : s.convert_to_ncr}
+ end
+
+# Converts XHTML+MathML named entities in string to Numeric Character References
+#
+# :call-seq:
+# string.to_ncr! -> str or nil
+#
+# Substitution is done in-place.
+#
+ def to_ncr!
+ self.gsub!(/&(?:(lt|gt|amp|quot|apos)|[a-zA-Z0-9]+);/){|s| $1 ? s : s.convert_to_ncr}
+ end
+
+# Converts XHTML+MathML named entities in string to UTF-8
+#
+# :call-seq:
+# string.to_utf8 -> string
+#
+ def to_utf8
+ self.gsub(/&(?:(lt|gt|amp|quot|apos)|[a-zA-Z0-9]+);/){|s| $1 ? s : s.convert_to_utf8}
+ end
+
+# Converts XHTML+MathML named entities in string to UTF-8
+#
+# :call-seq:
+# string.to_ncr! -> str or nil
+#
+# Substitution is done in-place.
+#
+ def to_utf8!
+ self.gsub!(/&(?:(lt|gt|amp|quot|apos)|[a-zA-Z0-9]+);/){|s| $1 ? s : s.convert_to_utf8}
+ end
+
+ protected
+
+ def convert_to_ncr #:nodoc:
+ self =~ /^&([a-zA-Z0-9]+);$/
+ name = $1
+ return MATHML_ENTITIES.has_key?(name) ? MATHML_ENTITIES[name] : "&" + name + ";"
+ end
+
+ def convert_to_utf8 #:nodoc:
+ self =~ /^&([a-zA-Z0-9]+);$/
+ name = $1
+ return MATHML_ENTITIES.has_key?(name) ? MATHML_ENTITIES[name].split(';').collect {|s| s.gsub(/^([A-F0-9]+)$/, '\1').hex }.pack('U*') : "&" + name + ";"
+ end
+
+
+end
+
+require 'rexml/element'
+module REXML #:nodoc:
+ class Element
+
+# Convert XHTML+MathML Named Entities in a REXML::Element to Numeric Character References
+#
+# :call-seq:
+# tree.to_ncr -> REXML::Element
+#
+# REXML, typically, converts NCRs to utf-8 characters, which is what you'll see when you
+# access the resulting REXML document.
+#
+# Note that this method needs to traverse the entire tree, converting text nodes and attributes
+# for each element. This can be SLOW. It will often be faster to serialize to a string and then
+# use String.to_ncr instead.
+#
+ def to_ncr
+ self.each_element { |el|
+ el.texts.each_index {|i|
+ el.texts[i].value = el.texts[i].to_s.to_ncr
+ }
+ el.attributes.each { |name,val|
+ el.attributes[name] = val.to_ncr
+ }
+ el.to_ncr if el.has_elements?
+ }
+ return self
+ end
+
+# Convert XHTML+MathML Named Entities in a REXML::Element to UTF-8
+#
+# :call-seq:
+# tree.to_utf8 -> REXML::Element
+#
+# Note that this method needs to traverse the entire tree, converting text nodes and attributes
+# for each element. This can be SLOW. It will often be faster to serialize to a string and then
+# use String.to_utf8 instead.
+#
+ def to_utf8
+ self.each_element { |el|
+ el.texts.each_index {|i|
+ el.texts[i].value = el.texts[i].to_s.to_utf8
+ }
+ el.attributes.each { |name,val|
+ el.attributes[name] = val.to_utf8
+ }
+ el.to_utf8 if el.has_elements?
+ }
+ return self
+ end
+
+ end
+end
+
+module HTML5 #:nodoc: all
+ module TreeWalkers
+
+ private
+
+ class << self
+ def [](name)
+ case name.to_s.downcase
+ when 'rexml'
+ require 'html5/treewalkers/rexml'
+ REXML::TreeWalker
+ when 'rexml2'
+ REXML2::TreeWalker
+ else
+ raise "Unknown TreeWalker #{name}"
+ end
+ end
+
+ alias :get_tree_walker :[]
+ end
+
+ module REXML2
+ class TreeWalker < HTML5::TreeWalkers::NonRecursiveTreeWalker
+
+ private
+
+ def node_details(node)
+ case node
+ when ::REXML::Document
+ [:DOCUMENT]
+ when ::REXML::Element
+ if !node.name
+ [:DOCUMENT_FRAGMENT]
+ else
+ [:ELEMENT, node.name,
+ node.attributes.map {|name,value| [name,value.to_utf8]},
+ node.has_elements? || node.has_text?]
+ end
+ when ::REXML::Text
+ [:TEXT, node.value.to_utf8]
+ when ::REXML::Comment
+ [:COMMENT, node.string]
+ when ::REXML::DocType
+ [:DOCTYPE, node.name, node.public, node.system]
+ when ::REXML::XMLDecl
+ [nil]
+ else
+ [:UNKNOWN, node.class.inspect]
+ end
+ end
+
+ def first_child(node)
+ node.children.first
+ end
+
+ def next_sibling(node)
+ node.next_sibling
+ end
+
+ def parent(node)
+ node.parent
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/xss_terminate/lib/rails_sanitize.rb b/vendor/plugins/xss_terminate/lib/rails_sanitize.rb
new file mode 100644
index 0000000..742a8d4
--- /dev/null
+++ b/vendor/plugins/xss_terminate/lib/rails_sanitize.rb
@@ -0,0 +1,4 @@
+# This class exists so including the Rails HTML sanitization helpers doesn't polute your models.
+class RailsSanitize
+ include ActionView::Helpers::SanitizeHelper
+end
\ No newline at end of file
diff --git a/vendor/plugins/xss_terminate/lib/xss_terminate.rb b/vendor/plugins/xss_terminate/lib/xss_terminate.rb
new file mode 100644
index 0000000..853fdf1
--- /dev/null
+++ b/vendor/plugins/xss_terminate/lib/xss_terminate.rb
@@ -0,0 +1,81 @@
+module XssTerminate
+
+ def self.sanitize_by_default=(value)
+ @@sanitize_by_default = value
+ end
+
+ def self.included(base)
+ base.extend(ClassMethods)
+ # sets up default of stripping tags for all fields
+ # FIXME read value from environment.rb
+ @@sanitize_by_default = false
+ base.send(:xss_terminate) if @@sanitize_by_default
+ end
+
+ module ClassMethods
+
+ def xss_terminate(options = {})
+ # :on is util when before_filter dont work for model
+ case options[:on]
+ when 'create'
+ before_create :sanitize_fields
+ when 'validation'
+ before_validation :sanitize_fields
+ else
+ before_save :sanitize_fields
+ end
+
+ sanitizer = case options[:with]
+ when 'html5lib'
+ HTML5libSanitize.new
+ when 'white_list'
+ RailsSanitize.white_list_sanitizer
+ else
+ RailsSanitize.full_sanitizer
+ end
+
+ write_inheritable_attribute(:xss_terminate_options, {
+ :except => (options[:except] || []),
+ :only => (options[:only] || options[:sanitize] || []),
+ :sanitizer => sanitizer,
+
+ :html5lib_sanitize => (options[:html5lib_sanitize] || [])
+ })
+
+ class_inheritable_reader :xss_terminate_options
+
+ include XssTerminate::InstanceMethods
+ end
+ end
+
+ module InstanceMethods
+
+ def sanitize_fields
+
+ columns = self.class.columns.select{ |i| i.type == :string || i.type == :text }.map{ |i| i.name }
+ columns_serialized = self.class.serialized_attributes.keys
+
+ if !xss_terminate_options[:only].empty?
+ columns.select{ |i| xss_terminate_options[:only].include?( i ) }
+ elsif !xss_terminate_options[:except].empty?
+ columns.delete_if{ |i| xss_terminate_options[:except].include?( i.to_sym ) }
+ end
+
+ columns.each do |column|
+ field = column.to_sym
+ if columns_serialized.include?(column)
+ next unless self[field]
+ self[field].each_key { |key|
+ key = key.to_sym
+ self[field][key] = xss_terminate_options[:sanitizer].sanitize(self[field][key].to_s)
+ }
+ else
+ self[field] = xss_terminate_options[:sanitizer].sanitize(self[field])
+ end
+ end
+
+ end
+
+ end
+
+end
diff --git a/vendor/plugins/xss_terminate/tasks/xss_terminate_tasks.rake b/vendor/plugins/xss_terminate/tasks/xss_terminate_tasks.rake
new file mode 100644
index 0000000..d9c4571
--- /dev/null
+++ b/vendor/plugins/xss_terminate/tasks/xss_terminate_tasks.rake
@@ -0,0 +1,7 @@
+desc "Given MODELS=Foo,Bar,Baz find all instances in the DB and save to sanitize existing records"
+task :xss_terminate => :environment do
+ models = ENV['MODELS'].split(',')
+ models.each do |model|
+ model.constantize.find(:all).map(&:save)
+ end
+end
diff --git a/vendor/plugins/xss_terminate/test/models/comment.rb b/vendor/plugins/xss_terminate/test/models/comment.rb
new file mode 100644
index 0000000..d452f3c
--- /dev/null
+++ b/vendor/plugins/xss_terminate/test/models/comment.rb
@@ -0,0 +1,5 @@
+# Commet uses the default: stripping tags fro all fields.
+class Comment < ActiveRecord::Base
+ belongs_to :entry
+ belongs_to :person
+end
diff --git a/vendor/plugins/xss_terminate/test/models/entry.rb b/vendor/plugins/xss_terminate/test/models/entry.rb
new file mode 100644
index 0000000..6eba8ed
--- /dev/null
+++ b/vendor/plugins/xss_terminate/test/models/entry.rb
@@ -0,0 +1,7 @@
+# Rails HTML sanitization on some fields
+class Entry < ActiveRecord::Base
+ belongs_to :person
+ has_many :comments
+
+ xss_terminate :sanitize => [:body, :extended]
+end
diff --git a/vendor/plugins/xss_terminate/test/models/message.rb b/vendor/plugins/xss_terminate/test/models/message.rb
new file mode 100644
index 0000000..193ad16
--- /dev/null
+++ b/vendor/plugins/xss_terminate/test/models/message.rb
@@ -0,0 +1,5 @@
+class Message < ActiveRecord::Base
+ belongs_to :person
+
+ xss_terminate :only => [ :body ]
+end
diff --git a/vendor/plugins/xss_terminate/test/models/person.rb b/vendor/plugins/xss_terminate/test/models/person.rb
new file mode 100644
index 0000000..635adc6
--- /dev/null
+++ b/vendor/plugins/xss_terminate/test/models/person.rb
@@ -0,0 +1,5 @@
+# This model excepts HTML sanitization on the name
+class Person < ActiveRecord::Base
+ has_many :entries
+ xss_terminate :except => [ :name ]
+end
diff --git a/vendor/plugins/xss_terminate/test/models/review.rb b/vendor/plugins/xss_terminate/test/models/review.rb
new file mode 100644
index 0000000..31655cc
--- /dev/null
+++ b/vendor/plugins/xss_terminate/test/models/review.rb
@@ -0,0 +1,5 @@
+class Review < ActiveRecord::Base
+ belongs_to :person
+
+ xss_terminate :html5lib_sanitize => [:body, :extended]
+end
diff --git a/vendor/plugins/xss_terminate/test/schema.rb b/vendor/plugins/xss_terminate/test/schema.rb
new file mode 100644
index 0000000..7d63c98
--- /dev/null
+++ b/vendor/plugins/xss_terminate/test/schema.rb
@@ -0,0 +1,34 @@
+ActiveRecord::Schema.define(:version => 0) do
+ create_table :people, :force => true do |t|
+ t.column :name, :string
+ end
+
+ create_table :entries, :force => true do |t|
+ t.column :title, :string
+ t.column :body, :text
+ t.column :extended, :text
+ t.column :person_id, :integer
+ t.column :created_on, :datetime
+ end
+
+ create_table :comments, :force => true do |t|
+ t.column :person_id, :integer
+ t.column :title, :string
+ t.column :body, :text
+ t.column :created_on, :datetime
+ end
+
+ create_table :messages, :force => true do |t|
+ t.column :person_id, :integer
+ t.column :recipient_id, :integer
+ t.column :body, :text
+ end
+
+ create_table :reviews, :force => true do |t|
+ t.column :title, :string
+ t.column :body, :text
+ t.column :extended, :text
+ t.column :person_id, :integer
+ t.column :created_on, :datetime
+ end
+end
diff --git a/vendor/plugins/xss_terminate/test/setup_test.rb b/vendor/plugins/xss_terminate/test/setup_test.rb
new file mode 100644
index 0000000..ad5d83a
--- /dev/null
+++ b/vendor/plugins/xss_terminate/test/setup_test.rb
@@ -0,0 +1,16 @@
+# borrowed from err who borrowed from topfunky who borrowed from...
+
+# set up test environment
+RAILS_ENV = 'test'
+require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
+require 'test/unit'
+
+# load test schema
+load(File.dirname(__FILE__) + "/schema.rb")
+
+# load test models
+require File.join(File.dirname(__FILE__), 'models/person')
+require File.join(File.dirname(__FILE__), 'models/entry')
+require File.join(File.dirname(__FILE__), 'models/comment')
+require File.join(File.dirname(__FILE__), 'models/message')
+require File.join(File.dirname(__FILE__), 'models/review')
\ No newline at end of file
diff --git a/vendor/plugins/xss_terminate/test/xss_terminate_test.rb b/vendor/plugins/xss_terminate/test/xss_terminate_test.rb
new file mode 100644
index 0000000..2b9f598
--- /dev/null
+++ b/vendor/plugins/xss_terminate/test/xss_terminate_test.rb
@@ -0,0 +1,71 @@
+require File.join(File.dirname(__FILE__), 'setup_test')
+
+class XssTerminateTest < Test::Unit::TestCase
+
+ XssTerminate.sanitize_by_default = true
+
+ def test_sanitize_by_default_is_true
+ assert XssTerminate.sanitize_by_default
+ end
+
+
+ def test_strip_tags_on_discovered_fields
+ c = Comment.create!(:title => "",
+ :body => "")
+
+ assert_equal "alert('xss in title')", c.title
+
+ assert_equal "alert('xss in body')", c.body
+ end
+
+ def test_rails_sanitization_on_specified_fields
+ e = Entry.create!(:title => "",
+ :body => "",
+ :extended => "",
+ :person_id => 1)
+
+ assert_equal [:body, :extended], e.xss_terminate_options[:only]
+
+ assert_equal "alert('xss in title')", e.title
+
+ assert_equal "", e.body
+
+ assert_equal "", e.extended
+ end
+
+ def test_excepting_specified_fields
+ p = Person.create!(:name => "Mallory")
+
+ assert_equal [:name], p.xss_terminate_options[:except]
+
+ assert_equal "Mallory", p.name
+ end
+
+
+ def test_html5lib_sanitization_on_specified_fields
+ r = Review.create!(:title => "",
+ :body => "",
+ :extended => "",
+ :person_id => 1)
+
+ assert_equal [:body, :extended], r.xss_terminate_options[:html5lib_sanitize]
+
+ assert_equal "alert('xss in title')", r.title
+
+ assert_equal "<script>alert('xss in body')</script>", r.body
+
+ assert_equal "<script>alert('xss in extended')</script>", r.extended
+ end
+
+
+ ### Tests for new features (the API rewriten)
+
+ def test_onlying_specified_fields
+ p = Message.create!(:body => "Mallory")
+
+ assert_equal [:body], p.xss_terminate_options[:only]
+
+ assert_equal "Mallory", p.body
+ end
+
+end
diff --git a/vendor/plugins/xss_terminate/uninstall.rb b/vendor/plugins/xss_terminate/uninstall.rb
new file mode 100644
index 0000000..9738333
--- /dev/null
+++ b/vendor/plugins/xss_terminate/uninstall.rb
@@ -0,0 +1 @@
+# Uninstall hook code here
--
libgit2 0.21.2