Better handle html-only emails (#16962).

git-svn-id: http://svn.redmine.org/redmine/trunk@14313 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Jean-Philippe Lang
2015-06-15 21:16:42 +00:00
parent 7fb35abd10
commit 3ae42cb326
14 changed files with 1312 additions and 19 deletions

View File

@@ -13,6 +13,7 @@ gem "mime-types"
gem "protected_attributes" gem "protected_attributes"
gem "actionpack-action_caching" gem "actionpack-action_caching"
gem "actionpack-xml_parser" gem "actionpack-xml_parser"
gem "loofah", "~> 2.0"
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :x64_mingw, :mswin, :jruby] gem 'tzinfo-data', platforms: [:mingw, :x64_mingw, :mswin, :jruby]

View File

@@ -433,14 +433,11 @@ class MailHandler < ActionMailer::Base
@plain_text_body = parts.map do |p| @plain_text_body = parts.map do |p|
body_charset = Mail::RubyVer.respond_to?(:pick_encoding) ? body_charset = Mail::RubyVer.respond_to?(:pick_encoding) ?
Mail::RubyVer.pick_encoding(p.charset).to_s : p.charset Mail::RubyVer.pick_encoding(p.charset).to_s : p.charset
Redmine::CodesetUtil.to_utf8(p.body.decoded, body_charset)
end.join("\r\n")
# strip html tags and remove doctype directive body = Redmine::CodesetUtil.to_utf8(p.body.decoded, body_charset)
if parts.any? {|p| p.mime_type == 'text/html'} # convert html parts to text
@plain_text_body = strip_tags(@plain_text_body.strip) p.mime_type == 'text/html' ? self.class.html_body_to_text(body) : body
@plain_text_body.sub! %r{^<!DOCTYPE .*$}, '' end.join("\r\n")
end
@plain_text_body @plain_text_body
end end
@@ -454,6 +451,11 @@ class MailHandler < ActionMailer::Base
subject.strip[0,255] subject.strip[0,255]
end end
# Converts a HTML email body to text
def self.html_body_to_text(html)
Redmine::WikiFormatting.html_parser.to_text(html)
end
def self.assign_string_attribute_with_limit(object, attribute, value, limit=nil) def self.assign_string_attribute_with_limit(object, attribute, value, limit=nil)
limit ||= object.class.columns_hash[attribute.to_s].limit || 255 limit ||= object.class.columns_hash[attribute.to_s].limit || 255
value = value.to_s.slice(0, limit) value = value.to_s.slice(0, limit)

View File

@@ -267,11 +267,8 @@ Redmine::Search.map do |search|
end end
Redmine::WikiFormatting.map do |format| Redmine::WikiFormatting.map do |format|
format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper format.register :textile
if Object.const_defined?(:Redcarpet) format.register :markdown if Object.const_defined?(:Redcarpet)
format.register :markdown, Redmine::WikiFormatting::Markdown::Formatter, Redmine::WikiFormatting::Markdown::Helper,
:label => 'Markdown'
end
end end
ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler

View File

