From f54fa6c18a8530a66f5c4cf2ceed27c9c17a17b8 Mon Sep 17 00:00:00 2001 From: JoenioCosta Date: Mon, 28 Apr 2008 17:29:50 +0000 Subject: [PATCH] ActionItem192: rewritten filter with an modified version of xss_terminate --- app/controllers/application.rb | 9 --------- app/controllers/my_profile/consumed_products_controller.rb | 10 ---------- app/controllers/my_profile/enterprise_validation_controller.rb | 11 ----------- app/controllers/my_profile/manage_products_controller.rb | 11 ----------- app/controllers/my_profile/memberships_controller.rb | 11 ----------- app/controllers/my_profile/profile_editor_controller.rb | 15 --------------- app/controllers/public/content_viewer_controller.rb | 11 ----------- app/controllers/public/enterprise_registration_controller.rb | 12 ------------ app/models/comment.rb | 2 ++ app/models/community.rb | 2 ++ app/models/consumption.rb | 3 +++ app/models/create_enterprise.rb | 2 ++ app/models/enterprise.rb | 3 ++- app/models/organization_info.rb | 4 ++++ app/models/person_info.rb | 2 ++ app/models/product.rb | 2 ++ app/models/profile.rb | 2 ++ app/models/validation_info.rb | 2 ++ test/functional/enterprise_validation_test.rb | 2 +- vendor/plugins/xss_terminate/MIT-LICENSE | 20 ++++++++++++++++++++ vendor/plugins/xss_terminate/README | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/xss_terminate/Rakefile | 22 ++++++++++++++++++++++ vendor/plugins/xss_terminate/init.rb | 1 + vendor/plugins/xss_terminate/install.rb | 1 + vendor/plugins/xss_terminate/lib/html5lib_sanitize.rb | 2454 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/xss_terminate/lib/rails_sanitize.rb | 4 ++++ vendor/plugins/xss_terminate/lib/xss_terminate.rb | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/xss_terminate/tasks/xss_terminate_tasks.rake | 7 +++++++ vendor/plugins/xss_terminate/test/models/comment.rb | 5 +++++ vendor/plugins/xss_terminate/test/models/entry.rb | 7 +++++++ vendor/plugins/xss_terminate/test/models/message.rb | 5 +++++ vendor/plugins/xss_terminate/test/models/person.rb | 5 +++++ vendor/plugins/xss_terminate/test/models/review.rb | 5 +++++ vendor/plugins/xss_terminate/test/schema.rb | 34 ++++++++++++++++++++++++++++++++++ vendor/plugins/xss_terminate/test/setup_test.rb | 16 ++++++++++++++++ vendor/plugins/xss_terminate/test/xss_terminate_test.rb | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/xss_terminate/uninstall.rb | 1 + 37 files changed, 2881 insertions(+), 92 deletions(-) create mode 100644 vendor/plugins/xss_terminate/MIT-LICENSE create mode 100644 vendor/plugins/xss_terminate/README create mode 100644 vendor/plugins/xss_terminate/Rakefile create mode 100644 vendor/plugins/xss_terminate/init.rb create mode 100644 vendor/plugins/xss_terminate/install.rb create mode 100644 vendor/plugins/xss_terminate/lib/html5lib_sanitize.rb create mode 100644 vendor/plugins/xss_terminate/lib/rails_sanitize.rb create mode 100644 vendor/plugins/xss_terminate/lib/xss_terminate.rb create mode 100644 vendor/plugins/xss_terminate/tasks/xss_terminate_tasks.rake create mode 100644 vendor/plugins/xss_terminate/test/models/comment.rb create mode 100644 vendor/plugins/xss_terminate/test/models/entry.rb create mode 100644 vendor/plugins/xss_terminate/test/models/message.rb create mode 100644 vendor/plugins/xss_terminate/test/models/person.rb create mode 100644 vendor/plugins/xss_terminate/test/models/review.rb create mode 100644 vendor/plugins/xss_terminate/test/schema.rb create mode 100644 vendor/plugins/xss_terminate/test/setup_test.rb create mode 100644 vendor/plugins/xss_terminate/test/xss_terminate_test.rb create mode 100644 vendor/plugins/xss_terminate/uninstall.rb 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(/&#x([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(/^&#x([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