@@ -28,12 +28,19 @@ module Redmine
yield self yield self
end end
def register(name, formatter, helper, options={}) def register(name, *args)
options = args.last.is_a?(Hash) ? args.pop : {}
name = name.to_s name = name.to_s
raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name] raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name]
formatter, helper, parser = args.any? ?
args :
%w(Formatter Helper HtmlParser).map {|m| "Redmine::WikiFormatting::#{name.classify}::#{m}".constantize}
@@formatters[name] = { @@formatters[name] = {
:formatter => formatter, :formatter => formatter,
:helper => helper, :helper => helper,
:html_parser => parser,
:label => options[:label] || name.humanize :label => options[:label] || name.humanize
} }
end end
@@ -42,6 +49,10 @@ module Redmine
formatter_for(Setting.text_formatting) formatter_for(Setting.text_formatting)
end end
def html_parser
html_parser_for(Setting.text_formatting)
end
def formatter_for(name) def formatter_for(name)
entry = @@formatters[name.to_s] entry = @@formatters[name.to_s]
(entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter (entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter
@@ -52,6 +63,11 @@ module Redmine
(entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper (entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper
end end
def html_parser_for(name)
entry = @@formatters[name.to_s]
(entry && entry[:html_parser]) || Redmine::WikiFormatting::HtmlParser
end
def format_names def format_names
@@formatters.keys.map @@formatters.keys.map
end end

View File

@@ -0,0 +1,54 @@
# Redmine - project management software
# Copyright (C) 2006-2015 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'loofah/helpers'
module Redmine
module WikiFormatting
class HtmlParser
class_attribute :tags
self.tags = {
'br' => {:post => "\n"}
}
def self.to_text(html)
html = html.gsub(/[\n\r]/, '').squeeze(' ')
doc = Loofah.document(html)
doc.scrub!(WikiTags.new(tags))
doc.scrub!(:newline_block_elements)
Loofah::Helpers.remove_extraneous_whitespace(doc.text).strip
end
class WikiTags < ::Loofah::Scrubber
def initialize(tags_to_text)
@direction = :bottom_up
@tags_to_text = tags_to_text || {}
end
def scrub(node)
formatting = @tags_to_text[node.name]
return CONTINUE unless formatting
node.add_next_sibling Nokogiri::XML::Text.new("#{formatting[:pre]}#{node.content}#{formatting[:post]}", node.document)
node.remove
end
end
end
end
end

View File

@@ -0,0 +1,40 @@
# Redmine - project management software
# Copyright (C) 2006-2015 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module Redmine
module WikiFormatting
module Markdown
class HtmlParser < Redmine::WikiFormatting::HtmlParser
self.tags = {
'b' => {:pre => '**', :post => '**'},
'strong' => {:pre => '**', :post => '**'},
'i' => {:pre => '_', :post => '_'},
'em' => {:pre => '_', :post => '_'},
'strike' => {:pre => '~~', :post => '~~'},
'br' => {:post => "\n"},
'h1' => {:pre => "\n\n# ", :post => "\n\n"},
'h2' => {:pre => "\n\n## ", :post => "\n\n"},
'h3' => {:pre => "\n\n### ", :post => "\n\n"},
'h4' => {:pre => "\n\n#### ", :post => "\n\n"},
'h5' => {:pre => "\n\n##### ", :post => "\n\n"},
'h6' => {:pre => "\n\n###### ", :post => "\n\n"}
}
end
end
end
end

View File

@@ -0,0 +1,41 @@
# Redmine - project management software
# Copyright (C) 2006-2015 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module Redmine
module WikiFormatting
module Textile
class HtmlParser < Redmine::WikiFormatting::HtmlParser
self.tags = {
'b' => {:pre => '*', :post => '*'},
'strong' => {:pre => '*', :post => '*'},
'i' => {:pre => '_', :post => '_'},
'em' => {:pre => '_', :post => '_'},
'u' => {:pre => '+', :post => '+'},
'strike' => {:pre => '-', :post => '-'},
'br' => {:post => "\n"},
'h1' => {:pre => "\n\nh1. ", :post => "\n\n"},
'h2' => {:pre => "\n\nh2. ", :post => "\n\n"},
'h3' => {:pre => "\n\nh3. ", :post => "\n\n"},
'h4' => {:pre => "\n\nh4. ", :post => "\n\n"},
'h5' => {:pre => "\n\nh5. ", :post => "\n\n"},
'h6' => {:pre => "\n\nh6. ", :post => "\n\n"}
}
end
end
end
end

View File

@@ -0,0 +1,966 @@
From: jsmith@somenet.foo
To: testuser@example.org
Subject: =?utf-8?Q?Test_email?=
Date: Mon, 11 May 2015 10:50:31 -0500
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="Mark=_539924359269962179476"
X-Priority: 3
This is a multi-part message in MIME format.
--Mark=_539924359269962179476
Content-Type: text/plain;
charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Simple, unadorned test email generated by Outlook 2010. It is in HTML f=
ormat, but no special formatting has been chosen. I=E2=80=99m going to =
save this as a draft and then manually drop it into the Inbox for scrap=
ing by Redmine 3.0.2.
--Mark=_539924359269962179476
Content-Type: text/html;
charset="utf-8"
Content-Transfer-Encoding: quoted-printable
<STYLE>
pre {
white-space: pre-wrap; /* css-3 */
white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
</STYLE>
<html xmlns:v=3D"urn:schemas-microsoft-com:vml" xmlns:o=3D"urn:schemas-=
microsoft-com:office:office" xmlns:w=3D"urn:schemas-microsoft-com:offic=
e:word" xmlns:m=3D"http://schemas.microsoft.com/office/2004/12/omml" xm=
lns=3D"http://www.w3.org/TR/REC-html40"><head><meta name=3DProgId conte=
nt=3DWord.Document><meta name=3DGenerator content=3D"Microsoft Word 15"=
><meta name=3DOriginator content=3D"Microsoft Word 15"><link rel=3DFile=
-List href=3D"cid:filelist.xml@01D08BD8.4D051580"><!--[if gte mso 9]><x=
ml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
</o:OfficeDocumentSettings>
</xml><![endif]--><link rel=3DthemeData href=3D"~~themedata~~"><link re=
l=3DcolorSchemeMapping href=3D"~~colorschememapping~~"><!--[if gte mso =
9]><xml>
<w:WordDocument>
<w:Zoom>120</w:Zoom>
<w:SpellingState>Clean</w:SpellingState>
<w:TrackMoves/>
<w:TrackFormatting/>
<w:EnvelopeVis/>
<w:PunctuationKerning/>
<w:ValidateAgainstSchemas/>
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:DoNotPromoteQF/>
<w:LidThemeOther>EN-US</w:LidThemeOther>
<w:LidThemeAsian>X-NONE</w:LidThemeAsian>
<w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
<w:Compatibility>
<w:DoNotExpandShiftReturn/>
<w:BreakWrappedTables/>
<w:SnapToGridInCell/>
<w:WrapTextWithPunct/>
<w:UseAsianBreakRules/>
<w:DontGrowAutofit/>
<w:SplitPgBreakAndParaMark/>
<w:EnableOpenTypeKerning/>
<w:DontFlipMirrorIndents/>
<w:OverrideTableStyleHps/>
</w:Compatibility>
<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
<m:mathPr>
<m:mathFont m:val=3D"Cambria Math"/>
<m:brkBin m:val=3D"before"/>
<m:brkBinSub m:val=3D"&#45;-"/>
<m:smallFrac m:val=3D"off"/>
<m:dispDef/>
<m:lMargin m:val=3D"0"/>
<m:rMargin m:val=3D"0"/>
<m:defJc m:val=3D"centerGroup"/>
<m:wrapIndent m:val=3D"1440"/>
<m:intLim m:val=3D"subSup"/>
<m:naryLim m:val=3D"undOvr"/>
</m:mathPr></w:WordDocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:LatentStyles DefLockedState=3D"false" DefUnhideWhenUsed=3D"false" De=
fSemiHidden=3D"false" DefQFormat=3D"false" DefPriority=3D"99" LatentSty=
leCount=3D"371">
<w:LsdException Locked=3D"false" Priority=3D"0" QFormat=3D"true" Name=3D=
"Normal"/>
<w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" Name=3D=
"heading 1"/>
<w:LsdException Locked=3D"false" Priority=3D"9" SemiHidden=3D"true" Unh=
ideWhenUsed=3D"true" QFormat=3D"true" Name=3D"heading 2"/>
<w:LsdException Locked=3D"false" Priority=3D"9" SemiHidden=3D"true" Unh=
ideWhenUsed=3D"true" QFormat=3D"true" Name=3D"heading 3"/>
<w:LsdException Locked=3D"false" Priority=3D"9" SemiHidden=3D"true" Unh=
ideWhenUsed=3D"true" QFormat=3D"true" Name=3D"heading 4"/>
<w:LsdException Locked=3D"false" Priority=3D"9" SemiHidden=3D"true" Unh=
ideWhenUsed=3D"true" QFormat=3D"true" Name=3D"heading 5"/>
<w:LsdException Locked=3D"false" Priority=3D"9" SemiHidden=3D"true" Unh=
ideWhenUsed=3D"true" QFormat=3D"true" Name=3D"heading 6"/>
<w:LsdException Locked=3D"false" Priority=3D"9" SemiHidden=3D"true" Unh=
ideWhenUsed=3D"true" QFormat=3D"true" Name=3D"heading 7"/>
<w:LsdException Locked=3D"false" Priority=3D"9" SemiHidden=3D"true" Unh=
ideWhenUsed=3D"true" QFormat=3D"true" Name=3D"heading 8"/>
<w:LsdException Locked=3D"false" Priority=3D"9" SemiHidden=3D"true" Unh=
ideWhenUsed=3D"true" QFormat=3D"true" Name=3D"heading 9"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"index 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"index 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"index 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"index 4"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"index 5"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"index 6"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"index 7"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"index 8"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"index 9"/>
<w:LsdException Locked=3D"false" Priority=3D"39" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" Name=3D"toc 1"/>
<w:LsdException Locked=3D"false" Priority=3D"39" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" Name=3D"toc 2"/>
<w:LsdException Locked=3D"false" Priority=3D"39" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" Name=3D"toc 3"/>
<w:LsdException Locked=3D"false" Priority=3D"39" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" Name=3D"toc 4"/>
<w:LsdException Locked=3D"false" Priority=3D"39" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" Name=3D"toc 5"/>
<w:LsdException Locked=3D"false" Priority=3D"39" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" Name=3D"toc 6"/>
<w:LsdException Locked=3D"false" Priority=3D"39" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" Name=3D"toc 7"/>
<w:LsdException Locked=3D"false" Priority=3D"39" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" Name=3D"toc 8"/>
<w:LsdException Locked=3D"false" Priority=3D"39" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" Name=3D"toc 9"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Normal Indent"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"footnote text"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"annotation text"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"header"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"footer"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"index heading"/>
<w:LsdException Locked=3D"false" Priority=3D"35" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" QFormat=3D"true" Name=3D"caption"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"table of figures"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"envelope address"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"envelope return"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"footnote reference"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"annotation reference"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"line number"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"page number"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"endnote reference"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"endnote text"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"table of authorities"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"macro"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"toa heading"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Bullet"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Number"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List 4"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List 5"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Bullet 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Bullet 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Bullet 4"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Bullet 5"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Number 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Number 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Number 4"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Number 5"/>
<w:LsdException Locked=3D"false" Priority=3D"10" QFormat=3D"true" Name=3D=
"Title"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Closing"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Signature"/>
<w:LsdException Locked=3D"false" Priority=3D"1" SemiHidden=3D"true" Unh=
ideWhenUsed=3D"true" Name=3D"Default Paragraph Font"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Body Text"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Body Text Indent"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Continue"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Continue 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Continue 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Continue 4"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"List Continue 5"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Message Header"/>
<w:LsdException Locked=3D"false" Priority=3D"11" QFormat=3D"true" Name=3D=
"Subtitle"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Salutation"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Date"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Body Text First Indent"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Body Text First Indent 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Note Heading"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Body Text 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Body Text 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Body Text Indent 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Body Text Indent 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Block Text"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Hyperlink"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"FollowedHyperlink"/>
<w:LsdException Locked=3D"false" Priority=3D"22" QFormat=3D"true" Name=3D=
"Strong"/>
<w:LsdException Locked=3D"false" Priority=3D"20" QFormat=3D"true" Name=3D=
"Emphasis"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Document Map"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Plain Text"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"E-mail Signature"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Top of Form"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Bottom of Form"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Normal (Web)"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Acronym"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Address"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Cite"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Code"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Definition"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Keyboard"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Preformatted"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Sample"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Typewriter"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"HTML Variable"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Normal Table"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"annotation subject"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"No List"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Outline List 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Outline List 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Outline List 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Simple 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Simple 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Simple 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Classic 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Classic 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Classic 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Classic 4"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Colorful 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Colorful 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Colorful 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Columns 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Columns 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Columns 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Columns 4"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Columns 5"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Grid 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Grid 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Grid 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Grid 4"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Grid 5"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Grid 6"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Grid 7"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Grid 8"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table List 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table List 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table List 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table List 4"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table List 5"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table List 6"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table List 7"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table List 8"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table 3D effects 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table 3D effects 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table 3D effects 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Contemporary"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Elegant"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Professional"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Subtle 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Subtle 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Web 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Web 2"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Web 3"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Balloon Text"/>
<w:LsdException Locked=3D"false" Priority=3D"59" Name=3D"Table Grid"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" UnhideWhenUsed=3D"=
true" Name=3D"Table Theme"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" Name=3D"Placeholde=
r Text"/>
<w:LsdException Locked=3D"false" Priority=3D"1" QFormat=3D"true" Name=3D=
"No Spacing"/>
<w:LsdException Locked=3D"false" Priority=3D"60" Name=3D"Light Shading"=
/>
<w:LsdException Locked=3D"false" Priority=3D"61" Name=3D"Light List"/>
<w:LsdException Locked=3D"false" Priority=3D"62" Name=3D"Light Grid"/>
<w:LsdException Locked=3D"false" Priority=3D"63" Name=3D"Medium Shading=
1"/>
<w:LsdException Locked=3D"false" Priority=3D"64" Name=3D"Medium Shading=
2"/>
<w:LsdException Locked=3D"false" Priority=3D"65" Name=3D"Medium List 1"=
/>
<w:LsdException Locked=3D"false" Priority=3D"66" Name=3D"Medium List 2"=
/>
<w:LsdException Locked=3D"false" Priority=3D"67" Name=3D"Medium Grid 1"=
/>
<w:LsdException Locked=3D"false" Priority=3D"68" Name=3D"Medium Grid 2"=
/>
<w:LsdException Locked=3D"false" Priority=3D"69" Name=3D"Medium Grid 3"=
/>
<w:LsdException Locked=3D"false" Priority=3D"70" Name=3D"Dark List"/>
<w:LsdException Locked=3D"false" Priority=3D"71" Name=3D"Colorful Shadi=
ng"/>
<w:LsdException Locked=3D"false" Priority=3D"72" Name=3D"Colorful List"=
/>
<w:LsdException Locked=3D"false" Priority=3D"73" Name=3D"Colorful Grid"=
/>
<w:LsdException Locked=3D"false" Priority=3D"60" Name=3D"Light Shading =
Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"61" Name=3D"Light List Acc=
ent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"62" Name=3D"Light Grid Acc=
ent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"63" Name=3D"Medium Shading=
1 Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"64" Name=3D"Medium Shading=
2 Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"65" Name=3D"Medium List 1 =
Accent 1"/>
<w:LsdException Locked=3D"false" SemiHidden=3D"true" Name=3D"Revision"/=
>
<w:LsdException Locked=3D"false" Priority=3D"34" QFormat=3D"true" Name=3D=
"List Paragraph"/>
<w:LsdException Locked=3D"false" Priority=3D"29" QFormat=3D"true" Name=3D=
"Quote"/>
<w:LsdException Locked=3D"false" Priority=3D"30" QFormat=3D"true" Name=3D=
"Intense Quote"/>
<w:LsdException Locked=3D"false" Priority=3D"66" Name=3D"Medium List 2 =
Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"67" Name=3D"Medium Grid 1 =
Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"68" Name=3D"Medium Grid 2 =
Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"69" Name=3D"Medium Grid 3 =
Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"70" Name=3D"Dark List Acce=
nt 1"/>
<w:LsdException Locked=3D"false" Priority=3D"71" Name=3D"Colorful Shadi=
ng Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"72" Name=3D"Colorful List =
Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"73" Name=3D"Colorful Grid =
Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"60" Name=3D"Light Shading =
Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"61" Name=3D"Light List Acc=
ent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"62" Name=3D"Light Grid Acc=
ent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"63" Name=3D"Medium Shading=
1 Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"64" Name=3D"Medium Shading=
2 Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"65" Name=3D"Medium List 1 =
Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"66" Name=3D"Medium List 2 =
Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"67" Name=3D"Medium Grid 1 =
Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"68" Name=3D"Medium Grid 2 =
Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"69" Name=3D"Medium Grid 3 =
Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"70" Name=3D"Dark List Acce=
nt 2"/>
<w:LsdException Locked=3D"false" Priority=3D"71" Name=3D"Colorful Shadi=
ng Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"72" Name=3D"Colorful List =
Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"73" Name=3D"Colorful Grid =
Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"60" Name=3D"Light Shading =
Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"61" Name=3D"Light List Acc=
ent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"62" Name=3D"Light Grid Acc=
ent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"63" Name=3D"Medium Shading=
1 Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"64" Name=3D"Medium Shading=
2 Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"65" Name=3D"Medium List 1 =
Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"66" Name=3D"Medium List 2 =
Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"67" Name=3D"Medium Grid 1 =
Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"68" Name=3D"Medium Grid 2 =
Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"69" Name=3D"Medium Grid 3 =
Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"70" Name=3D"Dark List Acce=
nt 3"/>
<w:LsdException Locked=3D"false" Priority=3D"71" Name=3D"Colorful Shadi=
ng Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"72" Name=3D"Colorful List =
Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"73" Name=3D"Colorful Grid =
Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"60" Name=3D"Light Shading =
Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"61" Name=3D"Light List Acc=
ent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"62" Name=3D"Light Grid Acc=
ent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"63" Name=3D"Medium Shading=
1 Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"64" Name=3D"Medium Shading=
2 Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"65" Name=3D"Medium List 1 =
Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"66" Name=3D"Medium List 2 =
Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"67" Name=3D"Medium Grid 1 =
Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"68" Name=3D"Medium Grid 2 =
Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"69" Name=3D"Medium Grid 3 =
Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"70" Name=3D"Dark List Acce=
nt 4"/>
<w:LsdException Locked=3D"false" Priority=3D"71" Name=3D"Colorful Shadi=
ng Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"72" Name=3D"Colorful List =
Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"73" Name=3D"Colorful Grid =
Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"60" Name=3D"Light Shading =
Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"61" Name=3D"Light List Acc=
ent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"62" Name=3D"Light Grid Acc=
ent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"63" Name=3D"Medium Shading=
1 Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"64" Name=3D"Medium Shading=
2 Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"65" Name=3D"Medium List 1 =
Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"66" Name=3D"Medium List 2 =
Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"67" Name=3D"Medium Grid 1 =
Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"68" Name=3D"Medium Grid 2 =
Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"69" Name=3D"Medium Grid 3 =
Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"70" Name=3D"Dark List Acce=
nt 5"/>
<w:LsdException Locked=3D"false" Priority=3D"71" Name=3D"Colorful Shadi=
ng Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"72" Name=3D"Colorful List =
Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"73" Name=3D"Colorful Grid =
Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"60" Name=3D"Light Shading =
Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"61" Name=3D"Light List Acc=
ent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"62" Name=3D"Light Grid Acc=
ent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"63" Name=3D"Medium Shading=
1 Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"64" Name=3D"Medium Shading=
2 Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"65" Name=3D"Medium List 1 =
Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"66" Name=3D"Medium List 2 =
Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"67" Name=3D"Medium Grid 1 =
Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"68" Name=3D"Medium Grid 2 =
Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"69" Name=3D"Medium Grid 3 =
Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"70" Name=3D"Dark List Acce=
nt 6"/>
<w:LsdException Locked=3D"false" Priority=3D"71" Name=3D"Colorful Shadi=
ng Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"72" Name=3D"Colorful List =
Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"73" Name=3D"Colorful Grid =
Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"19" QFormat=3D"true" Name=3D=
"Subtle Emphasis"/>
<w:LsdException Locked=3D"false" Priority=3D"21" QFormat=3D"true" Name=3D=
"Intense Emphasis"/>
<w:LsdException Locked=3D"false" Priority=3D"31" QFormat=3D"true" Name=3D=
"Subtle Reference"/>
<w:LsdException Locked=3D"false" Priority=3D"32" QFormat=3D"true" Name=3D=
"Intense Reference"/>
<w:LsdException Locked=3D"false" Priority=3D"33" QFormat=3D"true" Name=3D=
"Book Title"/>
<w:LsdException Locked=3D"false" Priority=3D"37" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" Name=3D"Bibliography"/>
<w:LsdException Locked=3D"false" Priority=3D"39" SemiHidden=3D"true" Un=
hideWhenUsed=3D"true" QFormat=3D"true" Name=3D"TOC Heading"/>
<w:LsdException Locked=3D"false" Priority=3D"41" Name=3D"Plain Table 1"=
/>
<w:LsdException Locked=3D"false" Priority=3D"42" Name=3D"Plain Table 2"=
/>
<w:LsdException Locked=3D"false" Priority=3D"43" Name=3D"Plain Table 3"=
/>
<w:LsdException Locked=3D"false" Priority=3D"44" Name=3D"Plain Table 4"=
/>
<w:LsdException Locked=3D"false" Priority=3D"45" Name=3D"Plain Table 5"=
/>
<w:LsdException Locked=3D"false" Priority=3D"40" Name=3D"Grid Table Lig=
ht"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"Grid Table 1 L=
ight"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"Grid Table 2"/=
>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"Grid Table 3"/=
>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"Grid Table 4"/=
>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"Grid Table 5 D=
ark"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"Grid Table 6 C=
olorful"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"Grid Table 7 C=
olorful"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"Grid Table 1 L=
ight Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"Grid Table 2 A=
ccent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"Grid Table 3 A=
ccent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"Grid Table 4 A=
ccent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"Grid Table 5 D=
ark Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"Grid Table 6 C=
olorful Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"Grid Table 7 C=
olorful Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"Grid Table 1 L=
ight Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"Grid Table 2 A=
ccent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"Grid Table 3 A=
ccent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"Grid Table 4 A=
ccent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"Grid Table 5 D=
ark Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"Grid Table 6 C=
olorful Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"Grid Table 7 C=
olorful Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"Grid Table 1 L=
ight Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"Grid Table 2 A=
ccent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"Grid Table 3 A=
ccent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"Grid Table 4 A=
ccent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"Grid Table 5 D=
ark Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"Grid Table 6 C=
olorful Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"Grid Table 7 C=
olorful Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"Grid Table 1 L=
ight Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"Grid Table 2 A=
ccent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"Grid Table 3 A=
ccent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"Grid Table 4 A=
ccent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"Grid Table 5 D=
ark Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"Grid Table 6 C=
olorful Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"Grid Table 7 C=
olorful Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"Grid Table 1 L=
ight Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"Grid Table 2 A=
ccent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"Grid Table 3 A=
ccent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"Grid Table 4 A=
ccent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"Grid Table 5 D=
ark Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"Grid Table 6 C=
olorful Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"Grid Table 7 C=
olorful Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"Grid Table 1 L=
ight Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"Grid Table 2 A=
ccent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"Grid Table 3 A=
ccent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"Grid Table 4 A=
ccent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"Grid Table 5 D=
ark Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"Grid Table 6 C=
olorful Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"Grid Table 7 C=
olorful Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"List Table 1 L=
ight"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"List Table 2"/=
>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"List Table 3"/=
>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"List Table 4"/=
>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"List Table 5 D=
ark"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"List Table 6 C=
olorful"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"List Table 7 C=
olorful"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"List Table 1 L=
ight Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"List Table 2 A=
ccent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"List Table 3 A=
ccent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"List Table 4 A=
ccent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"List Table 5 D=
ark Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"List Table 6 C=
olorful Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"List Table 7 C=
olorful Accent 1"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"List Table 1 L=
ight Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"List Table 2 A=
ccent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"List Table 3 A=
ccent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"List Table 4 A=
ccent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"List Table 5 D=
ark Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"List Table 6 C=
olorful Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"List Table 7 C=
olorful Accent 2"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"List Table 1 L=
ight Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"List Table 2 A=
ccent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"List Table 3 A=
ccent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"List Table 4 A=
ccent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"List Table 5 D=
ark Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"List Table 6 C=
olorful Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"List Table 7 C=
olorful Accent 3"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"List Table 1 L=
ight Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"List Table 2 A=
ccent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"List Table 3 A=
ccent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"List Table 4 A=
ccent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"List Table 5 D=
ark Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"List Table 6 C=
olorful Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"List Table 7 C=
olorful Accent 4"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"List Table 1 L=
ight Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"List Table 2 A=
ccent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"List Table 3 A=
ccent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"List Table 4 A=
ccent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"List Table 5 D=
ark Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"List Table 6 C=
olorful Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"List Table 7 C=
olorful Accent 5"/>
<w:LsdException Locked=3D"false" Priority=3D"46" Name=3D"List Table 1 L=
ight Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"47" Name=3D"List Table 2 A=
ccent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"48" Name=3D"List Table 3 A=
ccent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"49" Name=3D"List Table 4 A=
ccent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"50" Name=3D"List Table 5 D=
ark Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"51" Name=3D"List Table 6 C=
olorful Accent 6"/>
<w:LsdException Locked=3D"false" Priority=3D"52" Name=3D"List Table 7 C=
olorful Accent 6"/>
</w:LatentStyles>
</xml><![endif]--><style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:0;
mso-generic-font-family:roman;
mso-font-pitch:variable;
mso-font-signature:-536870145 1107305727 0 0 415 0;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;
mso-font-alt:"Times New Roman";
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:-536870145 1073786111 1 0 415 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-unhide:no;
mso-style-qformat:yes;
mso-style-parent:"";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:"Calibri",sans-serif;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Calibri;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
a:link, span.MsoHyperlink
{mso-style-noshow:yes;
mso-style-priority:99;
color:blue;
mso-themecolor:hyperlink;
text-decoration:underline;
text-underline:single;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-noshow:yes;
mso-style-priority:99;
color:purple;
mso-themecolor:followedhyperlink;
text-decoration:underline;
text-underline:single;}
p.MsoPlainText, li.MsoPlainText, div.MsoPlainText
{mso-style-noshow:yes;
mso-style-priority:99;
mso-style-link:"Plain Text Char";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:11.0pt;
mso-bidi-font-size:10.5pt;
font-family:"Calibri",sans-serif;
mso-fareast-font-family:Calibri;
mso-fareast-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
span.PlainTextChar
{mso-style-name:"Plain Text Char";
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-unhide:no;
mso-style-locked:yes;
mso-style-link:"Plain Text";
mso-bidi-font-size:10.5pt;
font-family:"Calibri",sans-serif;
mso-ascii-font-family:Calibri;
mso-hansi-font-family:Calibri;}
span.EmailStyle19
{mso-style-type:personal-compose;
mso-style-noshow:yes;
mso-style-unhide:no;}
.MsoChpDefault
{mso-style-type:export-only;
mso-default-props:yes;
font-size:10.0pt;
mso-ansi-font-size:10.0pt;
mso-bidi-font-size:10.0pt;
font-family:"Calibri",sans-serif;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Calibri;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;
mso-header-margin:.5in;
mso-footer-margin:.5in;
mso-paper-source:0;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 10]><style>/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:"";
mso-padding-alt:0in 5.4pt 0in 5.4pt;
mso-para-margin:0in;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Calibri",sans-serif;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;}
</style><![endif]--><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext=3D"edit" spidmax=3D"1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext=3D"edit">
<o:idmap v:ext=3D"edit" data=3D"1" />
</o:shapelayout></xml><![endif]--></head><body lang=3DEN-US link=3Dblue=
vlink=3Dpurple style=3D'tab-interval:.5in'><div class=3DWordSection1><=
p class=3DMsoPlainText>Simple, unadorned test email generated by Outloo=
k 2010. It is in HTML format, but no special formatting has been chosen=
. I=E2=80=99m going to save this as a draft and then manually drop it i=
nto the Inbox for scraping by Redmine 3.0.2.<o:p></o:p></p></div></body=
></html>
--Mark=_539924359269962179476--

View File

@@ -0,0 +1,65 @@
From: "John Smith" <jsmith@somenet.foo>
To: redmine <r@MYCOMPANYNAME.com>
Subject: Upgrade Redmine to 3.0.x
Thread-Topic: Upgrade Redmine to 3.0.x
Thread-Index: AQHQknBe94y5Or7Yl02JransMRF41p2Dv6Hu
Date: Tue, 19 May 2015 16:27:43 -0400
Message-ID: <A2D341A8808F024CAFA63F1287B9929CF1BC440F@EMBX01.exch.local>
Accept-Language: en-US
Content-Language: en-US
X-MS-Exchange-Organization-AuthAs: Internal
X-MS-Exchange-Organization-AuthMechanism: 04
X-MS-Exchange-Organization-AuthSource: EHUB01.exch.local
X-MS-Has-Attach:
X-MS-Exchange-Organization-SCL: -1
X-MS-TNEF-Correlator:
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
<html dir=3D"ltr">
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Diso-8859-=
1">
<style>=0A=
<!--=0A=
body=0A=
{font-family:Verdana,sans-serif;=0A=
font-size:0.8em;=0A=
color:#484848}=0A=
h1, h2, h3=0A=
{font-family:"Trebuchet MS",Verdana,sans-serif;=0A=
margin:0px}=0A=
h1=0A=
{font-size:1.2em}=0A=
h2, h3=0A=
{font-size:1.1em}=0A=
a, a:link, a:visited=0A=
{color:#2A5685}=0A=
a:hover, a:active=0A=
{color:#c61a1a}=0A=
fieldset.attachments=0A=
{border-width:1px 0 0 0}=0A=
hr=0A=
{width:100%;=0A=
height:1px;=0A=
background:#ccc;=0A=
border:0}=0A=
span.footer=0A=
{font-size:0.8em;=0A=
font-style:italic}=0A=
-->=0A=
</style><style id=3D"owaParaStyle" type=3D"text/css">P {margin-top:0;margin=
-bottom:0;}</style>
</head>
<body ocsi=3D"0" fpstyle=3D"1">
<div style=3D"direction: ltr;font-family: Tahoma;color: #000000;font-size: =
10pt;">A mess.<br>
<div><br>
<div style=3D"font-family:Tahoma; font-size:13px">--Geoff Maciolek<br>
MYCOMPANYNAME, LLC<br>
</div>
</div>
</div>
</body>
</html>

View File

@@ -15,8 +15,9 @@ Content-Transfer-Encoding: 7bit
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html> <html>
<head> <head>
<style>p {font-size:12.0pt;}</style>
</head> </head>
<body bgcolor="#ffffff" text="#000000"> <body bgcolor="#ffffff" text="#000000">
This is a <b>html-only</b> email.<br> This is a <b>html-only</b> email.<br><h1>With a title</h1><p>and a paragraph.</p>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,30 @@
# Redmine - project management software
# Copyright (C) 2006-2015 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../../../../test_helper', __FILE__)
class Redmine::WikiFormatting::HtmlParserTest < ActiveSupport::TestCase
def setup
@parser = Redmine::WikiFormatting::HtmlParser
end
def test_convert_line_breaks
assert_equal "A html snippet with\na new line.",
@parser.to_text('<p>A html snippet with<br>a new line.</p>')
end
end

View File

@@ -0,0 +1,30 @@
# Redmine - project management software
# Copyright (C) 2006-2015 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../../../../test_helper', __FILE__)
class Redmine::WikiFormatting::MarkdownHtmlParserTest < ActiveSupport::TestCase
def setup
@parser = Redmine::WikiFormatting::Markdown::HtmlParser
end
def test_should_convert_tags
assert_equal 'A **simple** html snippet.',
@parser.to_text('<p>A <b>simple</b> html snippet.</p>')
end
end

View File

@@ -0,0 +1,30 @@
# Redmine - project management software
# Copyright (C) 2006-2015 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../../../../test_helper', __FILE__)
class Redmine::WikiFormatting::TextileHtmlParserTest < ActiveSupport::TestCase
def setup
@parser = Redmine::WikiFormatting::Textile::HtmlParser
end
def test_should_convert_tags
assert_equal 'A *simple* html snippet.',
@parser.to_text('<p>A <b>simple</b> html snippet.</p>')
end
end

View File

@@ -797,13 +797,33 @@ class MailHandlerTest < ActiveSupport::TestCase
assert_equal Message.find(1), m.parent assert_equal Message.find(1), m.parent
end end
def test_should_strip_tags_of_html_only_emails def test_should_convert_tags_of_html_only_emails
issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'}) with_settings :text_formatting => 'textile' do
issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
assert issue.is_a?(Issue)
assert !issue.new_record?
issue.reload
assert_equal 'HTML email', issue.subject
assert_equal "This is a *html-only* email.\r\n\r\nh1. With a title\r\n\r\nand a paragraph.", issue.description
end
end
def test_should_handle_outlook_web_access_2010_html_only
issue = submit_email('outlook_web_access_2010_html_only.eml', :issue => {:project => 'ecookbook'})
assert issue.is_a?(Issue) assert issue.is_a?(Issue)
assert !issue.new_record?
issue.reload issue.reload
assert_equal 'HTML email', issue.subject assert_equal 'Upgrade Redmine to 3.0.x', issue.subject
assert_equal 'This is a html-only email.', issue.description assert_equal "A mess.\r\n\r\n--Geoff Maciolek\r\nMYCOMPANYNAME, LLC", issue.description
end
def test_should_handle_outlook_2010_html_only
issue = submit_email('outlook_2010_html_only.eml', :issue => {:project => 'ecookbook'})
assert issue.is_a?(Issue)
issue.reload
assert_equal 'Test email', issue.subject
assert_equal "Simple, unadorned test email generated by Outlook 2010. It is in HTML format, but" +
" no special formatting has been chosen. Im going to save this as a draft and then manually" +
" drop it into the Inbox for scraping by Redmine 3.0.2.", issue.description
end end
test "truncate emails with no setting should add the entire email into the issue" do test "truncate emails with no setting should add the entire email into the issue" do